Primitive catalog — the decision layer for plugin composition
Use this catalog while drafting a Primitive Decision Record (PDR) in design/CONTRACT.md. Each card in
references/cards/ is a decision-oriented distillation: exact syntax, version floors, context costs, and
failure modes. For exhaustive syntax the cards point to the official Claude Code docs
(https://code.claude.com/docs — fetch llms.txt for the page index) — never duplicate that
encyclopedia here.
Rules of use:
- Answer every loaded card's Consequence prompts in the PDR chain columns C1–C6 before committing to that primitive.
- When a card's Reject when criteria match, record the rejection as that capability's rejected alternative, naming the chain step that killed it.
- When a card's Eval hooks section cannot name a grader that observes the primitive in the target design, the choice is unverifiable → unbuildable (the C5 hard gate).
Master rubric 1 — who holds the plan
Escalate only as far as the capability demands; every step up costs tokens, latency, or interactivity.
| Level |
Who holds the plan |
Intermediates live in |
Repeatable unit |
Scale |
Pick when |
| Main conversation |
Claude, turn by turn |
Main context |
Nothing |
1 thread |
Frequent back-and-forth; phases share context |
| Skill (inline) |
The SKILL.md prompt |
Main context |
The instructions |
1 thread |
Repeatable process knowledge; standing rules |
| Subagent |
Delegation prompt + agent body |
Subagent context; summary returns |
The agent definition |
A few parallel |
Verbose-output isolation; tool restriction; clean expert lens |
Forked skill (context: fork / /subtask) |
SKILL.md as the fork's prompt |
Fork context (inherits conversation; shares prompt cache) |
The skill |
A few parallel |
Side task needs the accumulated conversation state |
| Agent team |
Lead + shared task list |
Task list + mailboxes (~/.claude/tasks/) |
Subagent definitions as roles |
3–5 peers, 5–6 tasks each |
Workers must discuss/challenge each other; file-partitioned parallel builds |
| Workflow |
The JS script |
Script variables |
The orchestration script itself |
Dozens–hundreds (16 concurrent, 1000/run) |
Homogeneous fan-out; intermediates would overflow context |
Master rubric 2 — loop primitives
| Primitive |
Next turn fires |
Stops when |
Persists |
Can a plugin ship it? |
/goal <condition> |
When the previous turn finishes |
Tool-less small-model evaluator judges the condition true from the transcript alone |
Session only (survives --resume, counters reset) |
No — session command (v2.1.139+; needs trust + hooks enabled) |
/loop |
On a time interval |
User or model decides |
Session only |
No |
| Stop hook (prompt/agent type) |
When the previous turn finishes |
Per the hook's script/prompt verdict |
Its settings scope — survives sessions |
Yes — via hooks/hooks.json; the productized /goal |
| Schedule (cloud routine / scheduled task) |
On cron, independent of open sessions |
Per schedule |
Account/repo level |
Plugin ships the skill it invokes, not the schedule |
A plugin cannot ship /goal itself. The distributable equivalent is a prompt- or agent-type Stop hook in
hooks/hooks.json (honoring stop_hook_active and the 8-block cap, CLAUDE_CODE_STOP_HOOK_BLOCK_CAP),
plus documented "goal recipes" — pre-written ≤4,000-char conditions users paste into /goal. Note:
scheduled tasks cannot invoke disable-model-invocation: true skills (v2.1.196+). Full loop mechanics:
references/cards/loops-card.md.
Master rubric 3 — MCP server vs bundled script
Does the capability need persistent connection state, OAuth to a remote API,
server push (channels), elicitation dialogs, MCP resources/prompts, or a large
tool surface (tool search scales)?
├─ YES → bundle an MCP server (.mcp.json at plugin root) → mcp-card.md
└─ NO
├─ One-shot computation or CLI call, no connection state
│ → bundled stdlib script + skill with
│ allowed-tools: Bash(${CLAUDE_SKILL_DIR}/scripts/x.sh *)
│ (zero prompts, no server lifecycle, no approval dialog,
│ no timeout design, headless-safe) → skills-card.md
├─ Long-running local watch (tail a log, poll a queue) → monitors-bin-card.md
└─ CLI users should call directly by name → bin/ on PATH, monitors-bin-card.md
Default to the script. MCP must earn its lifecycle cost: approval prompts, trust dialogs, timeout/idle
design, headless auth preflight, and stdio's never-reconnects failure mode.
Card index
Load only the cards relevant to the candidate compositions under discussion.
references/cards/skills-card.md — load when any capability could be a skill or command: invocation-control matrix (disable-model-invocation vs user-invocable), 1,536-char description cap and 1% listing budget, arguments, the !-backtick dynamic injection and its policy fallback, context: fork narrowing, 5k/25k compaction budgets, paths scoping, model/effort routing, stacking stop rule.
references/cards/hooks-card.md — load when behavior must be enforced rather than suggested, or automated at a lifecycle point: 30-event catalog with per-event matcher vocabulary, five executor types and their selection rule, exit-code discipline, per-event output schemas, Stop-loop mechanics, headless gaps.
references/cards/agents-teams-card.md — load when delegating to subagents or coordinating an agent team: plugin frontmatter stripping and its two workarounds, background 19-tool filter, memory: project, isolation: worktree base-branch gotcha, dual-mode bodies, resume-via-SendMessage, team task DAGs, plan approval, TaskCompleted gates.
references/cards/mcp-card.md — load when integrating external systems: transport selection, plugin-scoped tool naming, tool search and 2KB instruction discovery, timeouts and backgrounding, tools vs resources vs prompts vs elicitation vs channels, headless auth preflight, and the honest MCP-apps status note.
references/cards/lsp-card.md — load when the target plugin serves a programming language and post-edit diagnostics or code navigation would help: configure-never-bundle rule, official-plugin dependency route, first-server-wins, diagnostics toggle.
references/cards/workflows-card.md — load when a capability fans out over many homogeneous items: agent()/pipeline() with schema and label, 16/1000 caps, resume replay order, the ultracode-never-fires-headless trap, always-pair-with-a-script rule.
references/cards/loops-card.md — load when a capability is "keep working until done": /goal condition authoring, evaluator mechanics, shipped Stop-hook productization, /loop, ralph/karpathy outer-loop patterns.
references/cards/headless-card.md — load when anything must run under claude -p (CI, evals, routines): --bare hermeticity, output formats, --json-schema, system/init gating, permission rule syntax, session chaining.
references/cards/worktrees-card.md — load when work needs filesystem isolation: --worktree lifecycle, -p never cleans up, worktree.baseRef, .worktreeinclude, sharing semantics.
references/cards/monitors-bin-card.md — load for long-running background watchers (monitors/monitors.json, when: on-skill-invoke) and bin/ executables added to the Bash PATH.
references/cards/output-styles-settings-card.md — load when the plugin needs a persona shift or fleet display: output styles vs CLAUDE.md vs agents, force-for-plugin, plugin settings.json (agent, subagentStatusLine only).
references/cards/distribution-card.md — load when deciding install level and lifecycle: marketplaces, version strategy (SHA vs pinned semver), dependencies, renames, seed dirs for CI, cloud-session declaration.
1---2name: primitive-catalog3description: Decision cards for selecting Claude Code primitives while designing a plugin - skill vs hook vs subagent vs agent team vs MCP server vs bundled script vs LSP vs workflow vs loop. Load during any plugin architecture or composition discussion, when writing a Primitive Decision Record (design/CONTRACT.md), filling six-step consequence chains (trigger, context economics, enforcement, failure modes, testability, distribution), choosing who holds the plan, picking a loop primitive (/goal vs Stop hook vs /loop vs schedule), or deciding MCP-versus-bundled-script. Cards carry exact syntax, version floors, context costs, failure modes, and the grader type that can observe each primitive.4---56# Primitive catalog — the decision layer for plugin composition78Use this catalog while drafting a Primitive Decision Record (PDR) in `design/CONTRACT.md`. Each card in9`references/cards/` is a decision-oriented distillation: exact syntax, version floors, context costs, and10failure modes. For exhaustive syntax the cards point to the official Claude Code docs11(https://code.claude.com/docs — fetch llms.txt for the page index) — never duplicate that12encyclopedia here.1314Rules of use:15- Answer every loaded card's **Consequence prompts** in the PDR chain columns C1–C6 before committing to that primitive.16- When a card's **Reject when** criteria match, record the rejection as that capability's rejected alternative, naming the chain step that killed it.17- When a card's **Eval hooks** section cannot name a grader that observes the primitive in the target design, the choice is unverifiable → unbuildable (the C5 hard gate).1819## Master rubric 1 — who holds the plan2021Escalate only as far as the capability demands; every step up costs tokens, latency, or interactivity.2223| Level | Who holds the plan | Intermediates live in | Repeatable unit | Scale | Pick when |24|---|---|---|---|---|---|25| Main conversation | Claude, turn by turn | Main context | Nothing | 1 thread | Frequent back-and-forth; phases share context |26| Skill (inline) | The SKILL.md prompt | Main context | The instructions | 1 thread | Repeatable process knowledge; standing rules |27| Subagent | Delegation prompt + agent body | Subagent context; summary returns | The agent definition | A few parallel | Verbose-output isolation; tool restriction; clean expert lens |28| Forked skill (`context: fork` / `/subtask`) | SKILL.md as the fork's prompt | Fork context (inherits conversation; shares prompt cache) | The skill | A few parallel | Side task needs the accumulated conversation state |29| Agent team | Lead + shared task list | Task list + mailboxes (`~/.claude/tasks/`) | Subagent definitions as roles | 3–5 peers, 5–6 tasks each | Workers must discuss/challenge each other; file-partitioned parallel builds |30| Workflow | The JS script | Script variables | The orchestration script itself | Dozens–hundreds (16 concurrent, 1000/run) | Homogeneous fan-out; intermediates would overflow context |3132## Master rubric 2 — loop primitives3334| Primitive | Next turn fires | Stops when | Persists | Can a plugin ship it? |35|---|---|---|---|---|36| `/goal <condition>` | When the previous turn finishes | Tool-less small-model evaluator judges the condition true from the transcript alone | Session only (survives `--resume`, counters reset) | **No** — session command (v2.1.139+; needs trust + hooks enabled) |37| `/loop` | On a time interval | User or model decides | Session only | **No** |38| Stop hook (prompt/agent type) | When the previous turn finishes | Per the hook's script/prompt verdict | Its settings scope — survives sessions | **Yes** — via `hooks/hooks.json`; the productized `/goal` |39| Schedule (cloud routine / scheduled task) | On cron, independent of open sessions | Per schedule | Account/repo level | Plugin ships the skill it invokes, not the schedule |4041A plugin cannot ship `/goal` itself. The distributable equivalent is a prompt- or agent-type Stop hook in42`hooks/hooks.json` (honoring `stop_hook_active` and the 8-block cap, `CLAUDE_CODE_STOP_HOOK_BLOCK_CAP`),43plus documented "goal recipes" — pre-written ≤4,000-char conditions users paste into `/goal`. Note:44scheduled tasks cannot invoke `disable-model-invocation: true` skills (v2.1.196+). Full loop mechanics:45`references/cards/loops-card.md`.4647## Master rubric 3 — MCP server vs bundled script4849```50Does the capability need persistent connection state, OAuth to a remote API,51server push (channels), elicitation dialogs, MCP resources/prompts, or a large52tool surface (tool search scales)?53├─ YES → bundle an MCP server (.mcp.json at plugin root) → mcp-card.md54└─ NO55 ├─ One-shot computation or CLI call, no connection state56 │ → bundled stdlib script + skill with57 │ allowed-tools: Bash(${CLAUDE_SKILL_DIR}/scripts/x.sh *)58 │ (zero prompts, no server lifecycle, no approval dialog,59 │ no timeout design, headless-safe) → skills-card.md60 ├─ Long-running local watch (tail a log, poll a queue) → monitors-bin-card.md61 └─ CLI users should call directly by name → bin/ on PATH, monitors-bin-card.md62```6364Default to the script. MCP must earn its lifecycle cost: approval prompts, trust dialogs, timeout/idle65design, headless auth preflight, and stdio's never-reconnects failure mode.6667## Card index6869Load only the cards relevant to the candidate compositions under discussion.7071- **`references/cards/skills-card.md`** — load when any capability could be a skill or command: invocation-control matrix (`disable-model-invocation` vs `user-invocable`), 1,536-char description cap and 1% listing budget, arguments, the `!`-backtick dynamic injection and its policy fallback, `context: fork` narrowing, 5k/25k compaction budgets, `paths` scoping, model/effort routing, stacking stop rule.72- **`references/cards/hooks-card.md`** — load when behavior must be *enforced* rather than suggested, or automated at a lifecycle point: 30-event catalog with per-event matcher vocabulary, five executor types and their selection rule, exit-code discipline, per-event output schemas, Stop-loop mechanics, headless gaps.73- **`references/cards/agents-teams-card.md`** — load when delegating to subagents or coordinating an agent team: plugin frontmatter stripping and its two workarounds, background 19-tool filter, `memory: project`, `isolation: worktree` base-branch gotcha, dual-mode bodies, resume-via-SendMessage, team task DAGs, plan approval, TaskCompleted gates.74- **`references/cards/mcp-card.md`** — load when integrating external systems: transport selection, plugin-scoped tool naming, tool search and 2KB instruction discovery, timeouts and backgrounding, tools vs resources vs prompts vs elicitation vs channels, headless auth preflight, and the honest MCP-apps status note.75- **`references/cards/lsp-card.md`** — load when the target plugin serves a programming language and post-edit diagnostics or code navigation would help: configure-never-bundle rule, official-plugin dependency route, first-server-wins, diagnostics toggle.76- **`references/cards/workflows-card.md`** — load when a capability fans out over many homogeneous items: `agent()`/`pipeline()` with schema and label, 16/1000 caps, resume replay order, the ultracode-never-fires-headless trap, always-pair-with-a-script rule.77- **`references/cards/loops-card.md`** — load when a capability is "keep working until done": `/goal` condition authoring, evaluator mechanics, shipped Stop-hook productization, `/loop`, ralph/karpathy outer-loop patterns.78- **`references/cards/headless-card.md`** — load when anything must run under `claude -p` (CI, evals, routines): `--bare` hermeticity, output formats, `--json-schema`, `system/init` gating, permission rule syntax, session chaining.79- **`references/cards/worktrees-card.md`** — load when work needs filesystem isolation: `--worktree` lifecycle, `-p` never cleans up, `worktree.baseRef`, `.worktreeinclude`, sharing semantics.80- **`references/cards/monitors-bin-card.md`** — load for long-running background watchers (`monitors/monitors.json`, `when: on-skill-invoke`) and `bin/` executables added to the Bash PATH.81- **`references/cards/output-styles-settings-card.md`** — load when the plugin needs a persona shift or fleet display: output styles vs CLAUDE.md vs agents, `force-for-plugin`, plugin `settings.json` (`agent`, `subagentStatusLine` only).82- **`references/cards/distribution-card.md`** — load when deciding install level and lifecycle: marketplaces, version strategy (SHA vs pinned semver), `dependencies`, renames, seed dirs for CI, cloud-session declaration.