-
Notifications
You must be signed in to change notification settings - Fork 0
feat: third-party web-action contract — offer agentic browser before manual steps #24
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
2e2f876
c8c0c25
2489a5e
71b5478
915b57b
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1 +1 @@ | ||
| 1.62.0.0 | ||
| 1.63.0.0 |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -257,7 +257,7 @@ Web context: <none, optional, local-browser, or production> | |||||
| 1. Infer the mode from product stage, surface, requested artifact, mutation authorization, evidence needs, and deployment state. Do not route by keyword alone. | ||||||
| 2. Refine the public mode to the smallest applicable internal specialist set, then print the required execution header before any substantive output. | ||||||
| 3. Read each active module in full from the path shown in the mode/alias tables. Its specialist body, behavioral contract, STOP gates, and appended upstream judgment ports are binding. Read a lazy specialist phase in full only when the workflow reaches its package-local reference. | ||||||
| 4. Read \`references/EXECUTION-PROFILES.md\`, \`references/SHARED-JUDGMENT.md\`, and \`references/AUTHORITY-POLICY.md\` for every invocation. Infer Depth from structured operating conditions, then obey its mandatory modules, legal skips, artifacts, and claim limits. Read \`references/RUNTIME.md\` before capability-dependent work and \`references/WEB-CONTEXT.md\` before public-web work. When the target is a repository, read \`references/CODE-INTELLIGENCE.md\` once before substantive specialist work and follow its one-time indexing offer. | ||||||
| 4. Read \`references/EXECUTION-PROFILES.md\`, \`references/SHARED-JUDGMENT.md\`, and \`references/AUTHORITY-POLICY.md\` for every invocation. Infer Depth from structured operating conditions, then obey its mandatory modules, legal skips, artifacts, and claim limits. Read \`references/RUNTIME.md\` before capability-dependent work and \`references/WEB-CONTEXT.md\` before public-web work. When the target is a repository, read \`references/CODE-INTELLIGENCE.md\` once before substantive specialist work and follow its one-time indexing offer. Read \`references/THIRD-PARTY-ACTIONS.md\` before directing the user to act on a third-party website (API key registration, vendor accounts, dashboards). | ||||||
| 5. If an old asset path is unavailable, use \`references/ASSETS.md\`. If legacy prose invokes another retired skill, resolve it through \`references/COMPATIBILITY.md\` and stay inside these six dispatchers. | ||||||
| 6. Preserve report-only versus mutation boundaries. Missing mutation authorization fails closed: do not edit merely because a specialist can fix. Commits, pushes, PRs, merges, deploys, messages, and other external mutations still require affirmative authority from the user. | ||||||
| 7. Match the user's language. Keep code identifiers, commands, and source quotations original when translation would reduce accuracy. | ||||||
|
|
@@ -513,6 +513,25 @@ function webContextContract(): string { | |||||
| ].join('\n'); | ||||||
| } | ||||||
|
|
||||||
| function thirdPartyActionsContract(): string { | ||||||
| return [GENERATED, | ||||||
| '# Third-party web actions', | ||||||
| '', | ||||||
| 'A specialist 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 browsing authority; `SHARED-JUDGMENT.md` and `AUTHORITY-POLICY.md` remain binding, including approval before spending.', | ||||||
| '', | ||||||
| '1. Never hand the user a manual step list for a third-party site without first checking for an agentic browser that can act across their logged-in accounts. Today that is the Aside AI browser (its section in `references/BROWSER-PROVIDERS.md` owns detection and readiness); confirm the `aside` CLI is callable, for example `aside --version`. Never install it, and never treat binary presence as consent to browse.', | ||||||
| '', | ||||||
| '2. If such a browser is available, STOP and ask one explicit question before any browsing: name the exact site and the exact actions (for example "create a test-mode API token in the Duffel dashboard"), then offer A) drive it now through the agentic browser, 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, and identity verification remain user-performed steps: hand off and wait instead of acting. Prefer credential flows that never expose the secret to the agent, such as password-manager autofill or host-native copy.', | ||||||
| '', | ||||||
| '4. A captured secret (API key, token, webhook signing secret) never appears in chat output, logs, or shell history. Write it to a user-approved local file with owner-only permissions or the user\'s secret store, and keep generated-file destinations out of version control. Dashboard fields are often masked placeholders; verify the captured credential with one non-mutating API call before claiming success.', | ||||||
| '', | ||||||
| '5. If no agentic browser is available, or the user declines or defers, provide the manual steps and mark the step blocked on the user. Do not recommend or install new products to close the gap.', | ||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. P3: The defer choice does not actually defer the workflow because it still emits the manual step list, making options B and C behaviorally identical. A deferred task should be marked blocked and stop without providing the instructions. Prompt for AI agents
Suggested change
|
||||||
| '', | ||||||
| ].join('\n'); | ||||||
| } | ||||||
|
|
||||||
| function codeIntelligenceContract(): string { | ||||||
| return [GENERATED, | ||||||
| '# Optional code-intelligence indexing', | ||||||
|
|
@@ -621,6 +640,7 @@ function writeSharedContracts(): void { | |||||
| write(path.join(ROOT, 'skills', tree, 'references', 'AUTHORITY-POLICY.md'), authorityPolicyContract()); | ||||||
| write(path.join(ROOT, 'skills', tree, 'references', 'WEB-CONTEXT.md'), webContextContract()); | ||||||
| write(path.join(ROOT, 'skills', tree, 'references', 'CODE-INTELLIGENCE.md'), codeIntelligenceContract()); | ||||||
| write(path.join(ROOT, 'skills', tree, 'references', 'THIRD-PARTY-ACTIONS.md'), thirdPartyActionsContract()); | ||||||
| write(path.join(ROOT, 'skills', tree, 'references', 'RUNTIME.md'), runtimeContract()); | ||||||
| write(path.join(ROOT, 'skills', tree, 'references', 'BROWSER-PROVIDERS.md'), `${GENERATED}\n${renderBrowserProviderContract()}`); | ||||||
| write(path.join(ROOT, 'skills', tree, 'references', 'support', 'runtime-bootstrap.mjs'), bootstrap); | ||||||
|
|
||||||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -26,8 +26,10 @@ const ALLOWED_DISPOSITIONS = new Set(['VERBATIM_PORT', 'MECHANICAL_PORT', 'JUDGM | |||||||||||||||||||||||||||||||
| // overlay for issue #879 (28 -> 29, targets '*', all 55 modules) added 113 | ||||||||||||||||||||||||||||||||
| // more (2 per module + 3 regression checks). The founder-resources opt-out | ||||||||||||||||||||||||||||||||
| // overlay for issue #538 (29 -> 30, office-hours only) added 5 more. The | ||||||||||||||||||||||||||||||||
| // per-tree code-intelligence offer contract added 18 (3 per dispatcher). | ||||||||||||||||||||||||||||||||
| export const EXPECTED_PARITY_CHECKS = 5050; | ||||||||||||||||||||||||||||||||
| // per-tree code-intelligence offer contract added 18 (3 per dispatcher). The | ||||||||||||||||||||||||||||||||
| // third-party web-action contract added 24 more (4 per tree: exists, marker | ||||||||||||||||||||||||||||||||
| // format, dispatcher load, consent/secret content). | ||||||||||||||||||||||||||||||||
| export const EXPECTED_PARITY_CHECKS = 5074; | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| function sha256(value: string | Uint8Array): string { | ||||||||||||||||||||||||||||||||
| return createHash('sha256').update(value).digest('hex'); | ||||||||||||||||||||||||||||||||
|
|
@@ -182,6 +184,18 @@ export function runParity(): ParityResult { | |||||||||||||||||||||||||||||||
| `${tree} code-intelligence offer lost its silent-degrade, decline, or no-auto-install behavior`, | ||||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||
| check(dispatcher.includes('references/THIRD-PARTY-ACTIONS.md'), `${tree} dispatcher does not load the third-party web-action contract`); | ||||||||||||||||||||||||||||||||
| const thirdPartyPath = path.join(ROOT, 'skills', tree, 'references', 'THIRD-PARTY-ACTIONS.md'); | ||||||||||||||||||||||||||||||||
| if (fs.existsSync(thirdPartyPath)) { | ||||||||||||||||||||||||||||||||
| const thirdParty = fs.readFileSync(thirdPartyPath, 'utf8'); | ||||||||||||||||||||||||||||||||
| check( | ||||||||||||||||||||||||||||||||
| thirdParty.includes('STOP and ask one explicit question before any browsing') | ||||||||||||||||||||||||||||||||
| && thirdParty.includes('per-task consent') | ||||||||||||||||||||||||||||||||
| && thirdParty.includes('never appears in chat output, logs, or shell history') | ||||||||||||||||||||||||||||||||
| && thirdParty.includes('verify the captured credential with one non-mutating API call'), | ||||||||||||||||||||||||||||||||
|
Comment on lines
+192
to
+195
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. P2: Parity can still pass after losing several safety boundaries in Prompt for AI agents
Suggested change
|
||||||||||||||||||||||||||||||||
| `${tree} third-party web-action contract lost its consent gate or secret-handling rules`, | ||||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||
| const effectsPath = path.join(ROOT, 'skills', 'ship', 'references', 'EXTERNAL-EFFECTS.md'); | ||||||||||||||||||||||||||||||||
| check(fs.existsSync(effectsPath), 'Ship lacks the durable external-effect protocol'); | ||||||||||||||||||||||||||||||||
|
|
@@ -382,7 +396,7 @@ export function runParity(): ParityResult { | |||||||||||||||||||||||||||||||
| for (const tree of TREE_NAMES) { | ||||||||||||||||||||||||||||||||
| const compatibility = fs.readFileSync(path.join(ROOT, 'skills', tree, 'references', 'COMPATIBILITY.md'), 'utf8'); | ||||||||||||||||||||||||||||||||
| check(!compatibility.includes('../../../') && !compatibility.includes('compat/README.md'), `${tree} compatibility map escapes the selected package`); | ||||||||||||||||||||||||||||||||
| for (const reference of ['SHARED-JUDGMENT.md', 'WEB-CONTEXT.md', 'RUNTIME.md']) { | ||||||||||||||||||||||||||||||||
| for (const reference of ['SHARED-JUDGMENT.md', 'WEB-CONTEXT.md', 'RUNTIME.md', 'THIRD-PARTY-ACTIONS.md']) { | ||||||||||||||||||||||||||||||||
| const referencePath = path.join(ROOT, 'skills', tree, 'references', reference); | ||||||||||||||||||||||||||||||||
| check(fs.existsSync(referencePath), `${tree} lacks ${reference}`); | ||||||||||||||||||||||||||||||||
| if (fs.existsSync(referencePath)) { | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
P2: Webhook-signing-secret setup can never satisfy this success gate because that secret is not an API credential and cannot be validated by an authenticated read-only API call. Keep the API probe for API credentials and specify an appropriate non-exposing verification path for other secret types.
Prompt for AI agents