@thedecipherist/claude-packs 1.0.0 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +74 -0
- package/README.md +275 -18
- package/bin/claude-packs.mjs +18 -10
- package/configurations/base/config.json +1 -1
- package/configurations/cpp/config.json +2 -1
- package/configurations/full-stack/config.json +2 -1
- package/configurations/go/config.json +3 -1
- package/configurations/node/config.json +3 -1
- package/configurations/python/config.json +3 -1
- package/configurations/rust/config.json +106 -0
- package/configurations/synth-creator/config.json +1 -1
- package/global/hooks/lib/shell-writes.mjs +2 -293
- package/lib/build-queue.mjs +22 -0
- package/lib/claude-md.mjs +4 -2
- package/lib/config-cli.mjs +1 -1
- package/lib/coverage.mjs +10 -2
- package/lib/doctor.mjs +14 -3
- package/lib/fix-plan.mjs +2 -1
- package/lib/found-folders.mjs +25 -0
- package/lib/global.mjs +3 -3
- package/lib/hook-proof.mjs +24 -7
- package/lib/kit-command.mjs +14 -0
- package/lib/layout.mjs +27 -3
- package/lib/logs.mjs +45 -5
- package/lib/new.mjs +1 -1
- package/lib/packs.mjs +4 -2
- package/lib/rule-tests.mjs +42 -0
- package/lib/scan-detect.mjs +41 -5
- package/lib/scan.mjs +5 -2
- package/lib/suggest.mjs +16 -3
- package/lib/sync.mjs +5 -2
- package/lib/workorder.mjs +26 -0
- package/package.json +1 -1
- package/packs/audio-core/hooks/param-id-lock.mjs +59 -16
- package/packs/audio-core/pack.json +5 -0
- package/packs/audio-core/rules/a-control-is-proved-through-its-input.md +26 -0
- package/packs/audio-core/rules/cpu-worst-case-per-block.md +3 -1
- package/packs/audio-core/rules/house-control-behaviours.md +1 -1
- package/packs/audio-core/rules/scoped-no-denormals.md +1 -1
- package/packs/audio-core/rules/straight-on-and-aligned.md +1 -1
- package/packs/audio-core/rules/ui-matches-reference-look.md +2 -0
- package/packs/audio-core/skills/analyse-reference-look/SKILL.md +25 -11
- package/packs/audio-core/skills/prove-control/SKILL.md +2 -0
- package/packs/base/checks/one-walk-per-template.json +1 -1
- package/packs/base/hooks/code-shape.mjs +10 -6
- package/packs/base/hooks/dispatch-once.mjs +58 -21
- package/packs/base/hooks/folder-law.mjs +3 -0
- package/packs/base/hooks/git-guard.mjs +22 -109
- package/packs/base/hooks/lesson-checks.mjs +9 -1
- package/packs/base/hooks/lib/code-shapes.mjs +11 -6
- package/packs/base/hooks/lib/crash-policy.mjs +47 -0
- package/packs/base/hooks/lib/dup-index.mjs +6 -1
- package/packs/base/hooks/lib/dup.mjs +2 -2
- package/packs/base/hooks/lib/event-log.mjs +4 -3
- package/packs/base/hooks/lib/git-adds.mjs +2 -1
- package/packs/base/hooks/lib/git-auth.mjs +44 -0
- package/packs/base/hooks/lib/git-guard-selftest.mjs +93 -0
- package/packs/base/hooks/lib/languages.mjs +5 -2
- package/packs/base/hooks/lib/layout.mjs +6 -2
- package/packs/base/hooks/lib/making-check-selftest.mjs +3 -0
- package/packs/base/hooks/lib/near-copies.mjs +1 -1
- package/packs/base/hooks/lib/program-read.mjs +6 -3
- package/packs/base/hooks/lib/rust-scan.mjs +139 -0
- package/packs/base/hooks/lib/shape-lists.mjs +31 -0
- package/packs/base/hooks/lib/shape-prose.mjs +78 -0
- package/packs/base/hooks/lib/shape.mjs +18 -39
- package/packs/base/hooks/lib/turn.mjs +6 -1
- package/packs/base/hooks/lib/unread-writes.mjs +24 -0
- package/packs/base/hooks/making-check.mjs +12 -7
- package/packs/base/hooks/run-hooks.mjs +15 -7
- package/packs/base/hooks/shape-law.mjs +11 -4
- package/packs/base/hooks/suite-once.mjs +22 -6
- package/packs/base/rules/a-control-is-seen-to-fire.md +1 -1
- package/packs/base/rules/behaviour-lives-with-its-kind.md +1 -1
- package/packs/base/rules/bug-fix-starts-red.md +1 -1
- package/packs/base/rules/field-map-over-if-runs.md +1 -1
- package/packs/base/rules/instances-by-index-identities-by-id.md +2 -2
- package/packs/base/rules/lookup-over-if-chains.md +1 -1
- package/packs/base/rules/plan-and-logs.md +1 -1
- package/packs/base/rules/refusals-are-judged.md +1 -0
- package/packs/base/rules/test-the-template-once.md +2 -1
- package/packs/base/rules/unattended-runs.md +15 -0
- package/packs/base/skills/new-project/SKILL.md +23 -0
- package/packs/base/skills/write-a-workorder/SKILL.md +41 -0
- package/packs/cpp/checks/cpp-find-with-the-library.json +2 -2
- package/packs/go/pack.json +5 -0
- package/packs/hook-proof/rules/a-refusal-is-exit-2.md +2 -2
- package/packs/instrument-shell/rules/render-the-extremes.md +2 -2
- package/packs/midi/checks/position-not-integrated.json +5 -1
- package/packs/postgres/checks/pg-bind-values.json +33 -0
- package/packs/postgres/checks/pg-concurrently-in-txn.json +18 -0
- package/packs/postgres/checks/pg-fk-not-valid.json +18 -0
- package/packs/postgres/checks/pg-index-concurrently.json +18 -0
- package/packs/postgres/checks/pg-no-float-money.json +19 -0
- package/packs/postgres/checks/pg-no-money.json +18 -0
- package/packs/postgres/checks/pg-no-required-column.json +18 -0
- package/packs/postgres/checks/pg-no-volatile-default.json +18 -0
- package/packs/postgres/checks/pg-not-exists.json +18 -0
- package/packs/postgres/checks/pg-timestamptz.json +18 -0
- package/packs/postgres/hooks/db-wipe-guard.mjs +95 -0
- package/packs/postgres/pack.json +48 -0
- package/packs/postgres/rules/postgres-migrations-never-stop-traffic.md +28 -0
- package/packs/postgres/rules/postgres-one-pool-per-process.md +21 -0
- package/packs/postgres/rules/postgres-queries-are-null-safe-and-bounded.md +26 -0
- package/packs/postgres/rules/postgres-types-say-what-they-hold.md +22 -0
- package/packs/postgres/rules/postgres-values-are-bound.md +130 -0
- package/packs/postgres/skills/postgres-safe-migration/SKILL.md +45 -0
- package/packs/reverse-engineering/rules/addresses-name-their-space.md +1 -0
- package/packs/reverse-engineering/rules/reproduction-or-original.md +1 -1
- package/packs/reverse-engineering/skills/gather-sources/SKILL.md +1 -0
- package/packs/rust/checks/rust-allow-needs-reason.json +16 -0
- package/packs/rust/checks/rust-blocking-in-async.json +32 -0
- package/packs/rust/checks/rust-if-chain-is-a-match.json +32 -0
- package/packs/rust/checks/rust-static-mut.json +32 -0
- package/packs/rust/checks/rust-string-as-error.json +34 -0
- package/packs/rust/checks/rust-stub-left-in.json +32 -0
- package/packs/rust/checks/rust-unsafe-needs-safety.json +31 -0
- package/packs/rust/checks/rust-unwrap-in-library.json +34 -0
- package/packs/rust/checks/rust-wildcard-dependency.json +16 -0
- package/packs/rust/clippy.toml +5 -0
- package/packs/rust/pack.json +27 -0
- package/packs/rust/rules/rust-async-never-blocks.md +20 -0
- package/packs/rust/rules/rust-borrow-before-you-clone.md +19 -0
- package/packs/rust/rules/rust-errors-are-returned.md +22 -0
- package/packs/rust/rules/rust-lints-are-the-gate.md +23 -0
- package/packs/rust/rules/rust-repeats-become-templates.md +28 -0
- package/packs/rust/rules/rust-unsafe-is-proved.md +21 -0
- package/packs/rust/skills/rust-extract-template/SKILL.md +50 -0
- package/packs/rust/skills/rust-port/SKILL.md +22 -0
- package/packs/rust/skills/rust-review/SKILL.md +24 -0
- package/packs/rust/tools/rust-lints.toml +19 -0
- package/packs/sound-design/skills/bounce-a-plugin/SKILL.md +40 -0
- package/packs/sound-design/tools/vst3host/build.sh +73 -0
- package/packs/sound-design/tools/vst3host/host_events.h +101 -0
- package/packs/sound-design/tools/vst3host/options.h +172 -0
- package/packs/sound-design/tools/vst3host/render.cpp +245 -0
- package/packs/sound-design/tools/vst3host/session.h +241 -0
- package/packs/synth-creator/hooks/build-guard.mjs +7 -7
- package/packs/synth-creator/hooks/protect-vendor.mjs +2 -1
- package/packs/synth-creator/hooks/stage-guard.mjs +1 -1
- package/packs/synth-creator/rules/timing-from-synthcore.md +1 -1
- package/packs/synth-creator/skills/build-through-the-queue/SKILL.md +4 -2
- package/packs/synth-creator/tools/buildq.mjs +74 -0
- package/prompts/workorder/PROMPT.md +53 -0
- package/prompts/workorder/run.sh +36 -0
- package/prompts/workorder/workorder.md +59 -0
- package/global/hooks/lib/program-read.mjs +0 -196
- package/global/hooks/lib/program-writes.mjs +0 -177
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,79 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 1.1.0 (2026-11-05)
|
|
4
|
+
|
|
5
|
+
Two new packs, a kit that works outside C++ and JS, and the faults a real build found: the MPX 500 rebuild ran 1.0.0 for a whole unit, and its report ranks them.
|
|
6
|
+
|
|
7
|
+
New:
|
|
8
|
+
|
|
9
|
+
- `rust` pack and configuration: 6 rules, 9 lesson checks, 3 skills, a lint set for `Cargo.toml` and a `clippy.toml`. Each check was measured on ten crates (6,245 files) and its hits read. What clippy judges better stays with clippy: five candidates were dropped for it. The lint set was proved with real `cargo clippy` on planted faults. `rust-app` preset.
|
|
10
|
+
- `postgres` pack: 5 rules, 10 lesson checks, 1 hook, 1 skill. The checks were measured on 5,653 `.sql` files and 5,520 source files. Seven are on by default, and three that are right only on a large live table are opt-in (`pg-index-concurrently`, `pg-fk-not-valid`, `pg-timestamptz`). A line that is right anyway says so: `pg: allow <reason>`.
|
|
11
|
+
- `db-wipe-guard` (`postgres`): a forced reset, `db:drop`, `flush` or `dropdb` runs only against a local database, read from the command, then the checkout's `.env`.
|
|
12
|
+
- The repetition laws hold on Rust, in Rust's own terms. `once-only` and `dup` read `.rs`. `template-law` reads a method called six times as a table, and only a free function can be made again by name: a trait method must repeat, and a method lives in its type. `dispatch-once` refuses a second lookup table on an enum outside the enum, and leaves a `match` that does work alone: on eight crates, a port of the C++ law would have refused 7 to 12 in 100 of them, and the compiler already holds every match to every variant, which the lint set keeps true by denying `_ =>`. `rust-if-chain-is-a-match` refuses three branches on one value where a pattern can say it.
|
|
13
|
+
- `vst3host` (`sound-design`) and the `bounce-a-plugin` skill: an offline VST3 renderer with no DAW, no audio device and no JUCE, taken from a project where it ran on firmware emulators a JUCE host could not load. The plugin is an argument, it builds on macOS and Linux from the SDK inside a project's JUCE, and it writes 32-bit float. Measured on Linux with a real plugin: 2,200 parameters listed, two bounces byte-identical, a cutoff sweep rising at each step, a sysex file sent and `--dump-params` read. The macOS build and the Roland DT1 modes are ported but not run here.
|
|
14
|
+
- `workorder <name>` and the `write-a-workorder` skill: a work order in `docs/workorders/<name>`, with the steps, the prompt that runs them with nobody there and a runner that starts session after session, from what two whole builds taught. The runner turns permission prompts off, and says so.
|
|
15
|
+
- `new` with no packs takes base alone. It used to install a synth's laws on any project (KWB-84).
|
|
16
|
+
- `site/`: a web page for the kit, kept out of the npm package, with its numbers held true by a test. Not deployed yet.
|
|
17
|
+
- `suggest` reads Rust from `Cargo.toml`, and Postgres from a project's dependency files in any language.
|
|
18
|
+
- A lesson check can read with a language's own blanker (`"language": "rust"`) and leave out tests in the same file (`"notInTests": true`).
|
|
19
|
+
- `suite-once` knows `cargo test` and `cargo nextest run`.
|
|
20
|
+
- The README starts from what a new reader needs: the benefits and three ways in, a real refusal, how to install one pack, what is whose, what a project keeps, how it is tested, how to let it build on its own, questions, how to add a rule, and the words.
|
|
21
|
+
|
|
22
|
+
A project that is not C++ or JS (all of these were in 1.0.0):
|
|
23
|
+
|
|
24
|
+
- `folder-law` refused `src/new.py` in a new Python project, and the same in Go and Rust. `src/` counts as a code folder unless the layout names folders inside it (KWB-78).
|
|
25
|
+
- Seven universal rules, among them `bug-fix-starts-red`, loaded only for C++ and JS, and `doctor --strict` was red on a new project for it. They load on Python, Go and Rust now, and two on JS as well (KWB-79).
|
|
26
|
+
- A project with no `package.json` was told `npx --no-install ...`, which cannot work there. `suggest`, `scan` and `fix` print the form that does, and its CLAUDE.md block says so (KWB-76).
|
|
27
|
+
- `init <pack>` took the smallest configuration that fits: `init mongo` gave `python`. It takes the project's own now, where the project has code (KWB-80).
|
|
28
|
+
- A file could be legal and have no rules: `folder-law` allowed any layout folder, while base's `cpp` and `js` concepts meant only `src/` and `tests/`. On a new install the rules now follow the layout: a folder in it gets the rules for its code, and a stray file outside it is still reported by `doctor --strict`. A first install also adds the top-level folders a repo's source is in to its layout: before, `folder-law` refused a new file in the project's own `lib/`. An installed project keeps its layout, and takes this with `"followFolders": true`. A `new-project` skill says how to start (KWB-83).
|
|
29
|
+
- Every configuration's CLAUDE.md block named a folder on one machine, and release steps a project cannot take. An `update` rewrites that line (KWB-77).
|
|
30
|
+
- The Rust row of the language table misread lifetimes, char literals, raw strings and nested comments, and read no method in an `impl` (KWB-75).
|
|
31
|
+
|
|
32
|
+
What fails silently or fails open:
|
|
33
|
+
|
|
34
|
+
- A hook that crashes no longer lets the call through in silence. On a tool call the runner refuses it once and says why, and the same call again goes through, logged, so a broken hook cannot stop the write that fixes it. At Stop or a prompt the author is told. A crash has its own log, `crashes.jsonl`, and is no longer counted as a refusal (KF-18, KF-40).
|
|
35
|
+
- `logs crashes` lists crashes, and `logs clear <hook>|all fixed|superseded "<why>"` clears them, so `doctor --strict` can pass honestly. A crash older than the hook or any file in `hooks/lib/` is history. A later crash is red again.
|
|
36
|
+
- An inline edit through a local helper (`def sub(f, a, b): Path(f).read_text()`) crashed sixteen hooks. It is read now, and when no hook can read what a command writes to a source file, the author is told that no content law judged it (KF-40).
|
|
37
|
+
- A project already installed is told about these as a note, and stays green, so `update` turns nothing red. A new install is held to them. Adding `"ruleTests": {}` to `layout.json` is the choice.
|
|
38
|
+
- `doctor` is red for a live rule whose Check names a test nothing answers to: three such rules hid four real bugs for a whole build. A test answers with `proves: <rule>`, or `layout.json` `"ruleTests"` points at it or declines with `"none: <reason>"` (KF-31).
|
|
39
|
+
- `param-id-lock` starts its lock at the first id it sees, never reads the build output (`buildOutput`, `out/`, `_deps`), reports a pattern it cannot compile by name, and `doctor` is red for a unit with parameters and an empty lock (KF-15, KF-18).
|
|
40
|
+
- `suite-once` sees the whole suite through a project's wrapper, with options, in the background, and through `buildq` (KF-23).
|
|
41
|
+
- A new install has `git-guard`'s house laws, using the machine's own git and gh login, with the trunk left to the owner. An existing project changes only through `"enable": ["guards/git-house"]` (KF-8).
|
|
42
|
+
- `GH_TOKEN=$X` with X unset is refused, and the refusal names the logged-in account and `ghAuth: cli`. With `ghAuth: cli` a push needs no token in its URL, and with no owner a push over SSH is no longer refused for naming no token (KF-12).
|
|
43
|
+
- `global add` installs base's shell reader. The kit no longer keeps a hand copy of it in `global/`.
|
|
44
|
+
|
|
45
|
+
False refusals, each held against the build's real refusals in both directions:
|
|
46
|
+
|
|
47
|
+
- `shape-law`: 14 of its 25 refusals were wrong. It no longer reads a hex address after a concept word, a sentence in a string, first as a search (`the first program with this name`), a sum (`x + 1 == program`), a library's call, a longer proper name (`MIDI Program Change`), a role quoted from a source (`[MAN] Edit knob 1 selects`), or a concept's own name or a listed selector (`EDIT knob`) as an instance. A call that takes a count is told from one that takes an index by its declared parameter: `turnProgram (int steps, ...)` passes and `turnEditKnob (int knob, ...)` is refused (KF-13, KF-17, KF-20, KF-28, KF-36).
|
|
48
|
+
- `making-check` matches a camelCase concept by its row name, accepts the shape word its own rule asks for, and judges only the writes after a turn's last landing, since compaction lets one turn hold a whole run (KF-19, KF-24, KF-34, KF-39). It no longer reruns once-only's detector on writes once-only has judged: 462 ms to 353 ms on the real transcript (KF-33).
|
|
49
|
+
- `code-shape` reports every line at fault in one refusal, and counts a Python brace and a lambda in a list correctly (KF-14, KF-27). One long line per refusal was the largest cost the kit added: 37 of 132.
|
|
50
|
+
- `git-guard` and `stage-guard` read `git add -n` as a dry run, `git checkout --theirs` during a merge as a resolution, and judge the subcommand rather than a word in an argument, so `git rev-parse x^{commit}` is no commit (KF-10, KF-21).
|
|
51
|
+
- `position-not-integrated` leaves tests' stubs alone, and `cpp-find-with-the-library` needs a `return` or `break` on the match (KF-25, KF-26).
|
|
52
|
+
- `once-only` no longer counts a block of `using` lines, includes and one-line constants as a copy (KF-32).
|
|
53
|
+
- `dispatch-once` tells two kinds of one name apart by their cases, and refuses two switches on one kind in one new file (KF-35).
|
|
54
|
+
- `protect-vendor`'s refusal names `buildOutput` (KF-2).
|
|
55
|
+
|
|
56
|
+
New projects:
|
|
57
|
+
|
|
58
|
+
- The kit ships the build queue `build-guard` sends every build to, `.claude/tools/buildq.mjs`: two jobs at a time, machine-wide, ending with the command's own status. `doctor` is red when it is gone, and for a `build.sh` that queues nothing, unless `guards.build.queue` declines with a reason (KF-1, KF-37).
|
|
59
|
+
- `suggest` and `init --auto` read a project's notes when it has no source yet, and say so (KF-3).
|
|
60
|
+
- The lock's new `installed` lists every pack whose files are there, the configuration's own included (KF-4).
|
|
61
|
+
- `doctor --strict` can pass on a new project: a rule whose folder holds nothing yet waits for its first file, and is no longer dead (KF-9).
|
|
62
|
+
- `scoped-no-denormals` and `timing-from-synthcore` agree on `processBlock`'s first two lines (KF-5). A reproduction may copy the artwork when `guards.instrument.artwork` says `verbatim` (KF-6).
|
|
63
|
+
- New rule `unattended-runs`: with the user away, take the recommended choice, keep every law, record the choice (KF-7).
|
|
64
|
+
- `straight-on-and-aligned` loads in `design/` and on panel and look tools, where the analysis happens, not only in `src/app`.
|
|
65
|
+
- `gather-sources` covers a source that cannot be fetched (KF-11). `addresses-name-their-space` warns that a rising run may be pointers (KF-16). `cpu-worst-case-per-block` lists a program load and says how to measure on a shared machine (KF-29). `plan-and-logs` reads a licence before choosing a source (KF-38). `test-the-template-once` and `house-control-behaviours` ask for one cheap pass of every instance through its real input path (KF-41).
|
|
66
|
+
|
|
67
|
+
What the build taught:
|
|
68
|
+
|
|
69
|
+
- New rule `a-control-is-proved-through-its-input`: a gate that writes the parameter proves nothing about the control. Driving the real editor found five real bugs. `prove-control` starts there, and sees the gate go red with the control's input handling compiled out.
|
|
70
|
+
- `analyse-reference-look` asks for a control and a confidence per measure, seed boxes for a dark part on a dark panel, rectifying against a known anchor, how to rank sources that disagree, the typeface as a scored choice, planted faults diffed against the unplanted result, and the render measured by the code that measured the target.
|
|
71
|
+
- `ui-matches-reference-look`: a look gate checks geometry exactly, and a whole-picture score is never a pass.
|
|
72
|
+
|
|
73
|
+
## 1.0.1 (2026-11-05)
|
|
74
|
+
|
|
75
|
+
- `suggest` and `init --auto` no longer read `node_modules`. In a new project with no `.gitignore`, the kit's own installed files were taken as the project: it was called `node`, and `reverse-engineering` was missed.
|
|
76
|
+
|
|
3
77
|
## 1.0.0 (2026-11-05)
|
|
4
78
|
|
|
5
79
|
The first public release. From here versions follow semver: a change that can break an installed project is a major version.
|
package/README.md
CHANGED
|
@@ -1,27 +1,274 @@
|
|
|
1
1
|
# @thedecipherist/claude-packs
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
[](https://www.npmjs.com/package/@thedecipherist/claude-packs) [View on npm](https://www.npmjs.com/package/@thedecipherist/claude-packs)
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
AI coding agents make the same small mistakes again and again, and every fix costs a turn and tokens. claude-packs installs guardrails into a project's `.claude/` folder: **rules** that tell Claude Code how this kind of project is done, and **hooks** that refuse a bad write before it reaches the disk.
|
|
6
|
+
|
|
7
|
+
You install once. From then on Claude Code reads the rules and meets the hooks in every session, with nothing to run or remember. The files live in the repo, so the whole team gets them.
|
|
8
|
+
|
|
9
|
+
It works on a project in any language. The machine needs Node 22, because the hooks are Node scripts, and the project itself can be Rust, Python, Go, C++ or anything else.
|
|
10
|
+
|
|
11
|
+
## Getting started
|
|
6
12
|
|
|
7
|
-
|
|
13
|
+
Claude Code on its own is fast, and it forgets. Each session starts cold, the same mistakes come back, code gets written twice, and "done" means it says it's done. The kit gives a project what a good team has:
|
|
14
|
+
|
|
15
|
+
- **Mistakes stop at the write.** A hook refuses a bad write before it reaches the disk, and says why. You don't find it in review, because it never landed.
|
|
16
|
+
- **Nothing gets written twice.** Copies, near copies and functions made again are refused, with what differs between them, so repetition turns into one template.
|
|
17
|
+
- **The project remembers.** The plan, the bugs and the decisions live in plain files in the repo, so a new session picks up where the last one stopped.
|
|
18
|
+
- **Every bug makes it stronger.** A bug starts with a test that fails for it, and the fix can become a check that refuses that mistake from then on.
|
|
19
|
+
- **"Done" gets measured.** A step finishes on a test or a number. A gate is seen to fail on a planted fault before anyone trusts it.
|
|
20
|
+
- **You can see what works.** Every call and refusal is logged, so you can tell which hooks earn their place.
|
|
21
|
+
- **It can build on its own.** Give it a work order and it runs session after session with nobody there, deciding as it goes and writing down every choice. A whole plugin, firmware map to finished panel, was rebuilt this way overnight.
|
|
22
|
+
|
|
23
|
+
There are three ways in:
|
|
24
|
+
|
|
25
|
+
| You have | Do this |
|
|
26
|
+
|---|---|
|
|
27
|
+
| A brand new idea | `new <name>` sets up the folders, the plan, the bug logs, git and the kit |
|
|
28
|
+
| An existing repo | `suggest`, then `init --auto`, then `scan` and `fix` for what is already wrong |
|
|
29
|
+
| A big job to hand over | `workorder <name>`, write the steps, and [let it build on its own](#let-it-build-on-its-own) |
|
|
30
|
+
|
|
31
|
+
The commands are in [Start here](#start-here).
|
|
32
|
+
|
|
33
|
+
## See it work
|
|
34
|
+
|
|
35
|
+
A new Rust crate, and one command:
|
|
8
36
|
|
|
9
37
|
```
|
|
10
|
-
|
|
38
|
+
$ npx @thedecipherist/claude-packs init --auto
|
|
39
|
+
Packs: base, rust. 151 files managed, 22 rule paths refreshed.
|
|
40
|
+
|
|
41
|
+
$ git status --short
|
|
42
|
+
?? .claude/
|
|
43
|
+
?? CLAUDE.md
|
|
44
|
+
?? clippy.toml
|
|
11
45
|
```
|
|
12
46
|
|
|
13
|
-
Then
|
|
47
|
+
Then Claude tries to write this into `src/parser.rs`:
|
|
14
48
|
|
|
49
|
+
```rust
|
|
50
|
+
pub fn parse(text: &str) -> u32 {
|
|
51
|
+
text.parse::<u32>().unwrap()
|
|
52
|
+
}
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
The hook refuses it, and the file is never written. Claude gets this back:
|
|
56
|
+
|
|
57
|
+
```
|
|
58
|
+
BLOCKED by lesson-checks in src/parser.rs: this edit brings back a known bug.
|
|
59
|
+
[rust-unwrap-in-library] A failure the caller could handle becomes a panic with no reason. Return it with `?`, or say why it cannot happen with `.expect("...")`.
|
|
60
|
+
text.parse::<u32>().unwrap()
|
|
61
|
+
see .claude/rules/rust-errors-are-returned.md
|
|
15
62
|
```
|
|
63
|
+
|
|
64
|
+
Claude reads the reason, returns a `Result`, and the write goes through. Nobody had to catch it in review.
|
|
65
|
+
|
|
66
|
+
## How you use it
|
|
67
|
+
|
|
68
|
+
**1. Install, once.** One command writes the rules and hooks into `.claude/`. The npm package is only the installer and updater: what does the work is the files it leaves in your project.
|
|
69
|
+
|
|
70
|
+
**2. Work as usual.** Use Claude Code the way you already do. It reads `.claude/` at the start of every session, and the hooks run on every write.
|
|
71
|
+
|
|
72
|
+
When a new version comes out, `update` brings it in. Nothing new switches on unless you chose it.
|
|
73
|
+
|
|
74
|
+
## Start here
|
|
75
|
+
|
|
76
|
+
In a Node project, add the kit as a dev dependency, so the team gets the same version:
|
|
77
|
+
|
|
78
|
+
```
|
|
79
|
+
npm i -D @thedecipherist/claude-packs
|
|
16
80
|
npx --no-install @thedecipherist/claude-packs suggest # which packs this project needs, and why
|
|
17
81
|
npx --no-install @thedecipherist/claude-packs init --auto # install exactly that
|
|
18
82
|
npx --no-install @thedecipherist/claude-packs scan # everything already wrong, on a copy of the project
|
|
19
83
|
npx --no-install @thedecipherist/claude-packs fix # the scan as a work order: .claude/fix-plan.md
|
|
20
84
|
```
|
|
21
85
|
|
|
86
|
+
In any other project there is no `package.json` to add it to, so leave out `--no-install` and npx fetches the kit:
|
|
87
|
+
|
|
88
|
+
```
|
|
89
|
+
npx @thedecipherist/claude-packs suggest
|
|
90
|
+
npx @thedecipherist/claude-packs init --auto
|
|
91
|
+
```
|
|
92
|
+
|
|
22
93
|
Then tell Claude to work through `.claude/fix-plan.md`. The `fix-from-scan` skill says how.
|
|
23
94
|
|
|
24
|
-
|
|
95
|
+
A brand new project starts with `new <name>`: the house files, a git repo and the kit in one step. On an existing repo, the install adds the top-level folders your source is in to the layout, so the rules reach your code wherever it lives, and `folder-law` keeps new code inside those folders from then on.
|
|
96
|
+
|
|
97
|
+
`scan` is safe to run before installing anything: it works on a copy in a temp folder and never writes to the project. `suggest` only reads file names and dependency files.
|
|
98
|
+
|
|
99
|
+
## Install one pack
|
|
100
|
+
|
|
101
|
+
You don't have to take what `suggest` finds. Name the pack yourself:
|
|
102
|
+
|
|
103
|
+
| You want | Command |
|
|
104
|
+
|---|---|
|
|
105
|
+
| One pack, in a project with nothing installed yet | `init mongo` |
|
|
106
|
+
| Several packs at once | `init rust docker ci` |
|
|
107
|
+
| One more pack, in a project that already has the kit | `add docker` |
|
|
108
|
+
| A pack out again | `remove docker` |
|
|
109
|
+
| A stack's whole set | `init rust-app` (see [Presets](#presets)) |
|
|
110
|
+
| To see what there is | `list` |
|
|
111
|
+
|
|
112
|
+
Each of these goes after `npx @thedecipherist/claude-packs`, or `npx --no-install @thedecipherist/claude-packs` where the kit is a dev dependency.
|
|
113
|
+
|
|
114
|
+
A few things are worth knowing:
|
|
115
|
+
|
|
116
|
+
- **`base` always comes too.** It holds the hooks that run every pack's checks, so no pack works alone. `writing` and `hook-proof` come with every configuration as well.
|
|
117
|
+
- **A pack has to fit the project's configuration.** `add` refuses one that doesn't, and lists what fits. `config <name>` switches.
|
|
118
|
+
- **In a folder with no code yet,** name the configuration, or the kit has to guess it from the pack: `init mongo --config node`. In a project with code, `init <pack>` uses the configuration `suggest` finds.
|
|
119
|
+
|
|
120
|
+
## What is whose
|
|
121
|
+
|
|
122
|
+
Some of what you will see in `.claude/` is Claude Code's own, and some only works through the kit's hooks:
|
|
123
|
+
|
|
124
|
+
| Part | Whose | What it does |
|
|
125
|
+
|---|---|---|
|
|
126
|
+
| `CLAUDE.md` | Claude Code | Read at the start of every session |
|
|
127
|
+
| `.claude/rules/` | Claude Code | Short laws. One with `paths:` loads only when Claude touches a matching file |
|
|
128
|
+
| `.claude/skills/` | Claude Code | Steps for one job. The description is always loaded, the body when it is needed |
|
|
129
|
+
| `.claude/settings.json` | Claude Code | Registers the hooks |
|
|
130
|
+
| `.claude/hooks/` | The kit | The scripts Claude Code runs on a tool call |
|
|
131
|
+
| `.claude/checks/` | The kit | Patterns the `lesson-checks` hook reads |
|
|
132
|
+
| `.claude/layout.json` | The kit | Which folder holds what |
|
|
133
|
+
| `.claude/tools/` | The kit | Helpers its skills and gates run |
|
|
134
|
+
| `.claude/claude-packs.lock.json` | The kit | What is installed, with a hash per file |
|
|
135
|
+
|
|
136
|
+
## What a project keeps
|
|
137
|
+
|
|
138
|
+
Claude forgets between sessions, so everything worth keeping lives in files. `new <name>` starts them, and the rules keep them true:
|
|
139
|
+
|
|
140
|
+
| File | What it holds | Why it helps |
|
|
141
|
+
|---|---|---|
|
|
142
|
+
| `CLAUDE.md` | How this project works, read at every session's start | Claude starts each session knowing the layout and the laws |
|
|
143
|
+
| `build.md` | The plan: what is in progress, each step's `making:` line, and a log of what landed | Work resumes from the file, and a step is ticked only when it was measured |
|
|
144
|
+
| `bugs.md` | Every bug, logged before it is fixed, then closed with its cause, its fix and the test that now catches it | The same bug can't quietly come back |
|
|
145
|
+
| `workflow-bugs.md` | Faults in the process itself: a hook, a tool, a test run | The workflow improves too, with the evidence written down |
|
|
146
|
+
| `docs/versions.md` | Each dependency, with its latest version and when that was checked | No pinned version comes from memory |
|
|
147
|
+
| `design/shape.json` | Each concept, as one or many | "Slot 2" never gets hard-coded where there are four slots |
|
|
148
|
+
| `.claude/hooks.log` | Each hook's time on every call | `doctor` goes red for a hook that got slow |
|
|
149
|
+
| `.claude/logs/events.jsonl` | Every tool call and what each hook said | `logs` shows which hooks earn their place |
|
|
150
|
+
| `.claude/logs/refusals.jsonl` | Every refusal with its reason, then a verdict: right or wrong, and why | Wrong refusals get found and fixed, so the laws improve on evidence |
|
|
151
|
+
| `.claude/logs/crashes.jsonl` | Every hook that crashed | A broken guard can't fail quietly |
|
|
152
|
+
|
|
153
|
+
Logs are never cleared: a full one moves to `.claude/logs/` under a dated name. So the project keeps its own history, and a lesson from one bug can become a [lesson check](#add-your-own-rule) that holds for good.
|
|
154
|
+
|
|
155
|
+
## How it is tested
|
|
156
|
+
|
|
157
|
+
The kit is strict about what counts as proof:
|
|
158
|
+
|
|
159
|
+
- **A bug fix starts red.** Write the smallest test that shows the bug and see it fail for that reason, then fix the code (`bug-fix-starts-red`).
|
|
160
|
+
- **A test has to be able to fail.** A gate is shown red on a planted fault, a mistake put in on purpose. A test that can't fail proves nothing.
|
|
161
|
+
- **Anything used twice is tested once.** Behaviour is tested on the template, with one quick pass proving every instance really is that template (`test-the-template-once`).
|
|
162
|
+
- **While working, run only what the change reaches.** The `pick-tests` skill picks them, so a small change never costs a full run.
|
|
163
|
+
- **The whole suite runs once, on committed work, as the gate before landing.** `suite-once` refuses it on uncommitted work, so it can't be run again and again in place of thinking.
|
|
164
|
+
- **Finished work lands.** Green work is merged to the trunk and pushed in the same turn (`land-branch`), and it isn't called landed until the remote agrees.
|
|
165
|
+
- **The guards are tested too.** Every hook has a `--selftest`, every lesson check proves its `bad` and `good` example, and `doctor` runs them all.
|
|
166
|
+
|
|
167
|
+
## Let it build on its own
|
|
168
|
+
|
|
169
|
+
A work order is a written brief that a project can build from with nobody there. It suits anything that takes many sessions: a new product, a port, a big migration, a rebuild from a spec.
|
|
170
|
+
|
|
171
|
+
```
|
|
172
|
+
npx @thedecipherist/claude-packs workorder billing
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
That writes three files to `docs/workorders/billing/`:
|
|
176
|
+
|
|
177
|
+
| File | What it is |
|
|
178
|
+
|---|---|
|
|
179
|
+
| `workorder.md` | The steps. This is the part you write |
|
|
180
|
+
| `PROMPT.md` | How to run: take the recommended choice, never stop to ask, record every decision, resume from `progress.md` |
|
|
181
|
+
| `run.sh` | Starts session after session until the work is done |
|
|
182
|
+
|
|
183
|
+
Write the steps with Claude, and the `write-a-workorder` skill keeps them honest. What makes one work:
|
|
184
|
+
|
|
185
|
+
- **Say what finished looks like,** and what is known and not known, so no report claims more than the work shows.
|
|
186
|
+
- **List every source by path.** A run can't ask where something is.
|
|
187
|
+
- **Put proof before what depends on it:** find out, prove it, then build on it.
|
|
188
|
+
- **End every step with "Done when:"** and a number or a test. "Works" can't be measured, so it can't finish.
|
|
189
|
+
|
|
190
|
+
```markdown
|
|
191
|
+
## W2. The import
|
|
192
|
+
|
|
193
|
+
1. Read every record in `data/orders.csv` into the schema of W1.
|
|
194
|
+
2. Reject a bad row by name, with its line number. Never skip one silently.
|
|
195
|
+
|
|
196
|
+
**Done when:** all 41,206 rows of the sample load, the 12 known bad rows are each rejected with the right reason, and a planted bad row turns the test red.
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
To run it, type `Run docs/workorders/billing/PROMPT.md` in Claude Code and watch, or leave it going with `bash docs/workorders/billing/run.sh`. Everything lands in files as it goes: `progress.md` line by line, `decisions.md` with each choice so you can overturn it, `bugs.md`, and a report with counts at the end. If a session ends, the next one picks up from `progress.md`, and it stops on a `DONE` file.
|
|
200
|
+
|
|
201
|
+
**Read `run.sh` before you use it.** It runs Claude with permission prompts off, because nobody is there to answer. The hooks still judge every write, but use it only on a project you trust, in a repo you can roll back.
|
|
202
|
+
|
|
203
|
+
To change a run in progress, edit its `PROMPT.md` and commit it. A run won't act on an instruction it can't trace to its order or to you, so a file dropped beside it is ignored on purpose.
|
|
204
|
+
|
|
205
|
+
## Questions
|
|
206
|
+
|
|
207
|
+
**Do I need a Node project?** No. Node 22 has to be on the machine, and that's all. The kit has configurations for C++, Go, Python, Rust and Node, and `base` for anything else.
|
|
208
|
+
|
|
209
|
+
**Which Claude apps does it work in?** Claude Code, in the terminal and the IDE extensions. Hooks and rules don't work in Claude Desktop or a normal Claude chat: neither reads a project's `.claude/` folder.
|
|
210
|
+
|
|
211
|
+
**What does it cost in tokens?** A Rust install loads about 3,300 tokens when a session starts: the `CLAUDE.md` block, 10 rules with no `paths:` and 22 skill descriptions. The `making` hook adds about 107 tokens to each prompt, and `doctor` prints that figure for your project. Rules with `paths:` and full skills load only when they are needed. The other hooks run outside the model, so they cost nothing unless they refuse.
|
|
212
|
+
|
|
213
|
+
**Global or per project?** Per project. Claude Code also reads `~/.claude` for every project and `CLAUDE.md` from parent folders, and the project's own files are the most specific. The kit writes to `~/.claude` only if you run `global add`, which installs [three shell pieces](#the-global-part-exactly-three-pieces).
|
|
214
|
+
|
|
215
|
+
**Is it for one person or a team?** Both. The files live in the repo, a dev dependency pins the version, and a team can keep [its own packs](#custom-packs-share-your-own-with-your-team) in its own git repo.
|
|
216
|
+
|
|
217
|
+
**Can I turn a check off?** Yes: name it in `layout.json` `"disable"`, as in `"disable": ["checks/rust-unwrap-in-library.json"]`, and run `update`.
|
|
218
|
+
|
|
219
|
+
## Add your own rule
|
|
220
|
+
|
|
221
|
+
Found a mistake Claude keeps making? Start in the project.
|
|
222
|
+
|
|
223
|
+
**1. Write the rule.** A short file in `.claude/rules/`, and `paths:` says when it loads:
|
|
224
|
+
|
|
225
|
+
```markdown
|
|
226
|
+
---
|
|
227
|
+
paths:
|
|
228
|
+
- "src/billing/**"
|
|
229
|
+
---
|
|
230
|
+
|
|
231
|
+
# Money is integer cents
|
|
232
|
+
|
|
233
|
+
<constraints>
|
|
234
|
+
Always do:
|
|
235
|
+
- Store and pass money as `i64` cents.
|
|
236
|
+
|
|
237
|
+
Never do:
|
|
238
|
+
- Use `f32` or `f64` for an amount.
|
|
239
|
+
</constraints>
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
**2. Enforce it, if you want a refusal.** A rule tells Claude. A lesson check stops the write. Add `.claude/checks/money-no-float.json`, with an example of each side, which `doctor` proves:
|
|
243
|
+
|
|
244
|
+
```json
|
|
245
|
+
{
|
|
246
|
+
"id": "money-no-float",
|
|
247
|
+
"why": "A float cannot hold 0.10 exactly, so amounts drift.",
|
|
248
|
+
"rule": ".claude/rules/money-is-integer-cents.md",
|
|
249
|
+
"globs": ["src/billing/**"],
|
|
250
|
+
"pattern": "\\b(?:amount|price|total)\\s*:\\s*f(?:32|64)\\b",
|
|
251
|
+
"bad": "pub struct Line { price: f64 }",
|
|
252
|
+
"good": "pub struct Line { price_cents: i64 }"
|
|
253
|
+
}
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
**3. Share it when it applies everywhere.** Your own files survive every `update`. When a rule holds for every project you have, move it into [a pack of your own](#custom-packs-share-your-own-with-your-team).
|
|
257
|
+
|
|
258
|
+
## Words
|
|
259
|
+
|
|
260
|
+
| Word | What it means |
|
|
261
|
+
|---|---|
|
|
262
|
+
| Pack | A folder of rules, checks, hooks and skills for one subject: `rust`, `mongo`, `docker` |
|
|
263
|
+
| Configuration | A kind of project: which packs fit it, its folders, and what counts as source. A project has one |
|
|
264
|
+
| Preset | A named list of packs, so `init rust-app` installs four at once |
|
|
265
|
+
| Profile | A ready-made `layout.json` for a known project shape, taken with `init --profile` |
|
|
266
|
+
| Layout | `.claude/layout.json`: which folder holds what, and which rules apply where |
|
|
267
|
+
| Rule | A short law in `.claude/rules/`. It tells Claude, and refuses nothing |
|
|
268
|
+
| Lesson check | A pattern with a `bad` and a `good` example. It refuses an edit that adds a match |
|
|
269
|
+
| Hook | A script Claude Code runs on a tool call. It can refuse the call |
|
|
270
|
+
| Skill | The steps for one job, loaded when the job comes up |
|
|
271
|
+
| Plant | A fault put in on purpose, to prove a hook or a gate catches it |
|
|
25
272
|
|
|
26
273
|
## What happens when Claude writes code
|
|
27
274
|
|
|
@@ -57,6 +304,8 @@ A refusal names the copies and lists what differs between them, which are the te
|
|
|
57
304
|
|
|
58
305
|
One language table reads C, C++, Objective-C++, JS, TS, Python, shell, Go, Rust, Java, C#, Scala, Dart, Kotlin, Swift, Ruby, PHP and Lua. A new language is one row in `packs/base/hooks/lib/languages.mjs`. A folder of kind `copy`, or a glob in `guards.templates.exclude`, is left alone.
|
|
59
306
|
|
|
307
|
+
Each language keeps its own sense. In Rust a trait method must repeat, and a method lives in its type, so only a free function can be made again by name. A `match` that does work is good Rust in any number of files, since the compiler holds each to every variant: the lint set denies `_ =>` so it can, and `dispatch-once` refuses only a lookup table written outside its enum.
|
|
308
|
+
|
|
60
309
|
Anything used more than once is one template, and it is tested once. `test-the-template-once` says how: test the behaviour on one instance, and prove the rest are that template with a read of the table. `one-walk-per-template` refuses a test that presses every instance.
|
|
61
310
|
|
|
62
311
|
## Code stays small in every direction
|
|
@@ -70,8 +319,8 @@ Anything used more than once is one template, and it is tested once. `test-the-t
|
|
|
70
319
|
| Pack | For | Rules | Checks | Hooks | Skills |
|
|
71
320
|
|---|---|---|---|---|---|
|
|
72
321
|
| `ai` | Code that calls a model: untrusted input, explicit keys, model ids | 2 | 4 | 0 | 0 |
|
|
73
|
-
| `audio-core` | Any JUCE synth or effect: realtime safety, DSP quality, state, parameters |
|
|
74
|
-
| `base` | Universal engineering, in every configuration |
|
|
322
|
+
| `audio-core` | Any JUCE synth or effect: realtime safety, DSP quality, state, parameters | 42 | 8 | 2 | 7 |
|
|
323
|
+
| `base` | Universal engineering, in every configuration | 22 | 7 | 18 | 10 |
|
|
75
324
|
| `ci` | CI workflows: every language run, tools pinned, permissions stated | 2 | 2 | 0 | 0 |
|
|
76
325
|
| `content-site` | Sites that publish: complete page heads, one source per page, defended forms, sized media | 4 | 3 | 0 | 1 |
|
|
77
326
|
| `cpp` | Any C++ project: templates, thread contracts, headers, casts, static analysis | 10 | 14 | 0 | 1 |
|
|
@@ -91,12 +340,14 @@ Anything used more than once is one template, and it is tested once. `test-the-t
|
|
|
91
340
|
| `mongo` | MongoDB with the native driver | 6 | 18 | 0 | 0 |
|
|
92
341
|
| `multi-tenant` | One system, many customers: no role crosses a tenant | 1 | 2 | 0 | 1 |
|
|
93
342
|
| `nginx` | NGINX in front of containers | 2 | 7 | 0 | 1 |
|
|
343
|
+
| `postgres` | PostgreSQL: migrations that never stop traffic, values always bound, no database wiped by mistake | 5 | 10 | 1 | 1 |
|
|
94
344
|
| `python` | Python: templates, errors, resources, safe subprocess calls | 2 | 11 | 0 | 1 |
|
|
95
345
|
| `react` | React: failed requests, effects, accessible controls | 2 | 6 | 0 | 0 |
|
|
346
|
+
| `rust` | Rust: errors returned, unsafe proved, async never blocks, clippy as the gate, every repeat one template | 6 | 9 | 0 | 3 |
|
|
96
347
|
| `reverse-engineering` | Rebuilding a machine from firmware, manuals and banks: the machine's own names first, two sources before naming, every law sourced | 9 | 4 | 1 | 6 |
|
|
97
348
|
| `shell` | Shell scripts: strict mode, quoting, shared functions | 2 | 9 | 0 | 1 |
|
|
98
349
|
| `shell-hooks` | Shell and Node hooks for Claude Code | 1 | 4 | 0 | 0 |
|
|
99
|
-
| `sound-design` | Sound proved by measuring audio: algorithms as data, neutral is exact, the meter first | 6 | 5 | 0 |
|
|
350
|
+
| `sound-design` | Sound proved by measuring audio: algorithms as data, neutral is exact, the meter first, and an offline VST3 renderer | 6 | 5 | 0 | 5 |
|
|
100
351
|
| `stellix` | Laws of one synth project | 5 | 5 | 1 | 0 |
|
|
101
352
|
| `stored-text` | Text from a database reaches the page through one renderer | 1 | 4 | 0 | 1 |
|
|
102
353
|
| `synth-creator` | The synth-creator configuration's own laws | 6 | 2 | 9 | 2 |
|
|
@@ -122,6 +373,7 @@ A project is one configuration: a kind of project, as data in `configurations/<n
|
|
|
122
373
|
| `go` | Go projects | `go` |
|
|
123
374
|
| `node` | A Node.js or TypeScript service, web app, CLI, library or MCP server | `js-ts` |
|
|
124
375
|
| `python` | Python projects | `python` |
|
|
376
|
+
| `rust` | Rust crates and workspaces | `rust` |
|
|
125
377
|
| `full-stack` | A Fastify API and a Next.js web app, with one schemas folder and one database gateway. It fixes a folder layout, so it is offered and never assumed. It always takes `full-stack`, `http-api`, `fastify`, `zod` and `docker` | `js-ts`, `stored-text`, `ui-craft` |
|
|
126
378
|
| `synth-creator` | JUCE synths and effects | `cpp`, `audio-core` |
|
|
127
379
|
|
|
@@ -149,10 +401,11 @@ npx --no-install @thedecipherist/claude-packs config <name> [--dry-run] switch
|
|
|
149
401
|
| `python-app` | `python`, `shell`, `docker` |
|
|
150
402
|
| `shell-tools` | `shell` |
|
|
151
403
|
| `go-app` | `go`, `shell`, `docker`, `ci` |
|
|
404
|
+
| `rust-app` | `rust`, `shell`, `docker`, `ci` |
|
|
152
405
|
|
|
153
406
|
## Commands
|
|
154
407
|
|
|
155
|
-
Each is `npx --no-install @thedecipherist/claude-packs <command
|
|
408
|
+
Each is `npx @thedecipherist/claude-packs <command>`, or `npx --no-install @thedecipherist/claude-packs <command>` with the kit as a dev dependency. `--dir <project>` runs it on another folder.
|
|
156
409
|
|
|
157
410
|
| Command | What it does |
|
|
158
411
|
|---|---|
|
|
@@ -164,9 +417,10 @@ Each is `npx --no-install @thedecipherist/claude-packs <command>`, with `--dir <
|
|
|
164
417
|
| `remove <pack...>` | Remove packs; files you edited are kept |
|
|
165
418
|
| `update` | Re-sync installed packs from this version |
|
|
166
419
|
| `update-all <dir...>` | Update every listed project that has the kit |
|
|
167
|
-
| `logs` | Which hooks earn their place: calls, refusals and verdicts per hook. `logs refusals`, `logs mark <id> right\|wrong "<why>"` |
|
|
168
|
-
| `doctor [--strict] [--fresh]` | Verify the install: paths, hooks, selftests, checks' own examples, hook timing |
|
|
420
|
+
| `logs` | Which hooks earn their place: calls, refusals and verdicts per hook. `logs refusals`, `logs mark <id> right\|wrong "<why>"`, `logs crashes`, `logs clear <hook>\|all fixed\|superseded "<why>"` |
|
|
421
|
+
| `doctor [--strict] [--fresh]` | Verify the install: paths, hooks, selftests, checks' own examples, hook timing, and that a test answers each rule whose Check names one |
|
|
169
422
|
| `new <name>` | A new project: the house files, a git repo on a work branch, the kit installed |
|
|
423
|
+
| `workorder <name>` | A work order in `docs/workorders/<name>`: the steps, the prompt that runs them, and a runner |
|
|
170
424
|
| `new-pack <name> [--repo <git-url>]` | A new repository for a team's own pack |
|
|
171
425
|
| `list` | The packs and presets |
|
|
172
426
|
| `configs` | The configurations |
|
|
@@ -190,19 +444,19 @@ Each is `npx --no-install @thedecipherist/claude-packs <command>`, with `--dir <
|
|
|
190
444
|
| `once-only` | Write | Refuses a duplicate of code as written |
|
|
191
445
|
| `code-shape` | Write | Refuses wide lines, packed lines, long functions, long parameter lists |
|
|
192
446
|
| `file-size-guard` | Write | Refuses a source file past its line limit |
|
|
193
|
-
| `dispatch-once` | Write | Refuses a `switch` on a kind already switched on in another file |
|
|
447
|
+
| `dispatch-once` | Write | Refuses a `switch` on a kind already switched on in another file. In Rust, a second lookup table on an enum, outside the enum |
|
|
194
448
|
| `folder-law` | Write | Refuses a new source file outside the layout |
|
|
195
449
|
| `placement-law` | Write | Refuses a kind of thing in the wrong folder |
|
|
196
450
|
| `shape-law` | Write | Refuses a literal instance of a many concept |
|
|
197
451
|
| `brief-guard` | Write | Refuses a brief that names a fixed instance |
|
|
198
452
|
| `secrets-guard` | Write | Refuses a secret in code, or a secret file in git |
|
|
199
453
|
| `untrusted-boundary` | Write | Refuses a model call with outside text and no per-call boundary |
|
|
200
|
-
| `git-guard` | Bash | Refuses a token in git config, and
|
|
454
|
+
| `git-guard` | Bash | Refuses a token in git config, and the git laws: stage by name, no rebase or force, branches from the fetched trunk. A new install has them; an older project adds `"enable": ["guards/git-house"]` |
|
|
201
455
|
| `suite-once` | Bash | Refuses the whole test suite on uncommitted work |
|
|
202
456
|
| `repo-litter` | Bash | Refuses `git add` of a big file, a working screenshot in the root, or a debug dump |
|
|
203
457
|
| `making-check` | Stop | Sends a turn back when what it wrote is not what it said |
|
|
204
458
|
|
|
205
|
-
Packs add their own: `realtime-guard` and `param-id-lock` (`audio-core`), `stack-guard` (`full-stack`), `schemas-only` (`zod`), `firmware-out-of-git` (`reverse-engineering`), `browser-guard` (`gpu-painter`), `no-shipped-images` (`stellix`), and the `synth-creator` set: `build-guard`, `time-guard`, `spec-lock`, `frozen-files`, `protect-vendor`, `stage-guard`, and the opt-in `build-sweep`, `idle-wake` and `user-asks`.
|
|
459
|
+
Packs add their own: `realtime-guard` and `param-id-lock` (`audio-core`), `stack-guard` (`full-stack`), `schemas-only` (`zod`), `firmware-out-of-git` (`reverse-engineering`), `db-wipe-guard` (`postgres`), `browser-guard` (`gpu-painter`), `no-shipped-images` (`stellix`), and the `synth-creator` set: `build-guard`, `time-guard`, `spec-lock`, `frozen-files`, `protect-vendor`, `stage-guard`, and the opt-in `build-sweep`, `idle-wake` and `user-asks`.
|
|
206
460
|
|
|
207
461
|
Every hook is timed to `.claude/hooks.log`, and `doctor` is red for a median over 500 ms. Nothing is ever cleared: a log past 1 MB moves to `.claude/logs/` under a dated name (`"guards": { "logs": { "maxKb": 1024 } }`). A hook that crashes lets a call through, so `doctor` is red for that too, and the `hook-proof` pack holds hooks to exit 2. Hooks of one entry run in one Node process, through `run-hooks.mjs`.
|
|
208
462
|
|
|
@@ -210,7 +464,7 @@ Every hook is timed to `.claude/hooks.log`, and `doctor` is red for a median ove
|
|
|
210
464
|
|
|
211
465
|
Four packs carry what rebuilding classic machines from firmware taught, and most of it is about failures that pass every test: units deaf to the transport, presets silently on defaults, a list of algorithms behind one DSP path.
|
|
212
466
|
|
|
213
|
-
`reverse-engineering` starts from the machine's own names: `names-sweep` searches an image for what the manual prints, in the forms a display uses and through every wrapping met so far, and reports the record size, the order, the pools and the tables; `menu-map` joins every parameter to the page that reaches it. It needs two sources before anything is named, a source tag on every law and a debt ledger for what was tuned by ear, and it keeps firmware out of git. `midi` holds the law of clock and sync, and treats a program as records that round-trip byte for byte. `sound-design` proves sound by measuring audio. `instrument-shell` keeps sessions loadable and panels reachable. `init synth-rebuild` takes them all.
|
|
467
|
+
`reverse-engineering` starts from the machine's own names: `names-sweep` searches an image for what the manual prints, in the forms a display uses and through every wrapping met so far, and reports the record size, the order, the pools and the tables; `menu-map` joins every parameter to the page that reaches it. It needs two sources before anything is named, a source tag on every law and a debt ledger for what was tuned by ear, and it keeps firmware out of git. `midi` holds the law of clock and sync, and treats a program as records that round-trip byte for byte. `sound-design` proves sound by measuring audio, and `vst3host` bounces any VST3 with no DAW or audio device, so a plugin can be measured from a script (`bounce-a-plugin` says how). `instrument-shell` keeps sessions loadable and panels reachable. `init synth-rebuild` takes them all.
|
|
214
468
|
|
|
215
469
|
A project says what it is, in `"guards": { "instrument": { "kind": "reproduction" } }` or `"original"`, because the laws differ: on a reproduction the machine is the spec, aliasing and all.
|
|
216
470
|
|
|
@@ -222,10 +476,12 @@ Dates are facts in an article. The `no-time-or-date` check is opt-in, for an aut
|
|
|
222
476
|
|
|
223
477
|
## Knowing which hooks earn their place
|
|
224
478
|
|
|
225
|
-
A bug log only records the refusals somebody complained about, so it cannot say whether a hook works. The kit records them all. Every call is a line of `.claude/logs/events.jsonl`: the session, the tool, the file or command, and each hook's time, exit code and reason. Every refusal
|
|
479
|
+
A bug log only records the refusals somebody complained about, so it cannot say whether a hook works. The kit records them all. Every call is a line of `.claude/logs/events.jsonl`: the session, the tool, the file or command, and each hook's time, exit code and reason. Every refusal is also a line of `refusals.jsonl`, and every crash a line of `crashes.jsonl`, with an id, the branch and commit, the kit's version and the hash of the hook that decided. Secrets are masked, and file contents are not kept.
|
|
226
480
|
|
|
227
481
|
`logs` adds it all up, over every rotated file. `logs mark <id> right|wrong "<why>"` records a verdict. The logs stay out of git by default.
|
|
228
482
|
|
|
483
|
+
A hook that crashes has judged nothing. On a tool call the runner refuses the call once and says so, and the same call again goes through, logged, so a broken hook can never stop the write that fixes it. `doctor` stays red for the crash until the hook changes or `logs clear` records why it is over.
|
|
484
|
+
|
|
229
485
|
## Where things apply
|
|
230
486
|
|
|
231
487
|
- **`.claude/layout.json` is the one source of truth.** It names every folder and concept, and what goes where. Move a folder there, run `update`, and every rule follows.
|
|
@@ -235,6 +491,7 @@ A bug log only records the refusals somebody complained about, so it cannot say
|
|
|
235
491
|
- **Skills** for one area go into that folder's nested `.claude/skills/`, so they only appear once Claude works there.
|
|
236
492
|
- **Hooks judge only this project's files**, and a file in a git worktree by that worktree.
|
|
237
493
|
- **`doctor --strict`** fails on a rule that matches no file and a source file no rule covers.
|
|
494
|
+
- **`doctor`** fails on a live rule whose Check names a test nothing answers to. A test answers with `proves: <rule>` in it, or `layout.json` `"ruleTests"` points the rule at a file or declines it with `"none: <reason>"`. At the end of an install this is a note.
|
|
238
495
|
|
|
239
496
|
## It never overwrites your work
|
|
240
497
|
|
|
@@ -310,7 +567,7 @@ Global by design: they fix this machine's shell for Claude, not any project's ru
|
|
|
310
567
|
|
|
311
568
|
## Credits
|
|
312
569
|
|
|
313
|
-
The kit learned from [superpowers](https://github.com/obra/superpowers) (MIT), mddkit and MDD, Vercel's Web Interface Guidelines (MIT), Anthropic's frontend-design (Apache 2.0), Impeccable (Apache 2.0), taste-skill and imagegen-skills (MIT). [docs/ui-craft-sources.md](docs/ui-craft-sources.md) says what came from each UI source.
|
|
570
|
+
The kit learned from [superpowers](https://github.com/obra/superpowers) (MIT), mddkit and MDD, Vercel's Web Interface Guidelines (MIT), Anthropic's frontend-design (Apache 2.0), Impeccable (Apache 2.0), taste-skill and imagegen-skills (MIT), for Rust from [BeautifulRust](https://github.com/morganlinton/BeautifulRust) (MIT) and [rust-skills](https://github.com/leonardomso/rust-skills) (MIT), and for Postgres from [squawk](https://squawkhq.com/docs/rules) (MIT and Apache 2.0), [strong_migrations](https://github.com/ankane/strong_migrations) (MIT), [pg-aiguide](https://github.com/timescale/pg-aiguide) (Apache 2.0) and the PostgreSQL wiki's [Don't Do This](https://wiki.postgresql.org/wiki/Don't_Do_This). [docs/ui-craft-sources.md](docs/ui-craft-sources.md) says what came from each UI source.
|
|
314
571
|
|
|
315
572
|
## License
|
|
316
573
|
|
package/bin/claude-packs.mjs
CHANGED
|
@@ -18,15 +18,20 @@ import { addCustomPack, loadCustomPacks, newPack } from '../lib/custom-packs.mjs
|
|
|
18
18
|
import { fixPlan } from '../lib/fix-plan.mjs';
|
|
19
19
|
import { logsCommand } from '../lib/logs.mjs';
|
|
20
20
|
import { scan } from '../lib/scan.mjs';
|
|
21
|
-
import { suggest, suggestionOf } from '../lib/suggest.mjs';
|
|
21
|
+
import { detectedConfig, suggest, suggestionOf } from '../lib/suggest.mjs';
|
|
22
|
+
import { newWorkorder } from '../lib/workorder.mjs';
|
|
22
23
|
import { sync } from '../lib/sync.mjs';
|
|
23
24
|
import { ensureShape, isSynth, shapeCommand } from '../lib/shape-cli.mjs';
|
|
24
25
|
|
|
26
|
+
const INSTALLING = { installing: true }; // doctor at the end of an install: what the project has yet to do is a note
|
|
27
|
+
|
|
25
28
|
const HELP = `usage: npx --no-install @thedecipherist/claude-packs <command> [options]
|
|
26
29
|
|
|
27
30
|
new <name> a new project in <dir>/<name>: the house files (CLAUDE.md, build.md, bugs.md,
|
|
28
31
|
workflow-bugs.md, docs/versions.md), a git repo on a work/ branch, the kit installed
|
|
29
|
-
--packs <a,b> the packs (default
|
|
32
|
+
--packs <a,b> the packs (default base alone); --profile <name>, --config <name> as for init
|
|
33
|
+
workorder <name> a work order in docs/workorders/<name>: the steps, the prompt that runs them with nobody
|
|
34
|
+
there, and a runner that starts session after session
|
|
30
35
|
init [pack...] install packs or presets (e.g. init node-api; list shows them); base is always included
|
|
31
36
|
and create the layout folders
|
|
32
37
|
--config <name> the configuration (configs lists them; stored in layout.json
|
|
@@ -57,6 +62,7 @@ const HELP = `usage: npx --no-install @thedecipherist/claude-packs <command> [op
|
|
|
57
62
|
fix [--from <scan.json>] [--out <file>] the last scan as a work order for Claude, .claude/fix-plan.md; scans first if there is none
|
|
58
63
|
logs which hooks earn their place: calls, refusals and verdicts per hook, over all the history
|
|
59
64
|
logs refusals [--hook <h>] [--open]; logs mark <id> right|wrong "<why>"
|
|
65
|
+
logs crashes; logs clear <hook>|all fixed|superseded "<why>"
|
|
60
66
|
survey print the prompt that makes Claude write docs/project.md for tailoring
|
|
61
67
|
list show available packs
|
|
62
68
|
symmetry gen --cmake <out.cmake> | --list the generated gate shape_symmetry: one test per many concept in
|
|
@@ -103,18 +109,20 @@ async function main() {
|
|
|
103
109
|
|
|
104
110
|
switch (command) {
|
|
105
111
|
case 'new':
|
|
106
|
-
return (await newProject(dir, rest[0], { packs: packs ?? (config ? readConfig(config).packs.default : ['
|
|
112
|
+
return (await newProject(dir, rest[0], { packs: packs ?? (config ? readConfig(config).packs.default : ['base']), seedLayout, config })).code;
|
|
113
|
+
case 'workorder':
|
|
114
|
+
return newWorkorder(dir, rest[0]);
|
|
107
115
|
case 'init': {
|
|
108
116
|
if (rest.includes('--auto')) {
|
|
109
117
|
const pick = suggestionOf(dir);
|
|
110
118
|
await sync(dir, pick.packs.map((p) => p.pack), { force, mkdirs: true, seedLayout, config: pick.config });
|
|
111
|
-
return doctor(dir);
|
|
119
|
+
return doctor(dir, console.log, INSTALLING);
|
|
112
120
|
}
|
|
113
121
|
if (rest.length === 0 && !config) throw new Error('name at least one pack or a configuration, e.g. `init audio-core` or `init --config base` (`configs` lists them)');
|
|
114
122
|
const chosen = rest.length ? rest : readConfig(config).packs.default;
|
|
115
|
-
await sync(dir, chosen, { force, mkdirs: true, seedLayout, config });
|
|
123
|
+
await sync(dir, chosen, { force, mkdirs: true, seedLayout, config: config ?? detectedConfig(dir, chosen) });
|
|
116
124
|
if (isSynth(chosen) && ensureShape(dir)) console.log(' design/shape.json: written empty; add a row per concept (one or many) before building it');
|
|
117
|
-
return doctor(dir);
|
|
125
|
+
return doctor(dir, console.log, INSTALLING);
|
|
118
126
|
}
|
|
119
127
|
case 'planner-skills':
|
|
120
128
|
return plannerSkills(rest.includes('--out') ? resolve(rest[rest.indexOf('--out') + 1]) : null);
|
|
@@ -126,15 +134,15 @@ async function main() {
|
|
|
126
134
|
case 'add': {
|
|
127
135
|
const sources = fromUrl ? { ...fetched, [rest[0]]: addCustomPack(rest[0], fromUrl) } : fetched;
|
|
128
136
|
await sync(dir, [...installed, ...rest], { force, mkdirs: true, sources });
|
|
129
|
-
return doctor(dir);
|
|
137
|
+
return doctor(dir, console.log, INSTALLING);
|
|
130
138
|
}
|
|
131
139
|
case 'remove':
|
|
132
140
|
await sync(dir, installed.filter((p) => p === 'base' || !rest.includes(p)), { force });
|
|
133
|
-
return doctor(dir);
|
|
141
|
+
return doctor(dir, console.log, INSTALLING);
|
|
134
142
|
case 'update':
|
|
135
143
|
if (installed.length === 0) throw new Error('nothing installed here; run init first');
|
|
136
144
|
await sync(dir, installed, { force, mkdirs: true, sources: fetched });
|
|
137
|
-
return doctor(dir);
|
|
145
|
+
return doctor(dir, console.log, INSTALLING);
|
|
138
146
|
case 'update-all': {
|
|
139
147
|
let failed = 0;
|
|
140
148
|
for (const d of rest.map((x) => resolve(x))) {
|
|
@@ -143,7 +151,7 @@ async function main() {
|
|
|
143
151
|
console.log(`\n== ${d}`);
|
|
144
152
|
try {
|
|
145
153
|
await sync(d, lockPacks, { force, mkdirs: true });
|
|
146
|
-
failed += await doctor(d);
|
|
154
|
+
failed += await doctor(d, console.log, INSTALLING);
|
|
147
155
|
} catch (e) {
|
|
148
156
|
failed += 1;
|
|
149
157
|
console.log(` PROBLEM: ${e.message}`);
|
|
@@ -73,7 +73,7 @@
|
|
|
73
73
|
"Ask the user before inventing a new folder. A new folder goes into `.claude/layout.json` first.",
|
|
74
74
|
"When a hook, check or guard blocks work that is correct, stop and report its exact message. A blocking hook is a red check: fix the hook first, with a selftest, then continue.",
|
|
75
75
|
"When a command is refused or fails, the step fails loudly. Never report a refused write or a failed command as done.",
|
|
76
|
-
"claude-packs (
|
|
76
|
+
"claude-packs (`@thedecipherist/claude-packs`) is the source of truth for every rule, check, hook and skill this project's configuration installs. A fix to one of them is made in the kit, with its test, and comes here with `npx --no-install @thedecipherist/claude-packs update`. A project edits its installed copy only to try a fix before it goes into the kit."
|
|
77
77
|
],
|
|
78
78
|
"never": [
|
|
79
79
|
"Create source files outside these folders, or put a kind of thing anywhere but its place. The folder-law and placement-law hooks refuse both.",
|
|
@@ -15,6 +15,7 @@
|
|
|
15
15
|
"shell",
|
|
16
16
|
"ci",
|
|
17
17
|
"go",
|
|
18
|
+
"rust",
|
|
18
19
|
"reverse-engineering",
|
|
19
20
|
"midi",
|
|
20
21
|
"sound-design"
|
|
@@ -79,7 +80,7 @@
|
|
|
79
80
|
"Ask the user before inventing a new folder. A new folder goes into `.claude/layout.json` first.",
|
|
80
81
|
"When a hook, check or guard blocks work that is correct, stop and report its exact message. A blocking hook is a red check: fix the hook first, with a selftest, then continue.",
|
|
81
82
|
"When a command is refused or fails, the step fails loudly. Never report a refused write or a failed command as done.",
|
|
82
|
-
"claude-packs (
|
|
83
|
+
"claude-packs (`@thedecipherist/claude-packs`) is the source of truth for every rule, check, hook and skill this project's configuration installs. A fix to one of them is made in the kit, with its test, and comes here with `npx --no-install @thedecipherist/claude-packs update`. A project edits its installed copy only to try a fix before it goes into the kit."
|
|
83
84
|
],
|
|
84
85
|
"never": [
|
|
85
86
|
"Create source files outside these folders, or put a kind of thing anywhere but its place. The folder-law and placement-law hooks refuse both.",
|