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
7 changes: 4 additions & 3 deletions .claude/CLAUDE.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
# CLAUDE

Claude Code's own configuration for this repository: `settings.json`
(hook wiring) and `hooks/` (the hook scripts themselves -- see
`hooks/CLAUDE.md`). Tracked in Git so the configuration travels with the
repository rather than living only on one machine.
(hook wiring), `hooks/` (the hook scripts themselves -- see
`hooks/CLAUDE.md`), and `skills/` (reusable, user-invoked workflow
prompts -- see `skills/CLAUDE.md`). Tracked in Git so the configuration
travels with the repository rather than living only on one machine.

Found undocumented and unrecorded in either `docs/repository-manifest.md`
or `docs/planning/knowledge-architecture.md` during the 2026-08-19 F2
Expand Down
22 changes: 22 additions & 0 deletions .claude/skills/CLAUDE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# CLAUDE

Claude Code skills for this repository: reusable, user-invoked (`/<name>`)
prompt files that encode a workflow already documented elsewhere in the
repository, so it doesn't have to be re-described by hand each time it's
run. One subdirectory per skill, each `<name>/SKILL.md`.

- `ship/` -- the branch/TDD/blast-radius/preflight/CI/PR/merge sequence
from root `CLAUDE.md`'s Branch Discipline and Merge Gate sections. See
its own `CLAUDE.md`.

A skill here is a checklist referencing the repository's actual rules,
never a second copy of them -- if a skill's steps and the `CLAUDE.md`
section they cite disagree, the `CLAUDE.md` section wins, and the skill
gets fixed in the same change (the same restated-fact discipline
`docs/CLAUDE.md` asks of every generated document, applied here to a
hand-written one instead, since a skill's steps cannot be generated from
the rules they summarise).

Added 2026-09-08, alongside `ship/`, following the same "real content
first, `CLAUDE.md` and manifest entry in the same change" pattern
`tools/CLAUDE.md` already states for a new subdirectory.
13 changes: 13 additions & 0 deletions .claude/skills/ship/CLAUDE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# CLAUDE

`SKILL.md` -- the `/ship` skill: branch, TDD-first implementation, Blast
Radius doc propagation, `make preflight`, `make ci`, PR, and merge, in
that order. Every numbered step cites the root `CLAUDE.md` section it
restates rather than stating the rule independently, so the two cannot
quietly diverge -- see `../CLAUDE.md` for why that matters here
specifically.

Added 2026-09-08, at a user's direct request to stop re-describing the
same delivery loop by hand each session. Update this skill in the same
change as any of the root `CLAUDE.md` sections it cites, if that change
alters what the step actually requires.
77 changes: 77 additions & 0 deletions .claude/skills/ship/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
---
name: ship
description: Branch, implement TDD-first, propagate documentation, run the local gate, open a PR, watch CI, and merge -- the standard PyFlow delivery loop from root CLAUDE.md.
---

# Ship

This skill is a checklist, not new policy -- every step below restates a
rule that already lives in root `CLAUDE.md` or `docs/practices.md`. It
exists so the same sequence doesn't have to be re-described by hand each
time. If this file and one of those disagree, the other document wins;
fix this file in the same change.

1. **Branch before the first edit** (CLAUDE.md, Branch Discipline).
`git checkout main && git pull`, then create
`<kind>/<short-hyphenated-subject>` (`docs/practices.md`): `feat/` for
a roadmap task, `fix/` for a defect, `docs/` for documentation/
planning/process only. One branch per task -- don't fold an unrelated
second task onto a branch already in flight.

2. **Write the failing test first, then implement** (root CLAUDE.md,
Acceptance Criteria section; `docs/practices.md`'s TDD examples
throughout the roadmap). The test must assert intent -- the physical
or behavioural meaning a reader would check -- not an implementation
detail that would still pass under a wrong implementation.

3. **Implement until it's green**, re-reading any file where an import
was added before running tests against it -- the post-edit format
hook strips an import that has no usage yet in the same edit
(CLAUDE.md, Tooling Gotchas / Formatter Hook Interaction).

4. **Propagate the Blast Radius in the same change** (CLAUDE.md, Blast
Radius; Documentation Blast Radius). Grep for the name of whatever
changed and update every restatement: `README.md`, the relevant
handbook/manifest entry, the roadmap/backlog status line, the
`CHANGELOG`/`docs/CHANGELOG-DESIGN.md` where a decision was made, and
every `CLAUDE.md` that names the thing. If something in the radius
can't be updated now, say so explicitly in the PR description rather
than leaving an unrecorded gap.

5. **Before calling a user-facing feature done, run it** (CLAUDE.md,
Feature Verification Before Reporting Done). The exact command a user
would run, not the test suite standing in for it -- `pyflow run`,
`make graph`, whatever the feature's own entry point is. Confirm any
new CLI flag actually appears in `--help`. Then re-read the diff as a
hostile auditor and list anything overstated, defaulted off, or
unreachable.

6. **Run `make preflight`** (CLAUDE.md, Branch Discipline / Development
Commands) before the first commit on the branch, and again before
opening the PR. It regenerates the generated docs, then runs the link
checker, the fast structural-consistency checks, lint, typecheck, and
the test suite, failing at the first error.

7. **Commit.** No heredocs for the message -- write it with the Write
tool to a scratch file and use `git commit -F <file>` (CLAUDE.md,
Tooling Gotchas / Shell Usage). State what changed and why, not what
the diff already shows.

8. **Run `make ci` in full before merge** (CLAUDE.md, Merge Gate
criterion 1) -- `make preflight` is not a substitute. Push, open the
PR (`gh pr create`), and watch the real CI run on both platforms
(`gh pr checks --watch`) rather than assuming local green transfers.

9. **Before merging, re-check Merge Gate criteria 2-4**: every
restatement of every changed fact is updated in this branch, every
acceptance criterion is checked by something that would fail if the
intent were violated, and anything left unverified is said so
explicitly rather than implied by silence.

10. **Merge, delete the branch, return to `main`** before starting the
next task (CLAUDE.md, Branch Discipline).

**Exception**: a trivial single-file edit to a `CLAUDE.md` or other
process-rule file may skip straight to a direct commit on `main`, but
only when the user explicitly says so in that turn (CLAUDE.md, Branch
Discipline). Everything else follows the full sequence above.
102 changes: 102 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,26 @@ easiest to implement -- also `docs/practices.md`.

---

# Feature Verification Before Reporting Done

Before reporting a user-facing feature as done, run the exact command a
user would run -- `pyflow run`, `make graph`, whatever the feature's own
entry point is -- and describe the real output or the actual rendered
window, not the expected one. Confirm every new CLI flag actually
appears in `--help`.

Then re-read the diff as a hostile auditor, not as its author: list
anything overstated, defaulted off, or unreachable before calling the
work finished.

Added 2026-09-08, maintainer's instruction, after a HUD that shipped
defaulted off and a `--demos` flag that was never wired into the CLI
both passed review because neither was ever actually run. This is the
concrete form Merge Gate criterion 3 ("the intent is met") takes for
anything a person looks at or types.

---

# Branch Discipline

**All coding work happens on a branch, never directly on `main`.**
Expand All @@ -120,6 +140,20 @@ makes both apply every time rather than only when someone remembers to
branch first. `main` only receives commits by merge, once the Merge Gate
above is satisfied.

The one exception: a trivial single-file edit to a `CLAUDE.md` or other
process-rule file may be committed directly to `main` when the user
explicitly says so in the same turn -- it does not need its own
branch/PR. Everything else follows the full cycle: open a PR, watch CI
to green, merge, delete the branch, and return to `main` before starting
the next task. `make preflight` (Development Commands, below) must pass
locally before any commit made on a branch; it is a fast local gate, not
a substitute for `make ci` in full, which the Merge Gate above still
requires before merge.

Added 2026-09-08, later the same day as the standing rule above, after
noticing this section said "never directly on main" without saying what
to do once a branch exists.

---

# Acceptance Criteria for Simulation Work
Expand Down Expand Up @@ -440,13 +474,63 @@ prevent (P-011, single authoritative source).
- `make clean` -- remove what `make install` created; states on its own
output what it deliberately leaves alone (the `uv` binary, the shared
interpreter, `uv`'s package cache) rather than restated here.
- `make preflight` -- a fast local pre-commit gate, added 2026-09-08:
regenerates `docs/index.md` and `docs/repository-inventory.md`, then
runs the link checker, the two cheapest structural-consistency checks
(`check-manifest`, `check-references`), lint, typecheck, and the test
suite, in that order, stopping at the first failure. Unlike `make ci`
it regenerates before checking, so a merely-stale generated doc heals
itself instead of failing outright. Deliberately narrower than `make
ci` -- it skips `check-graph`, `check-scenarios`, `check-stages`,
`check-documents`, `check-status`, `check-config-template`,
`check-dates` and `check-benchmark-report`, none of which are cheap
enough to justify running on every commit -- so a green `make
preflight` is a reason to commit, not a reason to skip `make ci`
before merge. See the Branch Discipline section above for when it's
required.

Full detail, including what each target's acceptance criteria are and
why the project settled on `uv`+`make`: `README.md`'s Quick Start
section and `docs/planning/backlog.md` A1a/A1b/B2/B3.

---

# Tooling Gotchas

Environment-specific failure modes worth knowing before they cost a
retry cycle. Neither of these is a PyFlow behaviour -- both are the
local development environment fighting back -- but both have cost real
time more than once, which is the bar the rest of this file uses for
writing something down.

## Formatter Hook Interaction

The repository's `PostToolUse` hook (`.claude/hooks/post_edit_format.py`)
runs `ruff --fix`/`ruff format` on every file an Edit/Write call
touches, and `ruff --fix` removes an import it believes is unused. Add a
new import and its first usage in the *same* edit, never the import
alone -- an import added ahead of the code that uses it reads as unused
to the hook and gets silently stripped before the follow-up edit lands.
After any edit that touches imports, re-read the file to confirm the
import survived before running tests against it.

## Shell Usage (Git Bash)

Do not use heredocs for multi-line file content or commit messages on
this platform -- Git Bash's line-ending handling has mangled heredoc
writes into CRLF-corrupted or duplicated content before. Use the Write
tool for file content, and `git commit -F <file>` (a file written by the
Write tool) for a long commit message instead of `git commit -m` with an
inline heredoc. Never reorder sections of a file with `sed` or index
arithmetic -- a botched reorder has duplicated thousands of lines of a
planning document in a single command before; use targeted `Edit` calls
instead.

Added 2026-09-08, maintainer's instruction, after both failure modes had
each recurred across several sessions.

---

# Documentation

Documentation is treated as part of the implementation.
Expand All @@ -457,6 +541,24 @@ Generated documentation must never be edited manually.

Follow `docs/documentation-guidelines.md`.

## Documentation Blast Radius

Any change to behaviour, a CLI flag, or help text propagates in the same
commit to every place that restates it: `README.md`, the relevant
handbook or manifest entry, the roadmap/backlog status line, and every
`CLAUDE.md` that names the thing being changed. This is the Blast Radius
rule (above) applied specifically to documentation, because that is
where it has been missed most often -- run `make check-manifest`,
`make check-references` and `make check-docs` before committing (also
folded into `make preflight`, above), not only at full `make ci` time.

Never state a relative timeframe ("months ago", "recently", "a while
back"). Use a commit date, an explicit `YYYY-MM-DD`, or omit the claim
-- `git log` and a PR's actual merge time are the source of truth; a
session's own sense of elapsed time is not, and has been wrong before.

Added 2026-09-08, maintainer's instruction.

---

# Engineering Principles
Expand Down
29 changes: 28 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
check-manifest check-references check-scenarios check-stages check-documents \
check-claims check-dates check-duplicate-blocks status-report \
check-status config-template check-config-template docs graph demo benchmark \
benchmark-report check-benchmark-report record-benchmarks ci clean
benchmark-report check-benchmark-report record-benchmarks ci preflight clean

install:
uv sync
Expand Down Expand Up @@ -138,6 +138,33 @@ check-manifest:

ci: lint typecheck test check-docs check-docs-index check-graph check-dependency-tree check-inventory check-manifest check-references check-scenarios check-stages check-documents check-status check-config-template check-dates check-duplicate-blocks check-benchmark-report

# Fast local pre-commit gate (root CLAUDE.md, Branch Discipline section;
# added 2026-09-08). Not a substitute for `make ci` above -- it skips
# check-graph, check-scenarios, check-stages, check-documents,
# check-status, check-config-template, check-dates and
# check-benchmark-report, none of which are cheap enough to run on every
# commit -- but it catches the failures that show up most often before
# they reach CI: a stale generated doc, a broken relative link, a
# tracked file missing from the manifest, a path named in prose that
# doesn't resolve, a lint/type error, or a broken test.
#
# `docs`/`inventory` regenerate rather than check -- unlike `ci`, a
# merely-stale generated doc heals itself here instead of failing
# outright, since the point of a local gate is to fix what it can before
# a human looks at the diff.
#
# No single script in this repository is named "the self-consistency
# validator" -- `check-manifest` (every tracked file is named somewhere)
# and `check-references` (every path named in prose resolves) are the
# two structural-consistency checks fast enough to belong in a local
# gate; `check-graph` covers a third kind (the planning knowledge graph)
# and stays in full `make ci` only, since ordinary commits don't usually
# touch it.
#
# Runs in the order listed, stopping at the first failure, same as `ci`
# above.
preflight: docs inventory check-docs check-manifest check-references lint typecheck test

# Fails if prose names a repository path that does not exist. Gating:
# every rule is a definite structural fact (does this path resolve),
# with the judgement-shaped cases excluded by document rather than by a
Expand Down
Loading
Loading