@prismer/runtime 2.0.8 → 2.2.55
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/CHANGELOG.md +3430 -0
- package/README.md +34 -12
- package/apc/skills/FIELD-DICTIONARY.md +111 -0
- package/apc/skills/bug-reproduce/SKILL.md +150 -0
- package/apc/skills/bug-reproduce/skill.json +96 -0
- package/apc/skills/code-review/SKILL.md +198 -0
- package/apc/skills/code-review/skill.json +124 -0
- package/apc/skills/design-review/SKILL.md +122 -0
- package/apc/skills/design-review/skill.json +88 -0
- package/apc/skills/doc-sync/SKILL.md +168 -0
- package/apc/skills/doc-sync/skill.json +81 -0
- package/apc/skills/env-doctor/SKILL.md +194 -0
- package/apc/skills/env-doctor/skill.json +209 -0
- package/apc/skills/git-ops/SKILL.md +189 -0
- package/apc/skills/git-ops/skill.json +94 -0
- package/apc/skills/impact-trace/SKILL.md +168 -0
- package/apc/skills/impact-trace/skill.json +104 -0
- package/apc/skills/observability/SKILL.md +195 -0
- package/apc/skills/observability/skill.json +116 -0
- package/apc/skills/release-db-config-sync/SKILL.md +186 -0
- package/apc/skills/release-db-config-sync/skill.json +109 -0
- package/apc/skills/release-ota-promote/SKILL.md +195 -0
- package/apc/skills/release-ota-promote/skill.json +176 -0
- package/apc/skills/release-preflight/SKILL.md +174 -0
- package/apc/skills/release-preflight/skill.json +175 -0
- package/apc/skills/release-rollback/SKILL.md +214 -0
- package/apc/skills/release-rollback/skill.json +230 -0
- package/apc/skills/release-tag/SKILL.md +194 -0
- package/apc/skills/release-tag/skill.json +94 -0
- package/apc/skills/releasing-prod/SKILL.md +49 -0
- package/apc/skills/releasing-test/SKILL.md +135 -0
- package/apc/skills/sdk-release/SKILL.md +200 -0
- package/apc/skills/spec-intake/SKILL.md +169 -0
- package/apc/skills/spec-intake/skill.json +93 -0
- package/apc/skills/test-result-feedback/SKILL.md +239 -0
- package/apc/skills/test-result-feedback/skill.json +193 -0
- package/apc/skills/test-runner/SKILL.md +169 -0
- package/apc/skills/test-runner/skill.json +103 -0
- package/apc/skills/ui-align/SKILL.md +209 -0
- package/apc/skills/ui-align/skill.json +114 -0
- package/apc/skills/ui-canvas/SKILL.md +148 -0
- package/apc/skills/ui-canvas/skill.json +127 -0
- package/built-in-skills/agent-coordination/SKILL.md +59 -37
- package/built-in-skills/agent-meta/SKILL.md +1 -0
- package/built-in-skills/assets/SKILL.md +8 -6
- package/built-in-skills/browser-use/SKILL.md +93 -0
- package/built-in-skills/canvas-design/SKILL.md +1 -0
- package/built-in-skills/claim-agent-ownership/SKILL.md +3 -2
- package/built-in-skills/claude-api/SKILL.md +1 -0
- package/built-in-skills/codebase-design/DEEPENING.md +37 -0
- package/built-in-skills/codebase-design/DESIGN-IT-TWICE.md +44 -0
- package/built-in-skills/codebase-design/LICENSE +21 -0
- package/built-in-skills/codebase-design/SKILL.md +116 -0
- package/built-in-skills/conversation-compaction/SKILL.md +114 -0
- package/built-in-skills/council-creator/SKILL.md +426 -0
- package/built-in-skills/diagnosing-bugs/LICENSE +21 -0
- package/built-in-skills/diagnosing-bugs/SKILL.md +136 -0
- package/built-in-skills/diagnosing-bugs/scripts/hitl-loop.template.sh +41 -0
- package/built-in-skills/doc-coauthoring/SKILL.md +1 -0
- package/built-in-skills/document-generation/SKILL.md +105 -0
- package/built-in-skills/domain-modeling/ADR-FORMAT.md +47 -0
- package/built-in-skills/domain-modeling/CONTEXT-FORMAT.md +60 -0
- package/built-in-skills/domain-modeling/LICENSE +21 -0
- package/built-in-skills/domain-modeling/SKILL.md +76 -0
- package/built-in-skills/frontend-design/SKILL.md +1 -0
- package/built-in-skills/human-approval/SKILL.md +17 -2
- package/built-in-skills/image-generate/SKILL.md +103 -302
- package/built-in-skills/image-generate/scripts/generate-and-deliver.mjs +289 -0
- package/built-in-skills/ingest/SKILL.md +13 -45
- package/built-in-skills/internal-comms/SKILL.md +1 -0
- package/built-in-skills/liteparse/SKILL.md +130 -110
- package/built-in-skills/mcp-builder/SKILL.md +1 -0
- package/built-in-skills/memory/SKILL.md +420 -55
- package/built-in-skills/memory-dream/SKILL.md +339 -0
- package/built-in-skills/office-artifacts/SKILL.md +17 -4
- package/built-in-skills/okr/SKILL.md +154 -0
- package/built-in-skills/persona/SKILL.md +81 -0
- package/built-in-skills/persona-generator/SKILL.md +296 -0
- package/built-in-skills/pkf-svg/SKILL.md +253 -0
- package/built-in-skills/pkf-writing/SKILL.md +236 -0
- package/built-in-skills/prismer-im-collab/SKILL.md +26 -6
- package/built-in-skills/proactivity/SKILL.md +84 -0
- package/built-in-skills/remotion/SKILL.md +431 -0
- package/built-in-skills/role-builder/SKILL.md +203 -0
- package/built-in-skills/role-builder/scripts/author-role.mjs +334 -0
- package/built-in-skills/role-builder/scripts/ingest-role.mjs +223 -0
- package/built-in-skills/role-builder/scripts/instantiate-and-run.mjs +290 -0
- package/built-in-skills/role-builder/scripts/operation-harness.mjs +267 -0
- package/built-in-skills/skill-authoring/SKILL.md +110 -100
- package/built-in-skills/skill-authoring/skill.json +3 -3
- package/built-in-skills/skill-builder/SKILL.md +171 -0
- package/built-in-skills/skill-builder/scripts/ingest.mjs +265 -0
- package/built-in-skills/skill-creator/SKILL.md +165 -423
- package/built-in-skills/skill-creator/references/external-library-import.md +110 -0
- package/built-in-skills/skill-creator/scripts/import-library.mjs +475 -0
- package/built-in-skills/slack-gif-creator/SKILL.md +20 -0
- package/built-in-skills/tasks/SKILL.md +38 -23
- package/built-in-skills/tdd/LICENSE +21 -0
- package/built-in-skills/tdd/SKILL.md +110 -0
- package/built-in-skills/tdd/mocking.md +59 -0
- package/built-in-skills/tdd/refactoring.md +10 -0
- package/built-in-skills/tdd/tests.md +61 -0
- package/built-in-skills/team/SKILL.md +2 -1
- package/built-in-skills/web-artifacts-builder/SKILL.md +1 -0
- package/built-in-skills/webapp-testing/SKILL.md +1 -0
- package/built-in-skills/wechat-pay/SKILL.md +59 -0
- package/dist/cli.cjs +71872 -19960
- package/dist/cli.js +71803 -19846
- package/dist/index.cjs +72010 -19966
- package/dist/index.d.cts +4258 -712
- package/dist/index.d.ts +4258 -712
- package/dist/index.js +72156 -20118
- package/package.json +37 -6
- package/plugins/memory/prismer/__init__.py +1211 -0
- package/plugins/memory/prismer/plugin.yaml +8 -0
- package/plugins/memory/prismer/tool-schemas.generated.json +249 -0
- package/plugins/tools/prismer-recall/__init__.py +282 -0
- package/plugins/tools/prismer-recall/plugin.yaml +15 -0
- package/built-in-skills/memory-curation/SKILL.md +0 -135
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: agent-coordination
|
|
3
|
+
scope: common
|
|
3
4
|
description: Find other agents, list participants in a conversation, send routed messages, attach files, and recover earlier conversation context (history / resolve a fuzzy reference / read a quoted message / read compressed summaries). Use whenever you need to delegate to another agent, address a peer in a multi-agent conversation, send a message that carries a file, or pull context that scrolled out of your prompt window. Executes via `cloud discover`, `cloud im conversations`, `cloud send`, `cloud file send`, `cloud conversation history|resolve-identifier|summary`, and `cloud quote read` CLIs.
|
|
4
5
|
---
|
|
5
6
|
|
|
@@ -16,7 +17,16 @@ If you have an inline `Task` / `Subagent` / `ParallelAgents` / fan-out tool avai
|
|
|
16
17
|
- never @-mention the supposed assignee in the conversation
|
|
17
18
|
- finish in seconds, which to the user looks like you did the work yourself (because you did)
|
|
18
19
|
|
|
19
|
-
For peer-agent delegation, the canonical paths are **`cloud task create --assignee-name <peer>`** (tracked deliverable; see the `tasks` skill) and **`cloud send <peer-username
|
|
20
|
+
For peer-agent delegation, the canonical paths are **`cloud task create --assignee-name <peer>`** (tracked deliverable; see the `tasks` skill) and **`cloud send <peer-username> "<message>" --by-username --workspace-id "$PRISMER_WORKSPACE_ID"`** (ad-hoc message; see below). Anything else — including inline subagents — is the wrong tool, and the user will notice (the supposed assignee was never @-mentioned in chat, and your response came back too fast).
|
|
21
|
+
|
|
22
|
+
### `cloud task create` vs `cloud send` — 选哪条 + 结果回流
|
|
23
|
+
|
|
24
|
+
| 你想要的 | 用 | 结果怎么回来 |
|
|
25
|
+
| --- | --- | --- |
|
|
26
|
+
| **可追踪委派**(要交付物、要进度、要落看板) | `cloud task create --assignee-name <peer>` | **不自动回流**:peer 在独立 context 跑,产物落 task 卡;你须 `cloud task get <taskId>` 主动拉(`status=completed` 才算成)。详见 `tasks` skill 的「结果回流」段。 |
|
|
27
|
+
| **即兴消息**(问一句、转一份、打个招呼) | `cloud send <peer-username> "<message>" --by-username --workspace-id "$PRISMER_WORKSPACE_ID"` | peer 若在**同一会话**,回复直接出现在这条会话里;不落看板、不可追踪。 |
|
|
28
|
+
|
|
29
|
+
口诀:**要结果 / 要看板 → `cloud task create` 然后 `cloud task get` 取**;只是说句话 → `cloud send`。两者都不是 inline subagent。
|
|
20
30
|
|
|
21
31
|
## When to use
|
|
22
32
|
|
|
@@ -30,51 +40,62 @@ For peer-agent delegation, the canonical paths are **`cloud task create --assign
|
|
|
30
40
|
### Discover (workspace-wide directory)
|
|
31
41
|
|
|
32
42
|
```bash
|
|
33
|
-
cloud discover
|
|
34
|
-
cloud discover --capability code-review
|
|
35
|
-
cloud discover --online-only
|
|
43
|
+
cloud discover --workspace-id "$PRISMER_WORKSPACE_ID" # all agents in this workspace
|
|
44
|
+
cloud discover --workspace-id "$PRISMER_WORKSPACE_ID" --capability code-review # filter by capability
|
|
45
|
+
cloud discover --workspace-id "$PRISMER_WORKSPACE_ID" --online-only # only online agents
|
|
36
46
|
cloud im contacts # your contact list
|
|
37
47
|
```
|
|
38
48
|
|
|
49
|
+
`cloud discover` is a workspace-scoped Agent Registry contract: every result
|
|
50
|
+
is backed by an AgentCard in the requested workspace and carries its routing
|
|
51
|
+
`userId`. Human accounts and agents from other workspaces are contract
|
|
52
|
+
violations. When the target is already in the current conversation, prefer the
|
|
53
|
+
conversation members listing below instead of searching the wider workspace.
|
|
54
|
+
|
|
39
55
|
### List participants in a conversation (scoped)
|
|
40
56
|
|
|
41
57
|
```bash
|
|
42
58
|
cloud im conversations # all your conversations
|
|
43
59
|
cloud im conversations --unread # unread only
|
|
44
|
-
cloud im conversations <conversationId> --members #
|
|
60
|
+
cloud im conversations <conversationId> --members --json # exact agent + human participant fields
|
|
45
61
|
```
|
|
46
62
|
|
|
47
63
|
### Send a message
|
|
48
64
|
|
|
49
65
|
```bash
|
|
50
66
|
# Direct message to an agent
|
|
51
|
-
cloud send <to-username> "Please review the PR"
|
|
52
|
-
cloud send <to-username> "## Report" -t markdown
|
|
53
|
-
cloud send <to-username> --reply-to <messageId> "
|
|
67
|
+
cloud send <to-username> "Please review the PR" --by-username --workspace-id "$PRISMER_WORKSPACE_ID"
|
|
68
|
+
cloud send <to-username> "## Report" -t markdown --by-username --workspace-id "$PRISMER_WORKSPACE_ID"
|
|
69
|
+
cloud send <to-username> "Acknowledged" --reply-to <messageId> --by-username --workspace-id "$PRISMER_WORKSPACE_ID"
|
|
54
70
|
|
|
55
71
|
# Conversation-scoped (multi-agent group)
|
|
56
72
|
cloud im groups send <groupId> "Team update: feature shipped"
|
|
57
73
|
|
|
58
74
|
# With routing metadata
|
|
59
|
-
cloud send <to-username> "Need approval" --conversation-id <convId>
|
|
75
|
+
cloud send <to-username> "Need approval" --conversation-id <convId> --by-username --workspace-id "$PRISMER_WORKSPACE_ID"
|
|
60
76
|
```
|
|
61
77
|
|
|
62
78
|
### Send with attached file
|
|
63
79
|
|
|
64
80
|
> **决定怎么交付文件 — 先读这条:**
|
|
65
81
|
>
|
|
66
|
-
> -
|
|
67
|
-
> `${PRISMER_ARTIFACTS_DIR}`(当前 dispatch 的 `artifacts/`
|
|
68
|
-
>
|
|
69
|
-
>
|
|
82
|
+
> - **用户明确要求随当前回复交付的文件** → 写入
|
|
83
|
+
> `${PRISMER_ARTIFACTS_DIR}`(当前 dispatch 的 `artifacts/` 目录),然后显式运行
|
|
84
|
+
> `cloud deliver <abs-path>`。auto-scan 默认 OFF;只写文件不算交付。
|
|
85
|
+
> - **看板 task 的文件产物** → 显式运行 `cloud task attach <abs-path>`,并以
|
|
86
|
+
> 命令返回的 assetId 为准。
|
|
70
87
|
> - **`cloud file send` 会另起一条独立消息**(先于/晚于你的回复单独落),
|
|
71
88
|
> 只适合「对话进行中临时丢个文件给对方看」这种 ad-hoc 分享,**不要**用它
|
|
72
89
|
> 交付任务最终产物 —— 否则用户会看到「一条只有文件的消息」+「一条只有
|
|
73
90
|
> 文字的消息」分裂开(release201/30 §4 + §7)。
|
|
74
91
|
|
|
75
92
|
```bash
|
|
76
|
-
#
|
|
77
|
-
cp ./report.pdf "${PRISMER_ARTIFACTS_DIR}/"
|
|
93
|
+
# 当前回复的文件交付:写入 artifacts/ 后显式 deliver
|
|
94
|
+
cp ./report.pdf "${PRISMER_ARTIFACTS_DIR}/"
|
|
95
|
+
cloud deliver "${PRISMER_ARTIFACTS_DIR}/report.pdf"
|
|
96
|
+
|
|
97
|
+
# 看板 task 文件产物:显式 attach
|
|
98
|
+
cloud task attach "${PRISMER_ARTIFACTS_DIR}/report.pdf"
|
|
78
99
|
|
|
79
100
|
# ad-hoc 临时分享(会另起独立消息 — 不要拿来交付最终产物)
|
|
80
101
|
# 文字说明用 -c/--content(不是 --message —— 后者不存在,commander 会报
|
|
@@ -84,14 +105,15 @@ cloud file send <conversationId> ./report.pdf
|
|
|
84
105
|
cloud file send <conversationId> ./report.pdf --content "Latest numbers, please review"
|
|
85
106
|
cloud file send <conversationId> ./image.png --mime image/png
|
|
86
107
|
|
|
87
|
-
#
|
|
88
|
-
#
|
|
89
|
-
# (
|
|
90
|
-
|
|
108
|
+
# 常态(含 hermes):直接 `cloud file send <conversationId> <path>` 即可——daemon
|
|
109
|
+
# (release203/15c) 按 agent 身份自动关联你当前的 dispatch。仅当你要对另一个
|
|
110
|
+
# (非当前) dispatch 交付、或 daemon 报 409 歧义时,才从 <execution_context> 抄
|
|
111
|
+
# --run-id "<run_id>" 传入。Spawn 适配器 (claude-code / codex) env 已注入。
|
|
112
|
+
cloud file send <conversationId> ./report.pdf --run-id "<run_id>" # 仅跨-dispatch / 409 时
|
|
91
113
|
|
|
92
114
|
# Or upload first, then send by asset id
|
|
93
115
|
cloud file upload ./report.pdf # → returns assetId / uploadId
|
|
94
|
-
cloud send <to-username> "See attached" --asset-id <assetId>
|
|
116
|
+
cloud send <to-username> "See attached" --asset-id <assetId> --by-username --workspace-id "$PRISMER_WORKSPACE_ID"
|
|
95
117
|
```
|
|
96
118
|
|
|
97
119
|
### Attach a file to a message you ALREADY sent (`cloud attach`)
|
|
@@ -106,11 +128,11 @@ cloud send <to-username> "See attached" --asset-id <assetId>
|
|
|
106
128
|
```bash
|
|
107
129
|
cloud attach <messageId> ./addendum.pdf
|
|
108
130
|
|
|
109
|
-
#
|
|
110
|
-
#
|
|
111
|
-
#
|
|
112
|
-
#
|
|
113
|
-
cloud attach <messageId> ./addendum.pdf --run-id "<run_id>" --conversation-id "<conversation_id>"
|
|
131
|
+
# 常态(含 hermes):直接 `cloud attach <messageId> <path>` 即可——daemon
|
|
132
|
+
# (release203/15c) 按 agent 身份自动关联你当前的 dispatch(含 conversation)。
|
|
133
|
+
# 仅当你要对另一个 (非当前) dispatch 操作、或 daemon 报 409 歧义时,才从
|
|
134
|
+
# <execution_context> 抄 --run-id / --conversation-id 传入。
|
|
135
|
+
cloud attach <messageId> ./addendum.pdf --run-id "<run_id>" --conversation-id "<conversation_id>" # 仅跨-dispatch / 409 时
|
|
114
136
|
```
|
|
115
137
|
|
|
116
138
|
### Read earlier conversation context (on demand)
|
|
@@ -168,19 +190,19 @@ prismer session checkpoint restore <runId> # re-apply a saved snapshot
|
|
|
168
190
|
|
|
169
191
|
## Workflow (delegating to another agent)
|
|
170
192
|
|
|
171
|
-
1. **List conversation participants first.** `cloud im conversations <convId> --members` returns
|
|
172
|
-
2. **Pick the target.**
|
|
193
|
+
1. **List conversation participants first.** `cloud im conversations <convId> --members --json` returns a `participants` array. Each item has `{ id, role, user: { id, username, displayName, role, agentType } }`; it does not contain AgentCard capabilities or status. Don't `discover` if the intended target is already identifiable in this conversation.
|
|
194
|
+
2. **Pick the target.** For an existing participant, select an agent by `user.role === "agent"` and use its exact `user.id` or `user.username`; exclude yourself. If the request instead requires capability/status-based selection, use the workspace-scoped Agent Registry with `cloud discover --workspace-id "$PRISMER_WORKSPACE_ID"`.
|
|
173
195
|
3. **Compose a routed message** with: requested action, context, constraints, expected output. Don't bury the ask in pleasantries.
|
|
174
|
-
4. **Send with the exact `
|
|
196
|
+
4. **Send with the exact `username`** the listing returned via `cloud send <username> "<message>" --by-username --workspace-id "$PRISMER_WORKSPACE_ID"`. Don't transform "@Alice" → "alice" by yourself — use the exact string the service returned. Alternatively, pass the discovered `userId` directly and omit `--by-username`.
|
|
175
197
|
5. **Check the return value.** `cloud send` may return `{ ok: false, error: 'agent_not_found' }` even when you got the username from listing (the agent may have left between calls). If `ok: false`, surface the error; don't pretend dispatch succeeded.
|
|
176
198
|
|
|
177
199
|
## Workflow (file attachment)
|
|
178
200
|
|
|
179
201
|
1. Confirm the file exists locally and is the artifact the user should receive.
|
|
180
|
-
2.
|
|
181
|
-
3.
|
|
182
|
-
4.
|
|
183
|
-
5.
|
|
202
|
+
2. Follow the Runtime carrier directive first. An inline PKF is not a file attachment and must not create a parallel file.
|
|
203
|
+
3. For an explicitly requested file, write new output under `PRISMER_ARTIFACTS_DIR`, then run `cloud deliver <abs-path>` for the current reply or `cloud task attach <abs-path>` for a task. Auto-scan is OFF.
|
|
204
|
+
4. Use `cloud file send` for **ad-hoc conversation sharing**, or `cloud attach` to add a file to an existing message.
|
|
205
|
+
5. Record the asset ID returned by the service and mention the attachment only after the command succeeded.
|
|
184
206
|
|
|
185
207
|
## Operating Rules
|
|
186
208
|
|
|
@@ -188,8 +210,8 @@ prismer session checkpoint restore <runId> # re-apply a saved snapshot
|
|
|
188
210
|
|
|
189
211
|
- Choose capability filters based on the **actual task**, not broad role guesses. "Code review" not "developer".
|
|
190
212
|
- Use `--online-only` only when immediate response is required — otherwise async agents can pick up the task.
|
|
191
|
-
- Compare
|
|
192
|
-
- Use returned
|
|
213
|
+
- Compare `userId`, `username`, `name`, descriptions, capabilities, and status before picking. Identical names exist.
|
|
214
|
+
- Use the returned `userId` directly, or resolve the returned `username` with `--by-username --workspace-id "$PRISMER_WORKSPACE_ID"` — never invent or guess identifiers from chat text.
|
|
193
215
|
|
|
194
216
|
### List participants
|
|
195
217
|
|
|
@@ -203,7 +225,7 @@ prismer session checkpoint restore <runId> # re-apply a saved snapshot
|
|
|
203
225
|
- **Never send to yourself.**
|
|
204
226
|
- **Don't send to agents outside the conversation** unless this is a direct message (`cloud send <user-id>`).
|
|
205
227
|
- Don't include secrets or **unrelated private context** in the routed message. The agent on the other end gets the full text.
|
|
206
|
-
-
|
|
228
|
+
- For username routing, pass the exact username as the first argument with `--by-username --workspace-id "$PRISMER_WORKSPACE_ID"`; do not hand-write an `@username` mention in the message body.
|
|
207
229
|
|
|
208
230
|
### File attach
|
|
209
231
|
|
|
@@ -222,9 +244,9 @@ prismer session checkpoint restore <runId> # re-apply a saved snapshot
|
|
|
222
244
|
|
|
223
245
|
## Output reporting
|
|
224
246
|
|
|
225
|
-
After discover:
|
|
247
|
+
After discover: the default table exposes `User ID`, `Username`, `Name`, `Capabilities`, `Status`, and `Description`. Capability names may originate from either legacy strings or structured capability objects, but the table normalizes both to names.
|
|
226
248
|
|
|
227
|
-
After listing participants:
|
|
249
|
+
After listing participants: report `<user.id> · <user.username> · <user.displayName> · role=<user.role> · agentType=<user.agentType>`; participant rows do not contain AgentCard capabilities or status.
|
|
228
250
|
|
|
229
251
|
After send: echo the returned `messageId` and `conversationId`. If the service returned a redacted version (signed/encrypted), surface that.
|
|
230
252
|
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: agent-meta
|
|
3
|
+
scope: common
|
|
3
4
|
description: Inspect, snapshot, publish, and fork Prismer long-running agents through the cloud agent lifecycle API.
|
|
4
5
|
allowed-tools: cloud.agent.spec cloud.agent.snapshot cloud.agent.snapshots cloud.agent.restore cloud.agent.publish cloud.agent.packs cloud.agent.fork prismer.agent.snapshot prismer.agent.publish prismer.agent.fork
|
|
5
6
|
metadata:
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: assets
|
|
3
|
+
scope: common
|
|
3
4
|
description: Locate, inspect, and read content-addressed workspace assets — search by filename/metadata, describe before reading bytes, then read bounded ranges. Use whenever the user references an uploaded file, when you need to cite file evidence, or when a task input/output is an asset URI. Executes via the `cloud asset` CLI and tools.
|
|
4
5
|
---
|
|
5
6
|
|
|
@@ -106,11 +107,10 @@ pre-signed URL into prose:
|
|
|
106
107
|
{ "kind": "image", "assetId": "<assetId>", "mediaType": "image/png", "alt": "<one-line desc>" }
|
|
107
108
|
```
|
|
108
109
|
|
|
109
|
-
When it resolves
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
`
|
|
113
|
-
explicitly as):
|
|
110
|
+
When it resolves an existing **file** asset (PDF, CSV, archive), do not copy it
|
|
111
|
+
into `$PRISMER_ARTIFACTS_DIR` or create a duplicate upload. Return the existing
|
|
112
|
+
asset through the structured ContentBlock attachment using its authoritative
|
|
113
|
+
`assetId`:
|
|
114
114
|
|
|
115
115
|
```json
|
|
116
116
|
{ "kind": "file", "assetId": "<assetId>", "mediaType": "application/pdf", "filename": "<original>" }
|
|
@@ -119,7 +119,9 @@ explicitly as):
|
|
|
119
119
|
Do NOT paste raw bytes or `data:` URIs into the reply body — they bypass the
|
|
120
120
|
content-addressed store, defeat caching, and make follow-up retrieval
|
|
121
121
|
impossible. The chat renderer reads ContentBlock attachments and surfaces
|
|
122
|
-
them as previews
|
|
122
|
+
them as previews. If the user explicitly requests a newly generated local
|
|
123
|
+
file, that is a separate file carrier: write it under `artifacts/` and run
|
|
124
|
+
`cloud deliver <abs-path>` or `cloud task attach <abs-path>` explicitly.
|
|
123
125
|
|
|
124
126
|
## Backing capabilities (D22 mapping)
|
|
125
127
|
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: browser-use
|
|
3
|
+
scope: common
|
|
4
|
+
description: LLM-driven browser automation via the pre-installed browser-use library (chromium already in the image). Use whenever the task needs to interact with web pages beyond a single fetch — multi-step navigation, form filling, clicking, scrolling, structured data extraction, screenshots, or tasks the plain web tools can't complete. Runs as a Python script against the built-in chromium; LLM goes through the Prismer gateway (no external LLM key needed).
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Browser-Use (Web Automation)
|
|
8
|
+
|
|
9
|
+
The sandbox image ships `browser-use` (installed in `/home/user/.venv`) and a full
|
|
10
|
+
chromium build (playwright). This skill drives them: write a short Python script
|
|
11
|
+
with `Agent(task=..., llm=..., browser=...)`, run it, report the result.
|
|
12
|
+
|
|
13
|
+
## When to use
|
|
14
|
+
|
|
15
|
+
- Multi-step web tasks: search → open → extract → compare → download
|
|
16
|
+
- Form filling / login flows / clicking through pages
|
|
17
|
+
- Structured extraction (tables, listings, prices) that a single fetch can't parse
|
|
18
|
+
- Screenshots / visual confirmation of a page state
|
|
19
|
+
- Anything needing JS-rendered content (SPA pages the fetch tools miss)
|
|
20
|
+
|
|
21
|
+
For a single plain fetch, prefer the existing web tools (lighter). Reach for
|
|
22
|
+
browser-use when they come back empty or the task is interactive.
|
|
23
|
+
|
|
24
|
+
## How to run
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
# chromium executable (version dir may change — resolve dynamically):
|
|
28
|
+
CHROME="$(find /home/user/.cache/ms-playwright -name chrome -type f | head -1)"
|
|
29
|
+
|
|
30
|
+
# LLM = our gateway (OpenAI-compatible). PRISMER_BASE_URL / PRISMER_API_KEY
|
|
31
|
+
# are already in the environment; never hardcode them in the script.
|
|
32
|
+
cat > /tmp/bu_task.py <<'PY'
|
|
33
|
+
import os, asyncio
|
|
34
|
+
from browser_use import Agent, ChatOpenAI, Browser
|
|
35
|
+
|
|
36
|
+
async def main():
|
|
37
|
+
llm = ChatOpenAI(
|
|
38
|
+
base_url=f"{os.environ['PRISMER_BASE_URL']}/api/v1",
|
|
39
|
+
api_key=os.environ['PRISMER_API_KEY'],
|
|
40
|
+
model=os.environ.get('PRISMER_MODEL', 'deepseek-v4-flash'),
|
|
41
|
+
temperature=0.0,
|
|
42
|
+
# REQUIRED for the Prismer gateway: browser-use defaults to forcing
|
|
43
|
+
# JSON-schema structured output (response_format=json_schema) which
|
|
44
|
+
# our upstream models reject with 400 "response_format type
|
|
45
|
+
# unavailable" (verified 2026-08-07). Disable it; the agent still
|
|
46
|
+
# extracts via its normal flow.
|
|
47
|
+
dont_force_structured_output=True,
|
|
48
|
+
)
|
|
49
|
+
browser = Browser(
|
|
50
|
+
headless=True,
|
|
51
|
+
executable_path=os.environ['CHROME'],
|
|
52
|
+
)
|
|
53
|
+
agent = Agent(
|
|
54
|
+
task="<TASK>", # be specific: steps, URLs, what to extract, output format
|
|
55
|
+
llm=llm,
|
|
56
|
+
browser=browser,
|
|
57
|
+
)
|
|
58
|
+
history = await agent.run(max_steps=30)
|
|
59
|
+
print("RESULT:", history.final_result())
|
|
60
|
+
print("URLS:", history.urls())
|
|
61
|
+
print("ERRORS:", history.errors())
|
|
62
|
+
await browser.close()
|
|
63
|
+
|
|
64
|
+
asyncio.run(main())
|
|
65
|
+
PY
|
|
66
|
+
CHROME="$CHROME" /home/user/.venv/bin/python /tmp/bu_task.py
|
|
67
|
+
rm -f /tmp/bu_task.py
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
## Task-writing rules (from browser-use docs)
|
|
71
|
+
|
|
72
|
+
- **Be specific**: `"Go to https://…, use extract with query 'first 3 quotes and their authors', save to quotes.csv via write_file"` — open-ended tasks fail.
|
|
73
|
+
- **Name actions**: "use search action for …", "use click to open first result in a new tab", "use send_keys with 'Tab Tab Enter'" — the agent maps these to its built-in tools.
|
|
74
|
+
- **Error recovery**: if navigation is blocked, fall back to a search engine; if a click fails, use keyboard navigation (`send_keys`).
|
|
75
|
+
- **max_steps**: default 100; keep 30 for focused tasks, raise for long flows.
|
|
76
|
+
- **Anti-bot**: if a page blocks automation, try `use_cloud=True` — NOT available here (no Browser-Use Cloud key). Fall back to search/cache.
|
|
77
|
+
|
|
78
|
+
## Environment facts
|
|
79
|
+
|
|
80
|
+
| Item | Value |
|
|
81
|
+
| --- | --- |
|
|
82
|
+
| Python | `/home/user/.venv/bin/python` (browser-use installed here) |
|
|
83
|
+
| Chromium | `$(find /home/user/.cache/ms-playwright -name chrome -type f \| head -1)` |
|
|
84
|
+
| LLM | Prismer gateway (`PRISMER_BASE_URL` + `PRISMER_API_KEY`, OpenAI-compatible) |
|
|
85
|
+
| Model | `PRISMER_MODEL` env (default `deepseek-v4-flash`) — adjust for the task |
|
|
86
|
+
| Telemetry | browser-use collects anonymous telemetry by default — set `ANONYMIZED_TELEMETRY=false` |
|
|
87
|
+
|
|
88
|
+
## Output contract
|
|
89
|
+
|
|
90
|
+
Report to the user: `history.final_result()` (the extracted answer), the URLs
|
|
91
|
+
visited, and any errors. If `history.is_successful()` is False, say so plainly
|
|
92
|
+
with `history.errors()` — do not invent a completion. Attach screenshots
|
|
93
|
+
(`history.screenshot_paths()`) as task assets when they matter.
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: canvas-design
|
|
3
|
+
scope: persistence
|
|
3
4
|
description: Create beautiful visual art in .png and .pdf documents using design philosophy. You should use this skill when the user asks to create a poster, piece of art, design, or other static piece. Create original visual designs, never copying existing artists' work to avoid copyright violations.
|
|
4
5
|
license: Complete terms in LICENSE.txt
|
|
5
6
|
---
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: claim-agent-ownership
|
|
3
|
+
scope: common
|
|
3
4
|
description: |
|
|
4
5
|
Orchestrator skill for resolving multi-daemon binding contention. Use when you (the
|
|
5
6
|
orchestrator) detect an `agent.binding.contested` sync event indicating two daemons
|
|
@@ -73,7 +74,7 @@ curl -fsS \
|
|
|
73
74
|
```
|
|
74
75
|
|
|
75
76
|
`PRISMER_CLOUD_BASE` defaults to the cloud the daemon paired with
|
|
76
|
-
(`https://
|
|
77
|
+
(`https://prod.docbrew.cn` in prod, `http://127.0.0.1:3000` in local dev).
|
|
77
78
|
|
|
78
79
|
For pure-API use (orchestrator runtime, MCP tool, etc.), the underlying call is:
|
|
79
80
|
|
|
@@ -209,7 +210,7 @@ Action:
|
|
|
209
210
|
"$PRISMER_CLOUD_BASE/api/im/agent-bindings/u_agent_ceo/rebind"
|
|
210
211
|
|
|
211
212
|
Response: boundDaemonId='daemon-mac-studio-01', inFlightTaskCount=2
|
|
212
|
-
Orchestrator messages user: "Pinned
|
|
213
|
+
Orchestrator messages user: "Pinned Team Manager agent to your Mac Studio. 2 tasks finishing on
|
|
213
214
|
the cloud pod first."
|
|
214
215
|
```
|
|
215
216
|
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: claude-api
|
|
3
|
+
scope: coding
|
|
3
4
|
description: "Build, debug, and optimize Claude API / Anthropic SDK apps. Apps built with this skill should include prompt caching. Also handles migrating existing Claude API code between Claude model versions (4.5 → 4.6, 4.6 → 4.7, retired-model replacements). TRIGGER when: code imports `anthropic`/`@anthropic-ai/sdk`; user asks for the Claude API, Anthropic SDK, or Managed Agents; user adds/modifies/tunes a Claude feature (caching, thinking, compaction, tool use, batch, files, citations, memory) or model (Opus/Sonnet/Haiku) in a file; questions about prompt caching / cache hit rate in an Anthropic SDK project. SKIP: file imports `openai`/other-provider SDK, filename like `*-openai.py`/`*-generic.py`, provider-neutral code, general programming/ML."
|
|
4
5
|
license: Complete terms in LICENSE.txt
|
|
5
6
|
---
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# Deepening
|
|
2
|
+
|
|
3
|
+
How to deepen a cluster of shallow modules safely, given its dependencies. Assumes the vocabulary in [SKILL.md](SKILL.md) — **module**, **interface**, **seam**, **adapter**.
|
|
4
|
+
|
|
5
|
+
## Dependency categories
|
|
6
|
+
|
|
7
|
+
When assessing a candidate for deepening, classify its dependencies. The category determines how the deepened module is tested across its seam.
|
|
8
|
+
|
|
9
|
+
### 1. In-process
|
|
10
|
+
|
|
11
|
+
Pure computation, in-memory state, no I/O. Always deepenable — merge the modules and test through the new interface directly. No adapter needed.
|
|
12
|
+
|
|
13
|
+
### 2. Local-substitutable
|
|
14
|
+
|
|
15
|
+
Dependencies that have local test stand-ins (PGLite for Postgres, in-memory filesystem). Deepenable if the stand-in exists. The deepened module is tested with the stand-in running in the test suite. The seam is internal; no port at the module's external interface.
|
|
16
|
+
|
|
17
|
+
### 3. Remote but owned (Ports & Adapters)
|
|
18
|
+
|
|
19
|
+
Your own services across a network boundary (microservices, internal APIs). Define a **port** (interface) at the seam. The deep module owns the logic; the transport is injected as an **adapter**. Tests use an in-memory adapter. Production uses an HTTP/gRPC/queue adapter.
|
|
20
|
+
|
|
21
|
+
Recommendation shape: *"Define a port at the seam, implement an HTTP adapter for production and an in-memory adapter for testing, so the logic sits in one deep module even though it's deployed across a network."*
|
|
22
|
+
|
|
23
|
+
### 4. True external (Mock)
|
|
24
|
+
|
|
25
|
+
Third-party services (Stripe, Twilio, etc.) you don't control. The deepened module takes the external dependency as an injected port; tests provide a mock adapter.
|
|
26
|
+
|
|
27
|
+
## Seam discipline
|
|
28
|
+
|
|
29
|
+
- **One adapter means a hypothetical seam. Two adapters means a real one.** Don't introduce a port unless at least two adapters are justified (typically production + test). A single-adapter seam is just indirection.
|
|
30
|
+
- **Internal seams vs external seams.** A deep module can have internal seams (private to its implementation, used by its own tests) as well as the external seam at its interface. Don't expose internal seams through the interface just because tests use them.
|
|
31
|
+
|
|
32
|
+
## Testing strategy: replace, don't layer
|
|
33
|
+
|
|
34
|
+
- Old unit tests on shallow modules become waste once tests at the deepened module's interface exist — delete them.
|
|
35
|
+
- Write new tests at the deepened module's interface. The **interface is the test surface**.
|
|
36
|
+
- Tests assert on observable outcomes through the interface, not internal state.
|
|
37
|
+
- Tests should survive internal refactors — they describe behaviour, not implementation. If a test has to change when the implementation changes, it's testing past the interface.
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# Design It Twice
|
|
2
|
+
|
|
3
|
+
When the user wants to explore alternative interfaces for a chosen deepening candidate, use this parallel sub-agent pattern. Based on "Design It Twice" (Ousterhout) — your first idea is unlikely to be the best.
|
|
4
|
+
|
|
5
|
+
Uses the vocabulary in [SKILL.md](SKILL.md) — **module**, **interface**, **seam**, **adapter**, **leverage**.
|
|
6
|
+
|
|
7
|
+
## Process
|
|
8
|
+
|
|
9
|
+
### 1. Frame the problem space
|
|
10
|
+
|
|
11
|
+
Before spawning sub-agents, write a user-facing explanation of the problem space for the chosen candidate:
|
|
12
|
+
|
|
13
|
+
- The constraints any new interface would need to satisfy
|
|
14
|
+
- The dependencies it would rely on, and which category they fall into (see [DEEPENING.md](DEEPENING.md))
|
|
15
|
+
- A rough illustrative code sketch to ground the constraints — not a proposal, just a way to make the constraints concrete
|
|
16
|
+
|
|
17
|
+
Show this to the user, then immediately proceed to Step 2. The user reads and thinks while the sub-agents work in parallel.
|
|
18
|
+
|
|
19
|
+
### 2. Spawn sub-agents
|
|
20
|
+
|
|
21
|
+
Spawn 3+ sub-agents in parallel using the Agent tool. Each must produce a **radically different** interface for the deepened module.
|
|
22
|
+
|
|
23
|
+
Prompt each sub-agent with a separate technical brief (file paths, coupling details, dependency category from [DEEPENING.md](DEEPENING.md), what sits behind the seam). The brief is independent of the user-facing problem-space explanation in Step 1. Give each agent a different design constraint:
|
|
24
|
+
|
|
25
|
+
- Agent 1: "Minimize the interface — aim for 1–3 entry points max. Maximise leverage per entry point."
|
|
26
|
+
- Agent 2: "Maximise flexibility — support many use cases and extension."
|
|
27
|
+
- Agent 3: "Optimise for the most common caller — make the default case trivial."
|
|
28
|
+
- Agent 4 (if applicable): "Design around ports & adapters for cross-seam dependencies."
|
|
29
|
+
|
|
30
|
+
Include both [SKILL.md](SKILL.md) vocabulary and CONTEXT.md vocabulary in the brief so each sub-agent names things consistently with the architecture language and the project's domain language.
|
|
31
|
+
|
|
32
|
+
Each sub-agent outputs:
|
|
33
|
+
|
|
34
|
+
1. Interface (types, methods, params — plus invariants, ordering, error modes)
|
|
35
|
+
2. Usage example showing how callers use it
|
|
36
|
+
3. What the implementation hides behind the seam
|
|
37
|
+
4. Dependency strategy and adapters (see [DEEPENING.md](DEEPENING.md))
|
|
38
|
+
5. Trade-offs — where leverage is high, where it's thin
|
|
39
|
+
|
|
40
|
+
### 3. Present and compare
|
|
41
|
+
|
|
42
|
+
Present designs sequentially so the user can absorb each one, then compare them in prose. Contrast by **depth** (leverage at the interface), **locality** (where change concentrates), and **seam placement**.
|
|
43
|
+
|
|
44
|
+
After comparing, give your own recommendation: which design you think is strongest and why. If elements from different designs would combine well, propose a hybrid. Be opinionated — the user wants a strong read, not a menu.
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Matt Pocock
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: codebase-design
|
|
3
|
+
scope: coding
|
|
4
|
+
source: https://github.com/mattpocock/skills (MIT, © 2026 Matt Pocock)
|
|
5
|
+
description: Shared vocabulary for designing deep modules. Use when the user wants to design or improve a module's interface, find deepening opportunities, decide where a seam goes, make code more testable or AI-navigable, or when another skill needs the deep-module vocabulary.
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Codebase Design
|
|
9
|
+
|
|
10
|
+
Design **deep modules**: a lot of behaviour behind a small interface, placed at a clean seam, testable through that interface. Use this language and these principles wherever code is being designed or restructured. The aim is leverage for callers, locality for maintainers, and testability for everyone.
|
|
11
|
+
|
|
12
|
+
## Glossary
|
|
13
|
+
|
|
14
|
+
Use these terms exactly — don't substitute "component," "service," "API," or "boundary." Consistent language is the whole point.
|
|
15
|
+
|
|
16
|
+
**Module** — anything with an interface and an implementation. Deliberately scale-agnostic: a function, class, package, or tier-spanning slice. _Avoid_: unit, component, service.
|
|
17
|
+
|
|
18
|
+
**Interface** — everything a caller must know to use the module correctly: the type signature, but also invariants, ordering constraints, error modes, required configuration, and performance characteristics. _Avoid_: API, signature (too narrow — they refer only to the type-level surface).
|
|
19
|
+
|
|
20
|
+
**Implementation** — what's inside a module, its body of code. Distinct from **Adapter**: a thing can be a small adapter with a large implementation (a Postgres repo) or a large adapter with a small implementation (an in-memory fake). Reach for "adapter" when the seam is the topic; "implementation" otherwise.
|
|
21
|
+
|
|
22
|
+
**Depth** — leverage at the interface: the amount of behaviour a caller (or test) can exercise per unit of interface they have to learn. A module is **deep** when a large amount of behaviour sits behind a small interface, **shallow** when the interface is nearly as complex as the implementation.
|
|
23
|
+
|
|
24
|
+
**Seam** _(Michael Feathers)_ — a place where you can alter behaviour without editing in that place; the *location* at which a module's interface lives. Where to put the seam is its own design decision, distinct from what goes behind it. _Avoid_: boundary (overloaded with DDD's bounded context).
|
|
25
|
+
|
|
26
|
+
**Adapter** — a concrete thing that satisfies an interface at a seam. Describes *role* (what slot it fills), not substance (what's inside).
|
|
27
|
+
|
|
28
|
+
**Leverage** — what callers get from depth: more capability per unit of interface they learn. One implementation pays back across N call sites and M tests.
|
|
29
|
+
|
|
30
|
+
**Locality** — what maintainers get from depth: change, bugs, knowledge, and verification concentrate in one place rather than spreading across callers. Fix once, fixed everywhere.
|
|
31
|
+
|
|
32
|
+
## Deep vs shallow
|
|
33
|
+
|
|
34
|
+
**Deep module** = small interface + lots of implementation:
|
|
35
|
+
|
|
36
|
+
```
|
|
37
|
+
┌─────────────────────┐
|
|
38
|
+
│ Small Interface │ ← Few methods, simple params
|
|
39
|
+
├─────────────────────┤
|
|
40
|
+
│ │
|
|
41
|
+
│ Deep Implementation│ ← Complex logic hidden
|
|
42
|
+
│ │
|
|
43
|
+
└─────────────────────┘
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
**Shallow module** = large interface + little implementation (avoid):
|
|
47
|
+
|
|
48
|
+
```
|
|
49
|
+
┌─────────────────────────────────┐
|
|
50
|
+
│ Large Interface │ ← Many methods, complex params
|
|
51
|
+
├─────────────────────────────────┤
|
|
52
|
+
│ Thin Implementation │ ← Just passes through
|
|
53
|
+
└─────────────────────────────────┘
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
When designing an interface, ask:
|
|
57
|
+
|
|
58
|
+
- Can I reduce the number of methods?
|
|
59
|
+
- Can I simplify the parameters?
|
|
60
|
+
- Can I hide more complexity inside?
|
|
61
|
+
|
|
62
|
+
## Principles
|
|
63
|
+
|
|
64
|
+
- **Depth is a property of the interface, not the implementation.** A deep module can be internally composed of small, mockable, swappable parts — they just aren't part of the interface. A module can have **internal seams** (private to its implementation, used by its own tests) as well as the **external seam** at its interface.
|
|
65
|
+
- **The deletion test.** Imagine deleting the module. If complexity vanishes, it was a pass-through. If complexity reappears across N callers, it was earning its keep.
|
|
66
|
+
- **The interface is the test surface.** Callers and tests cross the same seam. If you want to test *past* the interface, the module is probably the wrong shape.
|
|
67
|
+
- **One adapter means a hypothetical seam. Two adapters means a real one.** Don't introduce a seam unless something actually varies across it.
|
|
68
|
+
|
|
69
|
+
## Designing for testability
|
|
70
|
+
|
|
71
|
+
Good interfaces make testing natural:
|
|
72
|
+
|
|
73
|
+
1. **Accept dependencies, don't create them.**
|
|
74
|
+
|
|
75
|
+
```typescript
|
|
76
|
+
// Testable
|
|
77
|
+
function processOrder(order, paymentGateway) {}
|
|
78
|
+
|
|
79
|
+
// Hard to test
|
|
80
|
+
function processOrder(order) {
|
|
81
|
+
const gateway = new StripeGateway();
|
|
82
|
+
}
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
2. **Return results, don't produce side effects.**
|
|
86
|
+
|
|
87
|
+
```typescript
|
|
88
|
+
// Testable
|
|
89
|
+
function calculateDiscount(cart): Discount {}
|
|
90
|
+
|
|
91
|
+
// Hard to test
|
|
92
|
+
function applyDiscount(cart): void {
|
|
93
|
+
cart.total -= discount;
|
|
94
|
+
}
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
3. **Small surface area.** Fewer methods = fewer tests needed. Fewer params = simpler test setup.
|
|
98
|
+
|
|
99
|
+
## Relationships
|
|
100
|
+
|
|
101
|
+
- A **Module** has exactly one **Interface** (the surface it presents to callers and tests).
|
|
102
|
+
- **Depth** is a property of a **Module**, measured against its **Interface**.
|
|
103
|
+
- A **Seam** is where a **Module**'s **Interface** lives.
|
|
104
|
+
- An **Adapter** sits at a **Seam** and satisfies the **Interface**.
|
|
105
|
+
- **Depth** produces **Leverage** for callers and **Locality** for maintainers.
|
|
106
|
+
|
|
107
|
+
## Rejected framings
|
|
108
|
+
|
|
109
|
+
- **Depth as ratio of implementation-lines to interface-lines** (Ousterhout): rewards padding the implementation. We use depth-as-leverage instead.
|
|
110
|
+
- **"Interface" as the TypeScript `interface` keyword or a class's public methods**: too narrow — interface here includes every fact a caller must know.
|
|
111
|
+
- **"Boundary"**: overloaded with DDD's bounded context. Say **seam** or **interface**.
|
|
112
|
+
|
|
113
|
+
## Going deeper
|
|
114
|
+
|
|
115
|
+
- **Deepening a cluster given its dependencies** — see [DEEPENING.md](DEEPENING.md): dependency categories, seam discipline, and replace-don't-layer testing.
|
|
116
|
+
- **Exploring alternative interfaces** — see [DESIGN-IT-TWICE.md](DESIGN-IT-TWICE.md): spin up parallel sub-agents to design the interface several radically different ways, then compare on depth, locality, and seam placement.
|