From 357498803d7b1b54224c30abd7c17607f4a14e0d Mon Sep 17 00:00:00 2001 From: Garry Tan Date: Fri, 14 Aug 2026 13:03:08 -0700 Subject: [PATCH] =?UTF-8?q?feat(skills):=20third-party=20web-actions=20con?= =?UTF-8?q?tract=20=E2=80=94=20offer=20to=20drive=20vendor-site=20steps,?= =?UTF-8?q?=20never=20just=20dump=20a=20manual=20list?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When a workflow needs something done on an external website the user controls (register an API key, create a vendor account, configure a dashboard/webhook/OAuth app), five skills (ship, spec, office-hours, setup-deploy, land-and-deploy) now follow one contract: offer to drive it in a visible browser via gstack's own stack ($B headed + handoff/resume, GStack Browser) behind ONE per-task consent question naming the exact site and actions; passwords, payment, CAPTCHA, and identity stay user-performed; captured secrets go to owner-only files or the user's secret store, never chat/logs/history; and the credential is verified with one non-mutating API call before any success claim — dashboards show masked placeholders, and a 401 catches them. Declining yields manual steps and a blocked-on-user mark; nothing new is ever installed to close the gap. New resolver token {{THIRD_PARTY_ACTIONS}} (adapted from the fork's contract — their Aside-browser detection swapped for our own driver stack; MIT portions noted). Parity guards bumped with growth itemized (ship 1.10->1.12 at measured 1.103x; office-hours skeleton 101K / 1.09 at measured 1.079x); ship goldens refreshed. Ported from time-attack/gstack (GStack 2), driver adaptation ours. Co-authored-by: Sina Matian Co-Authored-By: Claude Fable 5 --- land-and-deploy/SKILL.md | 14 +++++++++ land-and-deploy/SKILL.md.tmpl | 2 ++ office-hours/SKILL.md | 14 +++++++++ office-hours/SKILL.md.tmpl | 2 ++ scripts/resolvers/index.ts | 2 ++ scripts/resolvers/third-party-actions.ts | 33 ++++++++++++++++++++++ setup-deploy/SKILL.md | 14 +++++++++ setup-deploy/SKILL.md.tmpl | 2 ++ ship/SKILL.md | 14 +++++++++ ship/SKILL.md.tmpl | 2 ++ spec/SKILL.md | 14 +++++++++ spec/SKILL.md.tmpl | 2 ++ test/fixtures/golden/claude-ship-SKILL.md | 14 +++++++++ test/fixtures/golden/codex-ship-SKILL.md | 14 +++++++++ test/fixtures/golden/factory-ship-SKILL.md | 14 +++++++++ test/helpers/carve-guards.ts | 15 ++++++---- 16 files changed, 167 insertions(+), 5 deletions(-) create mode 100644 scripts/resolvers/third-party-actions.ts diff --git a/land-and-deploy/SKILL.md b/land-and-deploy/SKILL.md index b0bf7f662..0183eed28 100644 --- a/land-and-deploy/SKILL.md +++ b/land-and-deploy/SKILL.md @@ -795,6 +795,20 @@ Replace `SKILL_NAME`, `OUTCOME`, and `USED_BROWSE` before running. Skills that run plan reviews (`/plan-*-review`, `/codex review`) include the EXIT PLAN MODE GATE blocking checklist at the end of the skill, which verifies the plan file ends with `## GSTACK REVIEW REPORT` before ExitPlanMode is called. Skills that don't run plan reviews (operational skills like `/ship`, `/qa`, `/review`) typically don't operate in plan mode and have no review report to verify; this footer is a no-op for them. Writing the plan file is the one edit allowed in plan mode. +## Third-Party Web Actions + +A step sometimes requires action on an external website the user controls: registering an API key, creating a vendor or developer account, configuring a dashboard, webhook, OAuth app, billing plan, or domain verification. This contract governs that moment. It grants no new browsing authority — the AskUserQuestion format and one-way-door rules remain binding, including approval before anything that spends money. + +1. **Never hand the user a manual step list for a third-party site without first offering to drive it.** The driver is gstack's own browser stack: `$B` headed mode with handoff/resume for the human-only moments (see the /browse skill), or GStack Browser when installed. Never install new tooling to close the gap, and never treat tooling presence as consent to browse. + +2. **One explicit question before any browsing.** STOP and name the exact site and the exact actions (for example "create a test-mode API token in the Duffel dashboard"), then offer: A) I drive it now in a visible browser — you take over for sign-in and approvals, B) manual instructions, C) defer. The selection is per-task consent; never persist it as standing permission and never infer it from an earlier task. + +3. **When driving, touch only the named site and actions.** Password entry, new-account credential choice, payment, CAPTCHA, and identity verification are user-performed: hand off (`$B handoff`) and wait instead of acting. Prefer credential flows that never expose the secret to the agent, such as password-manager autofill or the dashboard's own copy button used by the human. + +4. **A captured secret never appears in chat output, logs, or shell history.** Write it to a user-approved local file with owner-only permissions (0600) or the user's secret store, and keep generated destinations out of version control. Dashboard fields are often masked placeholders — verify the captured credential with ONE non-mutating API call before claiming success; a 401 here has caught a placeholder masquerading as a key. + +5. **If the user declines or defers, or no browser is usable,** provide the manual steps and mark the step blocked on the user. Do not recommend or install new products to close the gap. + ## SETUP (run this check BEFORE any browse command) ```bash diff --git a/land-and-deploy/SKILL.md.tmpl b/land-and-deploy/SKILL.md.tmpl index 98976ad02..6788bc5c2 100644 --- a/land-and-deploy/SKILL.md.tmpl +++ b/land-and-deploy/SKILL.md.tmpl @@ -22,6 +22,8 @@ triggers: {{PREAMBLE}} +{{THIRD_PARTY_ACTIONS}} + {{BROWSE_SETUP}} {{BASE_BRANCH_DETECT}} diff --git a/office-hours/SKILL.md b/office-hours/SKILL.md index d81d89f2d..77d04863d 100644 --- a/office-hours/SKILL.md +++ b/office-hours/SKILL.md @@ -833,6 +833,20 @@ Replace `SKILL_NAME`, `OUTCOME`, and `USED_BROWSE` before running. Skills that run plan reviews (`/plan-*-review`, `/codex review`) include the EXIT PLAN MODE GATE blocking checklist at the end of the skill, which verifies the plan file ends with `## GSTACK REVIEW REPORT` before ExitPlanMode is called. Skills that don't run plan reviews (operational skills like `/ship`, `/qa`, `/review`) typically don't operate in plan mode and have no review report to verify; this footer is a no-op for them. Writing the plan file is the one edit allowed in plan mode. +## Third-Party Web Actions + +A step sometimes requires action on an external website the user controls: registering an API key, creating a vendor or developer account, configuring a dashboard, webhook, OAuth app, billing plan, or domain verification. This contract governs that moment. It grants no new browsing authority — the AskUserQuestion format and one-way-door rules remain binding, including approval before anything that spends money. + +1. **Never hand the user a manual step list for a third-party site without first offering to drive it.** The driver is gstack's own browser stack: `$B` headed mode with handoff/resume for the human-only moments (see the /browse skill), or GStack Browser when installed. Never install new tooling to close the gap, and never treat tooling presence as consent to browse. + +2. **One explicit question before any browsing.** STOP and name the exact site and the exact actions (for example "create a test-mode API token in the Duffel dashboard"), then offer: A) I drive it now in a visible browser — you take over for sign-in and approvals, B) manual instructions, C) defer. The selection is per-task consent; never persist it as standing permission and never infer it from an earlier task. + +3. **When driving, touch only the named site and actions.** Password entry, new-account credential choice, payment, CAPTCHA, and identity verification are user-performed: hand off (`$B handoff`) and wait instead of acting. Prefer credential flows that never expose the secret to the agent, such as password-manager autofill or the dashboard's own copy button used by the human. + +4. **A captured secret never appears in chat output, logs, or shell history.** Write it to a user-approved local file with owner-only permissions (0600) or the user's secret store, and keep generated destinations out of version control. Dashboard fields are often masked placeholders — verify the captured credential with ONE non-mutating API call before claiming success; a 401 here has caught a placeholder masquerading as a key. + +5. **If the user declines or defers, or no browser is usable,** provide the manual steps and mark the step blocked on the user. Do not recommend or install new products to close the gap. + ## SETUP (run this check BEFORE any browse command) ```bash diff --git a/office-hours/SKILL.md.tmpl b/office-hours/SKILL.md.tmpl index 8568fe73c..80deddab6 100644 --- a/office-hours/SKILL.md.tmpl +++ b/office-hours/SKILL.md.tmpl @@ -59,6 +59,8 @@ gbrain: {{PREAMBLE}} +{{THIRD_PARTY_ACTIONS}} + {{BROWSE_SETUP}} # YC Office Hours diff --git a/scripts/resolvers/index.ts b/scripts/resolvers/index.ts index aa598b867..148cdaca3 100644 --- a/scripts/resolvers/index.ts +++ b/scripts/resolvers/index.ts @@ -36,12 +36,14 @@ import { generateMakePdfSetup } from './make-pdf'; import { generateTasksSectionEmit, generateTasksSectionAggregate } from './tasks-section'; import { SECTION, SECTION_INDEX } from './sections'; import { generateRedactTaxonomyTable, generateRedactInvocationBlock } from './redact-doc'; +import { generateThirdPartyActions } from './third-party-actions'; export const RESOLVERS: Record = { SLUG_EVAL: generateSlugEval, SLUG_SETUP: generateSlugSetup, REDACT_TAXONOMY_TABLE: generateRedactTaxonomyTable, REDACT_INVOCATION_BLOCK: generateRedactInvocationBlock, + THIRD_PARTY_ACTIONS: generateThirdPartyActions, COMMAND_REFERENCE: generateCommandReference, SNAPSHOT_FLAGS: generateSnapshotFlags, PREAMBLE: generatePreamble, diff --git a/scripts/resolvers/third-party-actions.ts b/scripts/resolvers/third-party-actions.ts new file mode 100644 index 000000000..f325ac6ec --- /dev/null +++ b/scripts/resolvers/third-party-actions.ts @@ -0,0 +1,33 @@ +/** + * {{THIRD_PARTY_ACTIONS}} — the third-party web actions contract. + * + * Governs the moment a workflow needs something done on an external website + * the user controls: registering an API key, creating a vendor account, + * configuring a dashboard, webhook, OAuth app, billing plan, or domain + * verification. Instead of dumping a manual step list, the skill offers to + * drive the browser (consent-gated, secrets never in chat) and verifies the + * captured credential before claiming success. + * + * Adapted from time-attack/gstack's THIRD-PARTY-ACTIONS.md (GStack 2, MIT): + * the fork detected the Aside AI browser; we drive our own stack — browse + * headed mode + handoff/resume ($B), GStack Browser, and pair-agent. + * Portions copyright (c) 2026 Sina Matian, time-attack/gstack, MIT. + */ + +import type { TemplateContext } from './types'; + +export function generateThirdPartyActions(_ctx: TemplateContext): string { + return `## Third-Party Web Actions + +A step sometimes requires action on an external website the user controls: registering an API key, creating a vendor or developer account, configuring a dashboard, webhook, OAuth app, billing plan, or domain verification. This contract governs that moment. It grants no new browsing authority — the AskUserQuestion format and one-way-door rules remain binding, including approval before anything that spends money. + +1. **Never hand the user a manual step list for a third-party site without first offering to drive it.** The driver is gstack's own browser stack: \`$B\` headed mode with handoff/resume for the human-only moments (see the /browse skill), or GStack Browser when installed. Never install new tooling to close the gap, and never treat tooling presence as consent to browse. + +2. **One explicit question before any browsing.** STOP and name the exact site and the exact actions (for example "create a test-mode API token in the Duffel dashboard"), then offer: A) I drive it now in a visible browser — you take over for sign-in and approvals, B) manual instructions, C) defer. The selection is per-task consent; never persist it as standing permission and never infer it from an earlier task. + +3. **When driving, touch only the named site and actions.** Password entry, new-account credential choice, payment, CAPTCHA, and identity verification are user-performed: hand off (\`$B handoff\`) and wait instead of acting. Prefer credential flows that never expose the secret to the agent, such as password-manager autofill or the dashboard's own copy button used by the human. + +4. **A captured secret never appears in chat output, logs, or shell history.** Write it to a user-approved local file with owner-only permissions (0600) or the user's secret store, and keep generated destinations out of version control. Dashboard fields are often masked placeholders — verify the captured credential with ONE non-mutating API call before claiming success; a 401 here has caught a placeholder masquerading as a key. + +5. **If the user declines or defers, or no browser is usable,** provide the manual steps and mark the step blocked on the user. Do not recommend or install new products to close the gap.`; +} diff --git a/setup-deploy/SKILL.md b/setup-deploy/SKILL.md index fcc4b7a9b..f0b6e5a61 100644 --- a/setup-deploy/SKILL.md +++ b/setup-deploy/SKILL.md @@ -781,6 +781,20 @@ Replace `SKILL_NAME`, `OUTCOME`, and `USED_BROWSE` before running. Skills that run plan reviews (`/plan-*-review`, `/codex review`) include the EXIT PLAN MODE GATE blocking checklist at the end of the skill, which verifies the plan file ends with `## GSTACK REVIEW REPORT` before ExitPlanMode is called. Skills that don't run plan reviews (operational skills like `/ship`, `/qa`, `/review`) typically don't operate in plan mode and have no review report to verify; this footer is a no-op for them. Writing the plan file is the one edit allowed in plan mode. +## Third-Party Web Actions + +A step sometimes requires action on an external website the user controls: registering an API key, creating a vendor or developer account, configuring a dashboard, webhook, OAuth app, billing plan, or domain verification. This contract governs that moment. It grants no new browsing authority — the AskUserQuestion format and one-way-door rules remain binding, including approval before anything that spends money. + +1. **Never hand the user a manual step list for a third-party site without first offering to drive it.** The driver is gstack's own browser stack: `$B` headed mode with handoff/resume for the human-only moments (see the /browse skill), or GStack Browser when installed. Never install new tooling to close the gap, and never treat tooling presence as consent to browse. + +2. **One explicit question before any browsing.** STOP and name the exact site and the exact actions (for example "create a test-mode API token in the Duffel dashboard"), then offer: A) I drive it now in a visible browser — you take over for sign-in and approvals, B) manual instructions, C) defer. The selection is per-task consent; never persist it as standing permission and never infer it from an earlier task. + +3. **When driving, touch only the named site and actions.** Password entry, new-account credential choice, payment, CAPTCHA, and identity verification are user-performed: hand off (`$B handoff`) and wait instead of acting. Prefer credential flows that never expose the secret to the agent, such as password-manager autofill or the dashboard's own copy button used by the human. + +4. **A captured secret never appears in chat output, logs, or shell history.** Write it to a user-approved local file with owner-only permissions (0600) or the user's secret store, and keep generated destinations out of version control. Dashboard fields are often masked placeholders — verify the captured credential with ONE non-mutating API call before claiming success; a 401 here has caught a placeholder masquerading as a key. + +5. **If the user declines or defers, or no browser is usable,** provide the manual steps and mark the step blocked on the user. Do not recommend or install new products to close the gap. + # /setup-deploy — Configure Deployment for gstack You are helping the user configure their deployment so `/land-and-deploy` works diff --git a/setup-deploy/SKILL.md.tmpl b/setup-deploy/SKILL.md.tmpl index 587a993c0..5630f294b 100644 --- a/setup-deploy/SKILL.md.tmpl +++ b/setup-deploy/SKILL.md.tmpl @@ -25,6 +25,8 @@ allowed-tools: {{PREAMBLE}} +{{THIRD_PARTY_ACTIONS}} + # /setup-deploy — Configure Deployment for gstack You are helping the user configure their deployment so `/land-and-deploy` works diff --git a/ship/SKILL.md b/ship/SKILL.md index 4730797b0..20facb7cf 100644 --- a/ship/SKILL.md +++ b/ship/SKILL.md @@ -800,6 +800,20 @@ Replace `SKILL_NAME`, `OUTCOME`, and `USED_BROWSE` before running. Skills that run plan reviews (`/plan-*-review`, `/codex review`) include the EXIT PLAN MODE GATE blocking checklist at the end of the skill, which verifies the plan file ends with `## GSTACK REVIEW REPORT` before ExitPlanMode is called. Skills that don't run plan reviews (operational skills like `/ship`, `/qa`, `/review`) typically don't operate in plan mode and have no review report to verify; this footer is a no-op for them. Writing the plan file is the one edit allowed in plan mode. +## Third-Party Web Actions + +A step sometimes requires action on an external website the user controls: registering an API key, creating a vendor or developer account, configuring a dashboard, webhook, OAuth app, billing plan, or domain verification. This contract governs that moment. It grants no new browsing authority — the AskUserQuestion format and one-way-door rules remain binding, including approval before anything that spends money. + +1. **Never hand the user a manual step list for a third-party site without first offering to drive it.** The driver is gstack's own browser stack: `$B` headed mode with handoff/resume for the human-only moments (see the /browse skill), or GStack Browser when installed. Never install new tooling to close the gap, and never treat tooling presence as consent to browse. + +2. **One explicit question before any browsing.** STOP and name the exact site and the exact actions (for example "create a test-mode API token in the Duffel dashboard"), then offer: A) I drive it now in a visible browser — you take over for sign-in and approvals, B) manual instructions, C) defer. The selection is per-task consent; never persist it as standing permission and never infer it from an earlier task. + +3. **When driving, touch only the named site and actions.** Password entry, new-account credential choice, payment, CAPTCHA, and identity verification are user-performed: hand off (`$B handoff`) and wait instead of acting. Prefer credential flows that never expose the secret to the agent, such as password-manager autofill or the dashboard's own copy button used by the human. + +4. **A captured secret never appears in chat output, logs, or shell history.** Write it to a user-approved local file with owner-only permissions (0600) or the user's secret store, and keep generated destinations out of version control. Dashboard fields are often masked placeholders — verify the captured credential with ONE non-mutating API call before claiming success; a 401 here has caught a placeholder masquerading as a key. + +5. **If the user declines or defers, or no browser is usable,** provide the manual steps and mark the step blocked on the user. Do not recommend or install new products to close the gap. + ## Step 0: Detect platform and base branch First, detect the git hosting platform from the remote URL: diff --git a/ship/SKILL.md.tmpl b/ship/SKILL.md.tmpl index bd50a20c8..106ec703b 100644 --- a/ship/SKILL.md.tmpl +++ b/ship/SKILL.md.tmpl @@ -28,6 +28,8 @@ triggers: {{PREAMBLE}} +{{THIRD_PARTY_ACTIONS}} + {{BASE_BRANCH_DETECT}} {{GBRAIN_CONTEXT_LOAD}} diff --git a/spec/SKILL.md b/spec/SKILL.md index d5f3aeff1..49355703b 100644 --- a/spec/SKILL.md +++ b/spec/SKILL.md @@ -797,6 +797,20 @@ Replace `SKILL_NAME`, `OUTCOME`, and `USED_BROWSE` before running. Skills that run plan reviews (`/plan-*-review`, `/codex review`) include the EXIT PLAN MODE GATE blocking checklist at the end of the skill, which verifies the plan file ends with `## GSTACK REVIEW REPORT` before ExitPlanMode is called. Skills that don't run plan reviews (operational skills like `/ship`, `/qa`, `/review`) typically don't operate in plan mode and have no review report to verify; this footer is a no-op for them. Writing the plan file is the one edit allowed in plan mode. +## Third-Party Web Actions + +A step sometimes requires action on an external website the user controls: registering an API key, creating a vendor or developer account, configuring a dashboard, webhook, OAuth app, billing plan, or domain verification. This contract governs that moment. It grants no new browsing authority — the AskUserQuestion format and one-way-door rules remain binding, including approval before anything that spends money. + +1. **Never hand the user a manual step list for a third-party site without first offering to drive it.** The driver is gstack's own browser stack: `$B` headed mode with handoff/resume for the human-only moments (see the /browse skill), or GStack Browser when installed. Never install new tooling to close the gap, and never treat tooling presence as consent to browse. + +2. **One explicit question before any browsing.** STOP and name the exact site and the exact actions (for example "create a test-mode API token in the Duffel dashboard"), then offer: A) I drive it now in a visible browser — you take over for sign-in and approvals, B) manual instructions, C) defer. The selection is per-task consent; never persist it as standing permission and never infer it from an earlier task. + +3. **When driving, touch only the named site and actions.** Password entry, new-account credential choice, payment, CAPTCHA, and identity verification are user-performed: hand off (`$B handoff`) and wait instead of acting. Prefer credential flows that never expose the secret to the agent, such as password-manager autofill or the dashboard's own copy button used by the human. + +4. **A captured secret never appears in chat output, logs, or shell history.** Write it to a user-approved local file with owner-only permissions (0600) or the user's secret store, and keep generated destinations out of version control. Dashboard fields are often masked placeholders — verify the captured credential with ONE non-mutating API call before claiming success; a 401 here has caught a placeholder masquerading as a key. + +5. **If the user declines or defers, or no browser is usable,** provide the manual steps and mark the step blocked on the user. Do not recommend or install new products to close the gap. + # /spec — Author a Backlog-Ready Spec (issue + optional agent spawn) You are a **principal engineer who refuses to let ambiguous work into the backlog**. diff --git a/spec/SKILL.md.tmpl b/spec/SKILL.md.tmpl index 6c0c14e1b..8bec22c68 100644 --- a/spec/SKILL.md.tmpl +++ b/spec/SKILL.md.tmpl @@ -24,6 +24,8 @@ triggers: {{PREAMBLE}} +{{THIRD_PARTY_ACTIONS}} + # /spec — Author a Backlog-Ready Spec (issue + optional agent spawn) You are a **principal engineer who refuses to let ambiguous work into the backlog**. diff --git a/test/fixtures/golden/claude-ship-SKILL.md b/test/fixtures/golden/claude-ship-SKILL.md index 4730797b0..20facb7cf 100644 --- a/test/fixtures/golden/claude-ship-SKILL.md +++ b/test/fixtures/golden/claude-ship-SKILL.md @@ -800,6 +800,20 @@ Replace `SKILL_NAME`, `OUTCOME`, and `USED_BROWSE` before running. Skills that run plan reviews (`/plan-*-review`, `/codex review`) include the EXIT PLAN MODE GATE blocking checklist at the end of the skill, which verifies the plan file ends with `## GSTACK REVIEW REPORT` before ExitPlanMode is called. Skills that don't run plan reviews (operational skills like `/ship`, `/qa`, `/review`) typically don't operate in plan mode and have no review report to verify; this footer is a no-op for them. Writing the plan file is the one edit allowed in plan mode. +## Third-Party Web Actions + +A step sometimes requires action on an external website the user controls: registering an API key, creating a vendor or developer account, configuring a dashboard, webhook, OAuth app, billing plan, or domain verification. This contract governs that moment. It grants no new browsing authority — the AskUserQuestion format and one-way-door rules remain binding, including approval before anything that spends money. + +1. **Never hand the user a manual step list for a third-party site without first offering to drive it.** The driver is gstack's own browser stack: `$B` headed mode with handoff/resume for the human-only moments (see the /browse skill), or GStack Browser when installed. Never install new tooling to close the gap, and never treat tooling presence as consent to browse. + +2. **One explicit question before any browsing.** STOP and name the exact site and the exact actions (for example "create a test-mode API token in the Duffel dashboard"), then offer: A) I drive it now in a visible browser — you take over for sign-in and approvals, B) manual instructions, C) defer. The selection is per-task consent; never persist it as standing permission and never infer it from an earlier task. + +3. **When driving, touch only the named site and actions.** Password entry, new-account credential choice, payment, CAPTCHA, and identity verification are user-performed: hand off (`$B handoff`) and wait instead of acting. Prefer credential flows that never expose the secret to the agent, such as password-manager autofill or the dashboard's own copy button used by the human. + +4. **A captured secret never appears in chat output, logs, or shell history.** Write it to a user-approved local file with owner-only permissions (0600) or the user's secret store, and keep generated destinations out of version control. Dashboard fields are often masked placeholders — verify the captured credential with ONE non-mutating API call before claiming success; a 401 here has caught a placeholder masquerading as a key. + +5. **If the user declines or defers, or no browser is usable,** provide the manual steps and mark the step blocked on the user. Do not recommend or install new products to close the gap. + ## Step 0: Detect platform and base branch First, detect the git hosting platform from the remote URL: diff --git a/test/fixtures/golden/codex-ship-SKILL.md b/test/fixtures/golden/codex-ship-SKILL.md index b91468818..57bcd3039 100644 --- a/test/fixtures/golden/codex-ship-SKILL.md +++ b/test/fixtures/golden/codex-ship-SKILL.md @@ -786,6 +786,20 @@ Replace `SKILL_NAME`, `OUTCOME`, and `USED_BROWSE` before running. Skills that run plan reviews (`/plan-*-review`, `/codex review`) include the EXIT PLAN MODE GATE blocking checklist at the end of the skill, which verifies the plan file ends with `## GSTACK REVIEW REPORT` before ExitPlanMode is called. Skills that don't run plan reviews (operational skills like `/ship`, `/qa`, `/review`) typically don't operate in plan mode and have no review report to verify; this footer is a no-op for them. Writing the plan file is the one edit allowed in plan mode. +## Third-Party Web Actions + +A step sometimes requires action on an external website the user controls: registering an API key, creating a vendor or developer account, configuring a dashboard, webhook, OAuth app, billing plan, or domain verification. This contract governs that moment. It grants no new browsing authority — the AskUserQuestion format and one-way-door rules remain binding, including approval before anything that spends money. + +1. **Never hand the user a manual step list for a third-party site without first offering to drive it.** The driver is gstack's own browser stack: `$B` headed mode with handoff/resume for the human-only moments (see the /browse skill), or GStack Browser when installed. Never install new tooling to close the gap, and never treat tooling presence as consent to browse. + +2. **One explicit question before any browsing.** STOP and name the exact site and the exact actions (for example "create a test-mode API token in the Duffel dashboard"), then offer: A) I drive it now in a visible browser — you take over for sign-in and approvals, B) manual instructions, C) defer. The selection is per-task consent; never persist it as standing permission and never infer it from an earlier task. + +3. **When driving, touch only the named site and actions.** Password entry, new-account credential choice, payment, CAPTCHA, and identity verification are user-performed: hand off (`$B handoff`) and wait instead of acting. Prefer credential flows that never expose the secret to the agent, such as password-manager autofill or the dashboard's own copy button used by the human. + +4. **A captured secret never appears in chat output, logs, or shell history.** Write it to a user-approved local file with owner-only permissions (0600) or the user's secret store, and keep generated destinations out of version control. Dashboard fields are often masked placeholders — verify the captured credential with ONE non-mutating API call before claiming success; a 401 here has caught a placeholder masquerading as a key. + +5. **If the user declines or defers, or no browser is usable,** provide the manual steps and mark the step blocked on the user. Do not recommend or install new products to close the gap. + ## Step 0: Detect platform and base branch First, detect the git hosting platform from the remote URL: diff --git a/test/fixtures/golden/factory-ship-SKILL.md b/test/fixtures/golden/factory-ship-SKILL.md index 2d1dacd5f..64dc68e34 100644 --- a/test/fixtures/golden/factory-ship-SKILL.md +++ b/test/fixtures/golden/factory-ship-SKILL.md @@ -788,6 +788,20 @@ Replace `SKILL_NAME`, `OUTCOME`, and `USED_BROWSE` before running. Skills that run plan reviews (`/plan-*-review`, `/codex review`) include the EXIT PLAN MODE GATE blocking checklist at the end of the skill, which verifies the plan file ends with `## GSTACK REVIEW REPORT` before ExitPlanMode is called. Skills that don't run plan reviews (operational skills like `/ship`, `/qa`, `/review`) typically don't operate in plan mode and have no review report to verify; this footer is a no-op for them. Writing the plan file is the one edit allowed in plan mode. +## Third-Party Web Actions + +A step sometimes requires action on an external website the user controls: registering an API key, creating a vendor or developer account, configuring a dashboard, webhook, OAuth app, billing plan, or domain verification. This contract governs that moment. It grants no new browsing authority — the AskUserQuestion format and one-way-door rules remain binding, including approval before anything that spends money. + +1. **Never hand the user a manual step list for a third-party site without first offering to drive it.** The driver is gstack's own browser stack: `$B` headed mode with handoff/resume for the human-only moments (see the /browse skill), or GStack Browser when installed. Never install new tooling to close the gap, and never treat tooling presence as consent to browse. + +2. **One explicit question before any browsing.** STOP and name the exact site and the exact actions (for example "create a test-mode API token in the Duffel dashboard"), then offer: A) I drive it now in a visible browser — you take over for sign-in and approvals, B) manual instructions, C) defer. The selection is per-task consent; never persist it as standing permission and never infer it from an earlier task. + +3. **When driving, touch only the named site and actions.** Password entry, new-account credential choice, payment, CAPTCHA, and identity verification are user-performed: hand off (`$B handoff`) and wait instead of acting. Prefer credential flows that never expose the secret to the agent, such as password-manager autofill or the dashboard's own copy button used by the human. + +4. **A captured secret never appears in chat output, logs, or shell history.** Write it to a user-approved local file with owner-only permissions (0600) or the user's secret store, and keep generated destinations out of version control. Dashboard fields are often masked placeholders — verify the captured credential with ONE non-mutating API call before claiming success; a 401 here has caught a placeholder masquerading as a key. + +5. **If the user declines or defers, or no browser is usable,** provide the manual steps and mark the step blocked on the user. Do not recommend or install new products to close the gap. + ## Step 0: Detect platform and base branch First, detect the git hosting platform from the remote URL: diff --git a/test/helpers/carve-guards.ts b/test/helpers/carve-guards.ts index dc2f8451f..0f3de743a 100644 --- a/test/helpers/carve-guards.ts +++ b/test/helpers/carve-guards.ts @@ -131,9 +131,11 @@ export const CARVE_GUARDS: Record = { // v1.58.5.0: pre-push-guard install (#2077) stacks on the shared first-run-guidance preamble. // Fork port wave 2: multi-ecosystem test-detection evidence (Django/JVM // markers, test-file census — e3259078 port) + the #1079 gh pr edit REST - // fallback grew the union to 1.090x. Kept tight; the Apple release - // adapter raises this again deliberately with its own justification. - maxSizeRatio: 1.10, + // fallback grew the union to 1.090x; the third-party web-actions + // contract (consent-gated browser drive for API-key registration etc.) + // adds ~2.3KB inline judgment, measured 1.103x. Kept tight; the Apple + // release adapter raises this again deliberately. + maxSizeRatio: 1.12, }, 'plan-ceo-review': { skill: 'plan-ceo-review', @@ -241,10 +243,13 @@ export const CARVE_GUARDS: Record = { behavioral: 'prompt', // v1.2.0 activation lift: first-run-guidance section in the shared preamble, // plus the P1 office-hours closing handoff (AUQ that launches the next skill). - maxSkeletonBytes: 98_000, + // Fork port wave 2: the third-party web-actions contract sits inline + // (judgment must be visible before the workflow directs the user to a + // vendor site) — skeleton 99,780 / ratio 1.079 measured. Tight headroom. + maxSkeletonBytes: 101_000, minUnionBytes: 70_000, mustContain: ['design doc', 'problem statement'], - maxSizeRatio: 1.07, + maxSizeRatio: 1.09, }, 'document-release': { skill: 'document-release',