tools/list. That is why the terminal surface and the stdio surface stay aligned instead of drifting into two separate products.CLI Command Families
The canonical terminal form is short and boring. Good. I want a runtime surface that can be scripted without ceremony: asd <tool-name> [--flag value], with the short name derived from the engine tool by stripping sd_ and replacing underscores with hyphens. The pack-local install path is fixed, Node 20 or newer is required, and the launcher never falls back to a global executable or a sibling checkout. That last point matters in release verification because the bundle is supposed to prove it can stand on its own.
node platform/compiler/emit-packs.mjs --output /tmp/asd-packs
PACK=/tmp/asd-packs/cli
mkdir -p "$HOME/.local/bin"
ln -sf "$PACK/asd" "$HOME/.local/bin/asd"
export PATH="$HOME/.local/bin:$PATH"
asd --version
asd help
Flags map one-to-one onto tool arguments. Strings stay strings. Numbers, booleans, arrays, and objects are validated before the tool runs. Arrays and objects travel as JSON literals on the command line. Unknown flags, missing required flags, positional arguments, and invalid enum values exit 1 with a real error instead of a fuzzy best effort.
| Family | CLI command | Engine alias | Flags | What it does |
|---|---|---|---|---|
| Project | asd project-list | sd_project_list | — | List every project in the workspace. |
| Project | asd project-create | sd_project_create | --name --client --sector --service [--phase] | Create project.json plus evidence/, artifacts/, renders/, and sops/. |
| Project | asd project-open | sd_project_open | --projectId | Open one project and return metadata plus artifacts. |
| Project | asd project-status-set | sd_project_status_set | --projectId --status [--statusNote] | Set the engagement lifecycle status — the Kanban column — independently of the design phase. status is an enum: briefed, active, gated, blocked, archived. |
| Evidence | asd evidence-add | sd_evidence_add | --projectId --source --kind --body | Add one quote, telemetry, or document record. |
| Evidence | asd evidence-import | sd_evidence_import | --projectId --path --source [--encoding] [--maxBytes] [--onError] | Import transcript, CSV, or JSON evidence from inside ASD_WORKSPACE. |
| Evidence | asd evidence-query | sd_evidence_query | --projectId [--search] [--kind] | Search the project evidence register. |
| Artifacts | asd artifact-list | sd_artifact_list | --projectId [--kind] | List a project’s typed artifacts. |
| Artifacts | asd artifact-get | sd_artifact_get | --projectId --artifactId | Fetch one artifact in full, including nodes, evidence refs, and review state. |
| Artifacts | asd artifact-write | sd_artifact_write | --projectId --methodId --title --nodes [--edges] [--references] [--artifactId] | Write a method-produced artifact through the acceptance gate. |
| Methods | asd method-list | sd_method_list | [--phase] [--producesKind] | List methods from the registry. |
| Methods | asd method-run | sd_method_run | --methodId --projectId | Return the method contract, steps, inputs, and acceptance rules. |
| Review | asd review | sd_review | --projectId --artifactId --verdict --rows | Record a Critic pass or veto with evidence-cited review rows. |
| Review | asd review-list | sd_review_list | --projectId [--status] | Show the review board across draft and final artifacts. |
| Export | asd export-report | sd_export_report | --projectId --kind [--generatedAt] | Render a deterministic HTML report. |
| Export | asd export-artifact | sd_export_artifact | --projectId --artifactId [--width] | Render one artifact to deterministic SVG. |
| Knowledge | asd knowledge | sd_knowledge | [--query] [--phase] [--source] [--resourceQuery] [--resource] [--type] | Query methods, kinds, and optional corpus resources. |
| Factcheck | asd factcheck | sd_factcheck | --projectId | Replay integrity, acceptance, and review gates. Exit 1 on pass: false. |
| Templates/schema | asd template-list | sd_template_list | — | List the seven authored templates. |
| Templates/schema | asd template-get | sd_template_get | --id | Return one authored template and its body. |
| Templates/schema | asd schema-get | sd_schema_get | --kind | Return one registered artifact schema. |
| Templates/schema | asd practice-get | sd_practice_get | — | Return the machine-readable practice contract. |
| Canvas | asd canvas-add | sd_canvas_add | --projectId --label --url [--tool] | Link an external design canvas. |
| Canvas | asd canvas-list | sd_canvas_list | --projectId | List linked canvases. |
| Canvas | asd canvas-remove | sd_canvas_remove | --projectId --canvasId | Remove one canvas link without deleting the external file. |
| Orchestration | asd orchestration-plan | sd_orchestration_plan | --projectId --idempotencyKey --title --steps | Persist a host-independent plan. |
| Orchestration | asd orchestration-status | sd_orchestration_status | --projectId [--planId] | Read plans, dispatches, and handoffs. |
| Orchestration | asd orchestration-dispatch | sd_orchestration_dispatch | --projectId --planId --stepId --idempotencyKey --capability [--outcome] [--error] [--retryable] [--retryOf] | Persist one dispatch attempt. |
| Orchestration | asd orchestration-handoff | sd_orchestration_handoff | --projectId --planId --idempotencyKey --from --to --condition [--artifactId] [--artifactKind] | Persist a role-to-role handoff with an optional typed artifact pointer. |
| Phase | asd phase-advance | sd_phase_advance | --projectId --toPhase --idempotencyKey --approvalReceipt | Record a human-approved phase transition. |
Outside the 30 engine tools, the CLI also exposes asd help and asd --version. Everything else is the registry. That separation keeps the book simple: if a command begins with a practice verb such as project-create, method-run, or phase-advance, it is really the schema-backed tool under the hood.
Two CLI behaviors are worth memorizing because they surprise people coming from softer tools. First, booleans can be bare flags or explicit true/false, but arrays and objects must be valid JSON literals. Second, exit code 1 is overloaded on purpose: it means either a real usage or runtime error, or a completed gate returning a failing verdict such as sd_factcheck with \"pass\": false. That makes CI wiring simple. A green-looking report with a failing top-level gate cannot quietly slip through as success.
MCP Tools by Family
The MCP surface exposes the same 30 tools over newline-delimited JSON-RPC 2.0 on stdio. The naming stays explicit: sd_project_create, sd_method_run, sd_review, and so on. Hosts commonly prefix those names again when they mount the bundle, which is why a Claude Code transcript may show mcp__asd__sd_method_run even though the underlying tool remains sd_method_run.
What matters operationally is the family semantics. Project tools work on the workspace tree. Evidence tools allow only three evidence kinds: quote, telemetry, and document. Artifact writes always persist honestly: acceptance success still lands as draft when Critic review is outstanding, acceptance failure persists a draft with machine-readable failures, and a dangling evidence reference is rejected before any write. Review and phase tools are the governance spine, and they keep human authority separate from automated checks.
| Family | MCP tools | Key arguments | Boundary worth remembering |
|---|---|---|---|
| Project | sd_project_list, sd_project_create, sd_project_open | name, client, sector, service, optional phase; or projectId for open | Projects are files on disk. There is no hidden database. |
| Project | sd_project_status_set | projectId; status enum briefed, active, gated, blocked, archived; optional statusNote | Lifecycle status is the Kanban column, independent of design phase. Legal transitions run briefed → active → gated → blocked → archived; archived is reachable from any state and blocked ↔ active moves both ways. A same-status call is a no-op unless a note accompanies it. An unknown projectId fails, an illegal transition is rejected naming the legal targets, and a non-enum status exits 1. |
| Evidence | sd_evidence_add, sd_evidence_import, sd_evidence_query | kind is closed to quote, telemetry, document; import adds path, encoding, maxBytes, onError | Import never fetches URLs. It reads only workspace-local files and fails closed on invalid roots and malformed inputs. |
| Artifacts | sd_artifact_list, sd_artifact_get, sd_artifact_write | Write requires projectId, methodId, title, nodes; optional edges, references, artifactId | A failed acceptance check is not a crash. It is a persisted draft with failure rows. |
| Methods | sd_method_list, sd_method_run | List can filter by phase or producesKind; run requires methodId and projectId | sd_method_run returns the contract. It does not do the work for you. |
| Review | sd_review, sd_review_list | verdict is pass or veto; rows carry rowKind, severity, message, optional rule, fix, evidenceId | A veto needs at least one defect with a fix. A pass needs at least one evidence-cited row and cannot contain defects. |
| Export | sd_export_report, sd_export_artifact | Reports require kind; artifact export optionally takes width | Both outputs are deterministic derived files under renders/. |
| Knowledge | sd_knowledge | query, phase, source, resourceQuery, resource, type | This tool can search the registry and the bundled corpus in one call. |
| Factcheck | sd_factcheck | projectId | It replays integrity, acceptance, and review. Exit 1 on failure is a feature, not an exception. |
| Templates/schema | sd_template_list, sd_template_get, sd_schema_get, sd_practice_get | id for template lookup, kind for schema lookup, no arguments for practice contract | The seven authored templates do not imply one template per catalog row. |
| Canvas | sd_canvas_add, sd_canvas_list, sd_canvas_remove | label, url, optional tool where the enum is figma, penpot, paper, pencil, other | Canvas links are project records. They do not replace typed artifact writes. |
| Orchestration | sd_orchestration_plan, sd_orchestration_status, sd_orchestration_dispatch, sd_orchestration_handoff | Plan requires idempotencyKey, title, steps[{id, role, instruction, maxRetries?}]; dispatch adds stepId, capability, optional outcome, error, retryable, retryOf; handoff uses from, to, condition, optional artifactId, artifactKind | record-only is the generic supported dispatch capability. host-agent-spawn remains an explicit unsupported path unless a host adapter really implements it. |
| Phase | sd_phase_advance | toPhase, idempotencyKey, approvalReceipt{receiptId, approvedBy, decision, rationale, approvedAt} | The only legal receipt decision for advance is approve, and the human receipt never gets inferred from a passing artifact. |
Resources and Prompts
The MCP surface serves the corpus as resources and the role library as prompts. When the corpus roots are present, resources/list returns 228 resources total. The page size is 100, so a client that wants the full inventory must keep paginating by cursor until the list is exhausted. The URI space is intentionally small:
| URI pattern | What it serves |
|---|---|
asd://books/<book> | One book overview resource from the 20-book corpus. |
asd://books/<book>/<chapter> | One chapter resource from the book corpus. |
asd://articles/<NN> | One article resource from the method and case-study series. |
resources/read returns exact UTF-8 payload, MIME type, version, size, and logical provenance, never an absolute filesystem path. If the runtime is copied without its corpus roots, the list can legitimately come back empty while the 30 runtime tools still work. That is a visible boundary, not a silent fallback.
| Prompt name | Role |
|---|---|
orchestrator | Coordinates plans, handoffs, and human gates. |
researcher | Captures evidence and structures discovery work. |
synthesizer | Clusters, interprets, and sharpens evidence into insight. |
mapper | Builds journeys, ecosystems, mental models, and blueprints. |
ideator | Generates and filters service concepts. |
prototyper | Designs trials, walkthroughs, and prototype learning loops. |
measurer | Defines audit, measurement, maturity, and KPI logic. |
critic | Runs the evidence-cited review gate. |
presenter | Packages the work for human consumption without changing its facts. |
librarian | Maintains the catalog and curates knowledge growth. |
prompts/get returns the shared role contract followed by the role-specific instruction set as one user message. If ASD_AGENTS_ROOT is unavailable, the prompt list is empty by design. Again: explicit boundary, no fake fallback.
Client Configurations
The pack-local rule is simple: the emitted bundle’s launcher path is relative to the pack itself. When a client runs directly from the installed pack, the relative entrypoint is correct. When a client copies the snippet elsewhere, replace the relative path with an absolute path. The server launcher does not search PATH for a spare binary.
{
"mcpServers": {
"asd": {
"command": "node",
"args": ["mcp/bin/server.mjs"]
}
}
}
Claude Code uses the plugin-root variant:
{
"mcpServers": {
"asd": {
"command": "node",
"args": ["${CLAUDE_PLUGIN_ROOT}/mcp/bin/server.mjs"]
}
}
}
OpenCode uses the command-array form:
{
"$schema": "https://opencode.ai/config.json",
"mcp": {
"asd": {
"type": "local",
"command": ["node", "mcp/bin/server.mjs"]
}
}
}
Codex supports either the registration command or a TOML block:
codex mcp add asd -- node "$PWD/platform/packs/codex/mcp/bin/server.mjs"
[mcp_servers.asd]
command = "node"
args = ["mcp/bin/server.mjs"]
Those four snippets are enough to capture the pack-local rule and the three host-specific variants readers keep asking about. The operational nuance is that each host chooses its own working directory, which is why the relative bundle path is a rule of the installed pack, not a universal truth of the client machine.
Protocol and Error Codes
The stdio server speaks newline-delimited JSON-RPC 2.0 with MCP revision 2025-06-18. The lifecycle starts with one initialize call before tools/list, tools/call, resources/list, resources/read, prompts/list, or prompts/get. The response advertises tools, resources, and prompts, and identifies the server as asd-mcp version 0.1.0. Tool failures return MCP content blocks with isError: true; protocol framing remains valid.
{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-06-18"}}
Default tool timeout is 30 seconds. The frame limit is 1 MiB. Cancellation uses $/cancelRequest. Notifications remain silent. None of that is exotic, but it is precisely the kind of detail that matters when a client blames the server for behavior that actually belongs to the transport contract.
| Code | Meaning |
|---|---|
-32700 | Parse error. The incoming JSON frame is invalid. |
-32601 | Method not found. |
-32602 | Invalid params, unknown tool or prompt, bad cursor, or non-object arguments. |
-32603 | Unexpected internal handler failure. |
-32000 | Initialize required before the client can use the surface. |
-32001 | Tool call timed out. |
-32002 | Resource not found. |
One more boundary belongs here because it is easy to overclaim: ACP on the MCP surface is asd-acp/1 with capability record-only. The runtime can record orchestration plans, dispatch attempts, handoffs, and human gates. It does not prove that the host launched a new process. host-agent-spawn therefore remains an explicit unsupported path on the generic surface unless a host adapter really wires it up.
Environment and Workspace
ASD_WORKSPACE sets the root directory for projects. If I do nothing, the runtime uses ~/.asd/projects. That default is fine for live use. It is a bad idea for tests, demos, and disposable verification, which is why the docs push isolated temporary roots. The project tree itself is plain: project.json, evidence/index.json, artifact JSON files, exported renders, and sops/. Files are the record of truth.
export ASD_WORKSPACE="$(mktemp -d)/projects"
mkdir -p "$ASD_WORKSPACE"
asd project-create --name "Metrovale Access" --client "Fictional composite" \
--sector public-transport --service "step-free journeys" --phase discover
The MCP server adds three corpus-root environment variables beside the workspace root: ASD_BOOKS_ROOT, ASD_ARTICLES_ROOT, and ASD_AGENTS_ROOT. They control the served books, articles, and role prompts independently. That means a client can still use the 30 runtime tools even when the book corpus or prompt roots are unavailable.
| Variable | Default or typical value | What it controls |
|---|---|---|
ASD_WORKSPACE | ~/.asd/projects | Project file root for CLI and MCP runtime operations. |
ASD_BOOKS_ROOT | pack or checkout path | Book corpus resources under asd://books/<book>. |
ASD_ARTICLES_ROOT | pack or checkout path | Article corpus resources under asd://articles/<NN>. |
ASD_AGENTS_ROOT | pack or checkout path | Role prompt files exposed through prompts/list and prompts/get. |
buzz, claude-code, codex, kimi, mcp, and opencode. Each receipt proves initialize, 30 tools, 228 paginated resources, 10 prompts, and a representative project-to-review workflow from an isolated environment. It does not prove that every listed host has executed the pack in its native UI.The disposable verification pattern is stronger than it looks. Each verified bundle is run from an isolated HOME, PATH, current working directory, and workspace, then forced through a representative sequence: initialize, inspect the 30 tools, page through the 228 resources, load the 10 prompts, create a project, capture evidence, write an artifact, record an evidence-cited review, and replay factcheck. That is the right level of proof for a transport bundle. It shows pack-local interoperability without pretending that every host UI or every orchestration surface has already been exercised live.
That last sentence is the right place to stop. The CLI and MCP surfaces are fully specified, but they still obey the book’s broader honesty rule: prove what ran, say what the receipt covers, and do not promote an emitted pack into host-execution evidence unless the host actually exercised it.