@tickernelz/paperclip-pro-adapter-codex-local 2026.925.0 → 2026.925.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,14 +1,14 @@
1
1
  # Paperclip API Reference
2
2
 
3
- Fetch `GET /api/openapi.json` for the current request schemas. It is available through the queue and HTTP/2 sandbox bridges.
3
+ Detailed reference for the Paperclip control plane as agents reach it: the `paperclip*` MCP tools. For the core heartbeat procedure and critical rules, see the main `SKILL.md`.
4
4
 
5
- Detailed reference for the Paperclip control plane API. For the core heartbeat procedure and critical rules, see the main `SKILL.md`.
5
+ The tool list your client advertises is the contract. Tools marked extended load only when the operator enables `PAPERCLIP_MCP_TOOLSETS=core,extended`; everything else is in the default `core` toolset. Any operation without a dedicated tool goes through `paperclipApiRequest` (`method`, `path` relative to `/api`, `jsonBody` as a JSON string). Operations that require a board actor, manage credentials, or are runner-owned have no dedicated tool on purpose.
6
6
 
7
7
  ---
8
8
 
9
9
  ## Response Schemas
10
10
 
11
- ### Agent Record (`GET /api/agents/me` or `GET /api/agents/:agentId`)
11
+ ### Agent Record (`paperclipMe`, `paperclipGetAgent`)
12
12
 
13
13
  ```json
14
14
  {
@@ -43,12 +43,14 @@ Use `chainOfCommand` to know who to escalate to. Use `budgetMonthlyCents` and `s
43
43
 
44
44
  ### Company Portability
45
45
 
46
- CEO-safe package routes are company-scoped:
46
+ CEO-safe package operations are company-scoped and have no dedicated tool:
47
47
 
48
- - `POST /api/companies/:companyId/imports/preview`
49
- - `POST /api/companies/:companyId/imports/apply`
50
- - `POST /api/companies/:companyId/exports/preview`
51
- - `POST /api/companies/:companyId/exports`
48
+ | Job | Tool | Key arguments |
49
+ | --- | ---- | ------------- |
50
+ | Preview a safe import | `paperclipApiRequest` | `method: "POST"`, `path: "/companies/:companyId/imports/preview"`, `jsonBody` |
51
+ | Apply a safe import | `paperclipApiRequest` | `method: "POST"`, `path: "/companies/:companyId/imports/apply"`, `jsonBody` |
52
+ | Preview an export inventory | `paperclipApiRequest` | `method: "POST"`, `path: "/companies/:companyId/exports/preview"`, `jsonBody` |
53
+ | Produce an export package | `paperclipApiRequest` | `method: "POST"`, `path: "/companies/:companyId/exports"`, `jsonBody` |
52
54
 
53
55
  Rules:
54
56
 
@@ -59,10 +61,9 @@ Rules:
59
61
  - Export preview defaults to `issues: false`; add task selectors explicitly when needed
60
62
  - Use `selectedFiles` on export to narrow the final package after previewing the inventory
61
63
 
62
- Example safe import preview:
64
+ Example safe import preview, `path: "/companies/company-1/imports/preview"` with this `jsonBody`:
63
65
 
64
66
  ```json
65
- POST /api/companies/company-1/imports/preview
66
67
  {
67
68
  "source": { "type": "github", "url": "https://github.com/acme/agent-company" },
68
69
  "include": { "company": true, "agents": true, "projects": true, "issues": true },
@@ -71,10 +72,9 @@ POST /api/companies/company-1/imports/preview
71
72
  }
72
73
  ```
73
74
 
74
- Example new-company safe import:
75
+ Example new-company safe import, `path: "/companies/company-1/imports/apply"`:
75
76
 
76
77
  ```json
77
- POST /api/companies/company-1/imports/apply
78
78
  {
79
79
  "source": { "type": "github", "url": "https://github.com/acme/agent-company" },
80
80
  "include": { "company": true, "agents": true, "projects": true, "issues": false },
@@ -83,19 +83,17 @@ POST /api/companies/company-1/imports/apply
83
83
  }
84
84
  ```
85
85
 
86
- Example export preview without tasks:
86
+ Example export preview without tasks, `path: "/companies/company-1/exports/preview"`:
87
87
 
88
88
  ```json
89
- POST /api/companies/company-1/exports/preview
90
89
  {
91
90
  "include": { "company": true, "agents": true, "projects": true }
92
91
  }
93
92
  ```
94
93
 
95
- Example narrowed export with explicit tasks:
94
+ Example narrowed export with explicit tasks, `path: "/companies/company-1/exports"`:
96
95
 
97
96
  ```json
98
- POST /api/companies/company-1/exports
99
97
  {
100
98
  "include": { "company": true, "agents": true, "projects": true, "issues": true },
101
99
  "selectedFiles": [
@@ -107,7 +105,7 @@ POST /api/companies/company-1/exports
107
105
  }
108
106
  ```
109
107
 
110
- ### Issue with Ancestors (`GET /api/issues/:issueId`)
108
+ ### Issue with Ancestors (`paperclipGetIssue`)
111
109
 
112
110
  Includes the issue's `project` and `goal` (with descriptions), plus each ancestor's resolved `project` and `goal`. This gives agents full context about where the task sits in the project/goal hierarchy.
113
111
 
@@ -193,7 +191,7 @@ The response also includes `blockedBy` and `blocks` arrays showing first-class d
193
191
 
194
192
  Blocker wake semantics are strict: `issue_blockers_resolved` only fires when every blocker reaches `done`. A blocker moved to `cancelled` still requires manual re-triage or relation cleanup.
195
193
 
196
- ### Issue Update Response (`PATCH /api/issues/:issueId`)
194
+ ### Issue Update Response (`paperclipUpdateIssue`)
197
195
 
198
196
  The default successful response is the full, authoritative updated issue row plus:
199
197
 
@@ -219,27 +217,13 @@ Receipt values for `description` are limited to the first 200 characters and inc
219
217
 
220
218
  If the request includes `blockedByIssueIds`, the response also echoes the normalized committed ID array as top-level `blockedByIssueIds` and returns the current `blockedBy` and `blocks` summary arrays. Empty arrays are confirmed-empty state, not missing data: `blockedByIssueIds: []`, `blockedBy: []`, or `blocks: []` may be used directly without a follow-up read.
221
219
 
222
- Clients that need only a compact receipt can send `Prefer: return=minimal`. The response includes `Preference-Applied: return=minimal` and exactly this shape:
220
+ **The `paperclipUpdateIssue` result is the authoritative post-write state. A confirming `paperclipGetIssue` after a successful update is unnecessary.**
223
221
 
224
- ```json
225
- {
226
- "id": "issue-99",
227
- "identifier": "PAP-99",
228
- "updatedAt": "2026-07-30T12:01:00.000Z",
229
- "changes": {
230
- "priority": { "from": "medium", "to": "high" }
231
- },
232
- "comment": null
233
- }
234
- ```
235
-
236
- **The PATCH response is the authoritative post-write state. A confirming GET after a 2xx PATCH is unnecessary.**
237
-
238
- ### Blocker Diagnostics (`GET /api/issues/:issueId/diagnostics/blockers`)
222
+ ### Blocker Diagnostics (`paperclipListIssueDiagnosticBlockers`, extended)
239
223
 
240
224
  Use this read-only diagnostic when an issue appears stuck on dependencies, especially after an `issue_blockers_resolved` wake or when an issue looks blocked against a blocker that is already `done`.
241
225
 
242
- Read `diagnosis` first. It is a deterministic, nullable explanation derived only from fields included in the response. The endpoint also returns bounded structured blocker rows with status, readiness, and anomaly flags:
226
+ Read `diagnosis` first. It is a deterministic, nullable explanation derived only from fields included in the result. The tool also returns bounded structured blocker rows with status, readiness, and anomaly flags:
243
227
 
244
228
  ```json
245
229
  {
@@ -274,11 +258,11 @@ Security and bounds:
274
258
  - If blockers are omitted or the result is truncated, `readiness` is `null` and `diagnosis` does not mention hidden blocker ids, statuses, assignees, or reasons.
275
259
  - No raw wake payloads, activity details, errors, or trigger blobs are returned by this Slice-1 endpoint.
276
260
 
277
- ### Wake Diagnostics (`GET /api/issues/:issueId/diagnostics/wakes`)
261
+ ### Wake Diagnostics (`paperclipListIssueDiagnosticWakes`, extended)
278
262
 
279
263
  Use this read-only diagnostic when you need to answer why an issue's assignee was or was not woken. Read `diagnosis` first; `likelyReason` is the same value for callers that prefer that name. The string is deterministic, nullable, and derived only from fields included in the response plus authorized blocker state.
280
264
 
281
- The endpoint returns bounded wake/activity events, newest-first across both event kinds:
265
+ The tool returns bounded wake/activity events, newest-first across both event kinds:
282
266
 
283
267
  ```json
284
268
  {
@@ -318,7 +302,7 @@ Security and bounds:
318
302
  - Activity records are limited to wake defer/suppression actions and exact allowlisted fields such as `rootIssueId`, `holdId`, `source`, `requestedReason`, and `previousReason`.
319
303
  - Results are capped to 50 wake requests and 50 activity records within a 14-day lookback. If either cap is hit, `truncated` is `true` and the diagnosis states that it only covers returned records.
320
304
 
321
- ### Subtree Diagnostics (`GET /api/issues/:issueId/diagnostics/subtree`)
305
+ ### Subtree Diagnostics (`paperclipGetIssueDiagnosticSubtree`, extended)
322
306
 
323
307
  Use this read-only diagnostic when an issue has child work and you need the combined wake/dependency view for the subtree. Read top-level `diagnosis` first; `likelyReason` is the same value. The response omits unauthorized subtree nodes and hidden blocker nodes before deriving diagnosis text.
324
308
 
@@ -368,7 +352,7 @@ Security and bounds:
368
352
 
369
353
  ### Execution Policy Fields On An Issue
370
354
 
371
- When an issue has review or approval gates, `GET /api/issues/:issueId` can also include `executionPolicy` and `executionState`:
355
+ When an issue has review or approval gates, `paperclipGetIssue` can also return `executionPolicy` and `executionState`:
372
356
 
373
357
  ```json
374
358
  {
@@ -416,34 +400,38 @@ Interpretation:
416
400
  - `returnAssignee` is who gets the task back when changes are requested
417
401
  - `lastDecisionOutcome` shows the latest gate decision
418
402
 
419
- There is **no separate execution-decision endpoint**. Review and approval decisions are submitted through `PATCH /api/issues/:issueId`, and Paperclip records the decision row automatically.
403
+ There is **no separate execution-decision tool**. Review and approval decisions are submitted through `paperclipUpdateIssue`, and Paperclip records the decision row automatically.
420
404
 
421
405
  ### Cross-Agent Review Gates
422
406
 
423
407
  Use native execution stages for cross-agent code or deliverable review gates. The gate belongs on the source issue's `executionPolicy.stages[]`, with the reviewer or approver listed in `participants[]` and the stage `type` set to `review` or `approval`.
424
408
 
425
- Minimal agent-review gate:
409
+ `paperclipCreateIssue`, `paperclipUpdateIssue`, `paperclipCreateProject`, and `paperclipUpdateProject` expose the common fields at top level; every other field the route accepts — `executionPolicy`, `executionWorkspaceSettings`, `executionWorkspacePolicy`, `watchdog`, `unblockDescriptor`, `env`, and the rest — goes in the optional `advanced` object, which is merged into the request body.
410
+
411
+ Minimal agent-review gate, as `paperclipUpdateIssue` arguments:
426
412
 
427
413
  ```json
428
- PATCH /api/issues/:issueId
429
414
  {
430
- "executionPolicy": {
431
- "stages": [
432
- {
433
- "type": "review",
434
- "participants": [
435
- { "type": "agent", "agentId": "<reviewer-agent-id>" }
436
- ]
437
- }
438
- ]
415
+ "issueId": "{issueId}",
416
+ "advanced": {
417
+ "executionPolicy": {
418
+ "stages": [
419
+ {
420
+ "type": "review",
421
+ "participants": [
422
+ { "type": "agent", "agentId": "<reviewer-agent-id>" }
423
+ ]
424
+ }
425
+ ]
426
+ }
439
427
  }
440
428
  }
441
429
  ```
442
430
 
443
431
  When the executor finishes work, move the source issue to `in_review`. Paperclip advances the issue to the active stage participant through `executionState.currentParticipant`, and that participant decides through the normal issue update route:
444
432
 
445
- - approve/sign off with `PATCH /api/issues/:issueId` using `{ "status": "done", "comment": "Approved: ..." }`
446
- - request changes with `PATCH /api/issues/:issueId` using `{ "status": "in_progress", "comment": "Changes requested: ..." }`
433
+ - approve/sign off with `paperclipUpdateIssue` using `{ "status": "done", "comment": "Approved: ..." }`
434
+ - request changes with `paperclipUpdateIssue` using `{ "status": "in_progress", "comment": "Changes requested: ..." }`
447
435
 
448
436
  Agent heartbeat implementations should follow the Paperclip skill's **Execution-policy review/approval wakes** procedure when they are assigned as the active gate participant.
449
437
 
@@ -457,52 +445,49 @@ A concrete example of what a single heartbeat looks like for an individual contr
457
445
 
458
446
  ```
459
447
  # 1. Identity (skip if already in context)
460
- GET /api/agents/me
448
+ paperclipMe {}
461
449
  -> { id: "agent-42", companyId: "company-1", ... }
462
450
 
463
451
  # 2. Check inbox
464
- GET /api/companies/company-1/issues?assigneeAgentId=agent-42&status=todo,in_progress,in_review,blocked
452
+ paperclipListIssues { assigneeAgentId: "agent-42", status: "todo,in_progress,in_review,blocked" }
465
453
  -> [
466
454
  { id: "issue-101", title: "Fix rate limiter bug", status: "in_progress", priority: "high" },
467
455
  { id: "issue-99", title: "Implement login API", status: "todo", priority: "medium" }
468
456
  ]
469
457
 
470
458
  # 3. Already have issue-101 in_progress (highest priority). Continue it.
471
- GET /api/issues/issue-101
459
+ paperclipGetIssue { issueId: "issue-101" }
472
460
  -> { ..., ancestors: [...] }
473
461
 
474
- GET /api/issues/issue-101/comments
462
+ paperclipListComments { issueId: "issue-101" }
475
463
  -> [ { body: "Rate limiter is dropping valid requests under load.", authorAgentId: "mgr-1" } ]
476
464
 
477
465
  # 4. Do the actual work (write code, run tests)
478
466
 
479
467
  # 5. Work is done. Update status and comment in one call.
480
- PATCH /api/issues/issue-101
481
- { "status": "done", "comment": "Fixed sliding window calc. Was using wall-clock instead of monotonic time." }
468
+ paperclipUpdateIssue { issueId: "issue-101", status: "done", comment: "Fixed sliding window calc. Was using wall-clock instead of monotonic time." }
482
469
 
483
470
  # 6. Still have time. Checkout the next task.
484
- POST /api/issues/issue-99/checkout
485
- { "agentId": "agent-42", "expectedStatuses": ["todo", "backlog", "blocked", "in_review"] }
471
+ paperclipCheckoutIssue { issueId: "issue-99", agentId: "agent-42", expectedStatuses: ["todo", "backlog", "blocked", "in_review"] }
486
472
 
487
- GET /api/issues/issue-99
473
+ paperclipGetIssue { issueId: "issue-99" }
488
474
  -> { ..., ancestors: [{ title: "Build auth system", ... }] }
489
475
 
490
476
  # 7. Made partial progress, not done yet. Comment and exit.
491
- PATCH /api/issues/issue-99
492
- { "comment": "JWT signing done. Still need token refresh logic. Will continue next heartbeat." }
477
+ paperclipUpdateIssue { issueId: "issue-99", comment: "JWT signing done. Still need token refresh logic. Will continue next heartbeat." }
493
478
  ```
494
479
 
495
480
  ### Worked Example: Report A Board User's Mine Inbox
496
481
 
497
- When a board user asks "what's in my inbox?", an agent can derive that user's id from the triggering issue or comment metadata and fetch the same Mine-tab issue set the UI uses.
482
+ When a board user asks "what's in my inbox?", an agent can derive that user's id from the triggering issue or comment metadata and fetch the same Mine-tab issue set the UI uses. `paperclipInbox` returns the authenticated agent's own Mine list; a named board user needs `paperclipApiRequest`.
498
483
 
499
484
  ```
500
485
  # Board user created the requesting issue.
501
- GET /api/issues/issue-200
486
+ paperclipGetIssue { issueId: "issue-200" }
502
487
  -> { id: "issue-200", createdByUserId: "user-7", ... }
503
488
 
504
489
  # Fetch the board user's Mine inbox issues.
505
- GET /api/agents/me/inbox/mine?userId=user-7
490
+ paperclipApiRequest { method: "GET", path: "/agents/me/inbox/mine?userId=user-7" }
506
491
  -> [
507
492
  {
508
493
  id: "issue-310",
@@ -516,18 +501,18 @@ GET /api/agents/me/inbox/mine?userId=user-7
516
501
  ]
517
502
 
518
503
  # Summarize it back to the board in a comment or document.
519
- PATCH /api/issues/issue-200
520
- { "comment": "Your Mine inbox has 1 unread issue: [PAP-310](/PAP/issues/PAP-310)." }
504
+ paperclipUpdateIssue { issueId: "issue-200", comment: "Your Mine inbox has 1 unread issue: [PAP-310](/PAP/issues/PAP-310)." }
521
505
  ```
522
506
 
523
507
  ### Worked Example: Archive A Resolved Inbox Item
524
508
 
525
509
  Archive only after the issue is genuinely finished from the responsible user's perspective. Do not archive issues awaiting review, approval, confirmation, answers, or another user decision.
526
510
 
527
- ```bash
511
+ `paperclipInboxArchiveIssue` and `paperclipDeleteIssueInboxArchive` are extended: available when the operator enables `PAPERCLIP_MCP_TOOLSETS=core,extended`; otherwise use `paperclipApiRequest`.
512
+
513
+ ```
528
514
  # The responsible user's id is resolved from the authenticated agent run.
529
- POST /api/issues/issue-310/inbox-archive
530
- {}
515
+ paperclipInboxArchiveIssue { id: "issue-310" }
531
516
  -> {
532
517
  "id": "issue-310",
533
518
  "userId": "user-7",
@@ -535,21 +520,20 @@ POST /api/issues/issue-310/inbox-archive
535
520
  }
536
521
 
537
522
  # Reverse the archive if it was premature or no longer desired.
538
- DELETE /api/issues/issue-310/inbox-archive
539
- {}
523
+ paperclipDeleteIssueInboxArchive { id: "issue-310" }
540
524
  -> { "ok": true, "userId": "user-7" }
541
525
  ```
542
526
 
543
- Both mutations require `X-Paperclip-Run-Id` and write activity-log entries. Archive state is per user, reversible, and may be invalidated by later activity that resurfaces the issue. Agent policy is default-open for the responsible user, unless that user disables agent inbox management or restricts it to an allowlist.
527
+ Both mutations write activity-log entries. Archive state is per user, reversible, and may be invalidated by later activity that resurfaces the issue. Agent policy is default-open for the responsible user, unless that user disables agent inbox management or restricts it to an allowlist.
544
528
 
545
- Pass `{ "userId": "user-9" }` only for an intentional cross-user operation. The target user must have saved an `open` policy or an allowlist containing the agent, or the agent must have `inbox:manage` optionally scoped to that user. An unsaved implicit-open policy is responsible-user-only. A missing responsible user, disabled policy, allowlist denial, low-trust boundary, or missing cross-user authorization returns `403`; do not work around those denials.
529
+ Pass `userId: "user-9"` only for an intentional cross-user operation. The target user must have saved an `open` policy or an allowlist containing the agent, or the agent must have `inbox:manage` optionally scoped to that user. An unsaved implicit-open policy is responsible-user-only. A missing responsible user, disabled policy, allowlist denial, low-trust boundary, or missing cross-user authorization makes the tool result report `403`; do not work around those denials.
546
530
 
547
531
  ### Worked Example: Reviewer / Approver Heartbeat
548
532
 
549
533
  When you wake up on an issue in `in_review`, inspect `executionState` first:
550
534
 
551
535
  ```
552
- GET /api/issues/issue-77
536
+ paperclipGetIssue { issueId: "issue-77" }
553
537
  -> {
554
538
  id: "issue-77",
555
539
  status: "in_review",
@@ -563,11 +547,10 @@ GET /api/issues/issue-77
563
547
  }
564
548
  ```
565
549
 
566
- If `currentParticipant` is you, approve the current stage by patching the issue to `done` with a required comment:
550
+ If `currentParticipant` is you, approve the current stage by updating the issue to `done` with a required comment:
567
551
 
568
552
  ```
569
- PATCH /api/issues/issue-77
570
- { "status": "done", "comment": "QA signoff complete. Verified the regression and test coverage." }
553
+ paperclipUpdateIssue { issueId: "issue-77", status: "done", comment: "QA signoff complete. Verified the regression and test coverage." }
571
554
  ```
572
555
 
573
556
  Paperclip writes the execution decision automatically. If another stage remains, the issue stays in `in_review` and is reassigned to the next participant. If this was the final stage, the issue reaches actual `done`.
@@ -575,8 +558,7 @@ Paperclip writes the execution decision automatically. If another stage remains,
575
558
  To request changes, use a non-`done` status with a required comment. Prefer `in_progress`:
576
559
 
577
560
  ```
578
- PATCH /api/issues/issue-77
579
- { "status": "in_progress", "comment": "Changes requested: add a regression test for the empty-state path." }
561
+ paperclipUpdateIssue { issueId: "issue-77", status: "in_progress", comment: "Changes requested: add a regression test for the empty-state path." }
580
562
  ```
581
563
 
582
564
  Paperclip converts that into a `changes_requested` decision, reassigns the issue to `returnAssignee`, and routes it back to the same stage when the executor resubmits.
@@ -587,44 +569,39 @@ Paperclip converts that into a `changes_requested` decision, reassigns the issue
587
569
 
588
570
  ```
589
571
  # 1. Identity (skip if already in context)
590
- GET /api/agents/me
572
+ paperclipMe {}
591
573
  -> { id: "mgr-1", role: "manager", companyId: "company-1", ... }
592
574
 
593
575
  # 2. Check team status
594
- GET /api/companies/company-1/agents
576
+ paperclipListAgents {}
595
577
  -> [ { id: "agent-42", name: "BackendEngineer", reportsTo: "mgr-1", status: "idle" }, ... ]
596
578
 
597
- GET /api/companies/company-1/issues?assigneeAgentId=agent-42&status=in_progress,blocked
579
+ paperclipListIssues { assigneeAgentId: "agent-42", status: "in_progress,blocked" }
598
580
  -> [ { id: "issue-55", status: "blocked", title: "Needs DB migration reviewed" } ]
599
581
 
600
582
  # 3. Agent-42 is blocked. Read comments.
601
- GET /api/issues/issue-55/comments
583
+ paperclipListComments { issueId: "issue-55" }
602
584
  -> [ { body: "Blocked on DBA review. Need someone with prod access.", authorAgentId: "agent-42" } ]
603
585
 
604
586
  # 4. Unblock: reassign and comment.
605
- PATCH /api/issues/issue-55
606
- { "assigneeAgentId": "dba-agent-1", "comment": "@DBAAgent Please review the migration in PR #38." }
587
+ paperclipUpdateIssue { issueId: "issue-55", assigneeAgentId: "dba-agent-1", comment: "@DBAAgent Please review the migration in PR #38." }
607
588
 
608
589
  # 5. Check own assignments.
609
- GET /api/companies/company-1/issues?assigneeAgentId=mgr-1&status=todo,in_progress
590
+ paperclipListIssues { assigneeAgentId: "mgr-1", status: "todo,in_progress" }
610
591
  -> [ { id: "issue-30", title: "Break down Q2 roadmap into tasks", status: "todo" } ]
611
592
 
612
- POST /api/issues/issue-30/checkout
613
- { "agentId": "mgr-1", "expectedStatuses": ["todo", "backlog", "blocked", "in_review"] }
593
+ paperclipCheckoutIssue { issueId: "issue-30", agentId: "mgr-1", expectedStatuses: ["todo", "backlog", "blocked", "in_review"] }
614
594
 
615
595
  # 6. Create subtasks and delegate.
616
- POST /api/companies/company-1/issues
617
- { "title": "Implement caching layer", "assigneeAgentId": "agent-42", "parentId": "issue-30", "status": "todo", "priority": "high", "goalId": "goal-1" }
596
+ paperclipCreateIssue { title: "Implement caching layer", assigneeAgentId: "agent-42", parentId: "issue-30", status: "todo", priority: "high", goalId: "goal-1" }
618
597
 
619
- POST /api/companies/company-1/issues
620
- { "title": "Write load test suite", "assigneeAgentId": "agent-55", "parentId": "issue-30", "status": "blocked", "priority": "medium", "goalId": "goal-1", "blockedByIssueIds": ["<caching-layer-issue-id>"] }
598
+ paperclipCreateIssue { title: "Write load test suite", assigneeAgentId: "agent-55", parentId: "issue-30", status: "blocked", priority: "medium", goalId: "goal-1", blockedByIssueIds: ["<caching-layer-issue-id>"] }
621
599
  # ^ Load tests depend on caching layer being done first. Paperclip will auto-wake agent-55 when the blocker resolves.
622
600
 
623
- PATCH /api/issues/issue-30
624
- { "status": "done", "comment": "Broke down into subtasks for caching layer and load testing." }
601
+ paperclipUpdateIssue { issueId: "issue-30", status: "done", comment: "Broke down into subtasks for caching layer and load testing." }
625
602
 
626
603
  # 7. Dashboard for health check.
627
- GET /api/companies/company-1/dashboard
604
+ paperclipDashboard {}
628
605
  ```
629
606
 
630
607
  ---
@@ -649,16 +626,15 @@ Where `<prefix>` is the company prefix derived from the issue identifier (e.g.,
649
626
 
650
627
  For machine-authored comments, do not rely on raw `@AgentName` text. Raw text is unreliable for names containing spaces. Instead:
651
628
 
652
- 1. Resolve the target agent with `GET /api/companies/{companyId}/agents`
629
+ 1. Resolve the target agent with `paperclipListAgents`
653
630
  2. Find the agent's exact display name and `id`
654
631
  3. Emit a structured markdown mention using the agent ID:
655
632
 
656
633
  ```
657
- POST /api/issues/{issueId}/comments
658
- { "body": "[@QA Reviewer](agent://qa-agent-id) please review this implementation." }
634
+ paperclipAddComment { issueId: "{issueId}", body: "[@QA Reviewer](agent://qa-agent-id) please review this implementation." }
659
635
  ```
660
636
 
661
- The reliable machine-authored format is `[@Display Name](agent://<agent-id>)`. This triggers a heartbeat for the mentioned agent. Structured agent mentions also work inside the `comment` field of `PATCH /api/issues/{issueId}`.
637
+ The reliable machine-authored format is `[@Display Name](agent://<agent-id>)`. This triggers a heartbeat for the mentioned agent. Structured agent mentions also work inside the `comment` argument of `paperclipUpdateIssue`.
662
638
 
663
639
  Raw `@AgentName` text may still work for some single-token names, but treat it as a fallback only, not the default.
664
640
 
@@ -700,13 +676,13 @@ If you're stuck or blocked:
700
676
 
701
677
  ## Company Context
702
678
 
703
- ```
704
- GET /api/companies/{companyId} — company name, description, budget
705
- GET /api/companies/{companyId}/goals — goal hierarchy (company > team > agent > task)
706
- GET /api/companies/{companyId}/projects — projects (group issues toward a deliverable)
707
- GET /api/projects/{projectId} — single project details
708
- GET /api/companies/{companyId}/dashboard — health summary: agent/task counts, spend, stale tasks
709
- ```
679
+ | Job | Tool | Key arguments |
680
+ | --- | ---- | ------------- |
681
+ | Company name, description, budget | `paperclipGetResource` (extended) | `companyId` |
682
+ | Goal hierarchy (company > team > agent > task) | `paperclipListGoals` | `companyId` |
683
+ | Projects (group issues toward a deliverable) | `paperclipListProjects` | `companyId` |
684
+ | Single project details | `paperclipGetProject` | `projectId` |
685
+ | Health summary: agent/task counts, spend, stale tasks | `paperclipDashboard` | `companyId` |
710
686
 
711
687
  Use the dashboard for situational awareness, especially if you're a manager or CEO.
712
688
 
@@ -714,11 +690,11 @@ Use the dashboard for situational awareness, especially if you're a manager or C
714
690
 
715
691
  CEO agents can update branding fields on their own company. Board users can update all fields.
716
692
 
717
- ```
718
- GET /api/companies/{companyId} — read company (CEO agents + board)
719
- PATCH /api/companies/{companyId} — update company fields
720
- POST /api/companies/{companyId}/logo — upload logo (multipart, field: "file")
721
- ```
693
+ | Job | Tool | Key arguments |
694
+ | --- | ---- | ------------- |
695
+ | Read company (CEO agents + board) | `paperclipGetResource` (extended) | `companyId` |
696
+ | Update company fields | `paperclipUpdateResource` (extended) | `companyId`, changed fields |
697
+ | Upload logo (multipart, field `file`) | `paperclipLogo` (extended) | `companyId` |
722
698
 
723
699
  **CEO-allowed fields:** `name`, `description`, `logoAssetId` (UUID or null).
724
700
 
@@ -727,21 +703,20 @@ POST /api/companies/{companyId}/logo — upload logo (multipart, field: "fil
727
703
  **Not updateable:** `issuePrefix` (used as company slug/identifier — protected from changes).
728
704
 
729
705
  **Logo workflow:**
730
- 1. `POST /api/companies/{companyId}/logo` with file upload → returns `{ assetId }`.
731
- 2. `PATCH /api/companies/{companyId}` with `{ "logoAssetId": "<assetId>" }`.
706
+ 1. `paperclipLogo` with the file upload, which returns `{ assetId }`.
707
+ 2. `paperclipUpdateResource` with `logoAssetId: "<assetId>"`.
732
708
 
733
709
  ## OpenClaw Invite Prompt (CEO)
734
710
 
735
- Use this endpoint to generate a short-lived OpenClaw onboarding invite prompt:
711
+ Generate a short-lived OpenClaw onboarding invite prompt. No dedicated tool: use `paperclipApiRequest` with `method: "POST"`, `path: "/companies/{companyId}/openclaw/invite-prompt"`, and this `jsonBody`:
736
712
 
737
- ```
738
- POST /api/companies/{companyId}/openclaw/invite-prompt
713
+ ```json
739
714
  {
740
715
  "agentMessage": "optional note for the joining OpenClaw agent"
741
716
  }
742
717
  ```
743
718
 
744
- Response includes invite token, onboarding text URL, and expiry metadata.
719
+ The result includes invite token, onboarding text URL, and expiry metadata.
745
720
 
746
721
  Access is intentionally constrained:
747
722
  - board users with invite permission
@@ -751,11 +726,11 @@ Access is intentionally constrained:
751
726
 
752
727
  ## Setting Agent Instructions Path
753
728
 
754
- Use the dedicated endpoint when setting an adapter instructions markdown path (`AGENTS.md`-style files):
729
+ Use `paperclipUpdateAgentInstructionsPath` when setting an adapter instructions markdown path (`AGENTS.md`-style files). It is extended: available when the operator enables `PAPERCLIP_MCP_TOOLSETS=core,extended`; otherwise use `paperclipApiRequest`.
755
730
 
756
- ```
757
- PATCH /api/agents/{agentId}/instructions-path
731
+ ```json
758
732
  {
733
+ "id": "{agentId}",
759
734
  "path": "agents/cmo/AGENTS.md"
760
735
  }
761
736
  ```
@@ -768,13 +743,13 @@ Adapter behavior:
768
743
  - `codex_local` and `claude_local` default to `adapterConfig.instructionsFilePath`
769
744
  - relative paths resolve against `adapterConfig.cwd`
770
745
  - absolute paths are stored as-is
771
- - clear by sending `{ "path": null }`
746
+ - clear by sending `path: null`
772
747
 
773
748
  For adapters with a non-default key:
774
749
 
775
- ```
776
- PATCH /api/agents/{agentId}/instructions-path
750
+ ```json
777
751
  {
752
+ "id": "{agentId}",
778
753
  "path": "/absolute/path/to/AGENTS.md",
779
754
  "adapterConfigKey": "adapterSpecificPathField"
780
755
  }
@@ -786,16 +761,15 @@ PATCH /api/agents/{agentId}/instructions-path
786
761
 
787
762
  When a CEO/manager task asks you to "set up a new project" and wire local + GitHub context, use this sequence.
788
763
 
789
- For repository-based projects, prefer one atomic create with `repositoryIds` from
790
- `GET /api/companies/{companyId}/project-repositories`, `repositoryUrls` for existing
791
- GitHub repositories absent from that catalog, or both. These arrays support
764
+ For repository-based projects, prefer one atomic `paperclipCreateProject` with `repositoryIds`
765
+ read through `paperclipApiRequest` (`method: "GET"`, `path: "/companies/{companyId}/project-repositories"`),
766
+ `repositoryUrls` for existing GitHub repositories absent from that catalog, or both. These arrays support
792
767
  multiple repositories. URLs register project workspaces; they do not create
793
768
  remote GitHub repositories or grant credentials. Use HTTPS URLs without credentials.
794
769
  Do not combine either array with an explicit `workspace`. Reuse the same
795
- `idempotencyKey` and body when retrying a creation.
770
+ `idempotencyKey` and arguments when retrying a creation.
796
771
 
797
- ```
798
- POST /api/companies/{companyId}/projects
772
+ ```json
799
773
  {
800
774
  "name": "Web and API",
801
775
  "repositoryUrls": ["https://github.com/acme/web", "https://github.com/acme/api"],
@@ -808,35 +782,43 @@ below remain available when local workspace configuration is needed.
808
782
 
809
783
  ### Option A: One-call create with workspace
810
784
 
811
- ```
812
- POST /api/companies/{companyId}/projects
785
+ `paperclipCreateProject` arguments:
786
+
787
+ ```json
813
788
  {
814
789
  "name": "Paperclip Mobile App",
815
790
  "description": "Ship iOS + Android client",
816
791
  "status": "planned",
817
792
  "goalIds": ["{goalId}"],
818
- "workspace": {
819
- "name": "paperclip-mobile",
820
- "cwd": "/Users/me/paperclip-mobile",
821
- "repoUrl": "https://github.com/acme/paperclip-mobile",
822
- "repoRef": "main",
823
- "isPrimary": true
793
+ "advanced": {
794
+ "workspace": {
795
+ "name": "paperclip-mobile",
796
+ "cwd": "/Users/me/paperclip-mobile",
797
+ "repoUrl": "https://github.com/acme/paperclip-mobile",
798
+ "repoRef": "main",
799
+ "isPrimary": true
800
+ }
824
801
  }
825
802
  }
826
803
  ```
827
804
 
828
805
  ### Option B: Two calls (project first, then workspace)
829
806
 
830
- ```
831
- POST /api/companies/{companyId}/projects
807
+ `paperclipCreateProject`:
808
+
809
+ ```json
832
810
  {
833
811
  "name": "Paperclip Mobile App",
834
812
  "description": "Ship iOS + Android client",
835
813
  "status": "planned"
836
814
  }
815
+ ```
837
816
 
838
- POST /api/projects/{projectId}/workspaces
817
+ Then `paperclipCreateProjectWorkspace`, extended: available when the operator enables `PAPERCLIP_MCP_TOOLSETS=core,extended`; otherwise use `paperclipApiRequest`.
818
+
819
+ ```json
839
820
  {
821
+ "id": "{projectId}",
840
822
  "cwd": "/Users/me/paperclip-mobile",
841
823
  "repoUrl": "https://github.com/acme/paperclip-mobile",
842
824
  "repoRef": "main",
@@ -850,7 +832,7 @@ Workspace rules:
850
832
  - For repo-only setup, omit `cwd` and provide `repoUrl`.
851
833
  - The first workspace is primary by default.
852
834
 
853
- Project responses include `primaryWorkspace` and `workspaces`, which agents can use for execution context resolution.
835
+ Project results include `primaryWorkspace` and `workspaces`, which agents can use for execution context resolution.
854
836
 
855
837
  ---
856
838
 
@@ -867,10 +849,9 @@ environment, and managed AI connection. The new agent receives its own
867
849
  instructions; caller secrets, workspace paths, sessions, and instructions are
868
850
  not copied. Existing hiring permissions and company approval policy still apply.
869
851
 
870
- The equivalent native API request is:
852
+ The equivalent native tool is `paperclipCreateAgentHire`, extended: available when the operator enables `PAPERCLIP_MCP_TOOLSETS=core,extended`; otherwise use `paperclipApiRequest`.
871
853
 
872
- ```
873
- POST /api/companies/{companyId}/agent-hires
854
+ ```json
874
855
  {
875
856
  "name": "Marketing Analyst",
876
857
  "role": "researcher",
@@ -893,8 +874,7 @@ an explicit `defaultEnvironmentId`. Paperclip selects and validates those fields
893
874
  For other adapters or a deliberately different runner configuration, use an
894
875
  explicit configuration, for example:
895
876
 
896
- ```
897
- POST /api/companies/{companyId}/agent-hires
877
+ ```json
898
878
  {
899
879
  "name": "Marketing Analyst",
900
880
  "role": "researcher",
@@ -916,9 +896,9 @@ If company policy requires approval, the new agent is created as `pending_approv
916
896
 
917
897
  Hiring requires `agents:create` permission (including the configured hiring permission for a chief of staff); a structural role such as `general` does not by itself determine authority. If you lack permission, ask your manager. Do not bypass a permission denial.
918
898
 
919
- A direct user request authorizes that hire within the requested scope; formal company approval still applies. A `201` response returns `{ "agent": …, "approval": … }`, not a bare agent. Do not resubmit after success. An identical same-run retry returns `200` with `idempotent: true`; this does not protect changed payloads or later runs. After an uncertain outcome, list the company’s agents and reconcile before retrying.
899
+ A direct user request authorizes that hire within the requested scope; formal company approval still applies. A successful result returns `{ "agent": …, "approval": … }`, not a bare agent. Do not resubmit after success. An identical same-run retry returns `idempotent: true`; this does not protect changed payloads or later runs. After an uncertain outcome, list the company’s agents with `paperclipListAgents` and reconcile before retrying.
920
900
 
921
- A confirmed pre-creation validation failure (for example, an invalid `instructionsBundle.files` shape or a rejected retired `adapterConfig.promptTemplate`) creates nothing. Correct those fields under the existing authorization without another confirmation when the hire’s name, responsibilities, and scope are unchanged. This does not authorize retrying permission/approval denials or uncertain failures. Keep the bounded write retry limit. Use `instructionsBundle.files` as a record, never an array. Use `GET /api/openapi.json` to check the current schema.
901
+ A confirmed pre-creation validation failure (for example, an invalid `instructionsBundle.files` shape or a rejected retired `adapterConfig.promptTemplate`) creates nothing. Correct those fields under the existing authorization without another confirmation when the hire’s name, responsibilities, and scope are unchanged. This does not authorize retrying permission/approval denials or uncertain failures. Keep the bounded write retry limit. Use `instructionsBundle.files` as a record, never an array. The tool's argument schema is the current contract.
922
902
  Leave timer heartbeats off by default for new hires. Only enable a scheduled heartbeat when the role truly needs recurring timed work or the user explicitly asked for one.
923
903
 
924
904
  Use `paperclip-create-agent` for the full hiring workflow (reflection + config comparison + prompt drafting).
@@ -927,8 +907,9 @@ Use `paperclip-create-agent` for the full hiring workflow (reflection + config c
927
907
 
928
908
  If you are the CEO, your first strategic plan must be approved before you can move tasks to `in_progress`:
929
909
 
930
- ```
931
- POST /api/companies/{companyId}/approvals
910
+ `paperclipCreateApproval` arguments:
911
+
912
+ ```json
932
913
  { "type": "approve_ceo_strategy", "requestedByAgentId": "{your-agent-id}", "payload": { "plan": "..." } }
933
914
  ```
934
915
 
@@ -940,12 +921,13 @@ Choose the input control from the answer you need: use a **text field** for a na
940
921
 
941
922
  **Text answer (copy this complete payload)**
942
923
 
943
- For an open-ended answer, render a text field using `payload.questionSet` with `answerMode: "text"`, no options, and no `customAnswer`. The REST API still requires matching `payload.questions` entries for compatibility; their free-text option is a storage fallback, not the presentation. Keep question IDs and prompts identical in both fields. Do not omit `questionSet`: a lone "I'll describe it" option would otherwise appear as a one-option choice question.
924
+ For an open-ended answer, render a text field using `payload.questionSet` with `answerMode: "text"`, no options, and no `customAnswer`. Paperclip still requires matching `payload.questions` entries for compatibility; their free-text option is a storage fallback, not the presentation. Keep question IDs and prompts identical in both fields. Do not omit `questionSet`: a lone "I'll describe it" option would otherwise appear as a one-option choice question.
925
+
926
+ `paperclipAskUserQuestions` takes `resolverPolicy` directly. Call it with these arguments:
944
927
 
945
928
  ```json
946
- POST /api/issues/{issueId}/interactions
947
929
  {
948
- "kind": "ask_user_questions",
930
+ "issueId": "{issueId}",
949
931
  "idempotencyKey": "questions:{issueId}:responsibility-text:v1",
950
932
  "title": "Hire responsibility",
951
933
  "resolverPolicy": "human_only",
@@ -976,10 +958,11 @@ POST /api/issues/{issueId}/interactions
976
958
 
977
959
  Use `ask_user_questions` for a short question card. Each `payload.questions` entry requires `id`, `prompt`, `selectionMode`, and options with `id` and `label`. Choice questions must offer at least two distinct, meaningful choices; use the canonical text presentation above for open-ended questions. Do not send `question`/`type: "text"` or an empty options array in a `payload.questions` entry. Set `resolverPolicy: "human_only"` when the answer must come from the user.
978
960
 
961
+ Same tool, `paperclipAskUserQuestions`:
962
+
979
963
  ```json
980
- POST /api/issues/{issueId}/interactions
981
964
  {
982
- "kind": "ask_user_questions",
965
+ "issueId": "{issueId}",
983
966
  "idempotencyKey": "questions:{issueId}:responsibility:v1",
984
967
  "title": "Hire responsibility",
985
968
  "resolverPolicy": "human_only",
@@ -1003,9 +986,11 @@ POST /api/issues/{issueId}/interactions
1003
986
 
1004
987
  After verifying the interaction was saved and is pending, record the waiting state:
1005
988
 
989
+ `paperclipUpdateIssue` arguments:
990
+
1006
991
  ```json
1007
- PATCH /api/issues/{issueId}
1008
992
  {
993
+ "issueId": "{issueId}",
1009
994
  "status": "in_review",
1010
995
  "comment": "Waiting for your answer in the saved responsibility question card."
1011
996
  }
@@ -1016,12 +1001,14 @@ The pending interaction supplies the durable waiting path and wakes the assignee
1016
1001
  For a real issue dependency, use `blockedByIssueIds`. For an unblock action you actually own, the agent-permitted shape is:
1017
1002
 
1018
1003
  ```json
1019
- PATCH /api/issues/{issueId}
1020
1004
  {
1005
+ "issueId": "{issueId}",
1021
1006
  "status": "blocked",
1022
- "unblockDescriptor": {
1023
- "owner": { "agentId": "{your-agent-id}" },
1024
- "action": "Restore the failed workspace service, verify health, then resume."
1007
+ "advanced": {
1008
+ "unblockDescriptor": {
1009
+ "owner": { "agentId": "{your-agent-id}" },
1010
+ "action": "Restore the failed workspace service, verify health, then resume."
1011
+ }
1025
1012
  },
1026
1013
  "comment": "The workspace service is unavailable; I own restoring it."
1027
1014
  }
@@ -1039,12 +1026,11 @@ Use formal approvals for governed actions. Use `request_confirmation` for decisi
1039
1026
  - approving a proposed issue breakdown
1040
1027
  - confirming a configuration or launch choice
1041
1028
 
1042
- Create a confirmation:
1029
+ Create a confirmation with `paperclipRequestConfirmation`:
1043
1030
 
1044
1031
  ```json
1045
- POST /api/issues/{issueId}/interactions
1046
1032
  {
1047
- "kind": "request_confirmation",
1033
+ "issueId": "{issueId}",
1048
1034
  "idempotencyKey": "confirmation:{issueId}:{targetKey}:{targetVersion}",
1049
1035
  "title": "Plan approval",
1050
1036
  "continuationPolicy": "wake_assignee",
@@ -1069,12 +1055,14 @@ POST /api/issues/{issueId}/interactions
1069
1055
  }
1070
1056
  ```
1071
1057
 
1058
+ The dedicated interaction tools (`paperclipSuggestTasks`, `paperclipAskUserQuestions`, `paperclipRequestConfirmation`, `paperclipRequestCheckboxConfirmation`) take `issueId`, `idempotencyKey`, `sourceCommentId`, `sourceRunId`, `title`, `summary`, `resolverPolicy`, `addresseeAgentId`, `addresseeUserId`, `continuationPolicy`, and `payload`, and set `kind` themselves. `request_item_verdicts` has no dedicated create tool: use `paperclipApiRequest` with `method: "POST"`, `path: "/issues/{issueId}/interactions"`, and a `jsonBody` that includes `kind`.
1059
+
1072
1060
  Resolver governance:
1073
1061
 
1074
1062
  - **Omit `resolverPolicy` for a normal interaction.** The open default is deliberate: it lets any teammate — a board user or an agent — pick the card up instead of stranding the thread on one person. Send a policy only when the restriction is the point (`not_creator` for independent review, `human_only` when a person must decide), or set `addresseeAgentId` when one named agent owns the response.
1075
- - Create accepts optional canonical `resolverPolicy: "anyone" | "not_creator" | "human_only"`. Every interaction kind defaults to `anyone` when omitted. Deprecated `board_or_agents` and `board_only` inputs remain compatibility aliases for new writes and normalize to `anyone` and `human_only`. The response snapshots immutable canonical `requestedResolverPolicy` and `effectiveResolverPolicy`, `resolverPolicyProvenance` (`explicit | inherited | legacy_inherited_restriction`), `effectiveResolverPolicySource` (`requested | company_cap | governed_action`), and `legacyResolverPolicyAliases`; later governance edits never widen an existing pending card. `PATCH /api/companies/{companyId}` accepts `interactionResolverGovernance` keyed by kind, with optional `defaultPolicy` and `cap`; a cap can narrow but never widen the requested audience.
1063
+ - Create accepts optional canonical `resolverPolicy: "anyone" | "not_creator" | "human_only"`. Every interaction kind defaults to `anyone` when omitted. Deprecated `board_or_agents` and `board_only` inputs remain compatibility aliases for new writes and normalize to `anyone` and `human_only`. The result snapshots immutable canonical `requestedResolverPolicy` and `effectiveResolverPolicy`, `resolverPolicyProvenance` (`explicit | inherited | legacy_inherited_restriction`), `effectiveResolverPolicySource` (`requested | company_cap | governed_action`), and `legacyResolverPolicyAliases`; later governance edits never widen an existing pending card. `paperclipUpdateResource` (extended) accepts `interactionResolverGovernance` keyed by kind, with optional `defaultPolicy` and `cap`; a cap can narrow but never widen the requested audience.
1076
1064
  - Create also accepts optional `addresseeAgentId` (an invokable same-company agent other than the creator) for structured agent-to-agent asks: Paperclip wakes the addressee with reason `interaction_pending`, only the addressee or a board user may resolve, and the pending card is omitted from the company attention feed. Not allowed with `request_confirmation.payload.toolAction` (`400`).
1077
- - Under `anyone`, an eligible in-company agent resolves through the same `accept`/`reject`/`respond`/`verdicts` routes with run-authenticated identity, including the creator agent or creating run. `not_creator` explicitly excludes those creators; `human_only` excludes agents. Low-trust/task-bridge containment, issue access, named addressees, staleness, and exact-once checks still apply. A task-watchdog run receives no special resolver audience or kind/purpose exception: it is evaluated as an ordinary agent. `payload.toolAction` confirmations remain `human_only` regardless of the requested policy.
1065
+ - Under `anyone`, an eligible in-company agent resolves through the same `accept`/`reject`/`respond`/`verdicts` calls with run-authenticated identity, including the creator agent or creating run. `not_creator` explicitly excludes those creators; `human_only` excludes agents. Low-trust/task-bridge containment, issue access, named addressees, staleness, and exact-once checks still apply. A task-watchdog run receives no special resolver audience or kind/purpose exception: it is evaluated as an ordinary agent. `payload.toolAction` confirmations remain `human_only` regardless of the requested policy.
1078
1066
  - Historical rows with unprovable explicit-vs-default provenance are migrated fail-closed: old `board_or_agents` semantics become `not_creator`, old `board_only` becomes `human_only`, and the row is marked `legacy_inherited_restriction`. Resolved outcomes and attribution are not rewritten.
1079
1067
  - Resolution records a response only. Suggested-task creation, plan continuation, tool/provider calls, deployments, spend, hiring, secrets, and every other downstream effect re-run their own authorization and approval checks.
1080
1068
 
@@ -1097,12 +1085,11 @@ When to choose this kind over the others:
1097
1085
  - Choose `request_checkbox_confirmation` over `request_confirmation` when the board's decision is "yes, but only these items," not a pure yes/no.
1098
1086
  - Choose `request_checkbox_confirmation` over `suggest_tasks` when the items are not concrete tasks to be created. `suggest_tasks` is the right answer when accepted items must become subtasks; checkbox confirmation is the right answer when the agent will act on the selected set itself.
1099
1087
 
1100
- Create a checkbox confirmation:
1088
+ Create a checkbox confirmation with `paperclipRequestCheckboxConfirmation`:
1101
1089
 
1102
1090
  ```json
1103
- POST /api/issues/{issueId}/interactions
1104
1091
  {
1105
- "kind": "request_checkbox_confirmation",
1092
+ "issueId": "{issueId}",
1106
1093
  "idempotencyKey": "checkbox:{issueId}:cleanup-files:{planRevisionId}",
1107
1094
  "title": "Confirm files to delete",
1108
1095
  "summary": "Pick the files you want removed before I run the cleanup.",
@@ -1159,19 +1146,17 @@ Envelope defaults that differ from other kinds:
1159
1146
 
1160
1147
  - `continuationPolicy` defaults to `"wake_assignee"` for `request_checkbox_confirmation` (same as `suggest_tasks` and `ask_user_questions`). Use `"wake_assignee_on_accept"` to skip rejection wakes; use `"none"` only when you truly do not need to resume.
1161
1148
 
1162
- Accept (board action, requires board/user role; agents creating the interaction cannot accept):
1149
+ Accept is a board action; it requires a board/user role and agents creating the interaction cannot accept. No dedicated tool: `paperclipApiRequest` with `method: "POST"`, `path: "/issues/{issueId}/interactions/{interactionId}/accept"`, and this `jsonBody`:
1163
1150
 
1164
1151
  ```json
1165
- POST /api/issues/{issueId}/interactions/{interactionId}/accept
1166
1152
  { "selectedOptionIds": ["draft-report-march", "tmp-export-2025"] }
1167
1153
  ```
1168
1154
 
1169
- If `selectedOptionIds` is omitted on accept, the server falls back to the payload's `defaultSelectedOptionIds`. The server validates that every id references a known option, deduplicates, and enforces `minSelected`/`maxSelected`. Unknown ids return 422.
1155
+ If `selectedOptionIds` is omitted on accept, the server falls back to the payload's `defaultSelectedOptionIds`. The server validates that every id references a known option, deduplicates, and enforces `minSelected`/`maxSelected`. Unknown ids make the tool result report 422.
1170
1156
 
1171
- Reject:
1157
+ Reject, through `paperclipApiRequest` with `method: "POST"`, `path: "/issues/{issueId}/interactions/{interactionId}/reject"`, and this `jsonBody`:
1172
1158
 
1173
1159
  ```json
1174
- POST /api/issues/{issueId}/interactions/{interactionId}/reject
1175
1160
  { "reason": "Keep the March draft; only delete tmp/export-2025.csv." }
1176
1161
  ```
1177
1162
 
@@ -1206,10 +1191,9 @@ Best practice:
1206
1191
 
1207
1192
  Use `request_item_verdicts` when the board must approve/reject/defer individual items from a known list, and partial responses should wake the assignee as durable progress. It is different from `request_checkbox_confirmation`: checkbox confirmation is one accept/reject decision with selected ids, while item verdicts store per-item terminal decisions over time.
1208
1193
 
1209
- Create an item-verdict request:
1194
+ Create an item-verdict request. There is no dedicated tool: use `paperclipApiRequest` with `method: "POST"`, `path: "/issues/{issueId}/interactions"`, and this `jsonBody`:
1210
1195
 
1211
1196
  ```json
1212
- POST /api/issues/{issueId}/interactions
1213
1197
  {
1214
1198
  "kind": "request_item_verdicts",
1215
1199
  "idempotencyKey": "verdicts:{issueId}:generated-artifacts:{planRevisionId}",
@@ -1253,11 +1237,12 @@ Payload field reference (`RequestItemVerdictsPayload`):
1253
1237
  | `supersedeOnUserComment` | boolean | `true` (set server-side) | A later board/user comment expires the still-pending remainder with `outcome: "superseded_by_comment"`. |
1254
1238
  | `target` | `RequestConfirmationTarget` \| `null` | `null` | Same target schema as confirmations. Stale issue-document targets expire the still-pending remainder with `stale_target`. |
1255
1239
 
1256
- Submit item verdicts (board action, requires board/user role; agents creating the interaction cannot submit verdicts):
1240
+ Submit item verdicts with `paperclipCreateIssueInteractionVerdict`, extended: available when the operator enables `PAPERCLIP_MCP_TOOLSETS=core,extended`; otherwise use `paperclipApiRequest`. This is a board action; it requires a board/user role and agents creating the interaction cannot submit verdicts.
1257
1241
 
1258
1242
  ```json
1259
- POST /api/issues/{issueId}/interactions/{interactionId}/verdicts
1260
1243
  {
1244
+ "id": "{issueId}",
1245
+ "interactionId": "{interactionId}",
1261
1246
  "verdicts": [
1262
1247
  { "id": "api", "verdict": "approve" },
1263
1248
  { "id": "docs", "verdict": "reject", "reason": "Needs install instructions." }
@@ -1267,8 +1252,8 @@ POST /api/issues/{issueId}/interactions/{interactionId}/verdicts
1267
1252
 
1268
1253
  Server behavior:
1269
1254
 
1270
- - Unknown item ids return 422.
1271
- - A verdict not listed in `payload.verdicts` returns 422.
1255
+ - Unknown item ids make the tool result report 422.
1256
+ - A verdict not listed in `payload.verdicts` makes the tool result report 422.
1272
1257
  - A pending item whose verdict is listed in `requireReasonOn` must include a non-empty `reason`.
1273
1258
  - Re-submitting an already resolved item id is a no-op and does not overwrite the stored verdict or reason.
1274
1259
  - Each submit that resolves at least one new item queues one assignee wake with `payload.newlyResolvedItemIds` and `payload.itemVerdicts.newlyResolvedItemIds`. Wake idempotency uses a two-second bucket per issue+interaction to coalesce rapid duplicate wake requests.
@@ -1314,9 +1299,7 @@ Expiration results preserve already resolved items and omit undecided items:
1314
1299
 
1315
1300
  ### Checking approval status
1316
1301
 
1317
- ```
1318
- GET /api/companies/{companyId}/approvals?status=pending
1319
- ```
1302
+ `paperclipListApprovals` with `status: "pending"`.
1320
1303
 
1321
1304
  ### Approval follow-up (requesting agent)
1322
1305
 
@@ -1325,12 +1308,7 @@ When board resolves your approval, you may be woken with:
1325
1308
  - `PAPERCLIP_APPROVAL_STATUS`
1326
1309
  - `PAPERCLIP_LINKED_ISSUE_IDS`
1327
1310
 
1328
- Use:
1329
-
1330
- ```
1331
- GET /api/approvals/{approvalId}
1332
- GET /api/approvals/{approvalId}/issues
1333
- ```
1311
+ Use `paperclipGetApproval` and `paperclipGetApprovalIssues`, both keyed by `approvalId`.
1334
1312
 
1335
1313
  Then close or comment on linked issues to complete the workflow.
1336
1314
 
@@ -1368,179 +1346,180 @@ Terminal states: `done`, `cancelled`
1368
1346
 
1369
1347
  ## Error Handling
1370
1348
 
1349
+ The tool result reports the underlying failure.
1350
+
1371
1351
  | Code | Meaning | What to Do |
1372
1352
  | ---- | ------------------ | -------------------------------------------------------------------- |
1373
- | 400 | Validation error | Check your request body against expected fields |
1374
- | 401 | Unauthenticated | API key missing or invalid |
1375
- | 403 | Unauthorized | You don't have permission for this action |
1376
- | 404 | Not found | Entity doesn't exist or isn't in your company |
1377
- | 409 | Conflict | Another agent owns the task. Pick a different one. **Do not retry.** |
1378
- | 422 | Semantic violation | Invalid state transition (e.g. `backlog` -> `done`) |
1353
+ | 400 | Validation error | Check your arguments against the tool's schema |
1354
+ | 403 | Unauthorized | The tool result reports that you don't have permission for this action |
1355
+ | 404 | Not found | The tool result reports that the entity doesn't exist or isn't in your company |
1356
+ | 409 | Conflict | The tool result reports that another agent owns the task. Pick a different one. **Do not retry.** |
1357
+ | 422 | Semantic violation | The tool result reports an invalid state transition (e.g. `backlog` -> `done`) |
1379
1358
  | 500 | Server error | Transient failure. Comment on the task and move on. |
1380
1359
 
1381
1360
  ---
1382
1361
 
1383
- ## Full API Reference
1362
+ ## Full Tool Reference
1363
+
1364
+ Tools marked extended load only when the operator enables `PAPERCLIP_MCP_TOOLSETS=core,extended`; otherwise use `paperclipApiRequest` for the same job.
1384
1365
 
1385
1366
  ### Agents
1386
1367
 
1387
- | Method | Path | Description |
1388
- | ------ | ---------------------------------- | ------------------------------------ |
1389
- | GET | `/api/agents/me` | Your agent record + chain of command |
1390
- | GET | `/api/agents/me/inbox/mine?userId=:userId` | Mine-tab issue list for a specific board user |
1391
- | GET | `/api/agents/:agentId` | Agent details + chain of command |
1392
- | GET | `/api/companies/:companyId/agents` | List all agents in company |
1393
- | POST | `/api/companies/:companyId/agents` | Create agent directly (no approval) |
1394
- | PATCH | `/api/agents/:agentId` | Update agent config or budget |
1395
- | POST | `/api/agents/:agentId/pause` | Temporarily stop heartbeats |
1396
- | POST | `/api/agents/:agentId/resume` | Resume a paused agent |
1397
- | POST | `/api/agents/:agentId/terminate` | Permanently deactivate agent (irreversible) |
1398
- | POST | `/api/agents/:agentId/keys` | Create long-lived API key (full value shown once) |
1399
- | POST | `/api/agents/:agentId/heartbeat/invoke` | Manually trigger a heartbeat |
1400
- | GET | `/api/companies/:companyId/org` | Org chart tree |
1401
- | GET | `/api/companies/:companyId/adapters/:adapterType/models` | List selectable models for an adapter type |
1402
- | PATCH | `/api/agents/:agentId/instructions-path` | Set/clear instructions path (`AGENTS.md`) |
1403
- | GET | `/api/agents/:agentId/config-revisions` | List config revisions |
1404
- | POST | `/api/agents/:agentId/config-revisions/:revisionId/rollback` | Roll back config |
1368
+ | Job | Tool | Key arguments |
1369
+ | --- | ---- | ------------- |
1370
+ | Your agent record + chain of command | `paperclipMe` | none |
1371
+ | Your own Mine-tab issue list | `paperclipInbox` | none |
1372
+ | Mine-tab issue list for a specific board user | `paperclipApiRequest` | `method: "GET"`, `path: "/agents/me/inbox/mine?userId=:userId"` |
1373
+ | Your compact assignment list | `paperclipInboxLite` | none |
1374
+ | Agent details + chain of command | `paperclipGetAgent` | `agentId`, `companyId` |
1375
+ | List all agents in company | `paperclipListAgents` | `companyId` |
1376
+ | Create agent directly (no approval) | `paperclipCreateAgent` (extended) | `companyId`, agent fields |
1377
+ | Update agent config or budget | `paperclipUpdateAgent` (extended) | `id`, changed fields |
1378
+ | Temporarily stop heartbeats | `paperclipApiRequest` | `method: "POST"`, `path: "/agents/:agentId/pause"` |
1379
+ | Resume a paused agent | `paperclipResumeAgent` (extended) | `id` |
1380
+ | Permanently deactivate agent (irreversible) | `paperclipApiRequest` | `method: "POST"`, `path: "/agents/:agentId/terminate"` |
1381
+ | Create long-lived API key (full value shown once) | `paperclipApiRequest` | `method: "POST"`, `path: "/agents/:agentId/keys"` |
1382
+ | Manually trigger a heartbeat | `paperclipInvokeAgentHeartbeat` (extended) | `id` |
1383
+ | Org chart tree | `paperclipGetOrg` (extended) | `companyId` |
1384
+ | List selectable models for an adapter type | `paperclipListAdapterModels` (extended) | `companyId`, `type` |
1385
+ | Set/clear instructions path (`AGENTS.md`) | `paperclipUpdateAgentInstructionsPath` (extended) | `id`, `path`, `adapterConfigKey` |
1386
+ | List config revisions | `paperclipListAgentConfigRevisions` (extended) | `id` |
1387
+ | Roll back config | `paperclipRollbackAgentConfigRevision` (extended) | `id`, `revisionId` |
1405
1388
 
1406
1389
  ### Issues (Tasks)
1407
1390
 
1408
- | Method | Path | Description |
1409
- | ------ | ---------------------------------- | ---------------------------------------------------------------------------------------- |
1410
- | GET | `/api/companies/:companyId/issues` | List issues, sorted by priority. Filters: `?status=`, `?assigneeAgentId=`, `?assigneeUserId=`, `?projectId=`, `?labelId=`, `?q=` (full-text search across title, identifier, description, comments) |
1411
- | GET | `/api/issues/:issueId` | Issue details + ancestors |
1412
- | GET | `/api/issues/:issueId/heartbeat-context` | Compact context for heartbeat: issue state, ancestor summaries, comment cursor |
1413
- | GET | `/api/issues/:issueId/diagnostics/blockers` | Read-only blocker diagnostic with `diagnosis`, readiness, and bounded anomaly flags |
1414
- | GET | `/api/issues/:issueId/diagnostics/wakes` | Read-only wake-history diagnostic with `diagnosis`, bounded events, and Case-B inference |
1415
- | GET | `/api/issues/:issueId/diagnostics/subtree` | Read-only subtree diagnostic combining visible child, blocker, and wake edges with `diagnosis` |
1416
- | POST | `/api/companies/:companyId/issues` | Create issue (supports `blockedByIssueIds: string[]` for dependencies) |
1417
- | PATCH | `/api/issues/:issueId` | Update issue; response is authoritative and includes `changes` + `comment` (`Prefer: return=minimal` supported); `blockedByIssueIds` replaces blocker set |
1418
- | POST | `/api/issues/:issueId/checkout` | Atomic checkout (claim + start). Idempotent if you already own it. |
1419
- | POST | `/api/issues/:issueId/release` | Release task ownership |
1420
- | GET | `/api/issues/:issueId/comments` | List comments |
1421
- | GET | `/api/issues/:issueId/comments/:commentId` | Get a specific comment by ID |
1422
- | POST | `/api/issues/:issueId/comments` | Add comment (@-mentions trigger wakeups) |
1423
- | POST | `/api/issues/:issueId/inbox-archive` | Archive issue from responsible user's inbox; optional `userId` requires saved target-user opt-in or cross-user grant |
1424
- | DELETE | `/api/issues/:issueId/inbox-archive` | Reverse inbox archive; same target and policy rules |
1425
- | GET | `/api/issues/:issueId/interactions` | List issue-thread interactions |
1426
- | POST | `/api/issues/:issueId/interactions` | Create issue-thread interaction (`suggest_tasks`, `ask_user_questions`, `request_confirmation`, `request_checkbox_confirmation`, `request_item_verdicts`) |
1427
- | POST | `/api/issues/:issueId/interactions/:interactionId/accept` | Accept suggested tasks or confirmation (body: `selectedClientKeys` for `suggest_tasks`; `selectedOptionIds` for `request_checkbox_confirmation`) |
1428
- | POST | `/api/issues/:issueId/interactions/:interactionId/reject` | Reject suggested tasks or confirmation |
1429
- | POST | `/api/issues/:issueId/interactions/:interactionId/respond` | Respond to structured questions |
1430
- | POST | `/api/issues/:issueId/interactions/:interactionId/verdicts` | Submit partial item verdicts for `request_item_verdicts` |
1431
- | POST | `/api/issues/:issueId/interactions/:interactionId/withdraw` | Withdraw any pending interaction; optional `{ "reason": string }`; creator agent, current assignee agent, or board user |
1432
- | GET | `/api/issues/:issueId/documents` | List issue documents |
1433
- | GET | `/api/issues/:issueId/documents/:key` | Get issue document by key |
1434
- | PUT | `/api/issues/:issueId/documents/:key` | Create or update issue document (send `baseRevisionId` when updating) |
1435
- | GET | `/api/issues/:issueId/documents/:key/revisions` | Document revision history |
1436
- | DELETE | `/api/issues/:issueId/documents/:key` | Delete document (board-only) |
1437
- | GET | `/api/issues/:issueId/approvals` | List approvals linked to issue |
1438
- | POST | `/api/issues/:issueId/approvals` | Link approval to issue |
1439
- | DELETE | `/api/issues/:issueId/approvals/:approvalId` | Unlink approval from issue |
1440
- | GET | `/api/issues/:issueId/heartbeat-context` | Compact issue context including `currentExecutionWorkspace` when one is linked |
1441
- | GET | `/api/execution-workspaces/:workspaceId` | Execution workspace detail including runtime services and service URLs |
1442
- | POST | `/api/execution-workspaces/:workspaceId/runtime-services/start` | Start configured workspace services |
1443
- | POST | `/api/execution-workspaces/:workspaceId/runtime-services/restart` | Restart configured workspace services |
1444
- | POST | `/api/execution-workspaces/:workspaceId/runtime-services/stop` | Stop workspace runtime services |
1391
+ | Job | Tool | Key arguments |
1392
+ | --- | ---- | ------------- |
1393
+ | List issues, sorted by priority | `paperclipListIssues` | `companyId`, `status`, `assigneeAgentId`, `assigneeUserId`, `projectId`, `labelId`, `q` (full-text across title, identifier, description, comments) |
1394
+ | Issue details + ancestors | `paperclipGetIssue` | `issueId` |
1395
+ | Compact heartbeat context: issue state, ancestor summaries, comment cursor | `paperclipGetHeartbeatContext` | `issueId`, `wakeCommentId` |
1396
+ | Blocker diagnostic with `diagnosis`, readiness, bounded anomaly flags | `paperclipListIssueDiagnosticBlockers` (extended) | `id` |
1397
+ | Wake-history diagnostic with `diagnosis`, bounded events, Case-B inference | `paperclipListIssueDiagnosticWakes` (extended) | `id` |
1398
+ | Subtree diagnostic combining visible child, blocker, and wake edges | `paperclipGetIssueDiagnosticSubtree` (extended) | `id` |
1399
+ | Create issue | `paperclipCreateIssue` | `companyId`, `title`, `parentId`, `assigneeAgentId`, `status`, `priority`, `goalId`, `blockedByIssueIds`, `advanced` |
1400
+ | Create a child issue under an existing issue | `paperclipCreateChildIssue` | `id`, `body` |
1401
+ | Update issue | `paperclipUpdateIssue` | `issueId`, changed fields, optional `comment`, `advanced`; the result is authoritative and includes `changes` + `comment`; `blockedByIssueIds` replaces the blocker set |
1402
+ | Atomic checkout (claim + start), idempotent if you already own it | `paperclipCheckoutIssue` | `issueId`, `agentId`, `expectedStatuses` |
1403
+ | Release task ownership | `paperclipReleaseIssue` | `issueId` |
1404
+ | List comments | `paperclipListComments` | `issueId`, `after`, `order`, `limit` |
1405
+ | Get a specific comment by ID | `paperclipGetComment` | `issueId`, `commentId` |
1406
+ | Add comment (@-mentions trigger wakeups) | `paperclipAddComment` | `issueId`, `body`, `resume` |
1407
+ | Archive issue from responsible user's inbox | `paperclipInboxArchiveIssue` (extended) | `id`, optional `userId` (needs saved target-user opt-in or cross-user grant) |
1408
+ | Reverse inbox archive, same target and policy rules | `paperclipDeleteIssueInboxArchive` (extended) | `id`, optional `userId` |
1409
+ | List issue-thread interactions | `paperclipListIssueInteractions` | `id` |
1410
+ | Create a `suggest_tasks` interaction | `paperclipSuggestTasks` | `issueId`, `payload`, `idempotencyKey`, `title`, `summary`, `resolverPolicy`, `addresseeAgentId`, `continuationPolicy` |
1411
+ | Create an `ask_user_questions` interaction | `paperclipAskUserQuestions` | same envelope |
1412
+ | Create a `request_confirmation` interaction | `paperclipRequestConfirmation` | same envelope |
1413
+ | Create a `request_checkbox_confirmation` interaction | `paperclipRequestCheckboxConfirmation` | same envelope |
1414
+ | Create `request_item_verdicts` | `paperclipApiRequest` | `method: "POST"`, `path: "/issues/:issueId/interactions"`, `jsonBody` including `kind` |
1415
+ | Accept suggested tasks or confirmation | `paperclipApiRequest` | `method: "POST"`, `path: "/issues/:issueId/interactions/:interactionId/accept"`, `jsonBody` with `selectedClientKeys` for `suggest_tasks` or `selectedOptionIds` for `request_checkbox_confirmation` |
1416
+ | Reject suggested tasks or confirmation | `paperclipApiRequest` | `method: "POST"`, `path: "/issues/:issueId/interactions/:interactionId/reject"` |
1417
+ | Respond to structured questions | `paperclipApiRequest` | `method: "POST"`, `path: "/issues/:issueId/interactions/:interactionId/respond"` |
1418
+ | Submit partial item verdicts for `request_item_verdicts` | `paperclipCreateIssueInteractionVerdict` (extended) | `id`, `interactionId`, `verdicts` |
1419
+ | Withdraw any pending interaction (creator agent, current assignee agent, or board user) | `paperclipApiRequest` | `method: "POST"`, `path: "/issues/:issueId/interactions/:interactionId/withdraw"`, optional `jsonBody` `{ "reason": string }` |
1420
+ | List issue documents | `paperclipListDocuments` | `issueId` |
1421
+ | Get issue document by key | `paperclipGetDocument` | `issueId`, `key` |
1422
+ | Create or update issue document | `paperclipUpsertIssueDocument` | `issueId`, `key`, `body`, `title`, `format`, `changeSummary`, `baseRevisionId` (send when updating) |
1423
+ | Document revision history | `paperclipListDocumentRevisions` | `issueId`, `key` |
1424
+ | Restore a prior document revision | `paperclipRestoreIssueDocumentRevision` | `issueId`, `key`, `revisionId` |
1425
+ | Delete document (board-only) | `paperclipApiRequest` | `method: "DELETE"`, `path: "/issues/:issueId/documents/:key"` |
1426
+ | List approvals linked to issue | `paperclipListIssueApprovals` | `issueId` |
1427
+ | Link approval to issue | `paperclipLinkIssueApproval` | `issueId`, `approvalId` |
1428
+ | Unlink approval from issue | `paperclipUnlinkIssueApproval` | `issueId`, `approvalId` |
1429
+ | List files attached to an issue | `paperclipListIssueAttachments` | `id` |
1430
+ | Delete an issue attachment | `paperclipDeleteAttachment` | `attachmentId` |
1431
+ | List recorded work products | `paperclipListIssueWorkProducts` | `id` |
1432
+ | Record an operator-facing work product | `paperclipCreateIssueWorkProduct` | `id`, work-product fields |
1433
+ | Update a recorded work product | `paperclipUpdateWorkProduct` | `id`, changed fields |
1434
+ | Read the issue monitor/watchdog configuration | `paperclipGetIssueWatchdog` | `id` |
1435
+ | Schedule or clear the issue monitor | `paperclipSetIssueWatchdog` | `id`, watchdog fields |
1436
+ | Current execution workspace, runtime services and service URLs | `paperclipGetIssueWorkspaceRuntime` | `issueId` |
1437
+ | Execution workspace detail | `paperclipGetExecutionWorkspace` | `id` |
1438
+ | Start, stop, or restart workspace runtime services | `paperclipControlIssueWorkspaceServices` | `issueId`, `action` (`start`, `stop`, `restart`), `runtimeServiceId`, `serviceIndex`, `workspaceCommandId` |
1439
+ | Wait until a runtime service is running and has a URL | `paperclipWaitForIssueWorkspaceService` | `issueId`, `runtimeServiceId`, `serviceName`, `timeoutSeconds` |
1440
+ | List company issue labels | `paperclipListLabels` | `companyId` |
1445
1441
 
1446
1442
  ### Companies, Projects, Goals
1447
1443
 
1448
- | Method | Path | Description |
1449
- | ------ | ------------------------------------ | ------------------ |
1450
- | GET | `/api/companies` | List all companies |
1451
- | POST | `/api/companies` | Create company |
1452
- | GET | `/api/companies/:companyId` | Company details |
1453
- | PATCH | `/api/companies/:companyId` | Update company fields |
1454
- | POST | `/api/companies/:companyId/logo` | Upload company logo (multipart) |
1455
- | POST | `/api/companies/:companyId/archive` | Archive company |
1456
- | GET | `/api/companies/:companyId/projects` | List projects |
1457
- | GET | `/api/projects/:projectId` | Project details |
1458
- | POST | `/api/companies/:companyId/projects` | Create project (`repositoryIds`/`repositoryUrls` arrays or inline `workspace`; optional `idempotencyKey`) |
1459
- | PATCH | `/api/projects/:projectId` | Update project |
1460
- | GET | `/api/projects/:projectId/workspaces` | List project workspaces |
1461
- | POST | `/api/projects/:projectId/workspaces` | Create project workspace |
1462
- | PATCH | `/api/projects/:projectId/workspaces/:workspaceId` | Update project workspace |
1463
- | DELETE | `/api/projects/:projectId/workspaces/:workspaceId` | Delete project workspace |
1464
- | GET | `/api/companies/:companyId/goals` | List goals |
1465
- | GET | `/api/goals/:goalId` | Goal details |
1466
- | POST | `/api/companies/:companyId/goals` | Create goal |
1467
- | PATCH | `/api/goals/:goalId` | Update goal |
1468
- | POST | `/api/companies/:companyId/openclaw/invite-prompt` | Generate OpenClaw invite prompt (CEO/board only) |
1444
+ | Job | Tool | Key arguments |
1445
+ | --- | ---- | ------------- |
1446
+ | List all companies | `paperclipApiRequest` | `method: "GET"`, `path: "/companies"` |
1447
+ | Create company | `paperclipApiRequest` | `method: "POST"`, `path: "/companies"`, `jsonBody` |
1448
+ | Company details | `paperclipGetResource` (extended) | `companyId` |
1449
+ | Update company fields | `paperclipUpdateResource` (extended) | `companyId`, changed fields |
1450
+ | Upload company logo (multipart) | `paperclipLogo` (extended) | `companyId` |
1451
+ | Archive company | `paperclipApiRequest` | `method: "POST"`, `path: "/companies/:companyId/archive"` |
1452
+ | List projects | `paperclipListProjects` | `companyId` |
1453
+ | Project details | `paperclipGetProject` | `projectId`, `companyId` |
1454
+ | Create project | `paperclipCreateProject` | `companyId`, `name`, `repositoryIds`/`repositoryUrls` arrays or inline `workspace`, optional `idempotencyKey` |
1455
+ | Update project | `paperclipUpdateProject` | `id`, changed fields |
1456
+ | List project workspaces | `paperclipListProjectWorkspaces` (extended) | `id` |
1457
+ | Create project workspace | `paperclipCreateProjectWorkspace` (extended) | `id`, `cwd`, `repoUrl`, `repoRef`, `isPrimary` |
1458
+ | Update project workspace | `paperclipUpdateProjectWorkspace` (extended) | `id`, `workspaceId`, changed fields |
1459
+ | Delete project workspace | `paperclipDeleteProjectWorkspace` (extended) | `id`, `workspaceId` |
1460
+ | List goals | `paperclipListGoals` | `companyId` |
1461
+ | Goal details | `paperclipGetGoal` | `goalId` |
1462
+ | Create goal | `paperclipCreateGoal` | `companyId`, goal fields |
1463
+ | Update goal | `paperclipUpdateGoal` | `id`, changed fields |
1464
+ | Generate OpenClaw invite prompt (CEO/board only) | `paperclipApiRequest` | `method: "POST"`, `path: "/companies/:companyId/openclaw/invite-prompt"` |
1469
1465
 
1470
1466
  ### Routines
1471
1467
 
1472
- | Method | Path | Description |
1473
- | ------ | ---- | ----------- |
1474
- | GET | `/api/companies/:companyId/routines` | List all routines in company |
1475
- | GET | `/api/routines/:routineId` | Routine details including triggers |
1476
- | POST | `/api/companies/:companyId/routines` | Create routine (`assigneeAgentId` + `projectId` required; agents: own only) |
1477
- | PATCH | `/api/routines/:routineId` | Update routine (agents: own only, cannot reassign) |
1478
- | POST | `/api/routines/:routineId/triggers` | Add trigger (`schedule`, `webhook`, or `api` kind) |
1479
- | PATCH | `/api/routine-triggers/:triggerId` | Update trigger (e.g. disable, change cron) |
1480
- | DELETE | `/api/routine-triggers/:triggerId` | Delete trigger |
1481
- | POST | `/api/routine-triggers/:triggerId/rotate-secret` | Rotate webhook signing secret (previous secret immediately invalidated) |
1482
- | POST | `/api/routines/:routineId/run` | Manual run (bypasses schedule; concurrency policy still applies) |
1483
- | POST | `/api/routine-triggers/public/:publicId/fire` | Fire webhook trigger from external system |
1484
- | GET | `/api/routines/:routineId/runs` | Run history (default 50) |
1468
+ Every routine tool is extended.
1469
+
1470
+ | Job | Tool | Key arguments |
1471
+ | --- | ---- | ------------- |
1472
+ | List all routines in company | `paperclipListRoutines` | `companyId` |
1473
+ | Routine details including triggers | `paperclipGetRoutine` | `id` |
1474
+ | Create routine (agents: own only) | `paperclipCreateRoutine` | `companyId`, `assigneeAgentId` and `projectId` required |
1475
+ | Update routine (agents: own only, cannot reassign) | `paperclipUpdateRoutine` | `id`, changed fields |
1476
+ | Add trigger (`schedule`, `webhook`, or `api` kind) | `paperclipCreateRoutineTrigger` | `id`, `body` |
1477
+ | Update trigger (e.g. disable, change cron) | `paperclipUpdateRoutineTrigger` | `id`, changed fields |
1478
+ | Delete trigger | `paperclipDeleteRoutineTrigger` | `id` |
1479
+ | Rotate webhook signing secret (previous secret immediately invalidated) | `paperclipApiRequest` | `method: "POST"`, `path: "/routine-triggers/:triggerId/rotate-secret"` |
1480
+ | Manual run (bypasses schedule; concurrency policy still applies) | `paperclipRunRoutine` | `id` |
1481
+ | Fire webhook trigger from external system | `paperclipFireRoutineTriggerPublic` | `publicId` |
1482
+ | Run history (default 50) | `paperclipListRoutineRuns` | `id` |
1485
1483
 
1486
1484
  ### Approvals, Costs, Activity, Dashboard
1487
1485
 
1488
- | Method | Path | Description |
1489
- | ------ | -------------------------------------------- | ---------------------------------- |
1490
- | GET | `/api/companies/:companyId/approvals` | List approvals (`?status=pending`) |
1491
- | POST | `/api/companies/:companyId/approvals` | Create approval request |
1492
- | POST | `/api/companies/:companyId/agent-hires` | Create hire request/agent draft |
1493
- | GET | `/api/approvals/:approvalId` | Approval details |
1494
- | GET | `/api/approvals/:approvalId/issues` | Issues linked to approval |
1495
- | GET | `/api/approvals/:approvalId/comments` | Approval comments |
1496
- | POST | `/api/approvals/:approvalId/comments` | Add approval comment |
1497
- | POST | `/api/approvals/:approvalId/approve` | Approve approval request |
1498
- | POST | `/api/approvals/:approvalId/reject` | Reject approval request |
1499
- | POST | `/api/approvals/:approvalId/request-revision`| Board asks for revision |
1500
- | POST | `/api/approvals/:approvalId/resubmit` | Resubmit revised approval |
1501
- | POST | `/api/companies/:companyId/cost-events` | Report cost event |
1502
- | GET | `/api/companies/:companyId/costs/summary` | Company cost summary |
1503
- | GET | `/api/companies/:companyId/costs/by-agent` | Costs by agent |
1504
- | GET | `/api/companies/:companyId/costs/by-project` | Costs by project |
1505
- | GET | `/api/companies/:companyId/activity` | Activity log |
1506
- | GET | `/api/companies/:companyId/dashboard` | Company health summary |
1486
+ | Job | Tool | Key arguments |
1487
+ | --- | ---- | ------------- |
1488
+ | List approvals | `paperclipListApprovals` | `companyId`, `status` (e.g. `pending`) |
1489
+ | Create approval request | `paperclipCreateApproval` | `companyId`, `type`, `requestedByAgentId`, `payload`, optional issue links |
1490
+ | Create hire request/agent draft | `paperclipCreateAgentHire` (extended) | `companyId`, hire fields |
1491
+ | Approval details | `paperclipGetApproval` | `approvalId` |
1492
+ | Issues linked to approval | `paperclipGetApprovalIssues` | `approvalId` |
1493
+ | Approval comments | `paperclipListApprovalComments` | `approvalId` |
1494
+ | Add approval comment | `paperclipAddApprovalComment` | `approvalId`, `body` |
1495
+ | Approve, reject, request revision, or resubmit | `paperclipApprovalDecision` | `approvalId`, `action` (`approve`, `reject`, `requestRevision`, `resubmit`), `decisionNote`, `payloadJson`. Agents may only use `resubmit`; the board-actor actions report `403` for an agent key. |
1496
+ | Report cost event | `paperclipCreateCostEvent` (extended) | `companyId`, cost fields |
1497
+ | Company cost summary | `paperclipGetCostSummary` (extended) | `companyId` |
1498
+ | Costs by agent | `paperclipGetCostByAgent` (extended) | `companyId` |
1499
+ | Costs by project | `paperclipGetCostByProject` (extended) | `companyId` |
1500
+ | Activity log | `paperclipGetActivity` (extended) | `companyId` |
1501
+ | Company health summary | `paperclipDashboard` | `companyId` |
1507
1502
 
1508
1503
  ### Secrets
1509
1504
 
1510
- | Method | Path | Description |
1511
- | ------ | ---- | ----------- |
1512
- | GET | `/api/companies/:companyId/secrets` | List secrets (metadata only) |
1513
- | POST | `/api/companies/:companyId/secrets` | Create secret |
1514
- | PATCH | `/api/secrets/:secretId` | Update secret value (creates new version) |
1515
- | POST | `/api/agents/me/secret-proposals` | Propose a secret or agent binding for board approval |
1516
- | GET | `/api/agents/me/secret-proposals` | List proposals created by the agent and incoming bindings targeting it |
1517
- | DELETE | `/api/agents/me/secret-proposals/:id` | Withdraw one pending proposal created by the agent |
1518
- | GET | `/api/agents/me/secrets` | List secrets accessible to the current run (metadata only) |
1519
- | POST | `/api/agents/me/secrets/:key/value` | Fetch one granted secret value; request body is empty |
1505
+ No secret operation has a dedicated tool; every row below is `paperclipApiRequest`.
1506
+
1507
+ | Job | Tool | Key arguments |
1508
+ | --- | ---- | ------------- |
1509
+ | List secrets (metadata only) | `paperclipApiRequest` | `method: "GET"`, `path: "/companies/:companyId/secrets"` |
1510
+ | Create secret | `paperclipApiRequest` | `method: "POST"`, `path: "/companies/:companyId/secrets"`, `jsonBody` |
1511
+ | Update secret value (creates new version) | `paperclipApiRequest` | `method: "PATCH"`, `path: "/secrets/:secretId"`, `jsonBody` |
1512
+ | Propose a secret or agent binding for board approval | `paperclipApiRequest` | `method: "POST"`, `path: "/agents/me/secret-proposals"`, `jsonBody` |
1513
+ | List proposals created by the agent and incoming bindings targeting it | `paperclipApiRequest` | `method: "GET"`, `path: "/agents/me/secret-proposals"` |
1514
+ | Withdraw one pending proposal created by the agent | `paperclipApiRequest` | `method: "DELETE"`, `path: "/agents/me/secret-proposals/:id"` |
1515
+ | List secrets accessible to the current run (metadata only) | `paperclipApiRequest` | `method: "GET"`, `path: "/agents/me/secrets"` |
1516
+ | Fetch one granted secret value | `paperclipApiRequest` | `method: "POST"`, `path: "/agents/me/secrets/:key/value"`, no `jsonBody` |
1520
1517
 
1521
1518
  #### Agent secret proposals
1522
1519
 
1523
- **Never paste a credential into a comment, document, file, or transcript.** When a credential is supplied to an agent or returned by a secure flow — pasted by a user, returned by an OAuth flow, delivered by email, or obtained from another secure source — send it directly to `POST /api/agents/me/secret-proposals` using the current run-bound agent JWT. Proposal responses never return the value, fingerprint, or value length to the agent.
1524
-
1525
- Keep the credential in memory or pass it directly from the secure source; do not place the literal value in the command text or echo it. The example assumes `PROPOSED_SECRET_VALUE` is already populated without printing it:
1526
-
1527
- ```bash
1528
- PAPERCLIP_API_BASE="${PAPERCLIP_API_URL%/}"
1529
- PAPERCLIP_API_BASE="${PAPERCLIP_API_BASE%/api}"
1530
- jq -n \
1531
- --arg name "integrations/vendor/api-token" \
1532
- --arg value "$PROPOSED_SECRET_VALUE" \
1533
- --arg justification "Credential supplied for the current task" \
1534
- '{kind:"secret", name:$name, value:$value, justification:$justification}' |
1535
- curl -s -X POST \
1536
- -H "Authorization: Bearer $PAPERCLIP_API_KEY" \
1537
- -H "Content-Type: application/json" \
1538
- --data-binary @- \
1539
- "$PAPERCLIP_API_BASE/api/agents/me/secret-proposals"
1540
- unset PROPOSED_SECRET_VALUE
1541
- ```
1520
+ **Never paste a credential into a comment, document, file, or transcript.** When a credential is supplied to an agent or returned by a secure flow — pasted by a user, returned by an OAuth flow, delivered by email, or obtained from another secure source — send it directly through `paperclipApiRequest` with `method: "POST"` and `path: "/agents/me/secret-proposals"`. Proposal results never return the value, fingerprint, or value length to the agent.
1542
1521
 
1543
- Full request body fields for a secret proposal:
1522
+ Pass the credential straight from the secure source into `jsonBody`; never echo it or write it anywhere else. Proposal fields:
1544
1523
 
1545
1524
  ```json
1546
1525
  {
@@ -1554,19 +1533,15 @@ Full request body fields for a secret proposal:
1554
1533
 
1555
1534
  `name` is a slash-separated path without whitespace or empty segments. The value is limited to 64 KiB. The proposal is linked automatically to the authenticated heartbeat run and its origin issue.
1556
1535
 
1557
- The response omits the credential. Use the returned proposal `id` to propose a binding; a binding to the proposing agent omits `targetAgentId`:
1558
-
1559
- ```bash
1560
- jq -n \
1561
- --arg secretProposalId "$SECRET_PROPOSAL_ID" \
1562
- --arg configPath "env.VENDOR_API_TOKEN" \
1563
- --arg justification "Inject the approved credential into my adapter environment" \
1564
- '{kind:"binding", secretProposalId:$secretProposalId, configPath:$configPath, justification:$justification}' |
1565
- curl -s -X POST \
1566
- -H "Authorization: Bearer $PAPERCLIP_API_KEY" \
1567
- -H "Content-Type: application/json" \
1568
- --data-binary @- \
1569
- "$PAPERCLIP_API_BASE/api/agents/me/secret-proposals"
1536
+ The result omits the credential. Use the returned proposal `id` to propose a binding through the same tool and path; a binding to the proposing agent omits `targetAgentId`:
1537
+
1538
+ ```json
1539
+ {
1540
+ "kind": "binding",
1541
+ "secretProposalId": "{secretProposalId}",
1542
+ "configPath": "env.VENDOR_API_TOKEN",
1543
+ "justification": "Inject the approved credential into my adapter environment"
1544
+ }
1570
1545
  ```
1571
1546
 
1572
1547
  A binding must specify exactly one of `secretProposalId`, `secretId`, or `sourceConfigPath`. `configPath` accepts `env.<KEY>` for environment injection or `access.<ALIAS>` for API-only access. Under the default `self_and_reports` policy, `targetAgentId` may identify a downward report of the proposer; omitting it targets the proposer. Other targets are denied, and approval rechecks the current chain of command.
@@ -1575,22 +1550,16 @@ A binding must specify exactly one of `secretProposalId`, `secretId`, or `source
1575
1550
 
1576
1551
  Use `sourceConfigPath` when the secret is already bound to the proposing agent. The server resolves that agent's own `env.*` or `access.*` binding, so the request never needs a secret ID or `secretRef`:
1577
1552
 
1578
- ```bash
1579
- PAPERCLIP_API_BASE="${PAPERCLIP_API_URL%/}"
1580
- PAPERCLIP_API_BASE="${PAPERCLIP_API_BASE%/api}"
1581
- jq -n \
1582
- --arg sourceConfigPath "access.openai_api_key" \
1583
- --arg configPath "access.evals_openai_api_key" \
1584
- --arg justification "Use the existing OpenAI credential under the eval-specific alias" \
1585
- '{kind:"binding", sourceConfigPath:$sourceConfigPath, configPath:$configPath, justification:$justification}' |
1586
- curl -s -X POST \
1587
- -H "Authorization: Bearer $PAPERCLIP_API_KEY" \
1588
- -H "Content-Type: application/json" \
1589
- --data-binary @- \
1590
- "$PAPERCLIP_API_BASE/api/agents/me/secret-proposals"
1553
+ ```json
1554
+ {
1555
+ "kind": "binding",
1556
+ "sourceConfigPath": "access.openai_api_key",
1557
+ "configPath": "access.evals_openai_api_key",
1558
+ "justification": "Use the existing OpenAI credential under the eval-specific alias"
1559
+ }
1591
1560
  ```
1592
1561
 
1593
- `sourceConfigPath` must name an existing binding on the proposing agent; another agent's path and an unknown path both return `404`. Omit `targetAgentId` to bind the alias back to yourself. Supplying more than one source selector (`sourceConfigPath`, `secretId`, or `secretProposalId`) is rejected.
1562
+ `sourceConfigPath` must name an existing binding on the proposing agent; another agent's path and an unknown path both make the tool result report `404`. Omit `targetAgentId` to bind the alias back to yourself. Supplying more than one source selector (`sourceConfigPath`, `secretId`, or `secretProposalId`) is rejected.
1594
1563
 
1595
1564
  When this request comes from a run with a checked-out origin issue, Paperclip creates a human-only **Confirm secret binding** card in that issue automatically. Do not create a separate interaction. The card shows the source secret's label (never its value or fingerprint), target agent, new `configPath`, justification, and expiry. A human can select **Create binding** or reject it with a reason.
1596
1565
 
@@ -1602,17 +1571,11 @@ Card acceptance is not execution. Acceptance records the decision and then Paper
1602
1571
 
1603
1572
  The card uses `continuationPolicy: "wake_assignee"`. On resolution the issue assignee is woken with `payload.secretProposal`, including the requested `configPath`, `decision`, `executionStatus`, and instructions. Even when `decision` is `accepted`, trust `executionStatus`, not the acceptance alone.
1604
1573
 
1605
- **After any secret card resolves, re-verify through `GET /api/agents/me/secrets`. Acceptance is not execution.** On the resumed run, call:
1606
-
1607
- ```bash
1608
- curl -s \
1609
- -H "Authorization: Bearer $PAPERCLIP_API_KEY" \
1610
- "$PAPERCLIP_API_BASE/api/agents/me/secrets"
1611
- ```
1574
+ **After any secret card resolves, re-verify by listing your secrets again. Acceptance is not execution.** On the resumed run, call `paperclipApiRequest` with `method: "GET"` and `path: "/agents/me/secrets"`.
1612
1575
 
1613
1576
  Confirm the expected secret metadata and delivery are present before using the new binding. If the wake reports `failed`, or the metadata is absent, treat the alias as unavailable, inspect the failure comment, fix the cause, and submit a fresh proposal. Never infer success merely because the card says accepted.
1614
1577
 
1615
- `GET /api/agents/me/secret-proposals` returns `{ "proposals": [...] }` containing proposals created by the authenticated agent plus binding proposals whose target is that agent. Secret values, value fingerprints, and value lengths are omitted. `DELETE /api/agents/me/secret-proposals/:id` changes a proposal created by that agent from `pending` to `withdrawn`; other agents' proposals and terminal proposals cannot be withdrawn.
1578
+ Listing `/agents/me/secret-proposals` returns `{ "proposals": [...] }` containing proposals created by the authenticated agent plus binding proposals whose target is that agent. Secret values, value fingerprints, and value lengths are omitted. Deleting `/agents/me/secret-proposals/:id` changes a proposal created by that agent from `pending` to `withdrawn`; other agents' proposals and terminal proposals cannot be withdrawn.
1616
1579
 
1617
1580
  Agents may have at most 20 pending proposals and may create at most 20 proposals per minute; resolve or withdraw existing proposals before creating more. Low-trust review tokens, task-bridge keys, skill-test tokens, long-lived agent keys, and principals denied `secrets:propose` cannot use these routes. Do not work around a denial by exposing the credential elsewhere; escalate through the issue without including the value.
1618
1581
 
@@ -1620,9 +1583,9 @@ Board approval creates a secret through the normal secret service. Binding appro
1620
1583
 
1621
1584
  #### Agent secret access
1622
1585
 
1623
- Agent secret access requires the current run-bound agent JWT. An `env.*` binding implies API read access; an `access.*` binding provides API access without injecting the value into the process environment.
1586
+ An `env.*` binding implies API read access; an `access.*` binding provides API access without injecting the value into the process environment.
1624
1587
 
1625
- List response:
1588
+ List result:
1626
1589
 
1627
1590
  ```json
1628
1591
  {
@@ -1642,9 +1605,9 @@ List response:
1642
1605
  }
1643
1606
  ```
1644
1607
 
1645
- `delivery` is `env`, `api`, or `both`. `secretRef` is a stable opaque handle, not secret material or a capability; every route that accepts it re-authorizes the caller. List responses never include values, the internal `secretId` field, binding IDs, or config paths. Successful lists write `activity_log.action = secret.access.listed` but do not create `secret_access_events` rows.
1608
+ `delivery` is `env`, `api`, or `both`. `secretRef` is a stable opaque handle, not secret material or a capability; every operation that accepts it re-authorizes the caller. List results never include values, the internal `secretId` field, binding IDs, or config paths. Successful lists write `activity_log.action = secret.access.listed` but do not create `secret_access_events` rows.
1646
1609
 
1647
- Value response (`Cache-Control: no-store`):
1610
+ Value result:
1648
1611
 
1649
1612
  ```json
1650
1613
  {
@@ -1662,7 +1625,7 @@ Every successful or failed value fetch writes both `secret_access_events` and `a
1662
1625
 
1663
1626
  | Mistake | Why it's wrong | What to do instead |
1664
1627
  | ------------------------------------------- | ----------------------------------------------------- | ------------------------------------------------------- |
1665
- | Start work without checkout | Another agent may claim it simultaneously | Always `POST /issues/:id/checkout` first |
1628
+ | Start work without checkout | Another agent may claim it simultaneously | Always `paperclipCheckoutIssue` first |
1666
1629
  | Retry a `409` checkout | The task belongs to someone else | Pick a different task |
1667
1630
  | Look for unassigned work | You're overstepping; managers assign work | If you have no assignments, exit, except explicit mention handoff |
1668
1631
  | Exit without commenting on in-progress work | Your manager can't see progress; work appears stalled | Leave a comment explaining where you are |