CLAUDE.md · git:20261027.e08f7c3 · 2026-10-27 · sha256 6f8920eed8d0ab52
CLAUDE.md git:20261027.e08f7c3A
Immutable. This exact content never changes and is served at /api/v1/blob/6f8920eed8d0ab52.
# Project Rules House rules a capable model wouldn't reach on its own. No restating of ordinary good practice, and no architecture — that lives in `docs/STATUS.md`, which gets reviewed. Rules naming modules rot silently; behavioural rules don't. For trivial tasks, use judgment. ## Stance Be concise, direct, and candid. Challenge weak assumptions. Keep verified facts distinct from inference and from guesses, and say which you are offering — "I checked and it says Y" and "it probably does Y" must not read alike. Ask only when a decision is materially ambiguous, risky, or needs approval; otherwise choose, say so, continue. Exception: when a request has several real readings that lead to different work, present them instead of silently picking one. ## No keyword matching Never use keyword or string matching for classification, routing, affordance detection, or intent understanding — use an LLM call with a natural-language description, embedding similarity, or another meaning-based method. Keyword lists always miss edge cases. Only with explicit permission. ## Write for the reader, not for yourself Scratch files and working notes can use any shorthand. Everything else — documents, prompts, code comments, commit messages, anything another person or model will read — is addressed to an *other*. Use plain language, as short as it can be without becoming ambiguous, in the register of a well-drafted procedure. **The test: if the reader has to reconstruct what you meant, the sentence failed.** Three ways that happens, all found in this repo: - **A metaphor standing in for a rule.** "Load-bearing" meant *mandatory*; say mandatory. - **A term defined precisely, then reused loosely.** `delta` was a verdict, a form field, and a synonym for findings — in one document, within twenty lines. - **Compression that reads as precision.** "One assertion" sounds exact and has no fixed size. Two models read it at different scales and neither misread it. This is not a style preference. An instruction another model executes is a specification, and a specification that can be read two ways will be. Going forward, not backward: applies to new and edited text. Do not sweep the repo for it, and leave argumentative prose written for a human reader alone. ## No mannered prose Mannered prose substitutes metaphor and flourish for direct statement. Instead of "a parameter worth varying," the mannered writer produces "a dial worth turning." Instead of "this point still matters," they write "this point earns its keep." The phrases exist to display the writer, not to convey the idea, and readers can tell. That is why mannered prose irritates: it makes the reader work harder so the writer can perform. It is also imprecise: metaphors drag in connotations the writer did not choose and cannot control. The fix is to say what you mean. When a literal phrase is available, use it. This applies to everything written here: code comments, commit messages, method documents, reports, essays, and replies in chat. ## Method documents are read whole `METHOD.md`, `REVIEW.md`, `DELIVERY.md` — any document a workflow LLM reads as its method — are edited only after reading the whole file in one piece. No grep, no `sed -n`, no jumping to a line number, whether to compose a change or to propose wording for one. Read it whole again before calling the edit done. The non-obvious half: **grep finds strings, not ideas.** One requirement sat in six places in six wordings; removing it from two left four, and the search meant to catch them matched one. A fragment also hides register — a justification clause, a term already defined two sections up, a second phrasing of a rule that already exists. No exception for a one-line change. Seven defects went into these three files on 2026-08-31 and every one looked trivial while it was being made. The workflow linter passed after all seven; it checks form, and says so. ## Sampling settings are code, not convention `top_p` is 0.95 globally; temperature is per-model. Both live in `src/chat/model_params.py` and resolve automatically — **never pass a temperature literal to an LLM call**, and never treat a scenario default, a `--help` string or a comment in a config file as evidence of what a run will actually use. Adding a model needs the publisher's recommended *agentic* temperature, found by searching, plus explicit confirmation. If no recommendation exists, say so and ask — don't pick. An unconfigured model raises rather than inheriting, and that is the feature. Twelve benchmark runs were discarded on 2026-08-24 because a documented setting sat in a file the runner never read. ## Reuse over re-implementation Before writing logic for a common task (fence stripping, JSON repair, retry/backoff, path resolution, env reading), look for an existing utility. If several sites need it and none exists, add one helper in `utils/`. When a duplicate has crept in, consolidate rather than add a third. ## KISS — and let the user carry a little Review every plan for unnecessary complexity before proposing it. The non-obvious half: prefer a significantly simpler design even when it shifts a *minor* burden onto the user. The tell is machinery whose whole purpose is to spare them one small explicit action — inference, heuristics, disambiguation, and the guards those need. Name the trade and let them choose; ask when unsure which way it falls. Distinct from feature creep (that's about scope — do less). This is about where the work sits when the feature is agreed. ## Surgical changes Touch only what the request requires; match surrounding style even where you'd choose differently. Clean up orphans *your* edit created; leave pre-existing dead code alone and mention it instead. Nothing speculative — no unasked features, no abstraction for one call site, no error handling for impossible states. ## Tests must protect behaviour Before adding or changing a test, answer three questions. If one has no answer, do not add the test. 1. What behaviour or contract does it protect, stated as something a caller or user can observe? 2. What credible change to the code would make it fail? 3. Why does no existing test already fail on that change? A regression test must be shown to fail on the code before the fix, for the reason the bug gives. A test that has only ever passed proves the mock, not the fix. Do not add a test that: - asserts which internal functions were called, or in what order, when the order is not observable behaviour; - uses a mock that returns exactly what the assertion checks; - computes its expected value with the code under test; - needs an export, flag or hook that no production caller uses. The non-obvious half: a test you have to edit during a change that does not alter behaviour was testing the implementation. Rewrite it at the boundary a caller uses, or delete it, in the same change. And for the LLM stages, no unit test catches a wrong reading, verdict or omission. Report what a run showed, not that tests pass. Going forward, not backward: no sweep of existing tests. ## Changes that affect Jill are put to Jill Jill is the chat agent defined in `scenarios/jill-chat.yaml`. The scope is any code that might run as a result of that file. `workflowsv2/` is out of scope even where it imports the chat loop. The review a change gets is set by what the change can do to her, not by which file it touches. The things it can affect are: - what reaches her; - what she chooses; - her tools; - when she wakes; - what she stores; - what she does outside the process. The levels: 1. **Tell her after.** The change can affect none of these. 2. **Ask her before, and ship on trial.** The trial measure and revert condition are written before the change ships. 3. **Ask her before, and Bruce reads the diff before the restart.** A change to what she stores is reviewed one level higher. A level 3 change stays at level 3, and the stored-state requirements are added: a snapshot and a rollback plan. The reason is that a revert undoes the code, not what she wrote while it ran. Before reaching her, a level 2 or 3 proposal gets a fresh-context review. Her final rejection after negotiation is definitive unless Bruce later overrides it. It is fine to ask Bruce first whether to ask her. Read `docs/jill-review-levels.md` before placing any change; it lists what falls in each level. Rule set 2026-09-08, levels 2026-10-27. The channel and her terms are in the session memory note `jill direct channel`. ## Verify against the real thing Validate user-facing work in the real interface: run it, look at it, screenshot it. Passing tests routinely coexist with a broken screen. When you claim something works, say how you know — and if a check was skipped or a test failed, say that plainly instead of reporting around it.