@iamlbccc/tdxd 1.1.0 → 1.2.0
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/ONBOARD-PROMPT.md +44 -0
- package/README.md +16 -5
- package/lib/tpl.mjs +14 -50
- package/lib/ui.mjs +49 -95
- package/package.json +3 -1
- package/skills/paperclip/SKILL.md +630 -0
- package/skills/paperclip/references/api-reference.md +1511 -0
- package/skills/paperclip/references/artifacts.md +98 -0
- package/skills/paperclip/references/cases.md +295 -0
- package/skills/paperclip/references/company-skills.md +266 -0
- package/skills/paperclip/references/issue-workspaces.md +80 -0
- package/skills/paperclip/references/routines.md +231 -0
- package/skills/paperclip/references/workflows.md +141 -0
- package/skills/paperclip/scripts/paperclip-upload-artifact.sh +371 -0
- package/skills/paperclip-converting-plans-to-tasks/SKILL.md +60 -0
- package/tdxd-ctl.mjs +360 -71
- package/tdxd.mjs +3 -3
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
# Generated Artifacts and Work Products
|
|
2
|
+
|
|
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
|
+
|
|
5
|
+
Use the helper bundled with this skill. From an installed `paperclip` skill directory, the helper lives at `scripts/paperclip-upload-artifact.sh`:
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
scripts/paperclip-upload-artifact.sh path/to/output.webm \
|
|
9
|
+
--title "Walkthrough render" \
|
|
10
|
+
--summary "Rendered walkthrough for review"
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
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
|
+
|
|
15
|
+
## Workspace-Only File References
|
|
16
|
+
|
|
17
|
+
Use a workspace-only reference only when the file should stay in the project or
|
|
18
|
+
execution workspace, such as a source file, committed report, generated index,
|
|
19
|
+
or other file whose value is tied to the checkout. This is not a substitute for
|
|
20
|
+
uploading a deliverable file that a board user should be able to inspect outside
|
|
21
|
+
the workspace.
|
|
22
|
+
|
|
23
|
+
Annotate the work product with `metadata.resourceRef`:
|
|
24
|
+
|
|
25
|
+
```json
|
|
26
|
+
{
|
|
27
|
+
"type": "document",
|
|
28
|
+
"provider": "workspace",
|
|
29
|
+
"title": "Regression test plan",
|
|
30
|
+
"status": "ready_for_review",
|
|
31
|
+
"reviewState": "needs_board_review",
|
|
32
|
+
"summary": "Markdown plan committed in the execution workspace.",
|
|
33
|
+
"metadata": {
|
|
34
|
+
"resourceRef": {
|
|
35
|
+
"kind": "workspace_file",
|
|
36
|
+
"issueId": "<issue-id>",
|
|
37
|
+
"workspaceKind": "execution_workspace",
|
|
38
|
+
"workspaceId": "<execution-workspace-id>",
|
|
39
|
+
"relativePath": "doc/plans/regression-test-plan.md",
|
|
40
|
+
"line": 1,
|
|
41
|
+
"displayPath": "doc/plans/regression-test-plan.md"
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
`workspaceKind` is `execution_workspace` for the current issue checkout or
|
|
48
|
+
`project_workspace` for a shared project workspace. `line` and `column` are
|
|
49
|
+
optional positive integers. `relativePath` must be relative to the selected
|
|
50
|
+
workspace root; do not use host-local absolute paths in `resourceRef`.
|
|
51
|
+
|
|
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
|
+
In your final issue comment, link the uploaded attachment or work product and
|
|
93
|
+
describe what it contains. If the output is workspace-only, name the work
|
|
94
|
+
product and the relative path that was recorded in `metadata.resourceRef`.
|
|
95
|
+
Browse/search is the fallback for recovering a workspace file when the issue
|
|
96
|
+
chip or link cannot open it; it is not the preferred deliverable path. Do not
|
|
97
|
+
leave artifact-producing work `in_progress` with only a local path or a
|
|
98
|
+
`Remaining` note.
|
|
@@ -0,0 +1,295 @@
|
|
|
1
|
+
# Cases
|
|
2
|
+
|
|
3
|
+
Cases are agent-owned work records for durable outputs such as blog posts,
|
|
4
|
+
research packets, release notes, incidents, QA runs, or generated asset sets.
|
|
5
|
+
They are company-scoped and live beside issues: issues coordinate work, while
|
|
6
|
+
cases preserve the structured object an agent is producing.
|
|
7
|
+
|
|
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
|
|
10
|
+
must enable cases before the skill can use this surface.
|
|
11
|
+
|
|
12
|
+
## Core Model
|
|
13
|
+
|
|
14
|
+
A case has:
|
|
15
|
+
|
|
16
|
+
- `identifier`: server-assigned display id such as `PAP-C42`
|
|
17
|
+
- `caseType`: skill-owned type such as `blog_post`, `image_assets`, or `incident`
|
|
18
|
+
- `key`: optional deterministic upsert key inside `(companyId, caseType)`
|
|
19
|
+
- `title` and optional `summary`
|
|
20
|
+
- `status`: `draft`, `in_progress`, `in_review`, `approved`, `done`, or `cancelled`
|
|
21
|
+
- `fields`: JSON object owned by the skill using the case
|
|
22
|
+
- `parentCaseId`: optional parent case for child work
|
|
23
|
+
- documents, attachments, issue links, labels, and events
|
|
24
|
+
|
|
25
|
+
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.
|
|
28
|
+
|
|
29
|
+
## Upsert Semantics
|
|
30
|
+
|
|
31
|
+
`POST /api/companies/:companyId/cases` creates or upserts a case.
|
|
32
|
+
|
|
33
|
+
Request:
|
|
34
|
+
|
|
35
|
+
```json
|
|
36
|
+
{
|
|
37
|
+
"caseType": "blog_post",
|
|
38
|
+
"key": "launch-announcement",
|
|
39
|
+
"title": "Launch announcement",
|
|
40
|
+
"summary": "Draft launch post for operators.",
|
|
41
|
+
"status": "draft",
|
|
42
|
+
"fields": {
|
|
43
|
+
"slug": "launch-announcement",
|
|
44
|
+
"target_audience": "operators"
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
Response:
|
|
50
|
+
|
|
51
|
+
- `201` when a new case was created
|
|
52
|
+
- `200` when an existing `(caseType, key)` case was updated
|
|
53
|
+
|
|
54
|
+
Field behavior on upsert:
|
|
55
|
+
|
|
56
|
+
- `title` is required and replaces the previous title.
|
|
57
|
+
- `projectId`, `summary`, `status`, `fields`, and `parentCaseId` replace the
|
|
58
|
+
previous value when present.
|
|
59
|
+
- Omitted optional values preserve the previous value during upsert.
|
|
60
|
+
- `fields` is replaced as a whole object when provided. It is not deep-merged.
|
|
61
|
+
Send the complete desired JSON object each time.
|
|
62
|
+
- Concurrent retries with the same `(caseType, key)` converge to one case.
|
|
63
|
+
|
|
64
|
+
Do not use a random `key` for retryable skills. Use a stable content slug,
|
|
65
|
+
external id, source URL hash, or parent-derived request key.
|
|
66
|
+
|
|
67
|
+
## Read And Search
|
|
68
|
+
|
|
69
|
+
Get a case by UUID or identifier:
|
|
70
|
+
|
|
71
|
+
```http
|
|
72
|
+
GET /api/cases/PAP-C42
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
List cases for a company:
|
|
76
|
+
|
|
77
|
+
```http
|
|
78
|
+
GET /api/companies/:companyId/cases?type=blog_post&status=active&q=launch
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
Useful filters:
|
|
82
|
+
|
|
83
|
+
- `type`: exact `caseType`
|
|
84
|
+
- `status`: exact lifecycle status, or `active` for non-terminal cases
|
|
85
|
+
- `projectId` / `project`: project UUID
|
|
86
|
+
- `labelId` / `label`: label UUID
|
|
87
|
+
- `q`: identifier, title, summary, or key search
|
|
88
|
+
- `limit`: 1-200, default 100
|
|
89
|
+
|
|
90
|
+
## Documents
|
|
91
|
+
|
|
92
|
+
Use case documents for rich bodies such as drafts, briefs, reports, or plans.
|
|
93
|
+
|
|
94
|
+
```http
|
|
95
|
+
PUT /api/cases/:caseIdOrIdentifier/documents/body
|
|
96
|
+
Content-Type: application/json
|
|
97
|
+
|
|
98
|
+
{
|
|
99
|
+
"title": "Launch announcement body",
|
|
100
|
+
"format": "markdown",
|
|
101
|
+
"body": "# Launch announcement\n\nDraft copy...",
|
|
102
|
+
"changeSummary": "Initial draft"
|
|
103
|
+
}
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
Updating an existing case document requires `baseRevisionId`:
|
|
107
|
+
|
|
108
|
+
```json
|
|
109
|
+
{
|
|
110
|
+
"baseRevisionId": "latest-revision-uuid",
|
|
111
|
+
"body": "Updated body"
|
|
112
|
+
}
|
|
113
|
+
```
|
|
114
|
+
|
|
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`.
|
|
117
|
+
|
|
118
|
+
## Fields
|
|
119
|
+
|
|
120
|
+
Each skill owns the schema of `fields` for the `caseType` it creates. Keep fields
|
|
121
|
+
small, typed, and stable enough for other agents to inspect.
|
|
122
|
+
|
|
123
|
+
Examples:
|
|
124
|
+
|
|
125
|
+
```json
|
|
126
|
+
{
|
|
127
|
+
"slug": "launch-announcement",
|
|
128
|
+
"target_audience": "operators",
|
|
129
|
+
"publish_url": "https://example.com/blog/launch-announcement"
|
|
130
|
+
}
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
Patch fields or status with:
|
|
134
|
+
|
|
135
|
+
```http
|
|
136
|
+
PATCH /api/cases/:caseIdOrIdentifier
|
|
137
|
+
Content-Type: application/json
|
|
138
|
+
|
|
139
|
+
{
|
|
140
|
+
"status": "in_review",
|
|
141
|
+
"fields": {
|
|
142
|
+
"slug": "launch-announcement",
|
|
143
|
+
"target_audience": "operators",
|
|
144
|
+
"publish_url": "https://example.com/blog/launch-announcement"
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
Remember: `fields` replaces the whole object when present.
|
|
150
|
+
|
|
151
|
+
## Issue Links
|
|
152
|
+
|
|
153
|
+
Link cases to issues explicitly when needed:
|
|
154
|
+
|
|
155
|
+
```http
|
|
156
|
+
POST /api/cases/:caseIdOrIdentifier/links
|
|
157
|
+
Content-Type: application/json
|
|
158
|
+
|
|
159
|
+
{
|
|
160
|
+
"issueId": "issue-uuid",
|
|
161
|
+
"role": "reference"
|
|
162
|
+
}
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
Roles:
|
|
166
|
+
|
|
167
|
+
- `origin`: the issue/run that created the case
|
|
168
|
+
- `work`: an issue/run that changed the case
|
|
169
|
+
- `reference`: related issue context
|
|
170
|
+
|
|
171
|
+
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
|
|
173
|
+
document, patch, and attachment writes use `work` when no link already exists.
|
|
174
|
+
You do not need to manually link the current issue before writing the case.
|
|
175
|
+
|
|
176
|
+
## Child Cases
|
|
177
|
+
|
|
178
|
+
Create child cases by setting `parentCaseId` to the parent case UUID.
|
|
179
|
+
|
|
180
|
+
```json
|
|
181
|
+
{
|
|
182
|
+
"caseType": "image_assets",
|
|
183
|
+
"key": "launch-announcement:hero-images",
|
|
184
|
+
"title": "Hero images for launch announcement",
|
|
185
|
+
"parentCaseId": "parent-case-uuid",
|
|
186
|
+
"fields": {
|
|
187
|
+
"required_assets": ["hero", "social-card"]
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
Use child cases when the output has independently inspectable pieces or when
|
|
193
|
+
another agent can work on a bounded part without editing the parent case body.
|
|
194
|
+
|
|
195
|
+
## Attachments
|
|
196
|
+
|
|
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.
|
|
207
|
+
|
|
208
|
+
## Lifecycle
|
|
209
|
+
|
|
210
|
+
Use the lifecycle consistently:
|
|
211
|
+
|
|
212
|
+
- `draft`: case exists but useful work has not started
|
|
213
|
+
- `in_progress`: an agent is actively producing or revising it
|
|
214
|
+
- `in_review`: ready for reviewer, board, or downstream approval
|
|
215
|
+
- `approved`: accepted but not finally shipped or archived
|
|
216
|
+
- `done`: complete and no further action remains
|
|
217
|
+
- `cancelled`: intentionally abandoned
|
|
218
|
+
|
|
219
|
+
Terminal statuses are `done` and `cancelled`; setting either records
|
|
220
|
+
`completedAt`. Moving back to a non-terminal status clears `completedAt`.
|
|
221
|
+
|
|
222
|
+
## Worked Blog Post Example
|
|
223
|
+
|
|
224
|
+
Create or upsert the parent blog post:
|
|
225
|
+
|
|
226
|
+
```http
|
|
227
|
+
POST /api/companies/:companyId/cases
|
|
228
|
+
Content-Type: application/json
|
|
229
|
+
|
|
230
|
+
{
|
|
231
|
+
"caseType": "blog_post",
|
|
232
|
+
"key": "paperclip-cases-launch",
|
|
233
|
+
"title": "Introducing Paperclip Cases",
|
|
234
|
+
"summary": "Blog post explaining the cases surface for agent outputs.",
|
|
235
|
+
"status": "in_progress",
|
|
236
|
+
"fields": {
|
|
237
|
+
"slug": "paperclip-cases-launch",
|
|
238
|
+
"target_audience": "AI company operators",
|
|
239
|
+
"publish_url": null
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
Write the body:
|
|
245
|
+
|
|
246
|
+
```http
|
|
247
|
+
PUT /api/cases/PAP-C42/documents/body
|
|
248
|
+
Content-Type: application/json
|
|
249
|
+
|
|
250
|
+
{
|
|
251
|
+
"title": "Introducing Paperclip Cases",
|
|
252
|
+
"format": "markdown",
|
|
253
|
+
"body": "# Introducing Paperclip Cases\n\n..."
|
|
254
|
+
}
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
Create the child image-assets case:
|
|
258
|
+
|
|
259
|
+
```http
|
|
260
|
+
POST /api/companies/:companyId/cases
|
|
261
|
+
Content-Type: application/json
|
|
262
|
+
|
|
263
|
+
{
|
|
264
|
+
"caseType": "image_assets",
|
|
265
|
+
"key": "paperclip-cases-launch:image-assets",
|
|
266
|
+
"title": "Image assets for Introducing Paperclip Cases",
|
|
267
|
+
"parentCaseId": "parent-case-uuid",
|
|
268
|
+
"status": "in_progress",
|
|
269
|
+
"fields": {
|
|
270
|
+
"slug": "paperclip-cases-launch",
|
|
271
|
+
"required_assets": ["hero", "social-card"],
|
|
272
|
+
"publish_url": null
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
```
|
|
276
|
+
|
|
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
|
|
283
|
+
|
|
284
|
+
{
|
|
285
|
+
"status": "in_review",
|
|
286
|
+
"fields": {
|
|
287
|
+
"slug": "paperclip-cases-launch",
|
|
288
|
+
"target_audience": "AI company operators",
|
|
289
|
+
"publish_url": "https://example.com/blog/paperclip-cases-launch"
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
```
|
|
293
|
+
|
|
294
|
+
If the same skill retries the example with the same keys, it updates the parent
|
|
295
|
+
and child cases rather than creating duplicates.
|
|
@@ -0,0 +1,266 @@
|
|
|
1
|
+
# Company Skills Workflow
|
|
2
|
+
|
|
3
|
+
Use this reference when a board user, CEO, or manager asks you to find a skill, install it into the company library, or assign it to an agent.
|
|
4
|
+
|
|
5
|
+
## What Exists
|
|
6
|
+
|
|
7
|
+
- App-shipped catalog: a curated set of company skills in `@paperclipai/skills-catalog`, browseable and installable without leaving Paperclip.
|
|
8
|
+
- Company skill library: install, inspect, update, audit, reset, and read company skills for the whole company.
|
|
9
|
+
- Agent skill assignment: add or remove company skills on an existing agent.
|
|
10
|
+
- Hire/create composition: pass `desiredSkills` when creating or hiring an agent so the same assignment model applies immediately.
|
|
11
|
+
|
|
12
|
+
The canonical model is:
|
|
13
|
+
|
|
14
|
+
1. add the skill to the company library — either from the app catalog (`skills install`), an external source (`skills import`), or a managed local skill (`skills create`/`skills scan-projects`)
|
|
15
|
+
2. attach the company skill to the agent (`skills agent sync`)
|
|
16
|
+
3. optionally do step 2 during hire/create with `desiredSkills`
|
|
17
|
+
|
|
18
|
+
Catalog install ≠ agent attach. Installing a catalog skill only adds the row to
|
|
19
|
+
`company_skills`. The agent will not use it until you sync the agent's desired
|
|
20
|
+
set.
|
|
21
|
+
|
|
22
|
+
## Permission Model
|
|
23
|
+
|
|
24
|
+
- Company skill reads: any same-company actor
|
|
25
|
+
- Company skill mutations: open to same-company actors by default. Missing `skills:create` grants and `canCreateSkills` settings do not deny ordinary skill work; only an explicit company skill policy restriction does. Core safety and company-boundary checks always remain enforced.
|
|
26
|
+
- Agent skill assignment: same permission model as updating that agent
|
|
27
|
+
- Team installs continue to require `agents:create` because they import or create agents in addition to attaching skills.
|
|
28
|
+
|
|
29
|
+
## Core Endpoints
|
|
30
|
+
|
|
31
|
+
App-shipped catalog (read-only browse + company install):
|
|
32
|
+
|
|
33
|
+
- `GET /api/skills/catalog`
|
|
34
|
+
- `GET /api/skills/catalog/:catalogId`
|
|
35
|
+
- `GET /api/skills/catalog/ref?ref=<id|key|slug>`
|
|
36
|
+
- `GET /api/skills/catalog/:catalogId/files?path=SKILL.md`
|
|
37
|
+
- `POST /api/companies/:companyId/skills/install-catalog`
|
|
38
|
+
|
|
39
|
+
Company library:
|
|
40
|
+
|
|
41
|
+
- `GET /api/companies/:companyId/skills`
|
|
42
|
+
- `GET /api/companies/:companyId/skills/:skillId`
|
|
43
|
+
- `GET /api/companies/:companyId/skills/:skillId/files?path=SKILL.md`
|
|
44
|
+
- `POST /api/companies/:companyId/skills` (managed local create)
|
|
45
|
+
- `POST /api/companies/:companyId/skills/import`
|
|
46
|
+
- `POST /api/companies/:companyId/skills/scan-projects`
|
|
47
|
+
- `GET /api/companies/:companyId/skills/:skillId/update-status`
|
|
48
|
+
- `POST /api/companies/:companyId/skills/:skillId/install-update`
|
|
49
|
+
- `POST /api/companies/:companyId/skills/:skillId/audit`
|
|
50
|
+
- `POST /api/companies/:companyId/skills/:skillId/reset`
|
|
51
|
+
- `DELETE /api/companies/:companyId/skills/:skillId`
|
|
52
|
+
|
|
53
|
+
Agent attach and hire/create composition:
|
|
54
|
+
|
|
55
|
+
- `GET /api/agents/:agentId/skills`
|
|
56
|
+
- `POST /api/agents/:agentId/skills/sync`
|
|
57
|
+
- `POST /api/companies/:companyId/agent-hires`
|
|
58
|
+
- `POST /api/companies/:companyId/agents`
|
|
59
|
+
|
|
60
|
+
If a board user, CEO, or manager is driving locally, prefer the
|
|
61
|
+
`paperclipai skills` CLI documented in `doc/CLI.md` — it wraps every endpoint
|
|
62
|
+
above, accepts company skill or catalog refs by `id`/`key`/`slug`, and prints
|
|
63
|
+
the same JSON these endpoints return when called with `--json`.
|
|
64
|
+
|
|
65
|
+
## Install A Skill Into The Company
|
|
66
|
+
|
|
67
|
+
Two paths cover the common cases:
|
|
68
|
+
|
|
69
|
+
1. **App-shipped catalog** (preferred when the right skill exists in the
|
|
70
|
+
bundled/optional catalog) — browse it first, then install with the catalog
|
|
71
|
+
install endpoint. No external network fetch happens.
|
|
72
|
+
2. **External source** (skills.sh, GitHub, local path, or URL) — use the
|
|
73
|
+
import endpoint below.
|
|
74
|
+
|
|
75
|
+
### App-shipped catalog
|
|
76
|
+
|
|
77
|
+
Browse, inspect, and install catalog skills before reaching for an external
|
|
78
|
+
source. Bundled skills are the curated defaults for any company; optional
|
|
79
|
+
skills are role- or domain-specific.
|
|
80
|
+
|
|
81
|
+
```sh
|
|
82
|
+
curl -sS "$PAPERCLIP_API_URL/api/skills/catalog?kind=bundled" \
|
|
83
|
+
-H "Authorization: Bearer $PAPERCLIP_API_KEY"
|
|
84
|
+
|
|
85
|
+
curl -sS "$PAPERCLIP_API_URL/api/skills/catalog/ref?ref=github-pr-workflow" \
|
|
86
|
+
-H "Authorization: Bearer $PAPERCLIP_API_KEY"
|
|
87
|
+
|
|
88
|
+
curl -sS -X POST "$PAPERCLIP_API_URL/api/companies/$PAPERCLIP_COMPANY_ID/skills/install-catalog" \
|
|
89
|
+
-H "Authorization: Bearer $PAPERCLIP_API_KEY" \
|
|
90
|
+
-H "Content-Type: application/json" \
|
|
91
|
+
-d '{
|
|
92
|
+
"catalogSkillId": "paperclipai:bundled:software-development:github-pr-workflow"
|
|
93
|
+
}'
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
The install response records provenance (`catalogId`, `catalogKey`,
|
|
97
|
+
`packageVersion`, `originHash`) on the company skill so update/audit/reset
|
|
98
|
+
flows know the pinned origin. `force: true` may replace a same-key
|
|
99
|
+
catalog-managed skill but never bypasses hard-stop audit findings.
|
|
100
|
+
|
|
101
|
+
### External source import
|
|
102
|
+
|
|
103
|
+
Import using a **skills.sh URL**, a key-style source string, a GitHub URL, or a local path.
|
|
104
|
+
|
|
105
|
+
### Source types (in order of preference)
|
|
106
|
+
|
|
107
|
+
| Source format | Example | When to use |
|
|
108
|
+
|---|---|---|
|
|
109
|
+
| **skills.sh URL** | `https://skills.sh/google-labs-code/stitch-skills/design-md` | When a user gives you a `skills.sh` link. This is the managed skill registry — **always prefer it when available**. |
|
|
110
|
+
| **Key-style string** | `google-labs-code/stitch-skills/design-md` | Shorthand for the same skill — `org/repo/skill-name` format. Equivalent to the skills.sh URL. |
|
|
111
|
+
| **GitHub URL** | `https://github.com/vercel-labs/agent-browser` | When the skill is in a GitHub repo but not on skills.sh. |
|
|
112
|
+
| **Local path** | `/abs/path/to/skill-dir` | When the skill is on disk (dev/testing only). |
|
|
113
|
+
|
|
114
|
+
**Critical:** If a user gives you a `https://skills.sh/...` URL, use that URL or its key-style equivalent (`org/repo/skill-name`) as the `source`. Do **not** convert it to a GitHub URL — skills.sh is the managed registry and the source of truth for versioning, discovery, and updates.
|
|
115
|
+
|
|
116
|
+
### Example: skills.sh import (preferred)
|
|
117
|
+
|
|
118
|
+
```sh
|
|
119
|
+
curl -sS -X POST "$PAPERCLIP_API_URL/api/companies/$PAPERCLIP_COMPANY_ID/skills/import" \
|
|
120
|
+
-H "Authorization: Bearer $PAPERCLIP_API_KEY" \
|
|
121
|
+
-H "Content-Type: application/json" \
|
|
122
|
+
-d '{
|
|
123
|
+
"source": "https://skills.sh/google-labs-code/stitch-skills/design-md"
|
|
124
|
+
}'
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
Or equivalently using the key-style string:
|
|
128
|
+
|
|
129
|
+
```sh
|
|
130
|
+
curl -sS -X POST "$PAPERCLIP_API_URL/api/companies/$PAPERCLIP_COMPANY_ID/skills/import" \
|
|
131
|
+
-H "Authorization: Bearer $PAPERCLIP_API_KEY" \
|
|
132
|
+
-H "Content-Type: application/json" \
|
|
133
|
+
-d '{
|
|
134
|
+
"source": "google-labs-code/stitch-skills/design-md"
|
|
135
|
+
}'
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
### Example: GitHub import
|
|
139
|
+
|
|
140
|
+
```sh
|
|
141
|
+
curl -sS -X POST "$PAPERCLIP_API_URL/api/companies/$PAPERCLIP_COMPANY_ID/skills/import" \
|
|
142
|
+
-H "Authorization: Bearer $PAPERCLIP_API_KEY" \
|
|
143
|
+
-H "Content-Type: application/json" \
|
|
144
|
+
-d '{
|
|
145
|
+
"source": "https://github.com/vercel-labs/agent-browser"
|
|
146
|
+
}'
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
You can also use source strings such as:
|
|
150
|
+
|
|
151
|
+
- `google-labs-code/stitch-skills/design-md`
|
|
152
|
+
- `vercel-labs/agent-browser/agent-browser`
|
|
153
|
+
- `npx skills add https://github.com/vercel-labs/agent-browser --skill agent-browser`
|
|
154
|
+
|
|
155
|
+
If the task is to discover skills from the company project workspaces first:
|
|
156
|
+
|
|
157
|
+
```sh
|
|
158
|
+
curl -sS -X POST "$PAPERCLIP_API_URL/api/companies/$PAPERCLIP_COMPANY_ID/skills/scan-projects" \
|
|
159
|
+
-H "Authorization: Bearer $PAPERCLIP_API_KEY" \
|
|
160
|
+
-H "Content-Type: application/json" \
|
|
161
|
+
-d '{}'
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
## Inspect What Was Installed
|
|
165
|
+
|
|
166
|
+
```sh
|
|
167
|
+
curl -sS "$PAPERCLIP_API_URL/api/companies/$PAPERCLIP_COMPANY_ID/skills" \
|
|
168
|
+
-H "Authorization: Bearer $PAPERCLIP_API_KEY"
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
Read the skill entry and its `SKILL.md`:
|
|
172
|
+
|
|
173
|
+
```sh
|
|
174
|
+
curl -sS "$PAPERCLIP_API_URL/api/companies/$PAPERCLIP_COMPANY_ID/skills/<skill-id>" \
|
|
175
|
+
-H "Authorization: Bearer $PAPERCLIP_API_KEY"
|
|
176
|
+
|
|
177
|
+
curl -sS "$PAPERCLIP_API_URL/api/companies/$PAPERCLIP_COMPANY_ID/skills/<skill-id>/files?path=SKILL.md" \
|
|
178
|
+
-H "Authorization: Bearer $PAPERCLIP_API_KEY"
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
## Assign Skills To An Existing Agent
|
|
182
|
+
|
|
183
|
+
`desiredSkills` accepts:
|
|
184
|
+
|
|
185
|
+
- exact company skill key
|
|
186
|
+
- exact company skill id
|
|
187
|
+
- exact slug when it is unique in the company
|
|
188
|
+
|
|
189
|
+
The server persists canonical company skill keys.
|
|
190
|
+
|
|
191
|
+
The request must include a merge mode:
|
|
192
|
+
|
|
193
|
+
- `add` adds the named skills and keeps every other assignment.
|
|
194
|
+
- `remove` removes only the named skills.
|
|
195
|
+
- `replace` overwrites the complete desired skill set. Use it only after explicit confirmation.
|
|
196
|
+
|
|
197
|
+
```sh
|
|
198
|
+
curl -sS -X POST "$PAPERCLIP_API_URL/api/agents/<agent-id>/skills/sync" \
|
|
199
|
+
-H "Authorization: Bearer $PAPERCLIP_API_KEY" \
|
|
200
|
+
-H "Content-Type: application/json" \
|
|
201
|
+
-d '{
|
|
202
|
+
"mode": "add",
|
|
203
|
+
"desiredSkills": [
|
|
204
|
+
"vercel-labs/agent-browser/agent-browser"
|
|
205
|
+
]
|
|
206
|
+
}'
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
If you need the current state first:
|
|
210
|
+
|
|
211
|
+
```sh
|
|
212
|
+
curl -sS "$PAPERCLIP_API_URL/api/agents/<agent-id>/skills" \
|
|
213
|
+
-H "Authorization: Bearer $PAPERCLIP_API_KEY"
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
## Include Skills During Hire Or Create
|
|
217
|
+
|
|
218
|
+
Use the same company skill keys or references in `desiredSkills` when hiring or creating an agent:
|
|
219
|
+
|
|
220
|
+
```sh
|
|
221
|
+
curl -sS -X POST "$PAPERCLIP_API_URL/api/companies/$PAPERCLIP_COMPANY_ID/agent-hires" \
|
|
222
|
+
-H "Authorization: Bearer $PAPERCLIP_API_KEY" \
|
|
223
|
+
-H "Content-Type: application/json" \
|
|
224
|
+
-d '{
|
|
225
|
+
"name": "QA Browser Agent",
|
|
226
|
+
"role": "qa",
|
|
227
|
+
"adapterType": "codex_local",
|
|
228
|
+
"adapterConfig": {
|
|
229
|
+
"cwd": "/abs/path/to/repo"
|
|
230
|
+
},
|
|
231
|
+
"desiredSkills": [
|
|
232
|
+
"agent-browser"
|
|
233
|
+
]
|
|
234
|
+
}'
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
For direct create without approval:
|
|
238
|
+
|
|
239
|
+
```sh
|
|
240
|
+
curl -sS -X POST "$PAPERCLIP_API_URL/api/companies/$PAPERCLIP_COMPANY_ID/agents" \
|
|
241
|
+
-H "Authorization: Bearer $PAPERCLIP_API_KEY" \
|
|
242
|
+
-H "Content-Type: application/json" \
|
|
243
|
+
-d '{
|
|
244
|
+
"name": "QA Browser Agent",
|
|
245
|
+
"role": "qa",
|
|
246
|
+
"adapterType": "codex_local",
|
|
247
|
+
"adapterConfig": {
|
|
248
|
+
"cwd": "/abs/path/to/repo"
|
|
249
|
+
},
|
|
250
|
+
"desiredSkills": [
|
|
251
|
+
"agent-browser"
|
|
252
|
+
]
|
|
253
|
+
}'
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
## Notes
|
|
257
|
+
|
|
258
|
+
- Built-in Paperclip runtime skills are still added automatically when required by the adapter.
|
|
259
|
+
- If a reference is missing or ambiguous, the API returns `422`.
|
|
260
|
+
- Prefer linking back to the relevant issue, approval, and agent when you comment about skill changes.
|
|
261
|
+
- Use company portability routes when you need whole-package import/export, not just a skill:
|
|
262
|
+
- `POST /api/companies/:companyId/imports/preview`
|
|
263
|
+
- `POST /api/companies/:companyId/imports/apply`
|
|
264
|
+
- `POST /api/companies/:companyId/exports/preview`
|
|
265
|
+
- `POST /api/companies/:companyId/exports`
|
|
266
|
+
- Use skill-only import when the task is specifically to add a skill to the company library without importing the surrounding company/team/package structure.
|