From e11b457fd9cc39136de728f7e6ef35e89074775c Mon Sep 17 00:00:00 2001 From: Dotta <34892728+cryppadotta@users.noreply.github.com> Date: Sat, 29 Aug 2026 23:23:05 -0500 Subject: [PATCH] feat(runner): complete the canonical action catalog (#12360) ## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work > - The Paperclip Runner needs a stable list of semantic actions > - Earlier pull requests define the core and collaboration action groups > - The remaining domain and administration actions need the same contract form > - The complete catalog must remain data only until a later pull request binds actions to services > - This pull request completes and validates the canonical action inventory > - The benefit is one frozen source of truth for later discovery and authorization work ## Linked Issues or Issue Description **Subsystem affected** `packages/paperclip-runner` protocol contracts. **Problem or motivation** The runner does not yet have a complete canonical inventory for domain and administration actions. Later authorization code cannot project a stable operation catalog without this inventory. **Proposed solution** Add the remaining action contracts and aggregate all 41 actions. Validate every declared live and scenario projection with its own schema. **Alternatives considered** Binding these actions directly to production services would combine data contracts with authority. This pull request keeps every production service binding unbound. **Roadmap alignment** This change supports the experimental Paperclip Runner. It does not enable the runner or change an existing adapter. ## What Changed - Added 14 domain and administration action contracts. - Added the complete immutable 41-action catalog. - Added validation for live inputs and outputs. - Added validation for scenario inputs and capability-result envelopes. - Kept every production service binding unbound. ## Verification - `pnpm --filter @paperclipai/paperclip-runner test:typescript` - `pnpm -r typecheck` - `pnpm build` - The focused catalog test validates 41 actions. ## Risks Low risk. This pull request adds package-local contract data and tests. It does not authorize an action or change an adapter. ## Model Used OpenAI Codex with GPT-5.6 and repository tool use. ## Checklist - [x] I have included a thinking path that traces from project context to this change - [x] I have specified the model used (with version and capability details) - [x] I have checked ROADMAP.md and confirmed this PR does not duplicate planned core work - [x] I have searched GitHub for duplicate or related PRs and linked them above - [x] I have either (a) linked existing issues with `Fixes: #` / `Closes #` / `Refs #` OR (b) described the issue in-PR following the relevant issue template - [x] I have not referenced internal/instance-local Paperclip issues or links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip` URLs) - [x] My branch name describes the change (e.g. `docs/...`, `fix/...`) and contains no internal Paperclip ticket id or instance-derived details - [x] I have run tests locally and they pass - [x] I have added or updated tests where applicable - [x] I have updated relevant documentation to reflect my changes - [x] I have considered and documented any risks above - [ ] All Paperclip CI gates are green - [ ] Greptile is 5/5 with no open P2s, recommendations, or follow-ups - [x] I will address all Greptile and reviewer comments before requesting merge --- .../src/catalog/canonical-operations.ts | 27 ++ .../paperclip-runner/src/catalog/index.ts | 1 + .../catalog/protocol-action-contracts.test.ts | 70 +++++ .../protocol-actions/administer-company.ts | 146 ++++++++++ .../answer-status-question.ts | 7 + .../src/protocol-actions/block-task.ts | 7 + .../protocol-actions/comment-on-approval.ts | 8 + .../control-workspace-service.ts | 256 ++++++++++++++++++ .../src/protocol-actions/create-task.ts | 7 + .../src/protocol-actions/decide-approval.ts | 9 + .../src/protocol-actions/export-company.ts | 124 +++++++++ .../src/protocol-actions/finish-task.ts | 7 + .../protocol-actions/generic-api-request.ts | 208 ++++++++++++++ .../protocol-actions/get-workspace-runtime.ts | 144 ++++++++++ .../src/protocol-actions/index.ts | 90 ++++++ .../src/protocol-actions/list-cases.ts | 119 ++++++++ .../protocol-actions/list-company-skills.ts | 119 ++++++++ .../src/protocol-actions/list-routines.ts | 119 ++++++++ .../protocol-actions/list-secret-metadata.ts | 119 ++++++++ .../src/protocol-actions/manage-routine.ts | 124 +++++++++ .../src/protocol-actions/read-secret-value.ts | 138 ++++++++++ .../protocol-actions/register-deliverable.ts | 12 + .../src/protocol-actions/report-progress.ts | 7 + .../src/protocol-actions/request-approval.ts | 8 + .../protocol-actions/request-human-input.ts | 10 + .../src/protocol-actions/request-review.ts | 7 + .../src/protocol-actions/schedule-wake.ts | 163 +++++++++++ .../src/protocol-actions/set-dependencies.ts | 9 + .../protocol-actions/sync-company-skills.ts | 124 +++++++++ .../src/protocol-actions/upsert-case.ts | 141 ++++++++++ .../src/protocol-actions/write-document.ts | 10 + 31 files changed, 2340 insertions(+) create mode 100644 packages/paperclip-runner/src/catalog/canonical-operations.ts create mode 100644 packages/paperclip-runner/src/catalog/protocol-action-contracts.test.ts create mode 100644 packages/paperclip-runner/src/protocol-actions/administer-company.ts create mode 100644 packages/paperclip-runner/src/protocol-actions/control-workspace-service.ts create mode 100644 packages/paperclip-runner/src/protocol-actions/export-company.ts create mode 100644 packages/paperclip-runner/src/protocol-actions/generic-api-request.ts create mode 100644 packages/paperclip-runner/src/protocol-actions/get-workspace-runtime.ts create mode 100644 packages/paperclip-runner/src/protocol-actions/index.ts create mode 100644 packages/paperclip-runner/src/protocol-actions/list-cases.ts create mode 100644 packages/paperclip-runner/src/protocol-actions/list-company-skills.ts create mode 100644 packages/paperclip-runner/src/protocol-actions/list-routines.ts create mode 100644 packages/paperclip-runner/src/protocol-actions/list-secret-metadata.ts create mode 100644 packages/paperclip-runner/src/protocol-actions/manage-routine.ts create mode 100644 packages/paperclip-runner/src/protocol-actions/read-secret-value.ts create mode 100644 packages/paperclip-runner/src/protocol-actions/schedule-wake.ts create mode 100644 packages/paperclip-runner/src/protocol-actions/sync-company-skills.ts create mode 100644 packages/paperclip-runner/src/protocol-actions/upsert-case.ts diff --git a/packages/paperclip-runner/src/catalog/canonical-operations.ts b/packages/paperclip-runner/src/catalog/canonical-operations.ts new file mode 100644 index 0000000000..eac0c21c23 --- /dev/null +++ b/packages/paperclip-runner/src/catalog/canonical-operations.ts @@ -0,0 +1,27 @@ +/** Stable aggregate API over the per-action definitions in `src/protocol-actions/`. */ +import type { CapabilitySideEffectClass, CapabilityToolDisposition, CapabilityOptionalCatalogGroup, CapabilityToolTaskMode, ScenarioChatdempotencyBehavior } from "../tools/capability-semantic-tool-types.js"; +import { PAPERCLIP_PROTOCOL_ACTIONS } from "../protocol-actions/index.js"; + +export type CapabilityCatalogSurface = "scenario" | "live"; +export type CapabilityRealBindingStatus = "live_codex" | "scenario_mock" | "test_only"; +export interface CapabilityCanonicalOperation { + readonly operationId: string; readonly surfaces: readonly CapabilityCatalogSurface[]; + readonly placement: CapabilityToolDisposition; readonly optionalGroup: CapabilityOptionalCatalogGroup | null; + readonly requiredClaims: readonly string[]; readonly taskModes: readonly CapabilityToolTaskMode[]; + readonly allowedRoles?: readonly string[]; readonly sideEffectClass: CapabilitySideEffectClass; + readonly idempotency: ScenarioChatdempotencyBehavior; readonly disabledByDefault: boolean; + readonly realBindingStatus: CapabilityRealBindingStatus; readonly realServiceBinding: string; + readonly prpEvidence: string; readonly prpBindingStatus: "audit_pending" | "bound"; + readonly legacyAliases: readonly string[]; readonly note?: string; +} + +export const CAPABILITY_CANONICAL_OPERATIONS: readonly CapabilityCanonicalOperation[] = Object.freeze( + PAPERCLIP_PROTOCOL_ACTIONS + .map((action) => action.canonical as unknown as CapabilityCanonicalOperation) + .sort((left, right) => left.operationId.localeCompare(right.operationId)), +); +const byId = new Map(CAPABILITY_CANONICAL_OPERATIONS.map((operation) => [operation.operationId, operation])); +if (byId.size !== 41) throw new Error(`expected 41 canonical semantic operations, found ${byId.size}`); +export function capabilityCanonicalOperation(operationId: string): CapabilityCanonicalOperation | undefined { return byId.get(operationId); } +export function capabilityCanonicalOperationsForSurface(surface: CapabilityCatalogSurface): readonly CapabilityCanonicalOperation[] { return CAPABILITY_CANONICAL_OPERATIONS.filter((operation) => operation.surfaces.includes(surface)); } +export function capabilityCanonicalOperationIds(): readonly string[] { return CAPABILITY_CANONICAL_OPERATIONS.map((operation) => operation.operationId); } diff --git a/packages/paperclip-runner/src/catalog/index.ts b/packages/paperclip-runner/src/catalog/index.ts index 863cde6445..deabeb3070 100644 --- a/packages/paperclip-runner/src/catalog/index.ts +++ b/packages/paperclip-runner/src/catalog/index.ts @@ -1,2 +1,3 @@ +export * from "./canonical-operations.js"; export * from "./semantic-action-catalog.js"; export * from "./semantic-action-types.js"; diff --git a/packages/paperclip-runner/src/catalog/protocol-action-contracts.test.ts b/packages/paperclip-runner/src/catalog/protocol-action-contracts.test.ts new file mode 100644 index 0000000000..2ae21e152d --- /dev/null +++ b/packages/paperclip-runner/src/catalog/protocol-action-contracts.test.ts @@ -0,0 +1,70 @@ +import Ajv2020 from "ajv/dist/2020.js"; +import { describe, expect, it } from "vitest"; + +import { PAPERCLIP_PROTOCOL_ACTIONS } from "../protocol-actions/index.js"; + +describe("canonical Paperclip protocol action contracts", () => { + const ajv = new Ajv2020({ allErrors: true, allowUnionTypes: true, strict: false }); + + it.each(PAPERCLIP_PROTOCOL_ACTIONS.map((action) => [action.id, action] as const))( + "%s has a schema-valid canonical example and every declared projection", + (operationId, action) => { + expect(action.canonical.operationId).toBe(operationId); + expect(action.examples.call.operationId).toBe(operationId); + expect(action.examples.success.operationId).toBe(operationId); + expect(action.live !== null || action.scenario !== null).toBe(true); + expect(Object.isFrozen(action)).toBe(true); + expect(Object.isFrozen(action.canonical)).toBe(true); + + if (action.live !== null) { + expect(action.live.descriptor.operationId).toBe(operationId); + expect( + ajv.validate(action.live.descriptor.inputSchema, action.examples.call.input), + JSON.stringify(ajv.errors), + ).toBe(true); + expect( + ajv.validate(action.live.descriptor.outputSchema, action.examples.success.result), + JSON.stringify(ajv.errors), + ).toBe(true); + } + + if (action.scenario !== null) { + const scenarioProperties = action.scenario.descriptor.inputSchema.properties ?? {}; + const scenarioCall = "scenarioCall" in action.examples + ? action.examples.scenarioCall + : action.examples.call; + const scenarioOutput = { + schema: "paperclip.capability.tool-result.v1", + ok: true, + operationId, + operationResultId: "example-result", + value: action.examples.success.result, + commandResult: null, + authorization: {}, + }; + + expect(action.scenario.descriptor.operationId).toBe(operationId); + expect(scenarioCall.operationId).toBe(operationId); + expect( + Object.keys(scenarioCall.input).filter((key) => !(key in scenarioProperties)), + ).toEqual([]); + if (action.scenario.descriptor.idempotency === "required") { + expect(action.examples).toHaveProperty("scenarioCall"); + expect(scenarioCall.idempotencyKey).toEqual(expect.any(String)); + expect(scenarioCall.idempotencyKey).not.toHaveLength(0); + } else { + expect(scenarioCall).not.toHaveProperty("idempotencyKey"); + } + expect( + ajv.validate(action.scenario.descriptor.inputSchema, scenarioCall.input), + JSON.stringify(ajv.errors), + ).toBe(true); + expect( + ajv.validate(action.scenario.descriptor.outputSchema, scenarioOutput), + JSON.stringify(ajv.errors), + ).toBe(true); + expect(action.scenario.descriptor.mockCommandMapping).toBeDefined(); + } + }, + ); +}); diff --git a/packages/paperclip-runner/src/protocol-actions/administer-company.ts b/packages/paperclip-runner/src/protocol-actions/administer-company.ts new file mode 100644 index 0000000000..0bff0c682f --- /dev/null +++ b/packages/paperclip-runner/src/protocol-actions/administer-company.ts @@ -0,0 +1,146 @@ +/** Canonical definition and documentation for `administer_company`. */ +export const administerCompanyAction = { + "id": "administer_company", + "canonical": { + "operationId": "administer_company", + "surfaces": [ + "scenario" + ], + "placement": "optional_agent_tool", + "optionalGroup": "portability_admin", + "requiredClaims": [ + "company:admin" + ], + "taskModes": [ + "standard", + "skill_test" + ], + "allowedRoles": [ + "board", + "ceo", + "admin" + ], + "sideEffectClass": "admin", + "idempotency": "required", + "disabledByDefault": false, + "realBindingStatus": "scenario_mock", + "realServiceBinding": "unbound", + "prpEvidence": "company admin/portability item event plus audit record", + "prpBindingStatus": "audit_pending", + "legacyAliases": [], + "note": "Scenario/eval-only mock extension." + }, + "documentation": { + "title": "Administer Company", + "description": "Administer Company through the Capability portability admin capability set.", + "note": "Scenario/eval-only mock extension." + }, + "examples": { + "call": { + "operationId": "administer_company", + "input": { + "action": "example" + } + }, + "scenarioCall": { + "operationId": "administer_company", + "idempotencyKey": "example", + "input": { + "action": "example" + } + }, + "success": { + "ok": true, + "operationId": "administer_company", + "result": { + "schema": "paperclip.capability.tool-result.v1", + "ok": true, + "operationId": "example", + "operationResultId": "example", + "value": "example", + "commandResult": "example", + "authorization": "example" + } + } + }, + "live": null, + "scenario": { + "order": 35, + "descriptor": { + "operationId": "administer_company", + "version": 1, + "title": "Administer Company", + "description": "Administer Company through the Capability portability admin capability set.", + "inputSchema": { + "type": "object", + "properties": { + "action": { + "type": "string", + "minLength": 1 + }, + "payload": {} + }, + "required": [ + "action" + ], + "additionalProperties": false + }, + "outputSchema": { + "type": "object", + "properties": { + "schema": { + "type": "string", + "enum": [ + "paperclip.capability.tool-result.v1" + ] + }, + "ok": { + "type": "boolean" + }, + "operationId": { + "type": "string", + "minLength": 1 + }, + "operationResultId": { + "type": "string", + "minLength": 1 + }, + "value": {}, + "commandResult": {}, + "authorization": {} + }, + "required": [ + "schema", + "ok", + "operationId", + "operationResultId", + "value", + "commandResult", + "authorization" + ], + "additionalProperties": false + }, + "disposition": "optional_agent_tool", + "optionalGroup": "portability_admin", + "requiredClaims": [ + "company:admin" + ], + "allowedRoles": [ + "board", + "ceo", + "admin" + ], + "taskModes": [ + "standard", + "skill_test" + ], + "sideEffectClass": "admin", + "idempotency": "required", + "redaction": [], + "mockCommandMapping": { + "kind": "mock_extension", + "extension": "company.admin" + } + } + } +} as const; diff --git a/packages/paperclip-runner/src/protocol-actions/answer-status-question.ts b/packages/paperclip-runner/src/protocol-actions/answer-status-question.ts index 61a4033b14..9dd5f920e2 100644 --- a/packages/paperclip-runner/src/protocol-actions/answer-status-question.ts +++ b/packages/paperclip-runner/src/protocol-actions/answer-status-question.ts @@ -38,6 +38,13 @@ export const answerStatusQuestionAction = { "body": "example" } }, + "scenarioCall": { + "operationId": "answer_status_question", + "idempotencyKey": "example", + "input": { + "body": "example" + } + }, "success": { "ok": true, "operationId": "answer_status_question", diff --git a/packages/paperclip-runner/src/protocol-actions/block-task.ts b/packages/paperclip-runner/src/protocol-actions/block-task.ts index a292e8763c..036d198fd8 100644 --- a/packages/paperclip-runner/src/protocol-actions/block-task.ts +++ b/packages/paperclip-runner/src/protocol-actions/block-task.ts @@ -36,6 +36,13 @@ export const blockTaskAction = { "reason": "example" } }, + "scenarioCall": { + "operationId": "block_task", + "idempotencyKey": "example", + "input": { + "reason": "example" + } + }, "success": { "ok": true, "operationId": "block_task", diff --git a/packages/paperclip-runner/src/protocol-actions/comment-on-approval.ts b/packages/paperclip-runner/src/protocol-actions/comment-on-approval.ts index a6c14490ba..e82fa534f0 100644 --- a/packages/paperclip-runner/src/protocol-actions/comment-on-approval.ts +++ b/packages/paperclip-runner/src/protocol-actions/comment-on-approval.ts @@ -41,6 +41,14 @@ export const commentOnApprovalAction = { "body": "example" } }, + "scenarioCall": { + "operationId": "comment_on_approval", + "idempotencyKey": "example", + "input": { + "approvalId": "example", + "body": "example" + } + }, "success": { "ok": true, "operationId": "comment_on_approval", diff --git a/packages/paperclip-runner/src/protocol-actions/control-workspace-service.ts b/packages/paperclip-runner/src/protocol-actions/control-workspace-service.ts new file mode 100644 index 0000000000..5b9227dadb --- /dev/null +++ b/packages/paperclip-runner/src/protocol-actions/control-workspace-service.ts @@ -0,0 +1,256 @@ +/** Canonical definition and documentation for `control_workspace_service`. */ +export const controlWorkspaceServiceAction = { + "id": "control_workspace_service", + "canonical": { + "operationId": "control_workspace_service", + "surfaces": [ + "scenario", + "live" + ], + "placement": "optional_agent_tool", + "optionalGroup": "workspace_runtime", + "requiredClaims": [ + "workspace:control" + ], + "taskModes": [ + "standard", + "skill_test" + ], + "sideEffectClass": "workspace_control", + "idempotency": "required", + "disabledByDefault": false, + "realBindingStatus": "live_codex", + "realServiceBinding": "unbound", + "prpEvidence": "workspace service lifecycle event", + "prpBindingStatus": "audit_pending", + "legacyAliases": [] + }, + "documentation": { + "title": "Control workspace service", + "description": "Start, stop, or fault one active-task mock workspace service.", + "note": null + }, + "examples": { + "call": { + "operationId": "control_workspace_service", + "input": { + "idempotencyKey": "example", + "serviceId": "example", + "action": "start" + } + }, + "scenarioCall": { + "operationId": "control_workspace_service", + "idempotencyKey": "example", + "input": { + "serviceId": "example", + "action": "start" + } + }, + "success": { + "ok": true, + "operationId": "control_workspace_service", + "result": { + "commandId": "example", + "disposition": "applied", + "stateRevision": 1, + "entityRefs": [ + "example" + ], + "scheduledWakeIds": [ + "example" + ] + } + } + }, + "live": { + "order": 20, + "descriptor": { + "schema": "paperclip.semantic-tool.v1", + "operationId": "control_workspace_service", + "version": 1, + "title": "Control workspace service", + "description": "Start, stop, or fault one active-task mock workspace service.", + "exposure": "optional", + "requiredClaims": [ + "workspace:control" + ], + "allowedModes": [ + "standard", + "skill_test" + ], + "inputSchema": { + "type": "object", + "properties": { + "idempotencyKey": { + "type": "string", + "description": "Caller-stable retry key.", + "minLength": 1, + "maxLength": 240 + }, + "serviceId": { + "type": "string", + "description": "Mock workspace service id.", + "minLength": 1, + "maxLength": 200 + }, + "action": { + "enum": [ + "start", + "stop", + "fail" + ] + }, + "url": { + "type": [ + "string", + "null" + ], + "description": "Optional mock service URL.", + "maxLength": 20000 + } + }, + "required": [ + "idempotencyKey", + "serviceId", + "action" + ], + "additionalProperties": false + }, + "outputSchema": { + "type": "object", + "properties": { + "commandId": { + "type": "string", + "description": "Stable mock command identifier.", + "minLength": 1, + "maxLength": 200 + }, + "disposition": { + "enum": [ + "applied", + "duplicate" + ] + }, + "stateRevision": { + "type": "integer", + "minimum": 0 + }, + "entityRefs": { + "type": "array", + "description": "Mock entities affected by the operation.", + "items": { + "type": "string", + "minLength": 1 + }, + "maxItems": 200, + "uniqueItems": true + }, + "scheduledWakeIds": { + "type": "array", + "description": "Wake identifiers scheduled by the operation.", + "items": { + "type": "string", + "minLength": 1 + }, + "maxItems": 200, + "uniqueItems": true + } + }, + "required": [ + "commandId", + "disposition", + "stateRevision", + "entityRefs", + "scheduledWakeIds" + ], + "additionalProperties": false + } + } + }, + "scenario": { + "order": 27, + "descriptor": { + "operationId": "control_workspace_service", + "version": 1, + "title": "Control Workspace Service", + "description": "Control Workspace Service through the Capability workspace runtime capability set.", + "inputSchema": { + "type": "object", + "properties": { + "serviceId": { + "type": "string", + "minLength": 1 + }, + "action": { + "type": "string", + "enum": [ + "start", + "stop", + "fail" + ] + }, + "url": { + "type": "string" + } + }, + "required": [ + "serviceId", + "action" + ], + "additionalProperties": false + }, + "outputSchema": { + "type": "object", + "properties": { + "schema": { + "type": "string", + "enum": [ + "paperclip.capability.tool-result.v1" + ] + }, + "ok": { + "type": "boolean" + }, + "operationId": { + "type": "string", + "minLength": 1 + }, + "operationResultId": { + "type": "string", + "minLength": 1 + }, + "value": {}, + "commandResult": {}, + "authorization": {} + }, + "required": [ + "schema", + "ok", + "operationId", + "operationResultId", + "value", + "commandResult", + "authorization" + ], + "additionalProperties": false + }, + "disposition": "optional_agent_tool", + "optionalGroup": "workspace_runtime", + "requiredClaims": [ + "workspace:control" + ], + "taskModes": [ + "standard", + "skill_test" + ], + "sideEffectClass": "workspace_control", + "idempotency": "required", + "redaction": [], + "mockCommandMapping": { + "kind": "semantic_command", + "commandKind": "control_workspace_service" + } + } + } +} as const; diff --git a/packages/paperclip-runner/src/protocol-actions/create-task.ts b/packages/paperclip-runner/src/protocol-actions/create-task.ts index cf47440144..1c63348faf 100644 --- a/packages/paperclip-runner/src/protocol-actions/create-task.ts +++ b/packages/paperclip-runner/src/protocol-actions/create-task.ts @@ -40,6 +40,13 @@ export const createTaskAction = { "title": "example" } }, + "scenarioCall": { + "operationId": "create_task", + "idempotencyKey": "example", + "input": { + "title": "example" + } + }, "success": { "ok": true, "operationId": "create_task", diff --git a/packages/paperclip-runner/src/protocol-actions/decide-approval.ts b/packages/paperclip-runner/src/protocol-actions/decide-approval.ts index 8e4df7a919..a8dd70090b 100644 --- a/packages/paperclip-runner/src/protocol-actions/decide-approval.ts +++ b/packages/paperclip-runner/src/protocol-actions/decide-approval.ts @@ -45,6 +45,15 @@ export const decideApprovalAction = { "note": "example" } }, + "scenarioCall": { + "operationId": "decide_approval", + "idempotencyKey": "example", + "input": { + "approvalId": "example", + "decision": "approved", + "note": "example" + } + }, "success": { "ok": true, "operationId": "decide_approval", diff --git a/packages/paperclip-runner/src/protocol-actions/export-company.ts b/packages/paperclip-runner/src/protocol-actions/export-company.ts new file mode 100644 index 0000000000..29eaa40a7f --- /dev/null +++ b/packages/paperclip-runner/src/protocol-actions/export-company.ts @@ -0,0 +1,124 @@ +/** Canonical definition and documentation for `export_company`. */ +export const exportCompanyAction = { + "id": "export_company", + "canonical": { + "operationId": "export_company", + "surfaces": [ + "scenario" + ], + "placement": "optional_agent_tool", + "optionalGroup": "portability_admin", + "requiredClaims": [ + "portability:export" + ], + "taskModes": [ + "standard", + "skill_test" + ], + "sideEffectClass": "admin", + "idempotency": "required", + "disabledByDefault": false, + "realBindingStatus": "scenario_mock", + "realServiceBinding": "unbound", + "prpEvidence": "company admin/portability item event plus audit record", + "prpBindingStatus": "audit_pending", + "legacyAliases": [], + "note": "Scenario/eval-only mock extension." + }, + "documentation": { + "title": "Export Company", + "description": "Export Company through the Capability portability admin capability set.", + "note": "Scenario/eval-only mock extension." + }, + "examples": { + "call": { + "operationId": "export_company", + "input": {} + }, + "scenarioCall": { + "operationId": "export_company", + "idempotencyKey": "example", + "input": {} + }, + "success": { + "ok": true, + "operationId": "export_company", + "result": { + "schema": "paperclip.capability.tool-result.v1", + "ok": true, + "operationId": "example", + "operationResultId": "example", + "value": "example", + "commandResult": "example", + "authorization": "example" + } + } + }, + "live": null, + "scenario": { + "order": 34, + "descriptor": { + "operationId": "export_company", + "version": 1, + "title": "Export Company", + "description": "Export Company through the Capability portability admin capability set.", + "inputSchema": { + "type": "object", + "properties": {}, + "required": [], + "additionalProperties": false + }, + "outputSchema": { + "type": "object", + "properties": { + "schema": { + "type": "string", + "enum": [ + "paperclip.capability.tool-result.v1" + ] + }, + "ok": { + "type": "boolean" + }, + "operationId": { + "type": "string", + "minLength": 1 + }, + "operationResultId": { + "type": "string", + "minLength": 1 + }, + "value": {}, + "commandResult": {}, + "authorization": {} + }, + "required": [ + "schema", + "ok", + "operationId", + "operationResultId", + "value", + "commandResult", + "authorization" + ], + "additionalProperties": false + }, + "disposition": "optional_agent_tool", + "optionalGroup": "portability_admin", + "requiredClaims": [ + "portability:export" + ], + "taskModes": [ + "standard", + "skill_test" + ], + "sideEffectClass": "admin", + "idempotency": "required", + "redaction": [], + "mockCommandMapping": { + "kind": "mock_extension", + "extension": "portability.export" + } + } + } +} as const; diff --git a/packages/paperclip-runner/src/protocol-actions/finish-task.ts b/packages/paperclip-runner/src/protocol-actions/finish-task.ts index 3f9ab66926..a91b3e105a 100644 --- a/packages/paperclip-runner/src/protocol-actions/finish-task.ts +++ b/packages/paperclip-runner/src/protocol-actions/finish-task.ts @@ -36,6 +36,13 @@ export const finishTaskAction = { "summary": "example" } }, + "scenarioCall": { + "operationId": "finish_task", + "idempotencyKey": "example", + "input": { + "summary": "example" + } + }, "success": { "ok": true, "operationId": "finish_task", diff --git a/packages/paperclip-runner/src/protocol-actions/generic-api-request.ts b/packages/paperclip-runner/src/protocol-actions/generic-api-request.ts new file mode 100644 index 0000000000..05e129862b --- /dev/null +++ b/packages/paperclip-runner/src/protocol-actions/generic-api-request.ts @@ -0,0 +1,208 @@ +/** Canonical definition and documentation for `generic_api_request`. */ +export const genericApiRequestAction = { + "id": "generic_api_request", + "canonical": { + "operationId": "generic_api_request", + "surfaces": [ + "scenario", + "live" + ], + "placement": "optional_agent_tool", + "optionalGroup": "test_escape_hatch", + "requiredClaims": [ + "test:generic_api_request" + ], + "taskModes": [ + "skill_test" + ], + "sideEffectClass": "test_escape_hatch", + "idempotency": "required", + "disabledByDefault": true, + "realBindingStatus": "test_only", + "realServiceBinding": "unbound", + "prpEvidence": "test-only; excluded from product PRP evidence", + "prpBindingStatus": "audit_pending", + "legacyAliases": [], + "note": "Test-only escape hatch; explicitly cannot count as product capability coverage. Single unified claim test:generic_api_request." + }, + "documentation": { + "title": "Generic API request", + "description": "Test-only escape hatch. Disabled unless the scenario and explicit claim both enable it.", + "note": "Test-only escape hatch; explicitly cannot count as product capability coverage. Single unified claim test:generic_api_request." + }, + "examples": { + "call": { + "operationId": "generic_api_request", + "input": { + "method": "GET", + "path": "/mock/example" + } + }, + "scenarioCall": { + "operationId": "generic_api_request", + "idempotencyKey": "example", + "input": { + "method": "GET", + "path": "/mock/example" + } + }, + "success": { + "ok": true, + "operationId": "generic_api_request", + "result": {} + } + }, + "live": { + "order": 27, + "descriptor": { + "schema": "paperclip.semantic-tool.v1", + "operationId": "generic_api_request", + "version": 1, + "title": "Generic API request", + "description": "Test-only escape hatch. Disabled unless the scenario and explicit claim both enable it.", + "exposure": "optional", + "requiredClaims": [ + "test:generic_api_request" + ], + "allowedModes": [ + "skill_test" + ], + "disabledByDefault": true, + "inputSchema": { + "type": "object", + "properties": { + "method": { + "enum": [ + "GET", + "POST", + "PATCH" + ] + }, + "path": { + "type": "string", + "pattern": "^/mock/", + "maxLength": 500 + }, + "body": { + "type": "object", + "additionalProperties": true + } + }, + "required": [ + "method", + "path" + ], + "additionalProperties": false + }, + "outputSchema": { + "type": "object", + "additionalProperties": true + } + } + }, + "scenario": { + "order": 36, + "descriptor": { + "operationId": "generic_api_request", + "version": 1, + "title": "Generic Api Request", + "description": "Generic Api Request through the Capability test escape hatch capability set.", + "inputSchema": { + "type": "object", + "properties": { + "method": { + "type": "string", + "minLength": 1 + }, + "path": { + "type": "string", + "minLength": 1 + }, + "headers": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "body": {} + }, + "required": [ + "method", + "path" + ], + "additionalProperties": false + }, + "outputSchema": { + "type": "object", + "properties": { + "schema": { + "type": "string", + "enum": [ + "paperclip.capability.tool-result.v1" + ] + }, + "ok": { + "type": "boolean" + }, + "operationId": { + "type": "string", + "minLength": 1 + }, + "operationResultId": { + "type": "string", + "minLength": 1 + }, + "value": {}, + "commandResult": {}, + "authorization": {} + }, + "required": [ + "schema", + "ok", + "operationId", + "operationResultId", + "value", + "commandResult", + "authorization" + ], + "additionalProperties": false + }, + "disposition": "optional_agent_tool", + "optionalGroup": "test_escape_hatch", + "requiredClaims": [ + "test:generic_api_request" + ], + "taskModes": [ + "skill_test" + ], + "sideEffectClass": "test_escape_hatch", + "idempotency": "required", + "redaction": [ + { + "path": "$.headers.authorization", + "replacement": "[REDACTED]", + "appliesTo": [ + "input", + "output", + "error", + "authorization_record" + ] + }, + { + "path": "$.headers.cookie", + "replacement": "[REDACTED]", + "appliesTo": [ + "input", + "output", + "error", + "authorization_record" + ] + } + ], + "mockCommandMapping": { + "kind": "mock_extension", + "extension": "test.generic_api" + } + } + } +} as const; diff --git a/packages/paperclip-runner/src/protocol-actions/get-workspace-runtime.ts b/packages/paperclip-runner/src/protocol-actions/get-workspace-runtime.ts new file mode 100644 index 0000000000..744cd972a0 --- /dev/null +++ b/packages/paperclip-runner/src/protocol-actions/get-workspace-runtime.ts @@ -0,0 +1,144 @@ +/** Canonical definition and documentation for `get_workspace_runtime`. */ +export const getWorkspaceRuntimeAction = { + "id": "get_workspace_runtime", + "canonical": { + "operationId": "get_workspace_runtime", + "surfaces": [ + "scenario", + "live" + ], + "placement": "optional_agent_tool", + "optionalGroup": "workspace_runtime", + "requiredClaims": [ + "workspace:read" + ], + "taskModes": [ + "standard", + "ask", + "planning", + "skill_test" + ], + "sideEffectClass": "read", + "idempotency": "none", + "disabledByDefault": false, + "realBindingStatus": "live_codex", + "realServiceBinding": "unbound", + "prpEvidence": "read projection surfaced via a tool-result item event; no control-plane state diff", + "prpBindingStatus": "audit_pending", + "legacyAliases": [] + }, + "documentation": { + "title": "Get workspace runtime", + "description": "Read active-task mock workspace services.", + "note": null + }, + "examples": { + "call": { + "operationId": "get_workspace_runtime", + "input": {} + }, + "success": { + "ok": true, + "operationId": "get_workspace_runtime", + "result": {} + } + }, + "live": { + "order": 19, + "descriptor": { + "schema": "paperclip.semantic-tool.v1", + "operationId": "get_workspace_runtime", + "version": 1, + "title": "Get workspace runtime", + "description": "Read active-task mock workspace services.", + "exposure": "optional", + "requiredClaims": [ + "workspace:read" + ], + "allowedModes": [ + "standard", + "ask", + "planning", + "skill_test" + ], + "inputSchema": { + "type": "object", + "properties": {}, + "required": [], + "additionalProperties": false + }, + "outputSchema": { + "type": "object", + "additionalProperties": true + } + } + }, + "scenario": { + "order": 26, + "descriptor": { + "operationId": "get_workspace_runtime", + "version": 1, + "title": "Get Workspace Runtime", + "description": "Get Workspace Runtime through the Capability workspace runtime capability set.", + "inputSchema": { + "type": "object", + "properties": {}, + "required": [], + "additionalProperties": false + }, + "outputSchema": { + "type": "object", + "properties": { + "schema": { + "type": "string", + "enum": [ + "paperclip.capability.tool-result.v1" + ] + }, + "ok": { + "type": "boolean" + }, + "operationId": { + "type": "string", + "minLength": 1 + }, + "operationResultId": { + "type": "string", + "minLength": 1 + }, + "value": {}, + "commandResult": {}, + "authorization": {} + }, + "required": [ + "schema", + "ok", + "operationId", + "operationResultId", + "value", + "commandResult", + "authorization" + ], + "additionalProperties": false + }, + "disposition": "optional_agent_tool", + "optionalGroup": "workspace_runtime", + "requiredClaims": [ + "workspace:read" + ], + "taskModes": [ + "standard", + "ask", + "planning", + "skill_test" + ], + "sideEffectClass": "read", + "idempotency": "none", + "redaction": [], + "mockCommandMapping": { + "kind": "snapshot_read", + "projection": "active_task_workspace" + } + } + } +} as const; diff --git a/packages/paperclip-runner/src/protocol-actions/index.ts b/packages/paperclip-runner/src/protocol-actions/index.ts new file mode 100644 index 0000000000..4a0b05bf69 --- /dev/null +++ b/packages/paperclip-runner/src/protocol-actions/index.ts @@ -0,0 +1,90 @@ +import { administerCompanyAction } from "./administer-company.js"; +import { answerStatusQuestionAction } from "./answer-status-question.js"; +import { blockTaskAction } from "./block-task.js"; +import { commentOnApprovalAction } from "./comment-on-approval.js"; +import { controlWorkspaceServiceAction } from "./control-workspace-service.js"; +import { createTaskAction } from "./create-task.js"; +import { decideApprovalAction } from "./decide-approval.js"; +import { exportCompanyAction } from "./export-company.js"; +import { finishTaskAction } from "./finish-task.js"; +import { genericApiRequestAction } from "./generic-api-request.js"; +import { getAgentAction } from "./get-agent.js"; +import { getApprovalAction } from "./get-approval.js"; +import { getApprovalContextAction } from "./get-approval-context.js"; +import { getTaskContextAction } from "./get-task-context.js"; +import { getTaskHistoryAction } from "./get-task-history.js"; +import { getWorkspaceRuntimeAction } from "./get-workspace-runtime.js"; +import { inspectOperationResultAction } from "./inspect-operation-result.js"; +import { listAgentsAction } from "./list-agents.js"; +import { listApprovalsAction } from "./list-approvals.js"; +import { listCasesAction } from "./list-cases.js"; +import { listCompanySkillsAction } from "./list-company-skills.js"; +import { listDocumentRevisionsAction } from "./list-document-revisions.js"; +import { listDocumentsAction } from "./list-documents.js"; +import { listGoalsAction } from "./list-goals.js"; +import { listProjectsAction } from "./list-projects.js"; +import { listRoutinesAction } from "./list-routines.js"; +import { listSecretMetadataAction } from "./list-secret-metadata.js"; +import { manageRoutineAction } from "./manage-routine.js"; +import { readDocumentAction } from "./read-document.js"; +import { readSecretValueAction } from "./read-secret-value.js"; +import { registerDeliverableAction } from "./register-deliverable.js"; +import { reportProgressAction } from "./report-progress.js"; +import { requestApprovalAction } from "./request-approval.js"; +import { requestHumanInputAction } from "./request-human-input.js"; +import { requestReviewAction } from "./request-review.js"; +import { scheduleWakeAction } from "./schedule-wake.js"; +import { searchTasksAction } from "./search-tasks.js"; +import { setDependenciesAction } from "./set-dependencies.js"; +import { syncCompanySkillsAction } from "./sync-company-skills.js"; +import { upsertCaseAction } from "./upsert-case.js"; +import { writeDocumentAction } from "./write-document.js"; +import { deepFreezeProtocolAction } from "./freeze.js"; + +export const PAPERCLIP_PROTOCOL_ACTIONS = deepFreezeProtocolAction([ + administerCompanyAction, + answerStatusQuestionAction, + blockTaskAction, + commentOnApprovalAction, + controlWorkspaceServiceAction, + createTaskAction, + decideApprovalAction, + exportCompanyAction, + finishTaskAction, + genericApiRequestAction, + getAgentAction, + getApprovalAction, + getApprovalContextAction, + getTaskContextAction, + getTaskHistoryAction, + getWorkspaceRuntimeAction, + inspectOperationResultAction, + listAgentsAction, + listApprovalsAction, + listCasesAction, + listCompanySkillsAction, + listDocumentRevisionsAction, + listDocumentsAction, + listGoalsAction, + listProjectsAction, + listRoutinesAction, + listSecretMetadataAction, + manageRoutineAction, + readDocumentAction, + readSecretValueAction, + registerDeliverableAction, + reportProgressAction, + requestApprovalAction, + requestHumanInputAction, + requestReviewAction, + scheduleWakeAction, + searchTasksAction, + setDependenciesAction, + syncCompanySkillsAction, + upsertCaseAction, + writeDocumentAction, +] as const); + +export function paperclipProtocolAction(operationId: string) { + return PAPERCLIP_PROTOCOL_ACTIONS.find((action) => action.id === operationId); +} diff --git a/packages/paperclip-runner/src/protocol-actions/list-cases.ts b/packages/paperclip-runner/src/protocol-actions/list-cases.ts new file mode 100644 index 0000000000..4ca3d887bc --- /dev/null +++ b/packages/paperclip-runner/src/protocol-actions/list-cases.ts @@ -0,0 +1,119 @@ +/** Canonical definition and documentation for `list_cases`. */ +export const listCasesAction = { + "id": "list_cases", + "canonical": { + "operationId": "list_cases", + "surfaces": [ + "scenario" + ], + "placement": "optional_agent_tool", + "optionalGroup": "cases", + "requiredClaims": [ + "cases:read" + ], + "taskModes": [ + "standard", + "skill_test" + ], + "sideEffectClass": "read", + "idempotency": "none", + "disabledByDefault": false, + "realBindingStatus": "scenario_mock", + "realServiceBinding": "unbound", + "prpEvidence": "read projection surfaced via a tool-result item event; no control-plane state diff", + "prpBindingStatus": "audit_pending", + "legacyAliases": [], + "note": "Scenario/eval-only mock extension." + }, + "documentation": { + "title": "List Cases", + "description": "List Cases through the Capability cases capability set.", + "note": "Scenario/eval-only mock extension." + }, + "examples": { + "call": { + "operationId": "list_cases", + "input": {} + }, + "success": { + "ok": true, + "operationId": "list_cases", + "result": { + "schema": "paperclip.capability.tool-result.v1", + "ok": true, + "operationId": "example", + "operationResultId": "example", + "value": "example", + "commandResult": "example", + "authorization": "example" + } + } + }, + "live": null, + "scenario": { + "order": 24, + "descriptor": { + "operationId": "list_cases", + "version": 1, + "title": "List Cases", + "description": "List Cases through the Capability cases capability set.", + "inputSchema": { + "type": "object", + "properties": {}, + "required": [], + "additionalProperties": false + }, + "outputSchema": { + "type": "object", + "properties": { + "schema": { + "type": "string", + "enum": [ + "paperclip.capability.tool-result.v1" + ] + }, + "ok": { + "type": "boolean" + }, + "operationId": { + "type": "string", + "minLength": 1 + }, + "operationResultId": { + "type": "string", + "minLength": 1 + }, + "value": {}, + "commandResult": {}, + "authorization": {} + }, + "required": [ + "schema", + "ok", + "operationId", + "operationResultId", + "value", + "commandResult", + "authorization" + ], + "additionalProperties": false + }, + "disposition": "optional_agent_tool", + "optionalGroup": "cases", + "requiredClaims": [ + "cases:read" + ], + "taskModes": [ + "standard", + "skill_test" + ], + "sideEffectClass": "read", + "idempotency": "none", + "redaction": [], + "mockCommandMapping": { + "kind": "mock_extension", + "extension": "cases.list" + } + } + } +} as const; diff --git a/packages/paperclip-runner/src/protocol-actions/list-company-skills.ts b/packages/paperclip-runner/src/protocol-actions/list-company-skills.ts new file mode 100644 index 0000000000..c0622de7d1 --- /dev/null +++ b/packages/paperclip-runner/src/protocol-actions/list-company-skills.ts @@ -0,0 +1,119 @@ +/** Canonical definition and documentation for `list_company_skills`. */ +export const listCompanySkillsAction = { + "id": "list_company_skills", + "canonical": { + "operationId": "list_company_skills", + "surfaces": [ + "scenario" + ], + "placement": "optional_agent_tool", + "optionalGroup": "company_skills", + "requiredClaims": [ + "company_skills:read" + ], + "taskModes": [ + "standard", + "skill_test" + ], + "sideEffectClass": "read", + "idempotency": "none", + "disabledByDefault": false, + "realBindingStatus": "scenario_mock", + "realServiceBinding": "unbound", + "prpEvidence": "read projection surfaced via a tool-result item event; no control-plane state diff", + "prpBindingStatus": "audit_pending", + "legacyAliases": [], + "note": "Scenario/eval-only mock extension." + }, + "documentation": { + "title": "List Company Skills", + "description": "List Company Skills through the Capability company skills capability set.", + "note": "Scenario/eval-only mock extension." + }, + "examples": { + "call": { + "operationId": "list_company_skills", + "input": {} + }, + "success": { + "ok": true, + "operationId": "list_company_skills", + "result": { + "schema": "paperclip.capability.tool-result.v1", + "ok": true, + "operationId": "example", + "operationResultId": "example", + "value": "example", + "commandResult": "example", + "authorization": "example" + } + } + }, + "live": null, + "scenario": { + "order": 30, + "descriptor": { + "operationId": "list_company_skills", + "version": 1, + "title": "List Company Skills", + "description": "List Company Skills through the Capability company skills capability set.", + "inputSchema": { + "type": "object", + "properties": {}, + "required": [], + "additionalProperties": false + }, + "outputSchema": { + "type": "object", + "properties": { + "schema": { + "type": "string", + "enum": [ + "paperclip.capability.tool-result.v1" + ] + }, + "ok": { + "type": "boolean" + }, + "operationId": { + "type": "string", + "minLength": 1 + }, + "operationResultId": { + "type": "string", + "minLength": 1 + }, + "value": {}, + "commandResult": {}, + "authorization": {} + }, + "required": [ + "schema", + "ok", + "operationId", + "operationResultId", + "value", + "commandResult", + "authorization" + ], + "additionalProperties": false + }, + "disposition": "optional_agent_tool", + "optionalGroup": "company_skills", + "requiredClaims": [ + "company_skills:read" + ], + "taskModes": [ + "standard", + "skill_test" + ], + "sideEffectClass": "read", + "idempotency": "none", + "redaction": [], + "mockCommandMapping": { + "kind": "mock_extension", + "extension": "company_skills.list" + } + } + } +} as const; diff --git a/packages/paperclip-runner/src/protocol-actions/list-routines.ts b/packages/paperclip-runner/src/protocol-actions/list-routines.ts new file mode 100644 index 0000000000..173d0bdae9 --- /dev/null +++ b/packages/paperclip-runner/src/protocol-actions/list-routines.ts @@ -0,0 +1,119 @@ +/** Canonical definition and documentation for `list_routines`. */ +export const listRoutinesAction = { + "id": "list_routines", + "canonical": { + "operationId": "list_routines", + "surfaces": [ + "scenario" + ], + "placement": "optional_agent_tool", + "optionalGroup": "routines", + "requiredClaims": [ + "routines:read" + ], + "taskModes": [ + "standard", + "skill_test" + ], + "sideEffectClass": "read", + "idempotency": "none", + "disabledByDefault": false, + "realBindingStatus": "scenario_mock", + "realServiceBinding": "unbound", + "prpEvidence": "read projection surfaced via a tool-result item event; no control-plane state diff", + "prpBindingStatus": "audit_pending", + "legacyAliases": [], + "note": "Scenario/eval-only mock extension." + }, + "documentation": { + "title": "List Routines", + "description": "List Routines through the Capability routines capability set.", + "note": "Scenario/eval-only mock extension." + }, + "examples": { + "call": { + "operationId": "list_routines", + "input": {} + }, + "success": { + "ok": true, + "operationId": "list_routines", + "result": { + "schema": "paperclip.capability.tool-result.v1", + "ok": true, + "operationId": "example", + "operationResultId": "example", + "value": "example", + "commandResult": "example", + "authorization": "example" + } + } + }, + "live": null, + "scenario": { + "order": 28, + "descriptor": { + "operationId": "list_routines", + "version": 1, + "title": "List Routines", + "description": "List Routines through the Capability routines capability set.", + "inputSchema": { + "type": "object", + "properties": {}, + "required": [], + "additionalProperties": false + }, + "outputSchema": { + "type": "object", + "properties": { + "schema": { + "type": "string", + "enum": [ + "paperclip.capability.tool-result.v1" + ] + }, + "ok": { + "type": "boolean" + }, + "operationId": { + "type": "string", + "minLength": 1 + }, + "operationResultId": { + "type": "string", + "minLength": 1 + }, + "value": {}, + "commandResult": {}, + "authorization": {} + }, + "required": [ + "schema", + "ok", + "operationId", + "operationResultId", + "value", + "commandResult", + "authorization" + ], + "additionalProperties": false + }, + "disposition": "optional_agent_tool", + "optionalGroup": "routines", + "requiredClaims": [ + "routines:read" + ], + "taskModes": [ + "standard", + "skill_test" + ], + "sideEffectClass": "read", + "idempotency": "none", + "redaction": [], + "mockCommandMapping": { + "kind": "mock_extension", + "extension": "routines.list" + } + } + } +} as const; diff --git a/packages/paperclip-runner/src/protocol-actions/list-secret-metadata.ts b/packages/paperclip-runner/src/protocol-actions/list-secret-metadata.ts new file mode 100644 index 0000000000..83c7db252c --- /dev/null +++ b/packages/paperclip-runner/src/protocol-actions/list-secret-metadata.ts @@ -0,0 +1,119 @@ +/** Canonical definition and documentation for `list_secret_metadata`. */ +export const listSecretMetadataAction = { + "id": "list_secret_metadata", + "canonical": { + "operationId": "list_secret_metadata", + "surfaces": [ + "scenario" + ], + "placement": "optional_agent_tool", + "optionalGroup": "secrets", + "requiredClaims": [ + "secrets:metadata:read" + ], + "taskModes": [ + "standard", + "skill_test" + ], + "sideEffectClass": "read", + "idempotency": "none", + "disabledByDefault": false, + "realBindingStatus": "scenario_mock", + "realServiceBinding": "unbound", + "prpEvidence": "read projection surfaced via a tool-result item event; no control-plane state diff", + "prpBindingStatus": "audit_pending", + "legacyAliases": [], + "note": "Scenario/eval-only mock extension; metadata only." + }, + "documentation": { + "title": "List Secret Metadata", + "description": "List Secret Metadata through the Capability secrets capability set.", + "note": "Scenario/eval-only mock extension; metadata only." + }, + "examples": { + "call": { + "operationId": "list_secret_metadata", + "input": {} + }, + "success": { + "ok": true, + "operationId": "list_secret_metadata", + "result": { + "schema": "paperclip.capability.tool-result.v1", + "ok": true, + "operationId": "example", + "operationResultId": "example", + "value": "example", + "commandResult": "example", + "authorization": "example" + } + } + }, + "live": null, + "scenario": { + "order": 32, + "descriptor": { + "operationId": "list_secret_metadata", + "version": 1, + "title": "List Secret Metadata", + "description": "List Secret Metadata through the Capability secrets capability set.", + "inputSchema": { + "type": "object", + "properties": {}, + "required": [], + "additionalProperties": false + }, + "outputSchema": { + "type": "object", + "properties": { + "schema": { + "type": "string", + "enum": [ + "paperclip.capability.tool-result.v1" + ] + }, + "ok": { + "type": "boolean" + }, + "operationId": { + "type": "string", + "minLength": 1 + }, + "operationResultId": { + "type": "string", + "minLength": 1 + }, + "value": {}, + "commandResult": {}, + "authorization": {} + }, + "required": [ + "schema", + "ok", + "operationId", + "operationResultId", + "value", + "commandResult", + "authorization" + ], + "additionalProperties": false + }, + "disposition": "optional_agent_tool", + "optionalGroup": "secrets", + "requiredClaims": [ + "secrets:metadata:read" + ], + "taskModes": [ + "standard", + "skill_test" + ], + "sideEffectClass": "read", + "idempotency": "none", + "redaction": [], + "mockCommandMapping": { + "kind": "mock_extension", + "extension": "secrets.metadata" + } + } + } +} as const; diff --git a/packages/paperclip-runner/src/protocol-actions/manage-routine.ts b/packages/paperclip-runner/src/protocol-actions/manage-routine.ts new file mode 100644 index 0000000000..3f8377931c --- /dev/null +++ b/packages/paperclip-runner/src/protocol-actions/manage-routine.ts @@ -0,0 +1,124 @@ +/** Canonical definition and documentation for `manage_routine`. */ +export const manageRoutineAction = { + "id": "manage_routine", + "canonical": { + "operationId": "manage_routine", + "surfaces": [ + "scenario" + ], + "placement": "optional_agent_tool", + "optionalGroup": "routines", + "requiredClaims": [ + "routines:write" + ], + "taskModes": [ + "standard", + "skill_test" + ], + "sideEffectClass": "admin", + "idempotency": "required", + "disabledByDefault": false, + "realBindingStatus": "scenario_mock", + "realServiceBinding": "unbound", + "prpEvidence": "company admin/portability item event plus audit record", + "prpBindingStatus": "audit_pending", + "legacyAliases": [], + "note": "Scenario/eval-only mock extension." + }, + "documentation": { + "title": "Manage Routine", + "description": "Manage Routine through the Capability routines capability set.", + "note": "Scenario/eval-only mock extension." + }, + "examples": { + "call": { + "operationId": "manage_routine", + "input": {} + }, + "scenarioCall": { + "operationId": "manage_routine", + "idempotencyKey": "example", + "input": {} + }, + "success": { + "ok": true, + "operationId": "manage_routine", + "result": { + "schema": "paperclip.capability.tool-result.v1", + "ok": true, + "operationId": "example", + "operationResultId": "example", + "value": "example", + "commandResult": "example", + "authorization": "example" + } + } + }, + "live": null, + "scenario": { + "order": 29, + "descriptor": { + "operationId": "manage_routine", + "version": 1, + "title": "Manage Routine", + "description": "Manage Routine through the Capability routines capability set.", + "inputSchema": { + "type": "object", + "properties": {}, + "required": [], + "additionalProperties": false + }, + "outputSchema": { + "type": "object", + "properties": { + "schema": { + "type": "string", + "enum": [ + "paperclip.capability.tool-result.v1" + ] + }, + "ok": { + "type": "boolean" + }, + "operationId": { + "type": "string", + "minLength": 1 + }, + "operationResultId": { + "type": "string", + "minLength": 1 + }, + "value": {}, + "commandResult": {}, + "authorization": {} + }, + "required": [ + "schema", + "ok", + "operationId", + "operationResultId", + "value", + "commandResult", + "authorization" + ], + "additionalProperties": false + }, + "disposition": "optional_agent_tool", + "optionalGroup": "routines", + "requiredClaims": [ + "routines:write" + ], + "taskModes": [ + "standard", + "skill_test" + ], + "sideEffectClass": "admin", + "idempotency": "required", + "redaction": [], + "mockCommandMapping": { + "kind": "mock_extension", + "extension": "routines.manage" + } + } + } +} as const; diff --git a/packages/paperclip-runner/src/protocol-actions/read-secret-value.ts b/packages/paperclip-runner/src/protocol-actions/read-secret-value.ts new file mode 100644 index 0000000000..04b525f80b --- /dev/null +++ b/packages/paperclip-runner/src/protocol-actions/read-secret-value.ts @@ -0,0 +1,138 @@ +/** Canonical definition and documentation for `read_secret_value`. */ +export const readSecretValueAction = { + "id": "read_secret_value", + "canonical": { + "operationId": "read_secret_value", + "surfaces": [ + "scenario" + ], + "placement": "optional_agent_tool", + "optionalGroup": "secrets", + "requiredClaims": [ + "secrets:values:read" + ], + "taskModes": [ + "standard", + "skill_test" + ], + "sideEffectClass": "secret_read", + "idempotency": "none", + "disabledByDefault": false, + "realBindingStatus": "scenario_mock", + "realServiceBinding": "unbound", + "prpEvidence": "redacted tool-result item event; secret value never reaches the wire", + "prpBindingStatus": "audit_pending", + "legacyAliases": [], + "note": "Scenario/eval-only mock extension; secret value redacted from every observable sink." + }, + "documentation": { + "title": "Read Secret Value", + "description": "Read Secret Value through the Capability secrets capability set.", + "note": "Scenario/eval-only mock extension; secret value redacted from every observable sink." + }, + "examples": { + "call": { + "operationId": "read_secret_value", + "input": { + "name": "example" + } + }, + "success": { + "ok": true, + "operationId": "read_secret_value", + "result": { + "schema": "paperclip.capability.tool-result.v1", + "ok": true, + "operationId": "example", + "operationResultId": "example", + "value": "example", + "commandResult": "example", + "authorization": "example" + } + } + }, + "live": null, + "scenario": { + "order": 33, + "descriptor": { + "operationId": "read_secret_value", + "version": 1, + "title": "Read Secret Value", + "description": "Read Secret Value through the Capability secrets capability set.", + "inputSchema": { + "type": "object", + "properties": { + "name": { + "type": "string", + "minLength": 1 + } + }, + "required": [ + "name" + ], + "additionalProperties": false + }, + "outputSchema": { + "type": "object", + "properties": { + "schema": { + "type": "string", + "enum": [ + "paperclip.capability.tool-result.v1" + ] + }, + "ok": { + "type": "boolean" + }, + "operationId": { + "type": "string", + "minLength": 1 + }, + "operationResultId": { + "type": "string", + "minLength": 1 + }, + "value": {}, + "commandResult": {}, + "authorization": {} + }, + "required": [ + "schema", + "ok", + "operationId", + "operationResultId", + "value", + "commandResult", + "authorization" + ], + "additionalProperties": false + }, + "disposition": "optional_agent_tool", + "optionalGroup": "secrets", + "requiredClaims": [ + "secrets:values:read" + ], + "taskModes": [ + "standard", + "skill_test" + ], + "sideEffectClass": "secret_read", + "idempotency": "none", + "redaction": [ + { + "path": "$.value", + "replacement": "[SECRET_VALUE]", + "appliesTo": [ + "output", + "error", + "authorization_record" + ] + } + ], + "mockCommandMapping": { + "kind": "mock_extension", + "extension": "secrets.value" + } + } + } +} as const; diff --git a/packages/paperclip-runner/src/protocol-actions/register-deliverable.ts b/packages/paperclip-runner/src/protocol-actions/register-deliverable.ts index 040f3477db..f22781b40a 100644 --- a/packages/paperclip-runner/src/protocol-actions/register-deliverable.ts +++ b/packages/paperclip-runner/src/protocol-actions/register-deliverable.ts @@ -42,6 +42,18 @@ export const registerDeliverableAction = { "title": "example" } }, + "scenarioCall": { + "operationId": "register_deliverable", + "idempotencyKey": "example", + "input": { + "filename": "example", + "contentType": "example", + "byteSize": 1, + "sha256": "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef", + "contentRef": "example", + "title": "example" + } + }, "success": { "ok": true, "operationId": "register_deliverable", diff --git a/packages/paperclip-runner/src/protocol-actions/report-progress.ts b/packages/paperclip-runner/src/protocol-actions/report-progress.ts index f562c73f6e..9c1e27b753 100644 --- a/packages/paperclip-runner/src/protocol-actions/report-progress.ts +++ b/packages/paperclip-runner/src/protocol-actions/report-progress.ts @@ -40,6 +40,13 @@ export const reportProgressAction = { "body": "example" } }, + "scenarioCall": { + "operationId": "report_progress", + "idempotencyKey": "example", + "input": { + "body": "example" + } + }, "success": { "ok": true, "operationId": "report_progress", diff --git a/packages/paperclip-runner/src/protocol-actions/request-approval.ts b/packages/paperclip-runner/src/protocol-actions/request-approval.ts index 5f98ea1ef6..6f19a39a76 100644 --- a/packages/paperclip-runner/src/protocol-actions/request-approval.ts +++ b/packages/paperclip-runner/src/protocol-actions/request-approval.ts @@ -39,6 +39,14 @@ export const requestApprovalAction = { "payload": {} } }, + "scenarioCall": { + "operationId": "request_approval", + "idempotencyKey": "example", + "input": { + "approvalType": "example", + "payload": {} + } + }, "success": { "ok": true, "operationId": "request_approval", diff --git a/packages/paperclip-runner/src/protocol-actions/request-human-input.ts b/packages/paperclip-runner/src/protocol-actions/request-human-input.ts index 34081f7d3e..1039ddc9af 100644 --- a/packages/paperclip-runner/src/protocol-actions/request-human-input.ts +++ b/packages/paperclip-runner/src/protocol-actions/request-human-input.ts @@ -41,6 +41,16 @@ export const requestHumanInputAction = { "continuationPolicy": "none" } }, + "scenarioCall": { + "operationId": "request_human_input", + "idempotencyKey": "example", + "input": { + "interactionKind": "confirmation", + "title": "example", + "prompt": "example", + "continuationPolicy": "none" + } + }, "success": { "ok": true, "operationId": "request_human_input", diff --git a/packages/paperclip-runner/src/protocol-actions/request-review.ts b/packages/paperclip-runner/src/protocol-actions/request-review.ts index cb36d25d8d..e44fd0f7ea 100644 --- a/packages/paperclip-runner/src/protocol-actions/request-review.ts +++ b/packages/paperclip-runner/src/protocol-actions/request-review.ts @@ -36,6 +36,13 @@ export const requestReviewAction = { "summary": "example" } }, + "scenarioCall": { + "operationId": "request_review", + "idempotencyKey": "example", + "input": { + "summary": "example" + } + }, "success": { "ok": true, "operationId": "request_review", diff --git a/packages/paperclip-runner/src/protocol-actions/schedule-wake.ts b/packages/paperclip-runner/src/protocol-actions/schedule-wake.ts new file mode 100644 index 0000000000..ba3b4e8819 --- /dev/null +++ b/packages/paperclip-runner/src/protocol-actions/schedule-wake.ts @@ -0,0 +1,163 @@ +/** Canonical definition and documentation for `schedule_wake`. */ +export const scheduleWakeAction = { + "id": "schedule_wake", + "canonical": { + "operationId": "schedule_wake", + "surfaces": [ + "live" + ], + "placement": "optional_agent_tool", + "optionalGroup": null, + "requiredClaims": [ + "control_plane:wakes" + ], + "taskModes": [ + "standard", + "skill_test" + ], + "sideEffectClass": "task_write", + "idempotency": "required", + "disabledByDefault": false, + "realBindingStatus": "live_codex", + "realServiceBinding": "unbound", + "prpEvidence": "semantic-operation item event plus active-task state diff, work-assessment, and issue-status-decision events", + "prpBindingStatus": "audit_pending", + "legacyAliases": [], + "note": "Bounded, deterministic mock wake scheduling; requires the control_plane:wakes claim. Live-only continuation primitive." + }, + "documentation": { + "title": "Schedule bounded wake", + "description": "Schedule a deterministic mock continuation wake.", + "note": "Bounded, deterministic mock wake scheduling; requires the control_plane:wakes claim. Live-only continuation primitive." + }, + "examples": { + "call": { + "operationId": "schedule_wake", + "input": { + "idempotencyKey": "example", + "reason": "manual", + "delayTicks": 1 + } + }, + "success": { + "ok": true, + "operationId": "schedule_wake", + "result": { + "commandId": "example", + "disposition": "applied", + "stateRevision": 1, + "entityRefs": [ + "example" + ], + "scheduledWakeIds": [ + "example" + ] + } + } + }, + "live": { + "order": 26, + "descriptor": { + "schema": "paperclip.semantic-tool.v1", + "operationId": "schedule_wake", + "version": 1, + "title": "Schedule bounded wake", + "description": "Schedule a deterministic mock continuation wake.", + "exposure": "optional", + "requiredClaims": [ + "control_plane:wakes" + ], + "allowedModes": [ + "standard", + "skill_test" + ], + "inputSchema": { + "type": "object", + "properties": { + "idempotencyKey": { + "type": "string", + "description": "Caller-stable retry key.", + "minLength": 1, + "maxLength": 240 + }, + "reason": { + "enum": [ + "manual", + "issue_commented", + "interaction_resolved", + "approval_resolved", + "blockers_resolved", + "scheduled_retry", + "resume" + ] + }, + "payload": { + "type": "object", + "additionalProperties": true + }, + "delayTicks": { + "type": "integer", + "minimum": 1, + "maximum": 10000 + } + }, + "required": [ + "idempotencyKey", + "reason", + "delayTicks" + ], + "additionalProperties": false + }, + "outputSchema": { + "type": "object", + "properties": { + "commandId": { + "type": "string", + "description": "Stable mock command identifier.", + "minLength": 1, + "maxLength": 200 + }, + "disposition": { + "enum": [ + "applied", + "duplicate" + ] + }, + "stateRevision": { + "type": "integer", + "minimum": 0 + }, + "entityRefs": { + "type": "array", + "description": "Mock entities affected by the operation.", + "items": { + "type": "string", + "minLength": 1 + }, + "maxItems": 200, + "uniqueItems": true + }, + "scheduledWakeIds": { + "type": "array", + "description": "Wake identifiers scheduled by the operation.", + "items": { + "type": "string", + "minLength": 1 + }, + "maxItems": 200, + "uniqueItems": true + } + }, + "required": [ + "commandId", + "disposition", + "stateRevision", + "entityRefs", + "scheduledWakeIds" + ], + "additionalProperties": false + } + } + }, + "scenario": null +} as const; diff --git a/packages/paperclip-runner/src/protocol-actions/set-dependencies.ts b/packages/paperclip-runner/src/protocol-actions/set-dependencies.ts index b011948bb6..26eb9ff2e0 100644 --- a/packages/paperclip-runner/src/protocol-actions/set-dependencies.ts +++ b/packages/paperclip-runner/src/protocol-actions/set-dependencies.ts @@ -40,6 +40,15 @@ export const setDependenciesAction = { ] } }, + "scenarioCall": { + "operationId": "set_dependencies", + "idempotencyKey": "example", + "input": { + "blockedByTaskIds": [ + "example" + ] + } + }, "success": { "ok": true, "operationId": "set_dependencies", diff --git a/packages/paperclip-runner/src/protocol-actions/sync-company-skills.ts b/packages/paperclip-runner/src/protocol-actions/sync-company-skills.ts new file mode 100644 index 0000000000..a5ea0631da --- /dev/null +++ b/packages/paperclip-runner/src/protocol-actions/sync-company-skills.ts @@ -0,0 +1,124 @@ +/** Canonical definition and documentation for `sync_company_skills`. */ +export const syncCompanySkillsAction = { + "id": "sync_company_skills", + "canonical": { + "operationId": "sync_company_skills", + "surfaces": [ + "scenario" + ], + "placement": "optional_agent_tool", + "optionalGroup": "company_skills", + "requiredClaims": [ + "company_skills:write" + ], + "taskModes": [ + "standard", + "skill_test" + ], + "sideEffectClass": "admin", + "idempotency": "required", + "disabledByDefault": false, + "realBindingStatus": "scenario_mock", + "realServiceBinding": "unbound", + "prpEvidence": "company admin/portability item event plus audit record", + "prpBindingStatus": "audit_pending", + "legacyAliases": [], + "note": "Scenario/eval-only mock extension." + }, + "documentation": { + "title": "Sync Company Skills", + "description": "Sync Company Skills through the Capability company skills capability set.", + "note": "Scenario/eval-only mock extension." + }, + "examples": { + "call": { + "operationId": "sync_company_skills", + "input": {} + }, + "scenarioCall": { + "operationId": "sync_company_skills", + "idempotencyKey": "example", + "input": {} + }, + "success": { + "ok": true, + "operationId": "sync_company_skills", + "result": { + "schema": "paperclip.capability.tool-result.v1", + "ok": true, + "operationId": "example", + "operationResultId": "example", + "value": "example", + "commandResult": "example", + "authorization": "example" + } + } + }, + "live": null, + "scenario": { + "order": 31, + "descriptor": { + "operationId": "sync_company_skills", + "version": 1, + "title": "Sync Company Skills", + "description": "Sync Company Skills through the Capability company skills capability set.", + "inputSchema": { + "type": "object", + "properties": {}, + "required": [], + "additionalProperties": false + }, + "outputSchema": { + "type": "object", + "properties": { + "schema": { + "type": "string", + "enum": [ + "paperclip.capability.tool-result.v1" + ] + }, + "ok": { + "type": "boolean" + }, + "operationId": { + "type": "string", + "minLength": 1 + }, + "operationResultId": { + "type": "string", + "minLength": 1 + }, + "value": {}, + "commandResult": {}, + "authorization": {} + }, + "required": [ + "schema", + "ok", + "operationId", + "operationResultId", + "value", + "commandResult", + "authorization" + ], + "additionalProperties": false + }, + "disposition": "optional_agent_tool", + "optionalGroup": "company_skills", + "requiredClaims": [ + "company_skills:write" + ], + "taskModes": [ + "standard", + "skill_test" + ], + "sideEffectClass": "admin", + "idempotency": "required", + "redaction": [], + "mockCommandMapping": { + "kind": "mock_extension", + "extension": "company_skills.sync" + } + } + } +} as const; diff --git a/packages/paperclip-runner/src/protocol-actions/upsert-case.ts b/packages/paperclip-runner/src/protocol-actions/upsert-case.ts new file mode 100644 index 0000000000..4d8435e12a --- /dev/null +++ b/packages/paperclip-runner/src/protocol-actions/upsert-case.ts @@ -0,0 +1,141 @@ +/** Canonical definition and documentation for `upsert_case`. */ +export const upsertCaseAction = { + "id": "upsert_case", + "canonical": { + "operationId": "upsert_case", + "surfaces": [ + "scenario" + ], + "placement": "optional_agent_tool", + "optionalGroup": "cases", + "requiredClaims": [ + "cases:write" + ], + "taskModes": [ + "standard", + "skill_test" + ], + "sideEffectClass": "company_write", + "idempotency": "required", + "disabledByDefault": false, + "realBindingStatus": "scenario_mock", + "realServiceBinding": "unbound", + "prpEvidence": "semantic-operation item event plus company-entity state diff and audit record", + "prpBindingStatus": "audit_pending", + "legacyAliases": [], + "note": "Scenario/eval-only mock extension." + }, + "documentation": { + "title": "Upsert Case", + "description": "Upsert Case through the Capability cases capability set.", + "note": "Scenario/eval-only mock extension." + }, + "examples": { + "call": { + "operationId": "upsert_case", + "input": { + "key": "example", + "body": "example" + } + }, + "scenarioCall": { + "operationId": "upsert_case", + "idempotencyKey": "example", + "input": { + "key": "example", + "body": "example" + } + }, + "success": { + "ok": true, + "operationId": "upsert_case", + "result": { + "schema": "paperclip.capability.tool-result.v1", + "ok": true, + "operationId": "example", + "operationResultId": "example", + "value": "example", + "commandResult": "example", + "authorization": "example" + } + } + }, + "live": null, + "scenario": { + "order": 25, + "descriptor": { + "operationId": "upsert_case", + "version": 1, + "title": "Upsert Case", + "description": "Upsert Case through the Capability cases capability set.", + "inputSchema": { + "type": "object", + "properties": { + "key": { + "type": "string", + "minLength": 1 + }, + "body": { + "type": "string" + } + }, + "required": [ + "key", + "body" + ], + "additionalProperties": false + }, + "outputSchema": { + "type": "object", + "properties": { + "schema": { + "type": "string", + "enum": [ + "paperclip.capability.tool-result.v1" + ] + }, + "ok": { + "type": "boolean" + }, + "operationId": { + "type": "string", + "minLength": 1 + }, + "operationResultId": { + "type": "string", + "minLength": 1 + }, + "value": {}, + "commandResult": {}, + "authorization": {} + }, + "required": [ + "schema", + "ok", + "operationId", + "operationResultId", + "value", + "commandResult", + "authorization" + ], + "additionalProperties": false + }, + "disposition": "optional_agent_tool", + "optionalGroup": "cases", + "requiredClaims": [ + "cases:write" + ], + "taskModes": [ + "standard", + "skill_test" + ], + "sideEffectClass": "company_write", + "idempotency": "required", + "redaction": [], + "mockCommandMapping": { + "kind": "mock_extension", + "extension": "cases.upsert" + } + } + } +} as const; diff --git a/packages/paperclip-runner/src/protocol-actions/write-document.ts b/packages/paperclip-runner/src/protocol-actions/write-document.ts index 2b620352a3..454ddc9eb5 100644 --- a/packages/paperclip-runner/src/protocol-actions/write-document.ts +++ b/packages/paperclip-runner/src/protocol-actions/write-document.ts @@ -40,6 +40,16 @@ export const writeDocumentAction = { "baseRevisionId": "example" } }, + "scenarioCall": { + "operationId": "write_document", + "idempotencyKey": "example", + "input": { + "key": "example", + "title": "example", + "body": "example", + "baseRevisionId": "example" + } + }, "success": { "ok": true, "operationId": "write_document",