Skip to content
Merged
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
64 changes: 46 additions & 18 deletions .claude/commands/hew/auto.md
Original file line number Diff line number Diff line change
@@ -1,30 +1,58 @@
---
description: Autonomously drain the queue via the process-level loop (`hew loop run --until-empty`).
description: Drive the loop in-conversation, walking the children of one active epic.
---

Run the autonomous outer loop until the ready queue drains:
In-conversation, epic-scoped driver. `/hew:auto` stays inside the
current Claude session and walks the children of one active epic in
dependency order — one continuous transcript, full mid-loop steering.

This is **not** the subprocess loop. For fresh-context-per-iter with
prompt-cache hits, hard caps, and per-iter logs on disk, use
[`/hew:loop`](./loop.md) (`hew loop run`).

## Pick the active epic

If the user named one in the prompt, use it. Otherwise:

```sh
hew loop run --until-empty
hew epic list # open epics
hew epic tree <epic-id> # children + dep order for the chosen epic
```

`--until-empty` is on by default — stop signals fire when the queue
hits zero, when a budget caps, when the operator touches the stop-file,
or on a runtime error. Use `--max-iter N` to bound the run, `--strict`
(default) to promote craft warnings to failures, `--budget-tokens N` /
`--budget-wall <duration>` for hard caps.
If exactly one open epic exists, pick it. If several, ask the user once
which to drive. Never default to the full `bd ready` set — that's the
subprocess loop's job.

## The walk

Until the active epic has no open children:

1. From `hew epic tree <epic-id>`, pick the next unblocked child
(lowest-id ties break by creation order). Skip closed/in_progress
children belonging to another assignee.
2. Tail-call `/hew:next` for that task. `/hew:next` claims, runs the
full `hew-execute` loop (read → code → tests → `hew-guard` → close
→ commit → optional `hew remember`), and returns.
3. Loop. The session stays focused on one epic at a time; cross-epic
work needs an explicit re-invocation.

Stop when:

Per-iter logs land in `.hew/loop/<run-id>/iter-NNN.json`. Inspect with
`hew loop list`, `hew loop logs --tail 5`, `hew loop cancel`.
- All children of the active epic are closed → run `/hew:verify`,
then offer to close the epic and report done.
- A Rule-4 architectural change blocks progress → surface to the
user and wait.
- The user interrupts.

For the in-conversation walk through the workflow (older `/hew:auto`
behavior — useful when you want to drive iters from inside one Claude
session rather than spawning fresh subprocesses), call `/hew:work` and
let it tail-call `/hew:next` until either:
Honor every `hew-execute` rule along the way (guard before close,
deviation tags in close reasons, atomic commits, branching contract).

- `hew status` ready list is empty (call `/hew:verify`, then report done), or
- a Rule-4 architectural change blocks you (stop, surface, wait).
## When to reach for `/hew:loop` instead

Honor all guard / deviation / convention rules; atomic commits per task.
- You want each task in a fresh context window with a cache-warm
prefix.
- You want hard caps (token / wall-clock / max-iter) and per-iter
logs to disk.
- You're draining the global ready queue, not focusing one epic.

See `docs/LOOP.md` for the full design.
See [`docs/LOOP.md`](../docs/LOOP.md) for the full design.
29 changes: 21 additions & 8 deletions .claude/commands/hew/loop.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,14 @@ ready-queue empty, stop-file, max-iter, runtime error).
Common invocations:

```sh
hew loop run --dry-run --max-iter 1 # smoke: prompt-assemble, no spawn
hew loop run --until-empty # drain the ready queue (default on)
hew loop run --max-iter 5 --strict # bounded run, craft warnings = fail
hew loop run --budget-tokens 200000 # cap cumulative tokens
hew loop run --budget-wall 30m # cap wall clock
hew loop run --scope=ready --dry-run --max-iter 1 # smoke: prompt-assemble, no spawn
hew loop run --scope=ready --until-empty # drain the ready queue (default on)
hew loop run --scope=epics --epics=hew-6az # only tasks under one epic
hew loop run --scope=ready --max-iter 5 --strict # bounded run, craft warnings = fail
hew loop run --scope=ready --budget-tokens 200000 # cap cumulative tokens
hew loop run --scope=ready --budget-wall 30m # cap wall clock
hew loop run --scope=ready --runtime=codex # drive codex-cli instead of claude
hew loop run --scope=ready --fallback-runtime=codex # swap to codex on primary RuntimeError

hew loop list # recent runs + state
hew loop logs --tail 5 # last 5 iters of latest run
Expand All @@ -30,9 +33,19 @@ Per-iter artifacts land in `.hew/loop/<run-id>/`:
the loop to halt at the next iter boundary

The loop runner is process-level: each iter is one fresh `claude -p`
invocation. Prompt prefix (skill body + memory primer) is byte-stable
across iters of the same skill so Anthropic's prompt cache hits;
`prompt_prefix_hash` in the iter log lets you verify that.
(or `codex exec`) invocation. Prompt prefix (skill body + memory primer)
is byte-stable across iters of the same skill so the agent's prompt
cache hits; `prompt_prefix_hash` in the iter log lets you verify that.
`--fallback-runtime` is primary-sticky with a configurable cooldown
(`--fallback-cooldown-iters`, default 3); see `docs/LOOP.md` for the
full state machine.

**Scope is required.** Every `hew loop run` invocation declares which
slice of `bd ready` it consumes — `--scope=ready` for the whole queue,
or `--scope=epics --epics=<csv>` for tasks transitively under one or
more epics. Interactive runs get a picker; agent-driven runs that omit
the flag exit with `MissingFlag { flag: "scope" }`. See `docs/LOOP.md`
§ Scope.

For the full design + the 10 locked decisions behind the loop, see
`docs/LOOP.md` and the `hew-gr1` epic.
10 changes: 8 additions & 2 deletions .claude/commands/hew/ship.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,11 @@ description: Create a PR and (optionally) a gate for the next epic.
After the current epic verifies clean:
1. Push the branch (if not already on main).
2. Open a PR with a summary auto-generated from closed task descriptions.
3. Optionally create a Beads gate (gates aren't wrapped by `hew task new`; use bd directly): `bd create --type=gate --title="PR #N merged" --await-type=gh:pr --await-id=N`
4. Add the gate as a dependency of the next epic via `hew dep add <next-epic> --on <gate-id>` so the agent waits for merge.
3. Optionally create an external-state gate that blocks the next epic on
this PR's merge: `hew gate new --gh-pr=N --title="PR #N merged"`
(returns a gate task id). Backed by `gh pr view N --json state,mergedAt`;
the gate resolves when GitHub reports `state=MERGED`.
4. Wire the gate as a dependency of the next epic via
`hew dep add <next-epic> <gate-id>` so the loop blocks on merge.
5. Run `hew gate poll` periodically (or wire into a loop hook) to flip
resolved gates from open → done and unblock downstream work.
9 changes: 6 additions & 3 deletions .claude/skills/hew/SKILL.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<!-- hew:version=0.10.0 -->
<!-- hew:version=0.11.0 -->
---
name: hew
description: Index of installed hew skills. Loaded by the agent on session start.
Expand Down Expand Up @@ -156,7 +156,10 @@ Do not create planning markdown files (`PLAN.md`, `TODO.md`, `ROADMAP.md`,
code, not plans.

Do not use string-prefixed task titles (`"GATE: ..."`, `"PHASE: ..."`) to fake
structural roles. Beads has native types: `--type=gate`, `--type=epic`,
`bd mol bond`. Use them.
structural roles. Use the typed surfaces: `--type=epic` for hierarchical
containers, `--type=decision` for ADR-shaped records, and the dedicated
`hew gate` command for external-state gates (PR merge / future
issue-close / etc). `bd mol bond` is documented broken — wire cross-epic
ordering with `hew dep add` instead.

Do not skip the `hew-guard` step before `hew task close`. Drift compounds.
2 changes: 1 addition & 1 deletion .claude/skills/hew/brownfield/hew-audit.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<!-- hew:version=0.10.0 -->
<!-- hew:version=0.11.0 -->
---
name: hew-audit
category: brownfield
Expand Down
2 changes: 1 addition & 1 deletion .claude/skills/hew/brownfield/hew-boundary.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<!-- hew:version=0.10.0 -->
<!-- hew:version=0.11.0 -->
---
name: hew-boundary
category: brownfield
Expand Down
2 changes: 1 addition & 1 deletion .claude/skills/hew/brownfield/hew-convention.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<!-- hew:version=0.10.0 -->
<!-- hew:version=0.11.0 -->
---
name: hew-convention
category: brownfield
Expand Down
2 changes: 1 addition & 1 deletion .claude/skills/hew/brownfield/hew-migrate.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<!-- hew:version=0.10.0 -->
<!-- hew:version=0.11.0 -->
---
name: hew-migrate
category: brownfield
Expand Down
2 changes: 1 addition & 1 deletion .claude/skills/hew/brownfield/hew-scan.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<!-- hew:version=0.10.0 -->
<!-- hew:version=0.11.0 -->
---
name: hew-scan
category: brownfield
Expand Down
2 changes: 1 addition & 1 deletion .claude/skills/hew/core/hew-checkpoint.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<!-- hew:version=0.10.0 -->
<!-- hew:version=0.11.0 -->
---
name: hew-checkpoint
category: core
Expand Down
106 changes: 94 additions & 12 deletions .claude/skills/hew/core/hew-decompose.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<!-- hew:version=0.10.0 -->
<!-- hew:version=0.11.0 -->
---
name: hew-decompose
category: core
Expand Down Expand Up @@ -214,6 +214,63 @@ Heuristics for "too small":

Then merge it into the next task.

### Batch mode — `bd create --graph` for >3 tasks

`hew task new` in a loop hits `GOTCHA:zsh-cmd-substitution`: multi-line
descriptions with apostrophes, backticks, or `$(…)` substitutions blow up
the shell before they reach bd. For any decomposition above ~3 tasks,
emit a single graph-JSON file and run `bd create --graph plan.json` —
one transaction, deps wired inline, content passes through verbatim
(apostrophes/quotes/backticks/`$(…)` all survive).

This is a **documented bd hold-out**: `hew` doesn't wrap batch creation;
`bd create --graph` is the path.

```json
{
"nodes": [
{"key": "epic", "title": "Auth System", "type": "epic", "priority": 1,
"description": "JWT auth for /api/v1/*. See DECISION:auth."},

{"key": "contracts", "parent_key": "epic", "title": "Define auth contracts",
"type": "task", "priority": 1,
"description": "**Why:** interface-first ordering.\n**What:** AuthResponse, RefreshRequest, route paths /login /refresh /logout.\n**Files:** app/api/v1/auth/types.py."},

{"key": "login", "parent_key": "epic", "title": "Implement POST /login",
"type": "task", "priority": 1,
"description": "**Why:** D-04. **What:** validates body, returns AuthResponse.\nApostrophes', \"quotes\", $(this) and `backticks` all pass through verbatim.\nFiles: app/services/auth_service.py, tests/api/test_login.py."},

{"key": "refresh", "parent_key": "epic", "title": "Implement /refresh + rotation",
"type": "task", "priority": 1,
"description": "**What:** rotation-on-use, revoke-old, reuse-detection."}
],
"edges": [
{"from_key": "login", "to_key": "contracts", "type": "blocks"},
{"from_key": "refresh", "to_key": "contracts", "type": "blocks"}
]
}
```

Run it:

```
bd create --graph plan.json
# Created 4 issues
# epic -> hew-a3f8
# contracts -> hew-a3f8.1
# login -> hew-a3f8.2
# refresh -> hew-a3f8.3
```

Schema cheat-sheet:

- **`nodes[].key`** — local-only handle, used by edges and parent_key. Discarded after creation.
- **`nodes[].parent_key`** / **`nodes[].parent_id`** — wire hierarchy. Use `parent_key` for siblings in the same plan; `parent_id` for an already-existing parent (e.g. `"hew-a3f8"`).
- **`nodes[].type`** — `task` / `epic` / `feature` / `bug` / `chore` / `decision`. (No `gate` type — see Step 5.)
- **`edges[].from_key` / `to_key`** — `from` is the dependent (blocked); `to` is the prerequisite. `type` is typically `"blocks"`.

For a one-off task with no hostile content, plain `hew task new` is still fine. Reach for `--graph` when the plan is >3 tasks or any description carries shell-hostile characters.

## Step 4 — wire dependencies

A task `hew dep add <child> --on <prerequisite>` if it cannot start until
Expand All @@ -236,20 +293,27 @@ hew dep add hew-X.4 --on hew-X.2

## Step 5 — place gates for external blockers

Gates are for anything outside the Beads graph. Never fake a gate with a
title prefix. Create the blocked task first, then attach a gate to it.
Gates are for anything outside the Beads graph (a PR has to merge, CI
has to go green, a human has to approve). Never fake a gate with a title
prefix. Create the gate first, then wire it as a prerequisite of the
blocked task.

| Trigger | Command |
|---------|---------|
| Wait for PR merge | `bd gate create --type=gh:pr --blocks=<task-id> --await-id=42 --reason="PR #42 merge"` |
| Wait for CI | `bd gate create --type=gh:run --blocks=<task-id> --await-id=<run-id> --reason="CI green"` |
| Manual approval | `bd gate create --type=human --blocks=<task-id> --reason="Staging approved"` |
| Timer / cooldown | `bd gate create --type=timer --blocks=<task-id> --timeout=30m` |
| Wait for PR merge | `hew gate new --gh-pr=42 --title="PR #42 merged"` |
| Wait for CI / issue close / cmd | (deferred — only `--gh-pr` ships in v1; the `GateKind` enum scaffolds `GhIssue` / `GhRun` / `Cmd`) |
| Manual approval | create a normal task with title `"Approval: <thing>"`, leave it open until human closes — no special primitive needed |

Gate creation is a documented hold-out — `hew` has no `gate` wrapper yet
(`bd gate create` stays the path; `bd gate resolve <id>` closes manual
gates). Inspect with `bd gate list`. The `--blocks` flag does the
dependency wiring inline, so no separate `hew dep add` is needed.
Then attach the gate to the blocked task:

```
GATE=$(hew gate new --gh-pr=42 --title="PR #42 merged" --quiet)
hew dep add <next-epic> "$GATE"
```

Resolve gates periodically (or wire into a loop hook): `hew gate poll`
queries the external source and closes any whose state has resolved
(`MERGED` for `--gh-pr`). Inspect with `hew gate list`.

## Step 6 — pick types and priorities

Expand All @@ -260,7 +324,10 @@ dependency wiring inline, so no separate `hew dep add` is needed.
| `bug` | semantic alias — surfaces in bug queries |
| `chore` | refactor, cleanup, non-feature |
| `epic` | container; only closes when all children close |
| `gate` | external blocker (above) |
| `decision` | ADR-shaped record |

(External-blocker gates use the dedicated `hew gate` surface above, not
a task type — see Step 5.)

| `--priority=` | Meaning |
|---------------|---------|
Expand All @@ -275,6 +342,21 @@ dependency wiring inline, so no separate `hew dep add` is needed.
Priority inflation kills the signal. Reserve P0 for the critical path. If
everything is P0, you have not decomposed enough.

### Optional — flag heavy tasks for a stronger model

If one task in the batch is meaningfully harder than the rest
(thorny refactor, gnarly algorithm, architectural call inside the
slice), route just that task to a stronger model when `hew loop`
spawns it. Two cheap surfaces, both per-task:

- Add `<!-- hew:model=opus-4-7 -->` anywhere in the description.
- Or `bd label add <id> model:opus-4-7` after the task lands.

For batch-wide policy (e.g. "every P0 runs on opus-4-7"), use
`hew config set loop.model.by_priority.P0 opus-4-7` once and skip
the per-task annotation. See `docs/LOOP.md` "Per-task model
selection" for the full precedence chain.

## Step 7 — concrete example, end to end

User asks for "auth on an existing FastAPI app." Plan is approved.
Expand Down
13 changes: 9 additions & 4 deletions .claude/skills/hew/core/hew-execute.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<!-- hew:version=0.10.0 -->
<!-- hew:version=0.11.0 -->
---
name: hew-execute
category: core
Expand Down Expand Up @@ -457,9 +457,14 @@ it out. Future-you saves the lookup time.

Run `hew prime execute` again. Pick the next ready task. Continue.

If the user said "do this one task," stop after closing it. If "keep going"
or `/hew:auto`, loop until `hew prime execute` shows no ready tasks (then call `hew-verify`) or
a Rule-4 architectural decision blocks you (then surface and stop).
If the user said "do this one task," stop after closing it. If "keep going,"
loop until `hew prime execute` shows no ready tasks (then call `hew-verify`)
or a Rule-4 architectural decision blocks you (then surface and stop).

If invoked via `/hew:auto`, the walk is scoped to the children of one
active epic (`hew epic tree <id>`), not the global `bd ready` set —
finish the epic, run `/hew:verify`, then stop. For the subprocess loop
that drains the global queue with cache-warm prefixes, see `/hew:loop`.

### Step 10a — review picker (optional, config-gated)

Expand Down
2 changes: 1 addition & 1 deletion .claude/skills/hew/core/hew-guard.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<!-- hew:version=0.10.0 -->
<!-- hew:version=0.11.0 -->
---
name: hew-guard
category: core
Expand Down
2 changes: 1 addition & 1 deletion .claude/skills/hew/core/hew-new-project.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<!-- hew:version=0.10.0 -->
<!-- hew:version=0.11.0 -->
---
name: hew-new-project
category: core
Expand Down
Loading
Loading