Skip to content

Add /ran, a per-branch log of which workflow steps have run - #202

Merged
haacked merged 4 commits into
mainfrom
haacked/breadcrumbs
Aug 29, 2026
Merged

Add /ran, a per-branch log of which workflow steps have run#202
haacked merged 4 commits into
mainfrom
haacked/breadcrumbs

Conversation

@haacked

@haacked haacked commented Aug 29, 2026

Copy link
Copy Markdown
Owner

Adds /ran, which answers "which workflow steps have already run against this branch?" once a context clear has taken the answer with it.

Two Claude Code hooks record every workflow command, whether you type it or the model invokes it through the Skill tool, into an append-only JSONL log under ~/.local/state/ran keyed by org, repo, and branch. /ran renders that as a checklist. /go Step 2 reads the same data, so a resumed run stops repeating work the branch already has.

Staleness comes from attributing each commit to the most recent command logged before it, not from comparing shas to HEAD. A step commits after it runs, so its own work always lands at a later sha than the one it recorded, and a sha comparison would report a finished branch as entirely stale. A commit more than an hour after the last command counts as one you made by hand, and the steps before it need to see it again.

Reviews count only once they finish

Both hook events fire before the command does its work, so typing /review-code and pressing Esc wrote what a finished review wrote, and /go seeded the review step as done and skipped it.

Records now carry a status. The hooks write started, and ai/bin/log-step-done.sh writes done as the last action of /go, /review-fix-cycle, and /address-pr-reviews. The two review steps count only the done records, so an abandoned review reads as never run and gets offered again. Every other step still counts invocations, where a false positive costs a repeated /simplify rather than an unreviewed merge.

A bare /review-code and the built-in /code-review cannot record completion, since neither lives in this repo. Both read as never run, so a review that did happen gets offered a second time. That is the direction worth failing in, and ai/skills/ran/SKILL.md says so.

Records written before the status field exists satisfy no review step, so an existing branch is offered its review again rather than skipping it.

Test plan

  • All eight suites pass, 290 checks: ai/tests/test-skill-spec.sh, test-canonical-skills.sh, test-plain-writing-contract.sh, test-ai-installers.sh, test-command-log.sh, test-log-step-done.sh, ai/skills/ran/scripts/tests/test-ran-report.sh, and ai/helpers/tests/test-repo-context.sh. CI now runs all eight; the last two were not wired in before.
  • In a throwaway repo, feed /simplify, /commit, /create-pr, and /review-code to ai/bin/log-command.sh, then run ran-report.sh. review-code reads ✗ never run. Run ai/bin/log-step-done.sh review-code and it reads . Commit again by hand and it reads ⚠ stale while the rest of the pipeline stays put.
  • Run ai/install-claude.sh twice and confirm ~/.claude/settings.json ends with one ExitPlanMode hook and one log-command.sh entry per event.
  • Verified the interrupted-review path by hand as well as in fixtures, since it is the case the feature exists to get right.

@haacked
haacked marked this pull request as ready for review August 29, 2026 00:00
@haacked
haacked requested a lite review from Copilot August 29, 2026 00:01
Two Claude Code hooks record every workflow command, whether typed as a
slash command or invoked by the model through the Skill tool, into an
append-only JSONL log under ~/.local/state/ran keyed by org, repo, and
branch. The log outlives a context clear, so /ran reports which pipeline
steps have run against the current branch and which are missing or stale.

Staleness comes from attributing each commit to the most recent command
logged before it rather than from comparing shas to HEAD. A step commits
after it runs, so its own work always lands at a later sha than the one it
recorded, and a sha comparison would report a finished branch as entirely
stale. A commit more than an hour after the last command counts as one made
by hand.

/go Step 2 seeds its review steps from a fresh row instead of leaving them
pending. install-claude.sh prunes the hooks it owns before merging, so an
edited command or timeout replaces the old entry instead of firing beside it.
prune_managed_hooks now runs before the merge on install, not only on
uninstall. Its filter drops every hook whose command matches
/.dotfiles/ai/bin/, which includes suggest-go-after-plan.sh, and the merge
only restores what HOOKS_CONFIG ships. Registering it there keeps the
installer owning a hook the repo already ships, and preserves the
path-prefix prune that makes an edited hook converge on reinstall.

Claude-Session: https://claude.ai/code/session_01SWLskmDELSTbrL6ZSiCV9G
The hook records a command on UserPromptSubmit and PostToolUse, both of
which fire before the command runs, so a review abandoned at the prompt
logged what a finished one logged. /go seeded the review step from that
record and skipped a review nobody ran.

Records now carry a status. The hook writes "started"; ai/bin/log-step-done.sh
writes "done", called by /go, /review-fix-cycle, and /address-pr-reviews as
their last action. COMMAND_STEP_TABLE gains a completion evidence value, and
review-code and address-pr-reviews use it, so their rows count only the done
records. Entries predating the status field satisfy no completion step, so an
existing branch is offered its review again rather than skipping it.

Attribution reads the started records and skips the done ones: a commit
landing after a step reported finished is work that step never saw, and
crediting it there would hold the row fresh over an unreviewed commit.

Also fixes three verdict and report defects the same review surfaced:

- An unresolvable base branch left an empty commit list, so every logged step
  read fresh no matter what landed after it. The report now fails instead,
  which in --json mode emits an error with no rows and seeds nothing.
- A step was due only once the immediately preceding step had run, so skipping
  the optional comment-cleanup left every later step reading "not yet run"
  under "Nothing outstanding". It now walks back to the last required step.
- The --json block asserted only that the payload parsed, leaving the status
  field /go reads unchecked. It now asserts the parsed values.

Wires ai/helpers/tests/test-repo-context.sh and the new
ai/tests/test-log-step-done.sh into CI.

Claude-Session: https://claude.ai/code/session_01SWLskmDELSTbrL6ZSiCV9G

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

ai/bin/log-step-done.sh currently allows any declared step to be marked done, which can hide SKILL.md typos by exiting 0 while failing to satisfy the intended completion-only steps.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Pull request overview

Adds a persistent, per-branch workflow-step log (“/ran”) to track which parts of the repo’s PR workflow have been invoked/completed on the current branch, surviving context clears and enabling /go to resume without repeating finished work.

Changes:

  • Introduces command logging via Claude Code hooks (ai/bin/log-command.sh) and step-completion logging (ai/bin/log-step-done.sh) stored under ~/.local/state/ran/<org>/<repo>/<branch>.jsonl.
  • Adds the /ran skill plus a report implementation (ran-report.sh + ran-verdict.jq) to render/compute fresh/stale/missing state from the JSONL log and commit attribution.
  • Wires new test suites into CI and expands installer behavior to avoid duplicated hooks on reinstall.
File summaries
File Description
README.md Documents the new ran skill in the top-level skills list.
ai/README.md Adds the newly introduced test scripts to the documented test commands.
ai/install-claude.sh Adds hook pruning to make hook installation idempotent and prevent duplicate command-log hooks.
ai/bin/log-command.sh New Claude Code hook script to append started workflow command records for typed commands and Skill tool runs.
ai/bin/log-step-done.sh New script to append done completion records for steps that must only count finished runs.
ai/helpers/repo-context.sh Adds repo_context_is_path_safe to prevent origin-derived path traversal when writing logs.
ai/helpers/command-steps.sh Introduces the canonical step vocabulary, ordering, and log-path construction shared by writer and reader.
ai/tests/test-ai-installers.sh Adds assertions that reinstall converges (no duplicate hooks; edited hooks are replaced).
ai/tests/test-command-log.sh New tests for the command-log hook’s silence, containment, and mapping behavior.
ai/tests/test-log-step-done.sh New tests for completion logging being loud on typos and safe on containment/invalid repo states.
ai/skills/ran/SKILL.md New /ran skill definition and user-facing semantics for interpreting markers and limitations.
ai/skills/ran/scripts/ran-report.sh New report renderer (human + --json) that reads logs and local git state to produce the checklist.
ai/skills/ran/scripts/helpers/ran-verdict.jq New jq logic to compute per-step fresh/stale/missing/pending using commit attribution vs. logged entries.
ai/skills/ran/scripts/tests/test-ran-report.sh New fixture-driven tests validating attribution, staleness, completion-only evidence, and --json error behavior.
ai/skills/go/SKILL.md Updates /go Step 2 to consume ran-report.sh --json and seed review steps only from fresh completion evidence.
ai/skills/review-fix-cycle/SKILL.md Records review completion via log-step-done.sh review-code so /ran and /go can distinguish interrupted reviews.
ai/skills/address-pr-reviews/SKILL.md Records completion for address-pr-reviews (including the empty-comments case) to prevent repeated runs on resume.
ai/codex/excluded-skills.txt Excludes ran from Codex because it relies on Claude Code hook-produced logs.
.github/workflows/test.yml Wires the new test scripts into CI.
Review details
  • Files reviewed: 17/19 changed files
  • Comments generated: 1
  • Review effort level: Lite

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment on lines +14 to +17
# Exit codes:
# Default: 0 on success, 1 when there is no GitHub repo to report on and 1
# when no base branch can be resolved
# --json: always 0 (errors reported in the "error" field)
@haacked
haacked merged commit 895d4b0 into main Aug 29, 2026
1 check passed
@haacked
haacked deleted the haacked/breadcrumbs branch August 29, 2026 00:24
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants