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
13 changes: 13 additions & 0 deletions SKILL.md
Original file line numberDiff line numberDiff line change
Expand Up@@ -18,6 +18,19 @@ Start → Go. (Or granular: Intake → Capture → Verify → Run.)

Work-item storage is pluggable (`tracker.backend`: **markdown** default, or **linear**). Runtime/git (worktrees, merges, state locks, `config.yml`) always stay local.

## Primary loop

Most days you only need these:

| Command | What it does |
|---------|-------------|
| `/do-work start [brief]` | Record a brief and build the REQ backlog (ideate on by default; auto-installs). |
| `/do-work go [UR-NNN]` | Verify coverage, then audit + run when confidence ≥ threshold (default 90%). |
| `/do-work status [UR-NNN]` | Live situation room: in-flight, backlog, recent done, coverage. |
| `/do-work` | Help + suggested next steps for this project. |

Flags for start/go (`--no-ideate`, `--force`, `--auto-fix`, …) are in the full table below.

## Quick Reference

| Command | What it does |
Expand Down
2 changes: 1 addition & 1 deletion agents/capture.md
Original file line numberDiff line numberDiff line change
Expand Up@@ -849,7 +849,7 @@ If `config.next_steps.enabled` is `true` **and** this agent is running standalon
2. **"Run Go"** — Skip to verify + run in one shot
3. **"Skip"** — End the interaction

If `config.next_steps.enabled` is `false`, missing, or this agent is running as a delegate inside start: output "Next step: run verify to check coverage, or runthe loop to start executing." and stop.
If `config.next_steps.enabled` is `false`, missing, or this agent is running as a delegate inside start: output `Next step: /do-work go UR-NNN to verify coverage and run.` (substitute the real UR number) and stop.

---

Expand Down
2 changes: 1 addition & 1 deletion agents/go.md
Original file line numberDiff line numberDiff line change
Expand Up@@ -161,7 +161,7 @@ If `config.next_steps.enabled` is `true`:

The go agent is a top-level orchestrator — it is never a delegate, so no suppression logic is needed. Sub-agents (verify, run, log) must suppress their own AskUserQuestion prompts when running inside go.

If `config.next_steps.enabled` is `false` or missing: skip the AskUserQuestion and stop.
If `config.next_steps.enabled` is `false` or missing: output `Next step: /do-work status` (or `/do-work start "…" for new work) and stop.

---

Expand Down
28 changes: 24 additions & 4 deletions agents/help.md
Original file line numberDiff line numberDiff line change
Expand Up@@ -88,14 +88,34 @@ path-unit backlog detected: top-level path REQs define reachable flows; child RE

**If URs exist but backlog is empty:**

Do **not** treat every empty-backlog project the same. Distinguish URs that still need decomposition from a drained project whose REQs already live in `archive/` (or Linear done):

1. Find the **most recent** `UR-NNN` under `user-requests/` (highest N).
2. Check whether **any** REQ for that UR exists in backlog, `working/`, or `archive/` (markdown: `**UR:** UR-NNN` on REQ files; Linear: `list_reqs_for_ur`).
3. Also scan older open URs for any with **zero** REQs anywhere — those still need capture.

**A — Latest UR has no REQs yet (or any open UR has zero REQs):**

```
Suggested next steps:
/do-work capture UR-NNN — Decompose the request into tasks
/do-work go UR-NNN — Verify and run after capture
/do-work start "describe your feature or task" — Record a new brief instead
```

Prefer the **oldest** zero-REQ open UR for the capture line when more than one exists; otherwise use the latest UR. Replace `UR-NNN` with that real number.

**B — Backlog empty and all open URs already have REQs (drained / archive-only):**

```
Suggested next steps:
/do-work capture UR-NNN — Decompose the latest request into tasks
/do-work go UR-NNN — Verify and run for a specific request
/do-work start "describe your feature or task" — Record a new brief
/do-work status — Review the situation room
```

Replace `UR-NNN` with the most recent UR number.
Do **not** suggest `capture` for a UR that already has REQs in archive — that re-decomposes finished work and confuses operators.

Then (when the 4-suggestion cap allows) still add retro / close from the heuristics below.

**If `runs/` has entries but `.do-work/state/calibration.md` does not exist:**

Expand All@@ -107,7 +127,7 @@ Suggest retro alongside other applicable suggestions (do not replace them — ad

**If archived path-unit REQs exist for a UR but that UR has no `closure.md`:**

Suggest close alongside other applicable suggestions (add it when this condition is true and the 4-suggestion cap allows). Use the most recently completed UR:
Suggest close alongside other applicable suggestions (add it when this condition is true and the 4-suggestion cap allows). Use the most recently completed UR that still needs closure:

```
/do-work close UR-NNN — Walk path-unit entry points end-to-end and write the UR closure report
Expand Down
2 changes: 2 additions & 0 deletions agents/status.md
Original file line numberDiff line numberDiff line change
Expand Up@@ -54,6 +54,8 @@ bash {skill-root}/lib/synth-status.sh [UR-NNN] # passes the optional scope

Print stdout verbatim to the user.

Unscoped output prioritizes live work: backlog + working list fully; archive is capped to recent completed rows with a note when more exist. Scope with `UR-NNN` to list every matching archived REQ. Archive rows always show Status `done` even if a file header is stale.

If `$SKILL_ROOT/lib/synth-status.sh` is missing, report `"$SKILL_ROOT/lib/synth-status.sh not found — cannot render status."` and stop.

Then render a proof-backed status view. Glob REQ files in backlog, `working/`, and `archive/` (respecting `UR-NNN` scope when provided), and run:
Expand Down
2 changes: 1 addition & 1 deletion docs/commands.md
Original file line numberDiff line numberDiff line change
Expand Up@@ -163,7 +163,7 @@ Does **not** run the verify confidence gate (unlike `go`).

### `/do-work status [UR-NNN]`

Read-only situation room: REQs, claimers (`hostname.pid`), heartbeats, deadlock warnings, coverage rollup. Optional UR scope.
Read-only situation room: live REQs first (working + backlog), claimers (`hostname.pid`), heartbeats, deadlock warnings, coverage rollup. Unscoped archive is capped to recent completed rows; pass `UR-NNN` to list every matching archived REQ.

Use whenever something looks stuck or you are running parallel workers.

Expand Down
2 changes: 1 addition & 1 deletion docs/getting-started.md
Original file line numberDiff line numberDiff line change
Expand Up@@ -163,7 +163,7 @@ Flags:
/do-work status UR-001
```

Read-only situation room: backlog vs working vs archive, claimers, heartbeats, deadlock warnings, coverage rollup.
Read-only situation room: backlog vs working first, recent completed (archive capped when unscoped), claimers, heartbeats, deadlock warnings, coverage rollup.

## How you know it worked

Expand Down
57 changes: 47 additions & 10 deletions lib/synth-status.sh
Original file line numberDiff line numberDiff line change
Expand Up@@ -13,9 +13,9 @@
# Sources:
# - `.do-work/REQ-*.md` (Status: backlog)
# - `.do-work/working/REQ-*.md` (Status: in-progress / stopped)
# - `.do-work/archive/REQ-*.md` (Status: done; only shown when
# present so the snapshot reflects
# completed work in this run)
# - `.do-work/archive/REQ-*.md` (Status: always rendered as done;
# unscoped runs cap archive rows so
# the situation room stays scannable)
# 3. Empty case: a single "no REQs" message in place of the table when there
# are zero REQs across all three buckets.
# 4. Footer: deadlock warnings from `lib/deadlock-check.sh` if executable;
Expand DownExpand Up@@ -51,6 +51,9 @@ ARCHIVE_DIR="$DOWORK/archive"
CONFIG="$DOWORK/config.yml"
DEFAULT_THRESHOLD=300
FOOTPRINT_MAX=60
# Unscoped archive rows shown in the table (totals still count all archived).
# Scoped runs (`synth-status.sh UR-NNN`) list every matching archive row.
ARCHIVE_CAP=15

# Resolve sibling lib scripts via $0's directory so the script works from any
# cwd inside the project.
Expand DownExpand Up@@ -238,7 +241,8 @@ md_cell() {
# Bucket: backlog | working | archive
# Status column is derived from the file's own `**Status:**` field so that
# `stopped` is rendered correctly when a worker has marked a working slot
# stopped.
# stopped — except archive rows, which always display as `done` (location is
# authoritative; stale in-progress headers in archive used to confuse operators).
render_row() {
local path="$1"
local bucket="$2"
Expand All@@ -259,8 +263,12 @@ render_row() {
return 0
fi

status="$F_STATUS"
[ -z "$status" ] && status="—"
if [ "$bucket" = "archive" ]; then
status="done"
else
status="$F_STATUS"
[ -z "$status" ] && status="—"
fi

layer="$F_LAYER"
[ -z "$layer" ] && layer="—"
Expand DownExpand Up@@ -383,8 +391,13 @@ fi
printf '**Totals:** backlog=%d, working=%d, archived=%d\n\n' \
"$BACKLOG_N" "$WORKING_N" "$ARCHIVE_N"

# Idle project with history (unscoped only): no live work. Lead with a scan cue.
if [ -z "$UR_FILTER" ] && [ "$BACKLOG_N" -eq 0 ] && [ "$WORKING_N" -eq 0 ] && [ "$ARCHIVE_N" -gt 0 ]; then
printf '_No live work (backlog empty, nothing in-flight). Showing recent completed REQs only._\n\n'
fi

if [ "$TOTAL_N" -eq 0 ]; then
printf '_no REQs found in backlog, working, or archive._\n'
printf '_no REQs found in backlog, working, or archive. Next: `/do-work start "your brief"`._\n'
else
# Table header.
printf '| REQ | UR | Status | Layer | Claimer | Heartbeat-age | Deps-status | Footprint |\n'
Expand All@@ -403,9 +416,33 @@ else
done
fi
if [ "$ARCHIVE_N" -gt 0 ]; then
for f in "${ARCHIVE_FILES[@]}"; do
render_row "$f" "archive"
done
# Unscoped: cap archive rows (newest REQ ids last in glob → take tail).
# Scoped (UR-NNN): list every matching archive row — the filter already
# narrows the set and operators asked for that UR deliberately.
if [ -n "$UR_FILTER" ]; then
for f in "${ARCHIVE_FILES[@]}"; do
render_row "$f" "archive"
done
else
archive_shown=0
archive_start=0
if [ "$ARCHIVE_N" -gt "$ARCHIVE_CAP" ]; then
archive_start=$(( ARCHIVE_N - ARCHIVE_CAP ))
fi
i=0
for f in "${ARCHIVE_FILES[@]}"; do
if [ "$i" -ge "$archive_start" ]; then
render_row "$f" "archive"
archive_shown=$(( archive_shown + 1 ))
fi
i=$(( i + 1 ))
done
if [ "$ARCHIVE_N" -gt "$ARCHIVE_CAP" ]; then
hidden=$(( ARCHIVE_N - archive_shown ))
printf '\n_… and %d more archived. Scope with `/do-work status UR-NNN`, or inspect `.do-work/archive/`._\n' \
"$hidden"
fi
fi
fi
fi

Expand Down
64 changes: 64 additions & 0 deletions lib/tests/synth-status.test.sh
Original file line numberDiff line numberDiff line change
Expand Up@@ -282,6 +282,70 @@ if [ "$ELAPSED" -gt 10 ]; then
fi
teardown_fixture

# ----------------------------------------------------------------------
# Case 8: unscoped archive is capped; totals still count all archived.
# ----------------------------------------------------------------------
CURRENT_CASE="archive-cap"
CASES=$((CASES + 1))
setup_fixture
i=1
while [ "$i" -le 20 ]; do
# Zero-pad so glob order matches numeric order (REQ-01 … REQ-20).
id="$(printf 'REQ-%03d' "$i")"
write_archive_req "$TMP/.do-work/archive/${id}-a.md" "$id" "UR-020"
i=$((i + 1))
done
run_synth
assert_eq "0" "$RC" "$CURRENT_CASE rc=0"
assert_contains "archived=20" "$STDOUT" "$CURRENT_CASE totals count all 20"
assert_contains "No live work" "$STDOUT" "$CURRENT_CASE idle cue"
assert_contains "and 5 more archived" "$STDOUT" "$CURRENT_CASE cap note"
assert_contains "REQ-020" "$STDOUT" "$CURRENT_CASE newest archive row shown"
assert_not_contains "REQ-001" "$STDOUT" "$CURRENT_CASE oldest archive row hidden"
teardown_fixture

# ----------------------------------------------------------------------
# Case 9: archive bucket always shows status done (stale header ignored).
# ----------------------------------------------------------------------
CURRENT_CASE="archive-status-done"
CASES=$((CASES + 1))
setup_fixture
cat > "$TMP/.do-work/archive/REQ-900-stale-header.md" <<EOF
# REQ-900: Stale header

**UR:** UR-900
**Status:** in-progress
**Created:** 2026-05-21
**Layer:** agents
**Files:** src/a.ts
**Depends on:**
EOF
run_synth
assert_eq "0" "$RC" "$CURRENT_CASE rc=0"
assert_contains "REQ-900" "$STDOUT" "$CURRENT_CASE row present"
assert_contains "| REQ-900 | UR-900 | done |" "$STDOUT" "$CURRENT_CASE forced done"
assert_not_contains "| REQ-900 | UR-900 | in-progress |" "$STDOUT" "$CURRENT_CASE no stale in-progress"
teardown_fixture

# ----------------------------------------------------------------------
# Case 10: scoped status still lists all archive rows for that UR.
# ----------------------------------------------------------------------
CURRENT_CASE="archive-cap-scoped"
CASES=$((CASES + 1))
setup_fixture
i=1
while [ "$i" -le 18 ]; do
id="$(printf 'REQ-%03d' "$i")"
write_archive_req "$TMP/.do-work/archive/${id}-a.md" "$id" "UR-021"
i=$((i + 1))
done
run_synth "UR-021"
assert_eq "0" "$RC" "$CURRENT_CASE rc=0"
assert_contains "REQ-001" "$STDOUT" "$CURRENT_CASE scoped keeps oldest"
assert_contains "REQ-018" "$STDOUT" "$CURRENT_CASE scoped keeps newest"
assert_not_contains "more archived" "$STDOUT" "$CURRENT_CASE no cap note when scoped"
teardown_fixture

# ----------------------------------------------------------------------
# Summary
# ----------------------------------------------------------------------
Expand Down
Loading