@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.
@@ -2,6 +2,8 @@
2
2
 
3
3
  When work produces a user-inspectable file, upload true deliverables to the current issue before final disposition. Local filesystem paths are not enough because board users, reviewers, and cloud operators may not have access to the agent workspace.
4
4
 
5
+ Attachment upload is a multipart upload and has no MCP tool, so it keeps its own helper. Everything else on this page — listing and deleting attachments, and recording work products — is done with the `core` toolset tools named below.
6
+
5
7
  Use Bash to run the helper bundled with this skill; installed skill files may not retain executable permissions. From an installed `paperclip` skill directory, the helper lives at `scripts/paperclip-upload-artifact.sh`:
6
8
 
7
9
  ```bash
@@ -12,6 +14,37 @@ bash scripts/paperclip-upload-artifact.sh path/to/output.webm \
12
14
 
13
15
  The helper uses `PAPERCLIP_API_URL`, `PAPERCLIP_API_KEY`, `PAPERCLIP_COMPANY_ID`, `PAPERCLIP_TASK_ID`, and `PAPERCLIP_RUN_ID`. It uploads the file as an issue attachment, creates an attachment-backed artifact work product by default, and prints issue-safe markdown links for your final comment.
14
16
 
17
+ ## Inspect What Is Already On The Issue
18
+
19
+ - `paperclipListIssueAttachments` with `{ "id": "<issue-id>" }` lists the files attached to the issue, including each `attachmentId`.
20
+ - `paperclipListIssueWorkProducts` with `{ "id": "<issue-id>" }` lists the recorded work products. Add `"refreshPullRequests": "true"` when you need pull request state refreshed first.
21
+ - `paperclipDeleteAttachment` with `{ "attachmentId": "<attachment-id>" }` removes an attachment you uploaded by mistake. It is destructive; do not delete attachments you did not create.
22
+
23
+ ## Record The Work Product
24
+
25
+ When the uploaded file is the deliverable, record it with `paperclipCreateIssueWorkProduct`. The server canonicalizes attachment-backed artifact metadata from the `attachmentId`:
26
+
27
+ ```json
28
+ {
29
+ "id": "<issue-id>",
30
+ "type": "artifact",
31
+ "provider": "paperclip",
32
+ "title": "Walkthrough render",
33
+ "status": "ready_for_review",
34
+ "reviewState": "needs_board_review",
35
+ "isPrimary": true,
36
+ "metadata": { "attachmentId": "<uploaded-attachment-id>" }
37
+ }
38
+ ```
39
+
40
+ Read the returned work product record before you report the deliverable. If the tool returns an error instead of a record, the work product does not exist — fix the cause and retry rather than describing it as recorded.
41
+
42
+ When a recorded work product changes later, for example when its pull request merges, patch it with `paperclipUpdateWorkProduct` using the work product id:
43
+
44
+ ```json
45
+ { "id": "<work-product-id>", "status": "done" }
46
+ ```
47
+
15
48
  ## Workspace-Only File References
16
49
 
17
50
  Use a workspace-only reference only when the file should stay in the project or
@@ -20,10 +53,12 @@ or other file whose value is tied to the checkout. This is not a substitute for
20
53
  uploading a deliverable file that a board user should be able to inspect outside
21
54
  the workspace.
22
55
 
23
- Annotate the work product with `metadata.resourceRef`:
56
+ Annotate the work product with `metadata.resourceRef`, again through
57
+ `paperclipCreateIssueWorkProduct`:
24
58
 
25
59
  ```json
26
60
  {
61
+ "id": "<issue-id>",
27
62
  "type": "document",
28
63
  "provider": "workspace",
29
64
  "title": "Regression test plan",
@@ -49,46 +84,6 @@ Annotate the work product with `metadata.resourceRef`:
49
84
  optional positive integers. `relativePath` must be relative to the selected
50
85
  workspace root; do not use host-local absolute paths in `resourceRef`.
51
86
 
52
- Create the work product with:
53
-
54
- ```bash
55
- curl -sS -X POST \
56
- "$PAPERCLIP_API_URL/api/issues/$PAPERCLIP_TASK_ID/work-products" \
57
- -H "Authorization: Bearer $PAPERCLIP_API_KEY" \
58
- -H "X-Paperclip-Run-Id: $PAPERCLIP_RUN_ID" \
59
- -H "Content-Type: application/json" \
60
- --data-binary @workspace-file-work-product.json
61
- ```
62
-
63
- If the helper is unavailable, use the Paperclip API directly:
64
-
65
- ```bash
66
- curl -sS -X POST \
67
- "$PAPERCLIP_API_URL/api/companies/$PAPERCLIP_COMPANY_ID/issues/$PAPERCLIP_TASK_ID/attachments" \
68
- -H "Authorization: Bearer $PAPERCLIP_API_KEY" \
69
- -H "X-Paperclip-Run-Id: $PAPERCLIP_RUN_ID" \
70
- -F 'file=@"path/to/output.webm";type=video/webm'
71
- ```
72
-
73
- Then create a work product when the file is the deliverable. The server canonicalizes attachment-backed artifact metadata from the `attachmentId`:
74
-
75
- ```bash
76
- curl -sS -X POST \
77
- "$PAPERCLIP_API_URL/api/issues/$PAPERCLIP_TASK_ID/work-products" \
78
- -H "Authorization: Bearer $PAPERCLIP_API_KEY" \
79
- -H "X-Paperclip-Run-Id: $PAPERCLIP_RUN_ID" \
80
- -H "Content-Type: application/json" \
81
- --data-binary '{
82
- "type": "artifact",
83
- "provider": "paperclip",
84
- "title": "Walkthrough render",
85
- "status": "ready_for_review",
86
- "reviewState": "needs_board_review",
87
- "isPrimary": true,
88
- "metadata": { "attachmentId": "<uploaded-attachment-id>" }
89
- }'
90
- ```
91
-
92
87
  In your final issue comment, link the uploaded attachment or work product and
93
88
  describe what it contains. If the output is workspace-only, name the work
94
89
  product and the relative path that was recorded in `metadata.resourceRef`.
@@ -97,6 +92,8 @@ chip or link cannot open it; it is not the preferred deliverable path. Do not
97
92
  leave artifact-producing work `in_progress` with only a local path or a
98
93
  `Remaining` note.
99
94
 
95
+ ## External Chat Responses
96
+
100
97
  When the current run was started by an external chat request and the file is
101
98
  part of the response intended for that external conversation, have the upload
102
99
  helper bind that specific file to an explicit response comment:
@@ -107,21 +104,20 @@ bash scripts/paperclip-upload-artifact.sh path/to/result.png \
107
104
  --chat-comment "Here is the requested image."
108
105
  ```
109
106
 
110
- `--chat-comment` uses the current run-scoped API directly, so it does not depend
111
- on a separately installed CLI version. It first uploads the file and creates
112
- the same-run artifact work product, then binds that exact attachment to the
113
- comment. Concurrent matching invocations on one host serialize by API, company,
114
- task, run, filename, content hash, and media type. On retry, the helper reuses
115
- the server's immutable same-run attachment record instead of uploading a second
116
- copy. A retry from a different host is still subject to server-side attachment
117
- admission and should not be run concurrently.
118
-
119
- If the upload connection ends without an HTTP response, the helper records that
120
- ambiguous outcome locally. The same command polls briefly for Paperclip's
121
- immutable attachment record and otherwise stops instead of blindly creating a
122
- duplicate. Retry later. Use `--retry-unknown-upload` only after establishing
123
- that the first upload did not commit; this explicit override accepts the risk of
124
- creating a duplicate file.
107
+ It first uploads the file and creates the same-run artifact work product, then
108
+ binds that exact attachment to the comment. Concurrent matching invocations on
109
+ one host serialize by API, company, task, run, filename, content hash, and media
110
+ type. On retry, the helper reuses the server's immutable same-run attachment
111
+ record instead of uploading a second copy. A retry from a different host is
112
+ still subject to server-side attachment admission and should not be run
113
+ concurrently.
114
+
115
+ If the upload ends without a response, the helper records that ambiguous outcome
116
+ locally. The same command polls briefly for Paperclip's immutable attachment
117
+ record and otherwise stops instead of blindly creating a duplicate. Retry later.
118
+ Use `--retry-unknown-upload` only after establishing that the first upload did
119
+ not commit; this explicit override accepts the risk of creating a duplicate
120
+ file.
125
121
 
126
122
  The binding is durable Paperclip state, but it is not proof of external
127
123
  delivery—or even proof that the current run has an active external-chat origin.
@@ -147,7 +143,8 @@ When `register_deliverable` is available, use it for files in the bound local or
147
143
  remote workspace. Supply a workspace-relative `contentRef`, basename `filename`,
148
144
  `contentType`, exact `byteSize` and SHA-256, `title`, and a stable `idempotencyKey`.
149
145
  The tool verifies the file, stores an attachment and artifact work product, and
150
- binds it to the response. Generic API tools and a legacy API key are unnecessary.
146
+ binds it to the response. Do not also record the same file with
147
+ `paperclipCreateIssueWorkProduct`; the receipt already covers it.
151
148
 
152
149
  Wait for the receipt. It includes `attachmentId`, `contentPath`, and
153
150
  `downloadPath`, along with the existing command, revision, entity references,
@@ -6,9 +6,14 @@ They are company-scoped and live beside issues: issues coordinate work, while
6
6
  cases preserve the structured object an agent is producing.
7
7
 
8
8
  Cases are experimental and must be enabled with `experimental.enableCases`.
9
- If a route returns `403 Cases are disabled`, stop and report that the operator
9
+ If a case tool reports `Cases are disabled`, stop and report that the operator
10
10
  must enable cases before the skill can use this surface.
11
11
 
12
+ The case tools are in the `extended` toolset: they are available when the
13
+ operator enables `PAPERCLIP_MCP_TOOLSETS=core,extended`. When they are not
14
+ loaded, use `paperclipApiRequest` for the same operations. Every tool below
15
+ takes `companyId` only where noted; it defaults to the agent's company.
16
+
12
17
  ## Core Model
13
18
 
14
19
  A case has:
@@ -23,14 +28,12 @@ A case has:
23
28
  - documents, attachments, issue links, labels, and events
24
29
 
25
30
  Use deterministic `caseType` + `key` when a skill may be retried. Repeating
26
- `POST /api/companies/:companyId/cases` with the same `caseType` and `key`
27
- upserts the same case instead of creating a duplicate.
31
+ `paperclipCreateCase` with the same `caseType` and `key` upserts the same case
32
+ instead of creating a duplicate.
28
33
 
29
34
  ## Upsert Semantics
30
35
 
31
- `POST /api/companies/:companyId/cases` creates or upserts a case.
32
-
33
- Request:
36
+ `paperclipCreateCase` creates or upserts a case:
34
37
 
35
38
  ```json
36
39
  {
@@ -46,10 +49,9 @@ Request:
46
49
  }
47
50
  ```
48
51
 
49
- Response:
50
-
51
- - `201` when a new case was created
52
- - `200` when an existing `(caseType, key)` case was updated
52
+ The result is the case record, whether it was newly created or an existing
53
+ `(caseType, key)` case that was updated. Read `identifier` and `id` from it for
54
+ the follow-up calls.
53
55
 
54
56
  Field behavior on upsert:
55
57
 
@@ -66,36 +68,37 @@ external id, source URL hash, or parent-derived request key.
66
68
 
67
69
  ## Read And Search
68
70
 
69
- Get a case by UUID or identifier:
71
+ Get a case by UUID or identifier with `paperclipGetCase`:
70
72
 
71
- ```http
72
- GET /api/cases/PAP-C42
73
+ ```json
74
+ { "caseId": "PAP-C42" }
73
75
  ```
74
76
 
75
- List cases for a company:
77
+ List cases for a company with `paperclipListCases`:
76
78
 
77
- ```http
78
- GET /api/companies/:companyId/cases?type=blog_post&status=active&q=launch
79
+ ```json
80
+ { "type": "blog_post", "status": "active", "q": "launch" }
79
81
  ```
80
82
 
81
- Useful filters:
83
+ Useful arguments:
82
84
 
83
- - `type`: exact `caseType`
84
- - `status`: exact lifecycle status, or `active` for non-terminal cases
85
+ - `type` / `types`: exact `caseType`
86
+ - `status` / `statuses`: exact lifecycle status, or `active` for non-terminal cases
85
87
  - `projectId` / `project`: project UUID
86
88
  - `labelId` / `label`: label UUID
89
+ - `parent`: parent case filter
87
90
  - `q`: identifier, title, summary, or key search
88
91
  - `limit`: 1-200, default 100
89
92
 
90
93
  ## Documents
91
94
 
92
95
  Use case documents for rich bodies such as drafts, briefs, reports, or plans.
96
+ `paperclipSetCaseDocument` takes the case, the document `key`, and the body:
93
97
 
94
- ```http
95
- PUT /api/cases/:caseIdOrIdentifier/documents/body
96
- Content-Type: application/json
97
-
98
+ ```json
98
99
  {
100
+ "caseId": "PAP-C42",
101
+ "key": "body",
99
102
  "title": "Launch announcement body",
100
103
  "format": "markdown",
101
104
  "body": "# Launch announcement\n\nDraft copy...",
@@ -107,13 +110,16 @@ Updating an existing case document requires `baseRevisionId`:
107
110
 
108
111
  ```json
109
112
  {
113
+ "caseId": "PAP-C42",
114
+ "key": "body",
110
115
  "baseRevisionId": "latest-revision-uuid",
111
116
  "body": "Updated body"
112
117
  }
113
118
  ```
114
119
 
115
- If you get `409 stale_base_revision`, refetch the case detail, read the latest
116
- document revision id, merge intentionally, and retry with that `baseRevisionId`.
120
+ If the tool reports `stale_base_revision`, refetch the case detail, read the
121
+ latest document revision id, merge intentionally, and retry with that
122
+ `baseRevisionId`. A failed call wrote nothing — do not treat it as saved.
117
123
 
118
124
  ## Fields
119
125
 
@@ -130,13 +136,11 @@ Examples:
130
136
  }
131
137
  ```
132
138
 
133
- Patch fields or status with:
134
-
135
- ```http
136
- PATCH /api/cases/:caseIdOrIdentifier
137
- Content-Type: application/json
139
+ Patch fields or status with `paperclipUpdateCase`:
138
140
 
141
+ ```json
139
142
  {
143
+ "caseId": "PAP-C42",
140
144
  "status": "in_review",
141
145
  "fields": {
142
146
  "slug": "launch-announcement",
@@ -150,13 +154,11 @@ Remember: `fields` replaces the whole object when present.
150
154
 
151
155
  ## Issue Links
152
156
 
153
- Link cases to issues explicitly when needed:
154
-
155
- ```http
156
- POST /api/cases/:caseIdOrIdentifier/links
157
- Content-Type: application/json
157
+ Link cases to issues explicitly when needed with `paperclipCreateCaseLink`:
158
158
 
159
+ ```json
159
160
  {
161
+ "id": "PAP-C42",
160
162
  "issueId": "issue-uuid",
161
163
  "role": "reference"
162
164
  }
@@ -169,13 +171,14 @@ Roles:
169
171
  - `reference`: related issue context
170
172
 
171
173
  Agent run writes auto-link the run's issue when Paperclip can resolve it from
172
- the run JWT or `X-Paperclip-Run-Id`. Creation/upsert writes use `origin`; later
174
+ the run context the tools carry. Creation/upsert writes use `origin`; later
173
175
  document, patch, and attachment writes use `work` when no link already exists.
174
176
  You do not need to manually link the current issue before writing the case.
175
177
 
176
178
  ## Child Cases
177
179
 
178
- Create child cases by setting `parentCaseId` to the parent case UUID.
180
+ Create child cases with `paperclipCreateCase` by setting `parentCaseId` to the
181
+ parent case UUID.
179
182
 
180
183
  ```json
181
184
  {
@@ -194,16 +197,11 @@ another agent can work on a bounded part without editing the parent case body.
194
197
 
195
198
  ## Attachments
196
199
 
197
- Attach generated files with multipart form data:
198
-
199
- ```http
200
- POST /api/cases/:caseIdOrIdentifier/attachments
201
- Content-Type: multipart/form-data
202
-
203
- file=@hero.png
204
- ```
205
-
206
- The server records an asset and adds an `attachment_added` case event.
200
+ Case attachments are a multipart file upload, and multipart has no MCP tool.
201
+ Upload generated files as issue attachments with the upload helper described in
202
+ `artifacts.md`, then connect them to the case with `paperclipCreateCaseLink`
203
+ using the issue that holds the files. The case then carries the link, and the
204
+ issue carries the inspectable file.
207
205
 
208
206
  ## Lifecycle
209
207
 
@@ -221,12 +219,9 @@ Terminal statuses are `done` and `cancelled`; setting either records
221
219
 
222
220
  ## Worked Blog Post Example
223
221
 
224
- Create or upsert the parent blog post:
225
-
226
- ```http
227
- POST /api/companies/:companyId/cases
228
- Content-Type: application/json
222
+ Create or upsert the parent blog post with `paperclipCreateCase`:
229
223
 
224
+ ```json
230
225
  {
231
226
  "caseType": "blog_post",
232
227
  "key": "paperclip-cases-launch",
@@ -241,25 +236,21 @@ Content-Type: application/json
241
236
  }
242
237
  ```
243
238
 
244
- Write the body:
245
-
246
- ```http
247
- PUT /api/cases/PAP-C42/documents/body
248
- Content-Type: application/json
239
+ Write the body with `paperclipSetCaseDocument`:
249
240
 
241
+ ```json
250
242
  {
243
+ "caseId": "PAP-C42",
244
+ "key": "body",
251
245
  "title": "Introducing Paperclip Cases",
252
246
  "format": "markdown",
253
247
  "body": "# Introducing Paperclip Cases\n\n..."
254
248
  }
255
249
  ```
256
250
 
257
- Create the child image-assets case:
258
-
259
- ```http
260
- POST /api/companies/:companyId/cases
261
- Content-Type: application/json
251
+ Create the child image-assets case with `paperclipCreateCase`:
262
252
 
253
+ ```json
263
254
  {
264
255
  "caseType": "image_assets",
265
256
  "key": "paperclip-cases-launch:image-assets",
@@ -274,14 +265,12 @@ Content-Type: application/json
274
265
  }
275
266
  ```
276
267
 
277
- Attach generated assets to the child, then patch both cases as they move through
278
- review:
279
-
280
- ```http
281
- PATCH /api/cases/PAP-C42
282
- Content-Type: application/json
268
+ Attach the generated assets to the child's linked issue, then patch both cases
269
+ as they move through review with `paperclipUpdateCase`:
283
270
 
271
+ ```json
284
272
  {
273
+ "caseId": "PAP-C42",
285
274
  "status": "in_review",
286
275
  "fields": {
287
276
  "slug": "paperclip-cases-launch",