Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .claude-plugin/marketplace.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
{
"name": "claude-code-setup",
"description": "Marketplace for the cw plugin, a design/build/ship workflow of skills, orchestration agents, and guardrail hooks for Claude Code.",
"owner": {
"name": "Victor Kzam"
},
Expand Down
2 changes: 1 addition & 1 deletion .claude-plugin/plugin.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "cw",
"version": "1.0.0",
"version": "1.0.1",
"description": "Claude Code workflow plugin: design/build/ship skills, orchestration agents, and guardrail hooks.",
"author": {
"name": "Victor Kzam"
Expand Down
70 changes: 61 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# cw — a Claude Code workflow plugin

This repo *is* the Claude Code plugin `cw`: six skills, five agents, three
This repo *is* the Claude Code plugin `cw`: six skills, five agents, four
hooks, three rule files, one test runner, and CI. It implements a
`/cw:design` -> `/cw:build` -> `/cw:ship` pipeline — research-grounded
planning, delegated implementation with one atomic commit per task, and a
Expand Down Expand Up @@ -79,15 +79,27 @@ Loads the plugin for that session only.
`disable-model-invocation: true` deliberately — they change files, branches,
or open PRs, so they only run when you type the command.

### The design review loop

`/cw:design` converges with two `cw:design-reviewer` rounds by default (a
third only after a verified critical finding survives round two), then runs
`cw:direction-reviewer` once, but only when the design is architectural (a new
subsystem, a public interface or schema, or a change to the loop itself).
Append `lite` — `/cw:design <description> lite` — for a fix-up touching three
files or fewer: one research angle, one review round, no direction pass. A
review round that comes back with no parseable verdict follows the stall ladder
in `rules/orchestration.md` (nudge, nudge, respawn, escalate) rather than a
blind retry.

## Agents

| Agent | Model | Role |
|---|---|---|
| `cw:researcher` | sonnet | Web research, read-only |
| `cw:implementer` | sonnet (opus per-task for hard work) | Writes code, makes the task's commit |
| `cw:reviewer` | opus | Reviews an implementer's diff, read-only |
| `cw:design-reviewer` | opus | Doc/codebase fidelity review of a design draft |
| `cw:direction-reviewer` | opus, effort xhigh | Premise/direction review, once per design |
| Agent | Model | Turn cap | Role |
|---|---|---|---|
| `cw:researcher` | sonnet | 30 | Web research, read-only |
| `cw:implementer` | sonnet (opus per-task for hard work) | 50 | Writes code, makes the task's commit |
| `cw:reviewer` | opus | 40 | Reviews an implementer's diff, read-only |
| `cw:design-reviewer` | opus | 40 | Doc/codebase fidelity review of a design draft |
| `cw:direction-reviewer` | opus, effort xhigh | 15 | Premise/direction review, once per architectural design |

`/cw:design` also spawns the built-in `Explore` agent with `model: haiku` on
each call; the plugin ships no agent by that name — its agents load under the
Expand Down Expand Up @@ -186,7 +198,7 @@ claude plugin disable cw@skills-dir # install path (a)
claude plugin disable cw@claude-code-setup # install path (b)
```

Turns all three hooks off at once. This is also the answer for a repo that
Turns all four hooks off at once. This is also the answer for a repo that
pushes to `main` by convention — `protect-branches.sh` has no opt-out
environment variable by design, so disabling the plugin is the supported
escape hatch, not a bypass flag on the hook itself.
Expand Down Expand Up @@ -216,6 +228,46 @@ and a line of prose that spells out a push to the default branch inside a
command is blocked as if it were the command itself — keep such text in a file
instead.

## Notifications

Opt-in: create `${CLAUDE_CONFIG_DIR:-$HOME/.claude}/cw-notify.json` — an empty
`{}` turns it on with every default. `notify.sh` binds to `Notification`,
`Stop` and `StopFailure`, pinging only when a human is actually waited on.

Immediate pings (`Notification`): `permission_prompt` ("Permission needed"),
`worker_permission_prompt` ("Permission needed (worker)", agent teams),
`elicitation_dialog`/`elicitation_url_dialog` ("Input needed"), and
`agent_needs_input`/`push_notification` (the event's message, or "Attention
needed"). Inside a sub-agent only the two permission types pass, naming the
agent type. Silent by design: `agent_completed`, `auth_success`,
`computer_use_enter`/`computer_use_exit`, and the three quota types — a
completed agent isn't a human wait, and quota events are noise.

The waiting ping is the built-in `idle_prompt`, about 60 seconds after a turn
ends, gated on the background-task count every `Stop` records for the session
(`StopFailure` records 0): it pings only when that count is 0, and a missing
or stale record (older than `stale_seconds`) also counts as 0, so the hook
fails open.

Config keys in `cw-notify.json`, all optional: `enabled` (true), `presence`
(false), `idle_seconds` (300), `stale_seconds` (1800), `entrypoints`
(`["cli"]`), `idle_message` ("Waiting for your input"). `presence`, off by
default, only routes delivery: idle past `idle_seconds`, or a locked screen
with a Remote Control bridge, skips the banner (the phone channel already
delivers); a probe failure counts as "at the machine". `CW_NOTIFY=0` is the
kill switch; `CW_NOTIFY_DRY_RUN=1` prints the banner line instead of showing
it. Title is `<folder> · <session>` from the session registry, or the folder
alone when the registry is absent.

Linux delivers through `notify-send` when present, otherwise nothing. macOS
15+ delivers the banner as **Script Editor** and needs that app allowed under
System Settings › Notifications, or the hook exits 0 silently
(practitioner-sourced — Apple doesn't document this).

If a profile still has a user-level `Notification` hook in `settings.json`
from before this plugin, remove it by hand: `notify.sh` replaces it, and a
plugin hook and a settings hook bound to the same event both fire.

## Migration from the old installer

If you previously installed this project's files directly into `~/.claude`
Expand Down
26 changes: 17 additions & 9 deletions WORKFLOW.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,14 @@ closes the loop by feeding lessons back into project rules.
Plan mode. Reads project context, spawns `Explore` (haiku) and
`cw:researcher` (sonnet) subagents in parallel to ground the plan in the real
codebase and current sources, drafts one plan file with a task list, then
loops `cw:design-reviewer` (fresh context each pass, until findings converge,
escalating after 5 iterations) followed by `cw:direction-reviewer` once.
loops `cw:design-reviewer` — fresh context each pass, two rounds by default, a
third only after a verified critical finding survives round two — followed by
`cw:direction-reviewer` once, but only when the design is architectural (a new
subsystem, a public interface or schema, or a change to the loop itself).
`/cw:design <description> lite` trims this to one research angle, one review
round and no direction pass, for a fix-up touching three files or fewer. A
review round with no parseable verdict follows the stall ladder in
`rules/orchestration.md` rather than a blind retry.

The skill calls `ExitPlanMode` itself when the review loop converges — that
approval only ends drafting; it is not the real checkpoint. Plan mode writes
Expand Down Expand Up @@ -54,8 +60,8 @@ itself a permission mode). The orchestrating session:
5. Spawns `cw:reviewer` — a different model tier than the implementer used —
to review the diff fresh from disk. `NEEDS_WORK` respawns a new
implementer with the feedback (up to 2 retries); a reviewer that returns
no parseable verdict at all is retried once fresh, not treated as a pass
or a fail.
no parseable verdict is neither a pass nor a fail — it follows the stall
ladder in `rules/orchestration.md` and never consumes a review iteration.
6. Stops for your approval once every task's commit is in and the tasks-file
quality gate passes.

Expand Down Expand Up @@ -99,24 +105,26 @@ driving Google Docs/Drive from Claude, triggered when a task needs one.
format, checkpoints, mode transitions) and is meant to be imported by a
profile's `CLAUDE.md`. `rules/orchestration.md` carries the model-routing
table (public aliases, route-up-for-hard-work, the workflow-fan-out
threshold) and the review-loop semantics (`NO_VERDICT` vs `NEEDS_WORK`,
counter-model review, ground-truth verification). If a rule and this file
ever disagree, the rules file wins.
threshold) and the review-loop semantics (the stall ladder for a missing or
unparseable verdict, distinct from `NEEDS_WORK`, counter-model review,
ground-truth verification). If a rule and this file ever disagree, the rules
file wins.

## Hooks

Three hooks, registered by the plugin itself (`hooks/hooks.json`), fire in
Four hooks, registered by the plugin itself (`hooks/hooks.json`), fire in
every session the plugin is enabled in:

| Hook | Event | What it does |
|---|---|---|
| `protect-branches.sh` | PreToolUse (Bash) | Blocks a push whose destination is main/master, and any force push |
| `protect-secrets.sh` | PreToolUse (Write\|Edit\|MultiEdit\|NotebookEdit) | Blocks writes to `.env`, credentials, keys, and similar secret paths |
| `profile-check.sh` | SessionStart | Warns if the active profile doesn't match `~/.claude-profiles`, or if a `CLAUDE.md` `@import` target is missing |
| `notify.sh` | Notification, Stop, StopFailure | Opt-in desktop notifier, gated on `cw-notify.json` — see README's Notifications section |

A hook that exits non-zero is enforced, not advisory — CLAUDE.md conventions
get followed inconsistently; a `PreToolUse` hook that exits 2 blocks the call
outright. `claude plugin disable cw@<source>` turns all three off at once.
outright. `claude plugin disable cw@<source>` turns all four off at once.

## Tests

Expand Down
12 changes: 10 additions & 2 deletions agents/design-reviewer.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ name: design-reviewer
description: "Reviews a finalized design draft against the real codebase, current web best practices, and internal consistency. Returns a strict JSON verdict. Read-only — cannot modify files. Used by the /cw:design auto-review loop."
model: opus
effort: high
maxTurns: 25
maxTurns: 40
tools:
- Read
- Glob
Expand All @@ -15,7 +15,6 @@ tools:
- mcp__context7__resolve-library-id
- mcp__context7__query-docs
- Skill
memory: project
color: purple
---

Expand Down Expand Up @@ -61,6 +60,14 @@ the prompt.
- Only raise an issue you can back with evidence; if the design is sound,
say PASS.

## Budget
Your turn budget is finite and stated in the prompt; you have no write tool,
so there is no report file — keep a running list of confirmed issues in your
own reasoning as you go. Emit the JSON verdict once every method step is
done, or once roughly two thirds of the budget is spent, whichever comes
first. A step you did not reach goes under `unchecked`, not silently
dropped.

## Output — strict JSON only

Emit exactly one JSON object as your final message, no prose around it:
Expand All @@ -76,6 +83,7 @@ Emit exactly one JSON object as your final message, no prose around it:
"evidence": "file:line, citation, or contradiction location"
}
],
"unchecked": ["method step or claim not reached before the budget cutoff"],
"suggested_fixes": ["concrete, ordered fixes the orchestrator can apply"]
}
```
Expand Down
4 changes: 2 additions & 2 deletions agents/direction-reviewer.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ tools:
- Read
- Glob
- Grep
memory: project
color: red
---

Expand Down Expand Up @@ -57,7 +56,8 @@ Read both fresh.

## Output — strict JSON only

Emit exactly one JSON object as your final message, no prose around it:
Emit exactly one JSON object as your final message, no prose around it: the
JSON is the whole final message.

```json
{
Expand Down
11 changes: 8 additions & 3 deletions agents/implementer.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,16 +26,21 @@ scoped task from an orchestrator and execute it precisely.
- Consult framework and library docs (via the context7 tools) before relying
on an unfamiliar API surface.
- Make one logical change per commit, in conventional commit format.
- Commit as instructed by the orchestrator: one commit for the task, carrying
whatever trailer the project's workflow rules define.
- As soon as `verification` passes, stage and commit by explicit pathspec
(`git add -- <files> && git commit -- <files>`) before any optional check,
tidy-up, or re-read. Carry whatever trailer the project's workflow rules
define.
- If the design is ambiguous, make a reasonable choice and note it in your
output — do not stop to ask.
- Do not push commits or open pull requests; that is the orchestrator's job.
- Stay inside the files you were scoped to; flag anything outside that scope
instead of touching it.

## Output
When done, provide a concise summary:
Write full working notes to the report file the prompt names, not to the
final message; the exit report is the last thing you write — do not spend
turns on notes or memory beyond it. Your final message is at most about ten
lines:
1. Files created or modified
2. Design deviations, if any, and why
3. Test and build results
Expand Down
17 changes: 7 additions & 10 deletions agents/researcher.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,15 +45,12 @@ with the Skill tool rather than assuming its steps are already loaded.
gap.

## Output format (required)
Your final message is at most about 1,500 tokens: numbered findings, no
narrative, no restated questions.

### Findings
- [Claim] — Source: [URL] ([publisher], [date if available]) — Confidence: high|medium|low
1. [Claim], 2-3 lines. Grade: H (official docs) | M (practitioner, with
numbers) | L (inference). Source: [one URL].
2. ...

### Consensus
[strong|weak|conflicting] across [N] sources

### Gaps
- [What could not be verified or found]

### Recommendation
[One paragraph: what the evidence points to and why]
### Unsourced
- [Claim you could not back with a citation, stated plainly as a guess]
23 changes: 16 additions & 7 deletions agents/reviewer.md
Original file line number Diff line number Diff line change
@@ -1,22 +1,22 @@
---
name: reviewer
description: "Code review agent. Reviews changes for quality, correctness, and convention adherence. Read-only — cannot modify files. Used by the /cw:build review loop."
description: "Code review agent. Reviews changes for quality, correctness, and convention adherence. No Write or Edit tool; Bash writes only the report file the prompt names, nothing else in the tree. Used by the /cw:build review loop."
model: opus
effort: high
maxTurns: 20
maxTurns: 40
tools:
- Read
- Glob
- Grep
- Bash
memory: project
color: yellow
---

# Code Reviewer

You review code changes against the project's conventions and the approved
design. You have no Write or Edit tool: you are read-only.
design. You have no Write or Edit tool; Bash writes only the report file the
prompt names, nothing else in the tree.

## Process
1. Read the project's CLAUDE.md for conventions.
Expand All @@ -39,12 +39,21 @@ Every finding needs a `file:line` and either a failing command or a concrete,
reproducible scenario. Drop a finding you cannot back with evidence rather
than listing it anyway.

## Budget
Your turn budget is finite and stated in the prompt. Open the report file
the prompt names on your first turn and append each finding as you confirm
it (Bash `>>`), not in a batch at the end. Emit the final JSON verdict once
every check is done, or once roughly two thirds of the budget is spent —
whichever comes first. A check you did not reach goes under `unchecked`, not
silently dropped. No memory notes, no summary beyond the report file and the
final JSON.

## Output — required structured verdict
Your final message must end with a fenced JSON block matching exactly this
schema:
Your final message is the fenced JSON block below plus one line naming the
report file, nothing else:

```json
{"verdict": "PASS|NEEDS_WORK", "findings": [{"file": "...", "line": 0, "issue": "...", "evidence": "..."}]}
{"verdict": "PASS|NEEDS_WORK", "findings": [{"file": "...", "line": 0, "issue": "...", "evidence": "..."}], "unchecked": ["..."]}
```

Start each finding's `issue` text with its severity: `critical` (wrong
Expand Down
31 changes: 28 additions & 3 deletions docs/plans/cw-plugin/cw-plugin-design-draft.md

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading
Loading