---
title: Claude Code Plugin
description: Install the smithers Claude Code plugin and every Smithers run driven from Claude Code shows up live in the /workflows tree, with approvals and failures delivered to the session as notifications.
---

The repository ships a first-party Claude Code plugin at `claude-plugin/`. Installing it wires four things into every Claude Code session:

1. **The `smithers` MCP server** (`bunx smithers-orchestrator --mcp`): `list_workflows`, `run_workflow`, `watch_run`, `resolve_approval`, `ask_human`, and the rest of the semantic tool surface.
2. **The `smithers` skill**: teaches Claude to run durable, multi-step, or background work through Smithers instead of hand-rolled subagent trees, and to consult `https://smithers.sh/llms-full.txt` before writing any workflow code.
3. **The `/workflows` mirror**: a generic Workflow-tool script, `workflows/smithers-run.mjs`, that launches or attaches to a Smithers run and mirrors it live into Claude Code's `/workflows` progress tree. Works for every workflow with zero per-workflow setup.
4. **A background monitor** (experimental Claude Code component): `smithers claude monitor` streams approval requests, human-input requests, failures, and stalled-heartbeat warnings into the session as notifications, so Claude reacts even when no mirror is running. Finished and cancelled runs are not broadcast by default: the workspace store is shared by every session, so those FYI lines would wake each session for every other session's runs, and a run this session follows already reports completion through its `/workflows` mirror. Pass `--transitions all` to stream them anyway.

## The /workflows mirror

Claude Code's `/workflows` tree can only be populated from inside a session by a Workflow-tool script. The plugin therefore ships one generic script; the real work always stays in the Smithers engine, and the mirror is a live view. Claude launches it like this:

```
Workflow({
  scriptPath: "<plugin>/workflows/smithers-run.mjs",
  args: { workflow: "my-workflow", input: { ... } }
})
```

In launch mode the script starts the detached run itself and logs the runId. Passing `args: { runId: "run-123" }` instead attaches to an existing run (after a session restart, or for a run started elsewhere). The SessionStart hook announces the script's absolute path in every `.smithers` project, together with the number of non-terminal runs to re-attach to.

What the mirror renders:

- **Phases** from the workflow's real container tree: `Workflow name`, `Sequence label`, `Parallel label`, loop containers. Labels are read from the run's persisted frames, so data-dependent fan-outs and loop iterations appear as they materialize.
- **One row per node**: agent, human, approval, and dynamically discovered nodes by default (`mirrorAllNodes: true` in `args` adds compute/static rows). A running node gets a live watcher row that resolves with the node's output; nodes that finished before a slot freed get a completion row.
- **Approval and human-request banners** as narrator lines, with the exact resolving command.
- **Continue-as-new is followed**: when a run continues as a new runId, the mirror switches to it automatically.
- **Caps respected**: at most 6 live watcher rows at a time (the sync loop must never queue behind its own watchers), a 900-agent budget, and per-phase summary rows for runs above 150 nodes. Every cap logs when it engages.

Stopping the mirror workflow never stops the Smithers run. Cancelling the run is explicit: `bunx smithers-orchestrator cancel RUN_ID` (or the gateway `cancelRun` RPC).

## The `smithers claude` protocol

The mirror's agents run exactly one CLI command each and relay its JSON. All derivation and all blocking happens inside the CLI, against the durable store, under a frozen wire contract (`"contract": 1` in every response):

```bash
smithers claude tick RUN_ID --after-seq 412 --wait --timeout-ms 420000 --format json
```

One complete mirror frame: run status, event-log cursor (`seq`), the latest frame's phase plan, every node with `{nodeId, label, phase, kind, state}`, the nodeIds that changed after `--after-seq`, truncated outputs of nodes that became terminal, pending approvals and human requests, and `continuedAs` for continued runs. `--wait` blocks until a mirror-relevant event lands (tool-call and heartbeat chatter is ignored), the run reaches a terminal status, or the timeout expires (`"timedOut": true`, exit 0). With `--wait`, a store or run that does not exist yet is waited for too, so a mirror launched right after `workflow run --detach` cannot race the engine's first write.

```bash
smithers claude node-wait NODE_ID --run-id RUN_ID --timeout-ms 480000 --format json
```

Blocks until one node reaches a terminal state, then reports `{state, output, vanished, timedOut}`. A node pruned by a later frame reports `state: "skipped", vanished: true`. Watchers re-invoke on `timedOut: true`, which is how a row outlives the 10-minute Bash cap on multi-hour nodes.

```bash
smithers claude monitor
```

NDJSON follower for the plugin monitor: one line per notable transition (`approval-pending`, `human-request`, `run-finished`, `run-failed`, `run-cancelled`, `run-continued`, `run-stalled`), each with a summary and the resolving command. It does not replay history; already-pending gates are surfaced once at startup. In a project without a Smithers store it exits silently.

These commands are protocol surface for the plugin. Keep responses additive; a breaking shape change bumps `contract` and the shipped script refuses mismatched majors with an actionable message.

## Install

From the repository checkout (or a marketplace once published):

```bash
claude plugin install /path/to/smithers/claude-plugin
```

Nothing else is required. The MCP server and CLI run through `bunx smithers-orchestrator`, so the first invocation bootstraps the CLI from npm. In a project without `.smithers/`, the skill initializes Smithers before the first run.

## Failure modes

| Situation | Behavior |
| --- | --- |
| Plugin and CLI versions drift | `tick` responses carry `contract`; the mirror script stops with an update instruction instead of rendering wrong data |
| Claude Code without monitor support | monitors are additive; skill, MCP, and mirror work without them |
| Headless session without the MCP server | the mirror is CLI-over-Bash only and keeps working |
| Mirror stopped mid-run | the run continues; re-attach with `args: { runId }` |
