@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.
- package/dist/server/codex-home.d.ts +1 -0
- package/dist/server/codex-home.d.ts.map +1 -1
- package/dist/server/codex-home.js +8 -1
- package/dist/server/codex-home.js.map +1 -1
- package/dist/server/config-schema.d.ts.map +1 -1
- package/dist/server/config-schema.js +17 -0
- package/dist/server/config-schema.js.map +1 -1
- package/dist/server/execute.d.ts.map +1 -1
- package/dist/server/execute.js +21 -3
- package/dist/server/execute.js.map +1 -1
- package/dist/server/execute.paperclip-mcp.test.d.ts +2 -0
- package/dist/server/execute.paperclip-mcp.test.d.ts.map +1 -0
- package/dist/server/execute.paperclip-mcp.test.js +84 -0
- package/dist/server/execute.paperclip-mcp.test.js.map +1 -0
- package/package.json +3 -3
- package/skills/paperclip/SKILL.md +123 -134
- package/skills/paperclip/references/api-reference.md +339 -376
- package/skills/paperclip/references/artifacts.md +54 -57
- package/skills/paperclip/references/cases.md +57 -68
- package/skills/paperclip/references/company-skills.md +66 -146
- package/skills/paperclip/references/issue-workspaces.md +28 -43
- package/skills/paperclip/references/routines.md +52 -44
- package/skills/paperclip/references/workflows.md +32 -46
- package/skills/paperclip-board/SKILL.md +141 -334
- package/skills/paperclip-create-agent/SKILL.md +45 -62
- package/skills/paperclip-create-agent/references/api-reference.md +30 -31
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
# Paperclip API Reference
|
|
2
2
|
|
|
3
|
-
|
|
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
|
-
|
|
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 (`
|
|
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
|
|
46
|
+
CEO-safe package operations are company-scoped and have no dedicated tool:
|
|
47
47
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
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 (`
|
|
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 (`
|
|
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
|
-
|
|
220
|
+
**The `paperclipUpdateIssue` result is the authoritative post-write state. A confirming `paperclipGetIssue` after a successful update is unnecessary.**
|
|
223
221
|
|
|
224
|
-
|
|
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
|
|
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 (`
|
|
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
|
|
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 (`
|
|
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, `
|
|
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
|
|
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
|
-
|
|
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
|
-
"
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
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 `
|
|
446
|
-
- request changes with `
|
|
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
|
-
|
|
448
|
+
paperclipMe {}
|
|
461
449
|
-> { id: "agent-42", companyId: "company-1", ... }
|
|
462
450
|
|
|
463
451
|
# 2. Check inbox
|
|
464
|
-
|
|
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
|
-
|
|
459
|
+
paperclipGetIssue { issueId: "issue-101" }
|
|
472
460
|
-> { ..., ancestors: [...] }
|
|
473
461
|
|
|
474
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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 /
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
539
|
-
{}
|
|
523
|
+
paperclipDeleteIssueInboxArchive { id: "issue-310" }
|
|
540
524
|
-> { "ok": true, "userId": "user-7" }
|
|
541
525
|
```
|
|
542
526
|
|
|
543
|
-
Both mutations
|
|
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 `
|
|
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
|
-
|
|
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
|
|
550
|
+
If `currentParticipant` is you, approve the current stage by updating the issue to `done` with a required comment:
|
|
567
551
|
|
|
568
552
|
```
|
|
569
|
-
|
|
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
|
-
|
|
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
|
-
|
|
572
|
+
paperclipMe {}
|
|
591
573
|
-> { id: "mgr-1", role: "manager", companyId: "company-1", ... }
|
|
592
574
|
|
|
593
575
|
# 2. Check team status
|
|
594
|
-
|
|
576
|
+
paperclipListAgents {}
|
|
595
577
|
-> [ { id: "agent-42", name: "BackendEngineer", reportsTo: "mgr-1", status: "idle" }, ... ]
|
|
596
578
|
|
|
597
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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 `
|
|
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
|
-
|
|
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`
|
|
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
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
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
|
-
|
|
719
|
-
|
|
720
|
-
|
|
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. `
|
|
731
|
-
2. `
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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 `
|
|
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
|
|
790
|
-
`GET /
|
|
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
|
|
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
|
-
|
|
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
|
-
"
|
|
819
|
-
"
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
|
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.
|
|
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
|
-
|
|
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`.
|
|
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
|
-
"
|
|
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
|
-
"
|
|
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
|
-
"
|
|
1023
|
-
"
|
|
1024
|
-
|
|
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
|
-
"
|
|
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
|
|
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`
|
|
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
|
-
"
|
|
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
|
|
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
|
|
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
|
|
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
|
|
1271
|
-
- A verdict not listed in `payload.verdicts`
|
|
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
|
|
1374
|
-
|
|
|
1375
|
-
|
|
|
1376
|
-
|
|
|
1377
|
-
|
|
|
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
|
|
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
|
-
|
|
|
1388
|
-
|
|
|
1389
|
-
|
|
|
1390
|
-
|
|
|
1391
|
-
|
|
|
1392
|
-
|
|
|
1393
|
-
|
|
|
1394
|
-
|
|
|
1395
|
-
|
|
|
1396
|
-
|
|
|
1397
|
-
|
|
|
1398
|
-
|
|
|
1399
|
-
|
|
|
1400
|
-
|
|
|
1401
|
-
|
|
|
1402
|
-
|
|
|
1403
|
-
|
|
|
1404
|
-
|
|
|
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
|
-
|
|
|
1409
|
-
|
|
|
1410
|
-
|
|
|
1411
|
-
|
|
|
1412
|
-
|
|
|
1413
|
-
|
|
|
1414
|
-
|
|
|
1415
|
-
|
|
|
1416
|
-
|
|
|
1417
|
-
|
|
|
1418
|
-
|
|
|
1419
|
-
|
|
|
1420
|
-
|
|
|
1421
|
-
|
|
|
1422
|
-
|
|
|
1423
|
-
|
|
|
1424
|
-
|
|
|
1425
|
-
|
|
|
1426
|
-
|
|
|
1427
|
-
|
|
|
1428
|
-
|
|
|
1429
|
-
|
|
|
1430
|
-
|
|
|
1431
|
-
|
|
|
1432
|
-
|
|
|
1433
|
-
|
|
|
1434
|
-
|
|
|
1435
|
-
|
|
|
1436
|
-
|
|
|
1437
|
-
|
|
|
1438
|
-
|
|
|
1439
|
-
|
|
|
1440
|
-
|
|
|
1441
|
-
|
|
|
1442
|
-
|
|
|
1443
|
-
|
|
|
1444
|
-
|
|
|
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
|
-
|
|
|
1449
|
-
|
|
|
1450
|
-
|
|
|
1451
|
-
|
|
|
1452
|
-
|
|
|
1453
|
-
|
|
|
1454
|
-
|
|
|
1455
|
-
|
|
|
1456
|
-
|
|
|
1457
|
-
|
|
|
1458
|
-
|
|
|
1459
|
-
|
|
|
1460
|
-
|
|
|
1461
|
-
|
|
|
1462
|
-
|
|
|
1463
|
-
|
|
|
1464
|
-
|
|
|
1465
|
-
|
|
|
1466
|
-
|
|
|
1467
|
-
|
|
|
1468
|
-
|
|
|
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
|
-
|
|
1473
|
-
|
|
1474
|
-
|
|
|
1475
|
-
|
|
|
1476
|
-
|
|
|
1477
|
-
|
|
|
1478
|
-
|
|
|
1479
|
-
|
|
|
1480
|
-
|
|
|
1481
|
-
|
|
|
1482
|
-
|
|
|
1483
|
-
|
|
|
1484
|
-
|
|
|
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
|
-
|
|
|
1489
|
-
|
|
|
1490
|
-
|
|
|
1491
|
-
|
|
|
1492
|
-
|
|
|
1493
|
-
|
|
|
1494
|
-
|
|
|
1495
|
-
|
|
|
1496
|
-
|
|
|
1497
|
-
|
|
|
1498
|
-
|
|
|
1499
|
-
|
|
|
1500
|
-
|
|
|
1501
|
-
|
|
|
1502
|
-
|
|
|
1503
|
-
|
|
|
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
|
-
|
|
1511
|
-
|
|
1512
|
-
|
|
|
1513
|
-
|
|
|
1514
|
-
|
|
|
1515
|
-
|
|
|
1516
|
-
|
|
|
1517
|
-
|
|
|
1518
|
-
|
|
|
1519
|
-
|
|
|
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
|
|
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
|
-
|
|
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
|
|
1558
|
-
|
|
1559
|
-
```
|
|
1560
|
-
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
|
|
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
|
-
```
|
|
1579
|
-
|
|
1580
|
-
|
|
1581
|
-
|
|
1582
|
-
|
|
1583
|
-
|
|
1584
|
-
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
|
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 `
|
|
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 |
|