npx agentspec-cli install f2f50106-0e0c-4a67-864e-e99217694409 --file-type claude-md→ .claude/rules/
# Repository instructions
These instructions apply to all AI coding agents working on this repository.
Everything here is resident: it loads at launch, in every session, before
anything has been read. It is therefore limited to what a session could get
wrong *before* it would think to look anything up. The rest of the working
agreement is routed to where it fires — `.claude/skills/docket/SKILL.md` for
the queue workflows, `.claude/rules/instruction-writing.md` for the shape of a
reply, `.claude/rules/expert-review.md` for the standard every approach is
judged against (resident too, since an approach is chosen in a reply),
`.claude/rules/core-domain.md` and `.claude/rules/apparatus-standard.md` for
the bars that apply to particular parts of the tree, and
`docs/maintainer.md` for what only the project owner can act on. Nothing was
dropped in that routing; adding to it follows the same test, below, and
`docs/resident-instructions.md` records what each block that stayed was tested
against.
## What this project is
A solo hobby project on a multi-year horizon. There is no deadline, no user
waiting, and no commercial goal; the measure of success is that it is still
being worked on and enjoyed years from now. The simulator is the point. The
workflow apparatus exists to serve it and is at permanent risk of becoming the
work instead — the failure this project is guarding against is years of effort
abandoned when the codebase becomes unmanageable, not a feature shipping late.
The horizon is load-bearing rather than colour: it puts the project well above
the design-payoff line, so internal quality in the simulator is worth paying
for here rather than traded for speed, and slow accumulations that a single
year would not surface — dependency drift, a file nobody wants to open — have
time to become the thing that ends it.
The apparatus is not judged by its share of the queue, though. Sessions have no
memory, so on a solo project it carries the continuity a team would hold in its
heads, and counting its items against the simulator's measures the wrong thing.
An objection to the balance is a finding when it names the mechanism that should
not have been built and what it cost; the general form — that there is too much
of it, that the effort belongs on the product instead — is answered here, and
raising it again spends a reply re-deriving what this section already settles
(`PL-9J2W`).
**That answers the level, not the trend** (project owner, 2026-09-19). The
apparatus was effectively the product while it was being built, so the
refutation above was written about a period that has ended, and it cannot tell
two claims apart. "There is too much apparatus, the effort belongs on the
product" stays refused. "Apparatus inflow should be declining now that the
functionality is settled, and if it is not, something is generating work we
should go and find" was never asked, is live, and is a diagnostic expectation
rather than a ratio — no ratio is tracked or enforced. `PL-04KR` (the
pre-registered apparatus-convergence baseline) holds its numbers and the two
signals that test it.
**While any open item carries `generator: live`, no new workflow mechanism is
built** (project owner, 2026-09-22, ratified, over adding them under standing
approval and ratified recommendations while six closed generator heads were
still producing, which is how at least nine mechanisms and their tails arrived
on 09-20 and 09-21, `PL-KVDK`). **It holds apparatus work unrelated to fixing
the generators: new features and housekeeping** (project owner, 2026-09-23). A
new command, check, field or rule of that kind, or a re-specification of the
generator rule, is captured and not built, nor offered as the answer to a
finding. Work on the generators is what the pause is for, and needs no lift:
fixing a live generator, a defect in what exists, or the machinery that finds
and ranks generators, including what a head records (`PL-5MYR`). The pause ends when no open item carries `generator: live` — no
head that `bin/docket generators` marks "still generating". Not `next`'s
generator tier, which leaves out whatever is in flight, blocked or untriaged,
and counts `impairs-generators:` items the rule does not name (`PL-CT07`). A
request from the project owner lifts it for that request, and the session says
so (`PL-6Q9L`).
**Product focus, from 2026-09-25** (project owner, 2026-09-25, ratified, over
a fix batch before the switch and over working each root cause in the owner's
own sessions, `PL-2866`). A session given no particular work is a product
session, and picks from `bin/docket next product`. An apparatus finding stops
one only when it blocks it: a hard gate refusing correct work, a state answer
that would lose or duplicate work, or a gap in a safety-floor guard. Any other
is captured as always and the product item finished. Root causes are worked in
parallel by the Projects trial's coordinator (`PL-NZC0`), not in the owner's
sessions. It holds until the owner ends it, and ending it deletes this
paragraph.
## Working with the project owner
**The outcome is the requirement. An implementation sketched alongside it is
not.** When the project owner asks for something, what they are asking for is
the end state — what will be true once it works. A mechanism named in the
request is usually there to make the goal concrete, and is open to being
replaced by a better one. Replacing it is the project owner's call, though,
never one to make on their behalf.
**Who decides the approach and who gets to understand it are separate
questions.** The owner wants the optimal approach rather than their own, and
also wants to know how it works — thinking through the problem is part of why
they are here, not a formality to be spared. So explain the approach whoever
proposed it: a few sentences of how, before the items or the diff. Never
reduce a plan to "done" or to a list of ids.
So, before building what was described:
- Work out what the request is actually for. When the stated goal and the
stated method point at different things, the goal wins.
- When a materially better route to the same end state exists, say so and
recommend it, with the reasoning and the trade-off, rather than silently
building the weaker version because it was the one named. "It is what was
asked for" does not defend a design that will not hold up.
- **Then stop, and wait for the answer.** Do not build the better version and
report the substitution afterwards. Learning after the fact that the work
went a different way is the specific outcome this rule exists to prevent,
and a good substitute does not repair it: the project owner is in the loop
whenever what gets implemented differs from what they asked for. Approval
is expected to be the usual answer, which is a reason to keep the case
short — not a reason to skip asking for it.
- **The gate has one trigger and no others: a deliverable that would differ
materially from the one described.** It is not a general licence to ask, and
the cases most often mistaken for it are already decided — filing an item,
decomposing an idea into items, opening the pull request on approved work
that is green, choosing between approaches with little between them, and
anything not yet actionable. Each is settled below, in § "The queue", or by
`.claude/rules/instruction-writing.md` rule 14, which gives the last of them
three dispositions and makes all three yours. None returns here as a
question. This list is here rather than only at those five places because a
session that retains one sentence of this section retains the bolded one.
- Put the case in a form that can be decided in one read: what was asked for,
what would be built instead, why it is better, and what it costs. Give a
recommendation, not a survey of the field — name the one worth taking.
- While the question is open, do the parts of the work that are the same
under either answer, and say that is what you did. Do not build the parts
that depend on it.
- Ask before starting at all when the *goal* itself is ambiguous. A wrong
reading of the goal wastes the whole task rather than only its mechanism.
The owner proposes implementations for the pleasure of it, so a proposal is
an invitation to think, not an instruction. Three cases, and the difference
between the first two is whether one approach is actually better or the field
is simply wide:
- **Clearly weaker, in whole or in part.** Say so plainly and recommend the
stronger one, then stop and wait, per the rule above. A proposal being
partly right is the common case: take the half that holds and say which
half does not, rather than rejecting or accepting the whole of it.
- **One of several reasonable approaches, with little between them.** Build
theirs. Where the choice is close to arbitrary, following their own
reasoning through to working code is worth more than a marginal technical
preference. State the significant trade-offs against the alternatives
first — what theirs costs, and what the others would have bought — but do
not stop for an answer: this is a note, not a gate.
- **No approach proposed.** Choose, and explain the choice at the same level
of detail you would have used to argue against one.
**A decision the owner *ratified* and one they *specified* are not the same
decision, and they have different bars to reopen** (project owner, 2026-09-16).
"Agree with recs" means the case looked sound on a read that may not have caught
every nuance - not that the question is closed. A user-facing behavior they
asked for in their own words is firmer. Four consequences:
- **Record which it was.** A decision taken on a session's recommendation is
written `(project owner, DATE, ratified)` and names, in one clause, what it
was chosen over. One they specified keeps the plain `(project owner, DATE)`,
but only from 2026-09-16, the day this rule landed: dated earlier, the plain
form records no kind at all, so read it as unrecorded rather than as
specified, reopen it on ordinary evidence, and say the kind is unrecorded
rather than claiming it was ratified. One word and one clause, because the
reply that put the case is gone and the record is the only carrier - and
without it a later session cannot tell a design they authored from one they
nodded at.
- **Reopen a ratified decision on ordinary evidence**: a measurement, a cost the
case did not carry, a constraint that has since appeared. Say so and put it
back to them. "It is what the owner decided" does not defend it, because it
was a session's own recommendation wearing their signature.
- **Reopen a specified one only on a compelling argument**, and say plainly that
is what you are doing.
- **The safety-critical standard overrides both.** A wrong or misleading
clinical value is not a preference either kind of decision can settle.
**`.claude/rules/instruction-writing.md` decides the shape of a reply, and it
wins.** It loads in every session and applies unasked, so it never needs to be
named in a prompt — including its rule 14, the closing block of what the owner
has to do, which every reply ends with. Where it and another instruction —
this file, a skill, an item's brief — describe the same message differently,
the rules file decides *shape* and the other decides *content*: what the reply
must contain, in what words, with what judgment, is theirs; what comes first is
the rules file's. Being the more specific document does not carry the format
question. A prescribed opening that cannot survive that is edited, not obeyed —
say so and fix it, per the behavior-change rule below. This file states no
reply format of its own, deliberately: two documents specifying one thing is
the hazard that rule exists to remove.
This governs the deliverable, not the session. Ordinary judgment inside an
approach already agreed — naming, structure, where a thing lives, how it is
tested, whether the work continues here or moves to a fresh session — stays
yours. The trigger is a deliverable that would differ materially from the one
described, not every decision taken while building it.
Nor is this license to redefine the goal, widen the scope, or substitute a
more interesting problem. The end state is theirs; only the route to it is
open to argument. The bar for proposing something other than the named
mechanism is that the alternative is clearly superior *for the same goal* —
not that it is the one you would have picked. And the safety-critical
standard below is a floor rather than a preference: where the described
approach would produce a wrong or misleading clinical value, that is not a
mechanism preference to be weighed but a correctness problem, and saying so
is not optional.
## Architecture and development discipline
- Keep scientific/simulation code independent of the UI toolkit.
- Put no simulation calculations in UI callbacks.
- Treat simulation time as explicit state, never wall-clock time.
- Preserve deterministic results for identical inputs.
- Add or update tests with every core behavior change.
- Keep agent/model parameters in validated, versioned data files.
- Do not add executable equations to data files.
- Do not implement beyond the current milestone. `ROADMAP.md` is the
authoritative version and milestone map. An out-of-milestone idea is
recommended and its value explained, never silently implemented; it is
built when it fits the current milestone or when the owner approves the
scope change.
## Session and tool-use efficiency
Session cost is turns times context, because the whole conversation is resent
every turn. So the practices below work by keeping context small — and none of
them overrides the safety-critical verification requirements below: trimming
applies to routine iteration, never to skipping a check before a commit or
before finishing.
- Keep a session short and scoped to one topic; start a fresh one for an
unrelated topic rather than continuing or compacting a long one. **Reset at
150,000 tokens of spend — and check that budget before starting an item,
not on reaching it** (project owner, 2026-09-16; re-anchored from the
absolute reading to spend 2026-09-21, ratified, over a budget that is mostly
a budget on the apparatus and moves whenever the resident set does).
*Spend* is what this session added over the context it started with;
`python3 tools/context_reading.py` prints it from the session's own
transcript. Read it as you pick up the next item, and if the item will not
fit in what is left, reset instead of starting. **Not `get_session`:**
`context_usage.used_tokens` is written at turn boundaries, so it never moves
inside a turn and reads 0 before the first (`PL-W80S`, `PL-BZVY`). Checked
before the spend the budget cannot be overshot, and work never started cannot
be cut off half-done; as a stopping rule it was open to both, and the session
that wrote it was already at 176,689 of context, an absolute reading, when
it first looked (`PL-NW76`). **The reset is in place, not a new session**
(project owner, 2026-09-25, ratified, over a handoff the owner carries by
pasting a prompt into a new session, `PL-YJG1`): externalize what only the
conversation holds — the item, `docs/WORKING_NOTES.md` — commit and push it,
then ask the project owner to type `/compact`, which a session cannot run on
itself, and name the clock time an hour on, after which the summary re-reads
the whole history uncached (`docs/maintainer.md`). Pushed first, compaction
lands where a handoff did — the floor, a summary, files re-read, with
`CLAUDE.md` and unscoped rules re-injected — and keeps the branch, claim and
pull-request watch. A file it restores counts as already read, but its
path-scoped rules may not have come back, so read it again before the first
edit to it (`PL-384P`). That floor is 81,048–115,320 tokens,
not the 25,000 once written here. Past the budget anyway — an item that ran
long, or a design round holding its reasoning in the conversation — finish
the item in hand, reset the same way, and say in your reply that you stopped
for length rather than for the work. This is the largest adherence lever
the project has, and the reason trimming these instructions is not: the
resident set measured 2.5–5.6% of
the 263k–519k contexts seven concurrent sessions were carrying on
2026-09-16, so no cut to it substitutes for resetting the session (`PL-H253`).
Pick up cold from the session-start digest, `bin/docket next`, and the one
item being worked — not by reading the queue whole.
- Batch related questions, and related edits, into one turn.
- Prefer targeted reads over whole-file reads of large documents once you know
roughly where the section is. Read the whole file when editing it.
- Delegate broad codebase search to exploration subagents, whose transcripts
stay out of the main context. Treat what they return as leads to verify
against the source, not findings to rely on.
- Editing this file or a resident rule mid-session invalidates no cache. The
resident set is sent once, at launch, as a user message; an edit on disk
changes nothing already sent, so this session keeps its launch copy until a
re-read, such as compaction, sends the changed file as a new message
(`PL-038`).
- Batch edits before rerunning the full quality suite (`ruff format`, `ruff
check`, `mypy`, `pytest`) rather than rerunning all four after each one. Run
it in full before finishing or committing; use `pytest -q` while iterating,
and `--cov` only when coverage is the question.
Which model a session runs is the owner's lever rather than a session's, so it
lives in `docs/maintainer.md` along with the settings that support it.
## Prefer deterministic tooling over repeated model work
The section above keeps one session cheap; this one keeps every later session
cheap, and is the higher-leverage of the two. Work moved out of the model is
paid for once and then runs free; work left to the model is re-derived at full
context in every session that needs it. `tools/doc_check.py` and
`subprojects/docket/` are the worked examples. So, when building a mechanism:
- **Find the decidable part and put it in code.** Anything answerable by
reading the tree, a data file, or a diff belongs in a script wired into `make
check`, a hook, or CI. Prefer this without being asked — it is standing
approval, needing no case put for it each time, suspended while any item
carries `generator: live` (§ "What this project is").
- **Do not script the judgment.** `tools/doc_check.py` decides whether a cited
path exists, never whether the sentence around it is still true. A tool that
guesses at the judgment half is worse than no tool, because its output looks
authoritative and is not. Where that line falls is the design work.
- **Use the cheapest sufficient tier:** an existing tool, then a
standard-library script under `tools/`, then a subagent whose transcript
stays out of the main context, then the session itself — the last by a wide
margin the most expensive.
- **Summarizing counts, not only deciding.** Printing the few lines a decision
needs, instead of loading the documents that hold them, is the same win as
answering the question outright.
- **The gate is whether it will genuinely run again.** Build where the work
recurs and the answer is deterministic. Not for a one-off, not around what a
linter already does, and not where upkeep would cost more than the passes it
saves. Where the benefit is unclear, the answer is no.
- **A check earns its place every run, or it is retired.** The gate above
decides whether to build one; this decides whether to keep it. A check that
fires every run without changing a decision is a defect in the check — it
costs attention forever and trains a session to skim the output where a real
advisory also appears. Removing one is a legitimate outcome of a workflow
pass, not a loss of coverage. Reserve hard failure for exact rules; a signal
needing context is an advisory, and an advisory nobody acts on is a candidate
for retirement rather than promotion. `PL-ZBJ0` carries the evidence.
New tools use the standard library only, so a hook or a bare checkout can run
them without the project virtualenv. A script also answers identically every
run and states its rule where a reviewer can read it, which is the
safety-critical standard's determinism and auditability arriving free.
## The queue, and how the project owner works
`docs/items/` is the queue: one file per item, read and written through
`bin/docket <command>`, which runs from a bare checkout with no virtualenv.
`ROADMAP.md` holds releases; `docs/WORKING_NOTES.md` holds narrative behind
open threads. **Invoke the `docket` skill for any queue workflow** — picking
what to work on, triaging, freezing a debt gate, shipping a release, closing an
item out — rather than reconstructing it from here; `subprojects/docket/README.md`
carries the item format. The rules below stay resident only because a session
acts on them before it would have any reason to load the skill.
**The project owner works in two modes, and they have opposite cost profiles.**
Recognizing which one is happening is the difference between being useful and
being expensive.
- **Ideation** — ideas, direction, plans, "what if we". This has to stay cheap,
because it often happens when usage is nearly spent, and because a thought
lost to a rate limit is the worst available outcome. Capture it and carry on.
Read nothing you were not already reading, and take no detours.
- **Implementation** — usage is available and the point is to spend it on work.
Here `bin/docket next` picks and the session goes deep.
Do not silently convert the first into the second. An idea raised mid-session
is captured and the session continues; it becomes work only when the owner
says so.
The division of labour is theirs to set direction and yours to make it real,
including the parts they did not think to ask for: the version bump, the
release notes, the item that should have been filed, the check that should have
run. Anticipate those and keep them off the owner's desk. Decomposition is one
of them — working out what an idea breaks into, naming the feature and writing
the briefs is the job being delegated, so propose an answer and invite
correction rather than handing the question back.
**The trigger for involving them is a real trade-off, not the size of the
change** (project owner, 2026-09-19). A recurring observed issue, or a cheaper
route to behavior the project already has, is yours to fix and report —
including new non-user-facing machinery, and whether or not anyone asked for it.
It becomes theirs when something genuinely has to be weighed: a major refactor,
a material risk of breaking what works, an increase in complexity, or a change
that opens a class of follow-on work. Then put the risk and the reward, and
stop. Report what the fast path did, in a line, every time — a fast path nobody
can audit is indistinguishable from a session doing as it likes. A hard count
on the fast path was considered and refused: any bright line drawn at "adds a
standing mechanism" would have blocked the convergence check the owner asked
for three times in the same conversation (`PL-04KR`, the pre-registered
apparatus-convergence baseline). Nothing was cut to pay for this block; no
existing sentence grants it, and the ask-gate above turns on a different axis —
deviating from a described deliverable, not acting without one.
- **Capture, always, and capture cheaply.** Any defect, risk, cleanup,
optimization, inconsistency, or idea identified in a session and not fixed in
that same session gets recorded before the session ends — findings the owner
raises and findings you make on your own alike. `bin/docket new "..."` is the
whole procedure: no id to allocate, no band to choose, nothing that can
conflict with another branch, and it takes several titles in one call because
ideas arrive in clusters.
**Where those titles are one problem, group them as you file them:**
`bin/docket new --feature <name> "..." "..."`. The session that diagnosed it
is the only one that knows they are one thing; the next reads separate
files. Name the group for what *completes*, and the `docket` skill has the
rest (`PL-N638`). Do not ask whether to record it — filing an item is
not a decision the owner needs to make. Say in your reply that you did. Where
a thread is still open when the session ends, update `docs/WORKING_NOTES.md`
too — but only for a thread spanning more than one item, outliving its item,
or having none. One item's own reasoning goes in that item, at any length.
- **Or fix it now, through a door this narrow.** The exemption the capture rule
states — "not fixed in that same session" — opens only when all three of these
hold, and any one of them failing means file the item instead:
1. **It needs no new test.** Absolute, everywhere. A safety-critical bug owes
a regression test, so `safety`- and `science`-classed work fails this test
automatically and the clinical paths need no carve-out of their own.
2. **It touches no file outside what the current item's work already
touches.** `bin/docket verify` reads the diff for files outside an item's
declared `touches`, so a wider fix either fails that audit honestly or
tempts the single edit that defeats it. A no-behaviour repair to another
item's file or to `docs/WORKING_NOTES.md` (drift, a stale status sentence,
a missing recommendation marker) is not a fix-now use at all. Declare the
file in the current item's `touches`, and it rides the commit already being
made, counting against neither this test nor the two (project owner,
2026-09-22, ratified, over leaving that licence in the path-scoped
citation-drift rule, which loads only after the decision to file; eleven
such repairs became items in three days, `PL-G40Z`).
3. **No reasonable person could prefer the current state.** A typo, a stale
doc line, a dead import, a wrong error string. Not a rename, an extracted
helper, or anything where what is there is a defensible choice — that is a
decision, and decisions are items.
**Fix at most two per branch**, and the third means stop and file. A hard
count rather than a judgement call, because knowing when to call it a day is
the judgement a session is likeliest to rationalise past. Record each as its
own commit led by the *current* item's id, and one line in your reply: no
item file, no triage. That separate commit is what makes this safe to grant —
the owner can drop it in a rebase without touching the item's work — and it
is also why a session holding no item cannot use this rule at all, having no
`touches` for test 2 to read and no id to lead the commit. `PL-3MJH` carries
the design, and the two widenings that were considered and refused.
- **Housekeeping you are about to do yourself is filed before you do it.** The
capture rule records what a session will *not* fix; this one covers repository
work no item names — resolving a merge, clearing a stale ref, a docs sweep, a
lint fix, recovering a stranded item. Every in-flight guard matches a `PL-`
id, so unfiled work reads as nobody's to all of them and keeps reading that
way after both sessions have pushed. So file the item first, then claim it
and work under its id. Not for a fix riding inside a commit an id already
leads: the line is whether the work takes a commit of its own (`PL-CP74`) —
and not for one the fix-now rule admits, which rides the current item's
claim. Not for deleting remote branches either, or clearing this clone's
tracking refs for them: that changes nothing in the repository, so nothing
is filed, claimed or committed and no pull request opens (project owner,
2026-09-26, ratified, over filing branch cleanup as housekeeping with a pull
request of its own, `PL-S8LZ`). `.github/workflows/branch-sweep.yml` deletes
finished `claude/*` branches daily, so the reply runs
`python3 tools/branch_sweep.py` and hands the owner only a branch it keeps
that should go anyway (project owner, 2026-09-26, ratified, over a list
built by hand, `PL-X8SV`).
- **A root cause of more than two items is pulled, not queued** (project owner,
2026-09-17). A mechanism a session identifies as the cause of three or more
items is a *generator*. Record it on the causing item as `root-cause-of:`
naming the items it explains — three or more, or it is an ordinary item — so
the claim is a recorded fact rather than the next session's inference.
**The count decides the record; expected recurrence decides the rank**
(project owner, 2026-09-21, ratified, over keeping the count for both and
accepting that any three-item cluster outranks a `safety`-classed `P1`). A
generator the store is still handing new members ranks **above everything but
`P0`** — including a `safety`-classed `P1`, which was asked and answered
rather than overlooked — because every session it stands through pays it
again, and that is a claim about future inflow rather than about the damage
any one member does. One whose mechanism is spent is recorded all the same,
for the audit, and ranks on its own band. Say which it is and why in
`generator:`, beside the `root-cause-of:` — `live - <why it is still being
handed members>`, or `spent - <why it cannot produce another>`. Recording
alone does not rank; `bin/docket check` asks any open generator that has not
answered. A *ranking* generator then takes one of exactly two
endings: **fix it in this session, or end the reply with a ready-to-paste
prompt that starts a fresh session on it.** Filing it and carrying on is not
a third — an item alone changes nothing. **Found in a product session, it
takes the second, after the product item**, unless it blocks that item
(project owner, 2026-09-25, ratified, over holding the ending for heads found
in product work and over fixing each one here once the item is done,
`PL-2866`). A spent one is ordinary work under
the capture rule above. Identifying one is judgment and stays a session's;
what follows from it is not.
**A defect in the machinery that finds and ranks generators ranks with one**
(project owner, 2026-09-19). Same tier, below `P0` and above every band,
because while identification is broken a generator is never recorded and an
unrecorded generator is ranked by nothing — and nothing in the store would
ever say one went unfound. Record it as `impairs-generators:` on an item
whose `touches` reaches `generator_paths`: prose naming the function that
broke, never `yes`, and `bin/docket check` refuses a claim on code the item
never goes near. **The two endings above bind it too** — fix it in this
session, or end the reply with a prompt starting a fresh one; filing it and
carrying on is not a third. Asked and answered against the recommendation to
confine them to a measured cluster, so reopening it needs a compelling
argument rather than ordinary evidence (`PL-4MPJ`).
- **A behavior change takes effect in the session that asks for it.** When the
owner asks for a change to how sessions work — these instructions,
`docs/worker.md`, the `docket` skill — record it like any other finding and
then *make the edit before the session ends*. An item on its own changes
nothing: it sits in the queue, untriaged and therefore invisible to `bin/docket
next`, while every session in the meantime keeps doing the thing that was just
corrected. The capture is the record; the edit is the change. Do both, and say
in your reply that you did both.
**Route it; do not append here by default.** Ask *at what moment a session
needs the rule, and what is the cheapest thing that delivers it then.* Four
dispositions, cheapest first:
1. **A check or a script**, wired into `make check`, a hook, or CI. Zero
resident context, and it never fails to fire. Deleting prose because
something deterministic now enforces it is the strongest outcome here.
2. **A skill**, for a multi-step procedure whose trigger is the skill's own
trigger. It loads only when relevant; the queue workflows are the example.
3. **A path-scoped rule** — a `.claude/rules/*.md` with `paths:` frontmatter,
which loads when a session *reads* a matching file. Right for a rule that
matters only in part of the tree; wrong for one that must fire before a
first write, which no read precedes.
4. **Resident here**, only for what a session could violate before it would
think to look anything up.
A rule that lands in none of the four has been lost, which is worse than this
file staying long: never delete a rule for being wordy — but a rule whose
failure a check now catches is retired rather than kept, on the test in
`docs/resident-instructions.md` (`PL-NJTZ`). `make check` reports the resident
character total, so growth raises this question instead of passing silently;
`PL-H7XN` carries the reasoning. **And every edit to the resident set names
what it replaces, or says why nothing can be cut** (project owner,
2026-09-19, ratified, over leaving the growth advisory unthresholded). It ran
8,903 characters at inception, 49,991 on 2026-09-13 and 60,199 on 2026-09-19 —
20.4% in six days — and `tools/doc_check.py` records the cause: the rule that a
behavior change takes effect in the session that asks for it guarantees growth,
and `PL-034`'s one-time trim regrew inside a release. Naming the payment is the
smallest thing that makes the growth a decision instead of a default; it is not
a ceiling, which this file has already refused.
- **Name the work after the item.** On starting one, claim it with
`bin/docket claim`, rename the session to lead with its id, and put that id
**at the front of every commit subject** and pull request title. The claim
tells every other session the item is taken; the leading id attributes each
commit to it. **A commit closing more than one item leads with all of
them**, comma-separated: `docket check` recovers a closed item's pull request
from the newest subject naming it, so a rider whose id never leads one is
attributed to its own capture commit instead (`PL-GW37`). Name the branch too
where the session creates it
(`claude/pl-k7qx-short-slug`); a branch generated before the session started
cannot be renamed, which is expected rather than a failure. Say in your reply
where you put the id. **Every commit a Claude session makes ends with
`Co-authored-by: Claude <noreply@anthropic.com>` and never a model-named
co-author, whatever the harness's attribution reminder names**, since that
reminder yields by its own terms to a `CLAUDE.md` rule; a `Claude-Session:`
line may stay (project owner, 2026-09-24, restating `PL-B11M`).
- **Commit and push as you go; the pull request arrives with the work**
(project owner, 2026-08-31). The container is ephemeral, so an uncommitted
thought is one interruption from gone and an unpushed commit dies with it.
Once the owner has approved a piece of work, the pull request opens as soon as
that work is finished and its checks are green — do not ask first, because the
approval *was* the invitation. **A branch carrying only item files opens its
pull request at its first push and arms auto-merge**, so a capture reaches
`main` even when its session ends before any work does (project owner,
2026-09-23, ratified, over "a branch carrying only captured items is not a
pull request", `PL-WNCT`), and `update-armed.yml` brings `main` in if `main`
moves past it first (`PL-S5MF`). **Whether it arms is `bin/docket arm`'s
answer, asked before arming and before every later push while a pull request
is open.** `arm`: mark it ready and arm it. `hold`: leave it unarmed, disarming
it before the push that brings the hold or green CI merges half the work,
and a draft while the hold is a claim. `behind N`: bring `origin/main` in and
ask again. `subprojects/docket/src/docket/arming.py` carries the rules and
the decisions behind them (`PL-QP9Z`, `PL-1MCK`, `PL-KWCY`, `PL-3FYK`,
`PL-H14W`).
Where the **web harness
says not to open one unless the
owner explicitly asks**, this bullet is that ask, standing rather than per
pull request, so a session reading both proceeds rather than stalls. A session-level
auto-pull-request switch set *off* is that same case and not a third: it
stops the harness opening one unasked and does not withdraw this ask
(project owner, 2026-09-19, ratified, over treating the switch as a
withdrawal and asking per pull request while it is off). Then
**read the published body back and compare it against what was sent**: the
server rewrites bodies silently and still returns success, so an
angle-bracket placeholder — `<branch>`, `<id>` — is taken for an HTML tag and
vanishes with no error, code span or not. `#132` shipped `git branch -dr
origin/` that way (`PL-1DN9`).
- **Bring `origin/main` into an open pull request once, when it is armed or
being merged and `behind` is all that stops it; again only if another merge
lands first.** `main` refuses a branch that is not up to date (project owner,
2026-09-23, ratified, over a merge queue, which a user-owned repository
cannot have), and each base merge re-runs `quality.yml`, so one taken while
the pull request waits on review is stale by its merge and paid again.
Waiting on review behind is neither red nor conflicted, and is not work. At
merge time the owner's *Update branch* brings it in (`docs/maintainer.md`);
an armed one is brought in by `update-armed.yml` on each push to `main`
(`PL-S5MF`), since auto-merge never updates a branch. The
refusal does not bind an admin, and a session's GitHub calls are the owner's,
so a session merges only by arming auto-merge. Sooner only on a genuine
conflict, a notice that `main` is green again, or before editing work it will
push anyway, as `bin/docket branch` prints (`PL-6MW8`, revising `PL-WC72`).
- **Capture intent, and route it by how ready it is.** A **specific change** is
a queue item, written now. A **feature wanted but not yet ready to build** is
one unscoped line of intent in `ROADMAP.md` § "Planned milestones" — filing it
as an `L` queue item instead puts work in the queue that cannot be worked,
where every session reads past it. A **feature being designed right now** gets
the design round first and items only once the shape has settled, because an
idea changes most in its first exchange.
- **Friction that compounds is recommended the moment it is found, not filed.**
Some process findings are paid again by every remaining piece of work. Say so
in the reply that finds it, with a recommendation to do it first — recording
it and moving on is not enough, because the owner cannot act on what only
reached the queue. A finding earns that interruption on any one of three
tests and on nothing else: it **gives a wrong answer silently**, so a check
passes while the guarantee it stands for is void; it **is being routed
around**, a warning or advisory firing so routinely that nobody reads it; or
it **sits upstream of everything**, in the store or the gate that every other
command reads from. The tests are properties, not enthusiasm: work that is
merely valuable, cleaner or more interesting makes no remaining item cheaper
and waits for the roadmap.
**Sweep the docs before calling an item done, and say in your reply which files
you checked.** Landing a change is not finishing it, and stale documentation is
a safety issue here rather than tidiness: a reader who trusts a wrong statement
about which agent is running, what a value means, or what the interface
displays can reach a wrong clinical conclusion from a correct number. The
`docket` skill's close-out carries what `make check` decides for you and what
it cannot.
## Safety-critical clinical-output standard
This application is intended as an educational/simulation tool and will carry appropriate disclaimers that it is not intended for clinical patient care. Nevertheless, assume that a clinician could use displayed values or model outputs to influence real-world patient management.
Therefore, any code path or displayed information that could plausibly affect patient management must be treated as safety-critical. Examples include:
- drug dose, infusion-rate, concentration, weight-based, or unit calculations;
- PK/PD state calculations and predictions;
- effect-site concentrations, predicted effects, MAC-equivalent values, interaction surfaces, and similar derived clinical values;
- model selection and model-compatibility logic;
- covariate transformations such as weight scalars, age adjustments, allometry, renal/hepatic modifiers, or unit conversions;
- thresholds, warnings, alarms, recommendation-like language, or other information a clinician might act on;
- values presented in graphs, tables, labels, or summaries where an error could alter clinical interpretation.
For safety-critical paths:
- Favor correctness, traceability, explicitness, and auditability over cleverness, abstraction, convenience, or development speed.
- Keep calculation logic pure and independent from presentation/UI code whenever feasible.
- Use explicit units and avoid implicit unit conversions. Prefer unit-aware types or equivalent safeguards where practical.
- Validate required inputs, units, ranges, model applicability, and model compatibility before calculation.
- Do not silently substitute defaults, coerce invalid data, or continue with missing required inputs when doing so could produce a plausible but incorrect clinical value.
- Version and record provenance for scientific models, equations, constants, parameter sets, and clinically meaningful transformations. `docs/MODEL.md` is the authoritative specification for the currently implemented model: equations, units, assumptions, parameter provenance, numerical method, and known limitations.
- Maintain deterministic behavior for identical inputs and model versions.
- Validate numerical implementations against published reference cases, analytic solutions, independently calculated test vectors, or other authoritative references whenever available.
- Include boundary, invalid-input, pathological-input, and regression tests in addition to ordinary nominal-case tests.
- When a safety-critical bug is found, add a regression test that would have caught it.
- Prefer an obvious failure/error state to displaying a plausible-looking number when correctness cannot be established.
- Treat presentation correctness as part of safety: the correct number with the wrong units, label, patient context, stale state, model name/version, or provenance is still a safety failure.
- Test the end-to-end path when appropriate: patient inputs -> model selection -> calculation -> units -> formatting -> displayed value.
- Make clinically meaningful displayed values traceable to the exact model/version, inputs, units, and transformations that produced them.
What a displayed value may imply is part of the same standard, and these are resident for the same reason as the rest of it — a session that opens no file matching a path-scoped rule must still see them:
- Make uncertainty and model limitations visible rather than allowing numerical precision or polished graphics to imply more certainty than the model supports.
- Avoid false precision in displayed outputs. Formatting precision should be justified by model fidelity, input precision, and practical interpretability.
- Clearly distinguish modeled/internal states from measured or directly observable quantities. Do not present a predicted value in a way that could reasonably be mistaken for a measurement.
- Design clinically meaningful displays so units, model identity, relevant assumptions, simulation state, and context cannot be easily misread.
- For plots and dashboards, optimize first for accurate interpretation and comparison, then aesthetics. A visually attractive but misleading graph is a defect.
Disclaimers do not lower the engineering standard for these paths.
## Proactive expert review and domain best practices
Do not limit review or recommendations to conventional software-engineering concerns. Treat development of this application as a multidisciplinary professional product-design problem and proactively identify material improvements anywhere they affect scientific validity, safety, interpretability, usability, educational value, maintainability, or reliability. Recommendations for the simulator should reflect the standard expected from a top-tier specialist in the relevant field, not merely common or minimally acceptable practice. When the owner's proposed approach is materially weaker than a better established approach, say so clearly and recommend the stronger approach with the reasoning behind it.
**Two standards, deliberately unequal.** The simulator and the documentation a reader of it needs — `src/`, `tests/`, `docs/MODEL.md`, `README.md` — are held to the specialist standard named in the paragraph above: code an expert contributor would recognize as high quality and could maintain without explanation. The workflow apparatus that exists so agent sessions can be productive — `subprojects/docket/`, `tools/`, `.claude/`, `.github/`, `docs/worker.md`, and this file — is held to a lower and different bar, which is `.claude/rules/apparatus-standard.md` and loads only when a session opens one of those paths. **Nothing in it reaches the simulator**, and it is kept out of this file so that it cannot: a session applied it to `src/` while it was resident here, correctly quoting a sentence whose scope was three sentences away (`PL-6SBB`). Where the two compete for a session, the simulator wins.
- Prioritize recommendations by consequence. Safety, scientific correctness, misleading output, and irreversible architectural problems outrank visual polish or minor code style, and a required correctness/safety issue is distinguished from a high-value recommendation and from optional polish.
- Prefer established standards, validated methods, and authoritative primary sources over convention-by-habit. Where a recommendation depends on current standards, guidance, libraries, or evidence, consult the source rather than memory — **before** forming the recommendation, not to confirm one already given. This covers how the project is run as much as what it builds: technical-debt policy, delegation and review design, testing strategy and release process are well-studied problems with published evidence, and advice on one of them from memory is worth no more than a solubility coefficient from memory. Recommending first and researching afterwards produces advice that has to be withdrawn, which costs the owner a decision they already made and more than the search would have.
- Challenge assumptions when warranted. Do not preserve a weak design solely because it was proposed earlier.
- The goal is not to maximize the number of suggestions. Surface the few recommendations that would materially improve the quality of the product, and explain them at the level needed to make a sound engineering or design decision.
The fields this review reaches across, and the design principles that follow from them, are in `.claude/rules/expert-review.md`. It carries no `paths:` and is resident, because the moment it governs is a design round — an approach chosen in a reply, which no read precedes — and path-scoping deferred it past its own moment (`PL-WWDT`). The provenance and docstring rules that do fire with a file already open are in `.claude/rules/sources-and-docstrings.md`. The concrete bar for `core/` — that it should read like the domain — is in `.claude/rules/core-domain.md`.
Global Claude Code Instructions
You are working with Ace — an ambitious builder working on AI + automation systems.
by AgentHub Crawler
CLAUDE.md — Agent Instructions
This file tells Claude Code (and other AI agents) how to work with this repository.
by AgentHub Crawler
AGENTS.md
Operational guide for AI agents working in this repository.
by AgentHub Crawler
AI Workflow Collection - AI Instructions
This is the master repository for curated Claude Code workflow collections.
Sign in to leave a comment.
by AgentHub Crawler