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
6 changes: 5 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ jobs:
# merge-base. ~50 commits, so the full history costs nothing here.
fetch-depth: 0

# The hook, the two checkers, the two Python reports and their five suites are
# The hook, the two checkers, the three Python reports and their six suites are
# the only executables here,
# so lint plus those suites are the only mechanical gates we have. Everything else
# here is a prompt, and prompts have no typechecker (see README, "Contributing").
Expand Down Expand Up @@ -79,6 +79,9 @@ jobs:
# The run-analytics suite (vision step 2c, part 1), linted the same way.
docker run --rm -v "$PWD:/mnt" -w /mnt koalaman/shellcheck:v0.11.0 \
--shell=sh --exclude=SC2015 scripts/run-analytics.test.sh
# The loop-usefulness suite (vision step 2c, part 2), linted the same way.
docker run --rm -v "$PWD:/mnt" -w /mnt koalaman/shellcheck:v0.11.0 \
--shell=sh --exclude=SC2015 scripts/loop-usefulness.test.sh

# Two runs, because the hook has to be correct under both shells and the runner's
# /bin/sh is dash while a contributor's may be bash. HOOK_SH selects the shell the
Expand Down Expand Up @@ -106,6 +109,7 @@ jobs:
sh scripts/check-version-bump.test.sh
sh scripts/ledger-metrics.test.sh
sh scripts/run-analytics.test.sh
sh scripts/loop-usefulness.test.sh

# Invariant 12 itself needs a base to diff against, so it runs only on pull
# requests — a push to main has no PR base, and diffing the push range would just
Expand Down
20 changes: 11 additions & 9 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@ scripts/ledger-metrics.py # read-only report over the ledger + git (visi
scripts/ledger-metrics.test.sh # its regression suite — fixture repos, expected text
scripts/run-analytics.py # gate-call effort from local logs (vision step 2c, part 1)
scripts/run-analytics.test.sh # its regression suite — fixture home + repos, expected text
scripts/loop-usefulness.py # warning light over recorded review cycles (vision step 2c, part 2)
scripts/loop-usefulness.test.sh # its regression suite — fixture repo + store, expected text
plugins/dev-workflow/
.claude-plugin/plugin.json # metadata only — no component keys (invariant 6)
CHANGELOG.md # every manifest version, newest first
Expand All @@ -66,10 +68,10 @@ source-files/ # the extraction seed this repo was built from
**Boundaries.** `skills/`, `commands/`, `agents/` and `hooks/hooks.json` are loaded by convention
from their paths. The executable artifacts are the hook and its test, plus the two
repo-local CI checkers and their tests (`scripts/check-invariants.{sh,test.sh}` and
`scripts/check-version-bump.{sh,test.sh}`), plus two Python reports with their suites:
`scripts/ledger-metrics.{py,test.sh}` (read-only) and `scripts/run-analytics.{py,test.sh}`
(writes only its own store under `.context/telemetry/`) — the hook ships in the plugin, the
checkers and the reports do not; everything else is text read by a model. `examples/` is reference material,
`scripts/check-version-bump.{sh,test.sh}`), plus three Python reports with their suites:
`scripts/ledger-metrics.{py,test.sh}` and `scripts/loop-usefulness.{py,test.sh}` (read-only),
and `scripts/run-analytics.{py,test.sh}` (writes only its own store under
`.context/telemetry/`) — the hook ships in the plugin, the checkers and the reports do not; everything else is text read by a model. `examples/` is reference material,
outside the loaded surface: never scaffolded or copied into a user's project, though it
does ship inside the plugin package.

Expand Down Expand Up @@ -259,9 +261,9 @@ Every command below was run in this session and observed to exit 0.

| Role | Command |
|---|---|
| quality (the whole battery — what CI runs) | `shellcheck --shell=sh plugins/dev-workflow/hooks/codex-gate.sh && shellcheck --shell=sh --exclude=SC2015 plugins/dev-workflow/hooks/codex-gate.test.sh && shellcheck --shell=sh scripts/check-invariants.sh && shellcheck --shell=sh --exclude=SC2015 scripts/check-invariants.test.sh && shellcheck --shell=sh scripts/check-version-bump.sh && shellcheck --shell=sh scripts/check-version-bump.test.sh && shellcheck --shell=sh --exclude=SC2015 scripts/ledger-metrics.test.sh && shellcheck --shell=sh --exclude=SC2015 scripts/run-analytics.test.sh && HOOK_SH=sh sh plugins/dev-workflow/hooks/codex-gate.test.sh && HOOK_SH=dash dash plugins/dev-workflow/hooks/codex-gate.test.sh && sh scripts/check-invariants.test.sh && sh scripts/check-invariants.sh && sh scripts/check-version-bump.test.sh && sh scripts/check-version-bump.sh main && sh scripts/ledger-metrics.test.sh && sh scripts/run-analytics.test.sh && claude plugin validate . --strict` |
| typecheck | n/a — no typed sources (shell, two untyped Python reports, markdown) |
| lint | `shellcheck --shell=sh plugins/dev-workflow/hooks/codex-gate.sh && shellcheck --shell=sh --exclude=SC2015 plugins/dev-workflow/hooks/codex-gate.test.sh && shellcheck --shell=sh scripts/check-invariants.sh && shellcheck --shell=sh --exclude=SC2015 scripts/check-invariants.test.sh && shellcheck --shell=sh scripts/check-version-bump.sh && shellcheck --shell=sh scripts/check-version-bump.test.sh && shellcheck --shell=sh --exclude=SC2015 scripts/ledger-metrics.test.sh && shellcheck --shell=sh --exclude=SC2015 scripts/run-analytics.test.sh` |
| quality (the whole battery — what CI runs) | `shellcheck --shell=sh plugins/dev-workflow/hooks/codex-gate.sh && shellcheck --shell=sh --exclude=SC2015 plugins/dev-workflow/hooks/codex-gate.test.sh && shellcheck --shell=sh scripts/check-invariants.sh && shellcheck --shell=sh --exclude=SC2015 scripts/check-invariants.test.sh && shellcheck --shell=sh scripts/check-version-bump.sh && shellcheck --shell=sh scripts/check-version-bump.test.sh && shellcheck --shell=sh --exclude=SC2015 scripts/ledger-metrics.test.sh && shellcheck --shell=sh --exclude=SC2015 scripts/run-analytics.test.sh && shellcheck --shell=sh --exclude=SC2015 scripts/loop-usefulness.test.sh && HOOK_SH=sh sh plugins/dev-workflow/hooks/codex-gate.test.sh && HOOK_SH=dash dash plugins/dev-workflow/hooks/codex-gate.test.sh && sh scripts/check-invariants.test.sh && sh scripts/check-invariants.sh && sh scripts/check-version-bump.test.sh && sh scripts/check-version-bump.sh main && sh scripts/ledger-metrics.test.sh && sh scripts/run-analytics.test.sh && sh scripts/loop-usefulness.test.sh && claude plugin validate . --strict` |
| typecheck | n/a — no typed sources (shell, three untyped Python reports, markdown) |
| lint | `shellcheck --shell=sh plugins/dev-workflow/hooks/codex-gate.sh && shellcheck --shell=sh --exclude=SC2015 plugins/dev-workflow/hooks/codex-gate.test.sh && shellcheck --shell=sh scripts/check-invariants.sh && shellcheck --shell=sh --exclude=SC2015 scripts/check-invariants.test.sh && shellcheck --shell=sh scripts/check-version-bump.sh && shellcheck --shell=sh scripts/check-version-bump.test.sh && shellcheck --shell=sh --exclude=SC2015 scripts/ledger-metrics.test.sh && shellcheck --shell=sh --exclude=SC2015 scripts/run-analytics.test.sh && shellcheck --shell=sh --exclude=SC2015 scripts/loop-usefulness.test.sh` |
| test | `HOOK_SH=sh sh plugins/dev-workflow/hooks/codex-gate.test.sh && HOOK_SH=dash dash plugins/dev-workflow/hooks/codex-gate.test.sh` — two runs; `HOOK_SH` selects the shell the HOOK runs under, and without it a dash invocation only exercises the harness |
| invariant checks (5 pinning, 6 manifest, prompt conformance) | `sh scripts/check-invariants.test.sh && sh scripts/check-invariants.sh` |
| invariant check (12 version bump) | `sh scripts/check-version-bump.test.sh && sh scripts/check-version-bump.sh main` |
Expand All @@ -276,8 +278,8 @@ invariant 5; `dash` is addressed by name because it is the system shell, not a p
tool. Without it the second run cannot start, and dropping that run is what let a
`dash`-only defect ship once already. The metrics report's suite also needs
**`python3`** 3.8 or later, addressed by name for the same reason as `dash`: it is the
system interpreter, not a pinned tool. `scripts/run-analytics.py` also needs git 2.36 or later
and checks for it.
system interpreter, not a pinned tool. `scripts/run-analytics.py` and `scripts/loop-usefulness.py`
also need git 2.36 or later and check for it.

**The `--exclude=SC2015` on the test file** is a single-code exclusion, not a blanket
disable: every other shellcheck rule still applies to that file. Its hits are all
Expand Down
9 changes: 8 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,7 @@ CI ([`.github/workflows/ci.yml`](.github/workflows/ci.yml)) runs four checks on
PR and push to main: `shellcheck --shell=sh` over the three shell executables and every
shell test file, the hook's test suite,
[`scripts/check-invariants.sh`](scripts/check-invariants.sh) (invariants 5 and 6, plus three prompt-conformance checks) plus
both checkers' regression suites, the two reports' suites, and
both checkers' regression suites, the three reports' suites, and
`claude plugin validate . --strict`.

`python3 scripts/ledger-metrics.py` prints a read-only report over the hardening ledger
Expand All @@ -172,6 +172,13 @@ on this machine and reports how many gate calls each review cycle and story took
they ran and how many tokens they used, including effort no closed cycle accounts for. It
keeps numbers and identifiers only, in `.context/telemetry/` of this clone, for 365 days.

`python3 -B scripts/loop-usefulness.py [<ref>]` gives every review cycle whose records are in the
history read a warning light (a skipped cycle ran no loop and is listed without one):
red or amber where its recorded passes or rising findings call for reassessing review effort,
no warning where no threshold is reached, and not determinable where missing or conflicting
data leaves the state open. It does not say whether a loop was worth its effort, and it writes
nothing (`-B` keeps the interpreter from writing bytecode too).

A fifth check runs **on pull requests only**:
[`scripts/check-version-bump.sh`](scripts/check-version-bump.sh) (invariant 12), which
needs a base branch to diff against. Its *suite* runs unconditionally with the others;
Expand Down
Loading