Appearance
Self-maintenance — changing the machinery
Load when: the change is to the project's own apparatus rather than to its product — a script, a process file, a gate, a role, a skill, the guide, this system itself.
Anything that changes the machinery is a task, regardless of size. Not because small changes deserve ceremony, but because a machinery change with no record is silent drift in the worst possible place. This is a rule about category, not size — it does not contradict small stays small, which is about product work someone asked for casually.
The system stream
One field, one generated view. No new entity.
stream: product | system. A field rather than a label, because it changes behaviour — board membership and whether history is mandatory — and a label only filters.
What lands in system: scripts and helpers · process — ladders, gates, settings that change behaviour · the project's own documentation (product documentation is product work) · the shape of the team · skills · project-scope resources.
One new type, not six: tooling. Its definition of done is honestly different: name the routine it replaces · it is discoverable · it is documented · someone other than the author used it once. Everything else system-shaped is an ordinary chore in this stream until its DoD proves it needs its own type — a type is earned by a diverging definition of done, not by feeling like different work.
A short ladder, not an exemption: doing → done. If a one-line script change had to cross four stages, people would route around it, and then none of this holds.
Scripts the project writes for itself — four rules before the first one lands. The stack is what the project already runs; where nothing runs yet, POSIX shell until the first structure more complex than a pipe, then the project's main language — a helper in a language nobody here reads is a dependency wearing a filename. Standard library first, and a real dependency walks through the import gate like any other arrival. Size is a signal: a helper pushing past ~150 lines, or wanting dependencies of its own, is §23 speaking — promote it to its own repository and re-import it as an external tool, exactly the law skills already follow (./skills), so the repo never grows a monster it cannot shed. And a guard gets a test or it is a hope — a script that decides something is exercised by a script beside it, the same habit this corpus keeps for its own validators.
Intake reuses triage. An audit finding, a field note, a proposal — all land there with the four dispositions. This is what fixes the oldest hole in the audit: its output was a report, and a report lives until the end of the scroll. Through triage a finding gets an age and a place in the attention view.
Review is a gate on done, not a stage. A request routed to a non-author is the review gate, so no column is needed and the non-author rule still holds. For machinery it matters more than for product work: an unnoticed change to a gate is a quietly weakened gate.
And it is never self-merged. The project's own definition is append-only: proposed to a human, never merged by whoever proposed it. That is the same line as nobody edits the bar they are measured against, applied to the bar itself.
What the history is made of
The task is not a new record — it is the anchor that makes four existing ones findable together:
| Record | Answers |
|---|---|
| the task file | what, when, who filed it, what done means |
| the run history | who did it, with what, how many attempts, what it cost |
| git | the diff, the author, human or agent |
| the decisions log | why, for anything that changes behaviour |
Without the task these all exist and none of them is findable from the others.
Effect at the next boundary
A change to the machinery takes effect at the next boundary, never mid-flight. Work in progress finishes on the version it started with → ./upgrading.
This is one rule covering three things that used to be three: a settings change, an edit to the guide, and a new version of a skill. One version per unit of work, and the advisor reports which version it is now running — an agent on the old version that proposed the new one runs its next task on the new one, which is normal, but a single unit of work does not change under itself.
Field notes — friction recorded where it happens
Working inside a system surfaces stumbles the guide never predicted, and they are worth more than anything a planning session produces: recorded friction from real use finds what nobody thought of, and it is cheaper and better than combinatorics.
One line, the moment it happens: date · flow · symptom · evidence · fix candidate. Append-only — a correction is a new entry, never an edit to an old one.
Swept at natural checkpoints — end of session, a status check, before a release cut — into the backlog, deduplicated so a re-sweep is idempotent, and an entry that ships gets closed with the version. A sweep that found nothing writes that it found nothing — with its date and what it looked at. An empty log is otherwise unreadable: "a quiet week" and "nobody looked" leave the identical trace, and the second is the one worth knowing about. Naming the scope is what makes the empty entry evidence rather than a shrug — "swept the release flow, nothing" can be wrong later and be seen to be wrong, which "nothing to report" never can. That makes caught → logged → backlog → done → released one visible chain rather than four disconnected places.
Field note or blocking task? One question: does this stop me now?
- No → a field note, and carry on. It becomes a task if it recurs — twice — written from
templates/TASK-template.mdunder the rules in./writing-work, in the system stream, with both occasions named in it. A second occurrence recorded nowhere is a first occurrence again. - Yes → say so where you are, agree what is needed, and the original takes a
blocked_byon atoolingtask.
Proactive is right here. Naming the friction while the decision is still cheap beats naming it after the work has been built around the workaround. The bound on it is the same as everywhere: earned, not reflexive — and twice, not once.
Packaging a problem upstream
When the friction is in this system rather than in the project, the owner needs something they can send. There is no channel for that by default, which for a public tool means people hit something, complain aloud, and say nothing outward.
Assemble: version · the flow · the symptom · the evidence — the exchange, the run record with model, effort, attempt and outcome, the state of the files involved — and the environment fingerprint where it smells relevant.
Screenshots are the owner's attachments, not ours. Dropped into the conversation they are already task resources, so the package references them rather than creating anything.
De-identify with the same discipline as releasing a skill: project names, internal paths, ticket keys and above all anything secret — and a human reads the diff before it goes anywhere. A bug report is by nature full of paths and fragments.
One artifact, where the owner says. Same rule as a consultation: nothing written silently.
And there is a door for it, /opsinist:report, because of when it gets used. The moment someone wants to report a defect is the moment they least want to compose a request — they are already annoyed, and the capability they need is one they have no reason to know exists. A door is how a capability is found, and this one also spares them a classification they should not have to make: whose defect is this? is decided here, from the evidence, not asked of the person who just hit it. Saying it in a sentence reaches the same place.
And it is written whole, to a path that is said out loud. A report that exists only as conversation is a report that scrolls away — the owner comes back an hour later, the session is gone, and what remains of a real bug is a memory of having complained.
It is written outside the repository, and that is not a detail. This report is about the skill, not about the project it was met in — putting it in their tree makes it a commit in somebody else's history, reviewed by people it does not concern, carried in a clone forever. The default is the owner's downloads folder — ~/Downloads/opsinist-report-<date>-<flow>.md — somewhere they already know how to find, move, attach and delete, and the owner may name anywhere else. The path is stated in the reply rather than left to be discovered.
The dividing line, because the two logs look alike: friction in this project is a field note and lives in its repository (_ops/FIELD-NOTES.md); friction in the system operating it is this package and lives outside. Whose defect is it decides where it is written — and it is the same rule that keeps a guest's record out of a maintainer's tree (./entering).
Then the ways to send it are offered, because "there is no channel" is the sentence that ends in silence. Name them and let the owner pick:
| Route | When it fits |
|---|---|
an issue on the skill's own repository — github.com/jamillazarev/opsinist/issues | the default. It is public, it is where fixes are tracked, and a report there outlives whoever read it |
| straight to the author, if they know them | a short path for something small, urgent, or awkward to say in public |
| keep it, send nothing | a complete answer. The file stays, the friction is recorded, and it can go later — a report nobody sends is still worth more than one nobody wrote |
We do not send it, on any of those routes. Publishing is outward, from their account. We produce the file, we say where it is, we name the ways — they post it.
What a capability owes before it ships
Four things, each traced to a release where shipping without it produced something that looked finished and was not. Clauses 1 and 2 are the sibling's word for word and both ledgers carry those receipts. Clauses 3 and 4 are this repository's partition, not a shared one — the sibling's bar reads a scenario and the fixture it needs and a door where this one reads a dated claim and the trio. The obligations behind the two lists are close to the same set cut differently, and neither repository said so until 2026-09-07; the partition is not the finding, the clauses are (LATER.md holds the reconciliation):
- A form where the rule can fail — never a stronger sentence. Rules stated clearly in the always-loaded core measured 0/5; the same rules rebuilt as refusing hooks went 5/5. A refusal moves the rate; a note does not (the sibling's dispatch-nudge moved nothing and ships honestly as an aid).
- A mutation test showing the form denying the mutant AND passing the honest twin — a gate without its test is a hope (
scripts/test-audit-gate.shis the house pattern). And the mutation asserts that it changed the file, because a wrong anchor makes the edit a no-op and the resulting green reads as the mutant survived — a conclusion about the assertion when the truth is about the patch. Two neighbours of the same shape: restoring a fixture withgit checkout -- <file>restores from the index, so state staged by an earlier assertion survives and later ones pass on the leftover (git checkout HEAD --is the one that means it); and reusing a record id an earlier commit already took means a gate scoped to added files never examines the fixture at all. All three make a green assertion that measures nothing — so a must not fire assertion is paired with a must fire twin on the same fixture, and the pair is what proves the subject was looked at. - The claim dated, with the measurement behind it — enforcement is a form × path × version matrix, and a probe's evidence is a stamp, never the model's account of itself.
- The showcase trio — a diagram, a situation, a fact — or the mechanic is invisible to everyone who did not write it. The diagram lives beside the rule it draws;
./diagramsholds only the ones that cross several rules — a gallery holding every diagram collides with the chapter budget at each new mechanic, and a chapter of the crossing ones does not. Promoted 2026-09-07 on two occasions a fortnight apart, both recorded in the deferred list: the contradiction stop's diagram went to./escalatingand the cost one to./cost, and the question of what./diagramsis for was answered by that use rather than by argument. Whether the trio exists at all is still judgement, and so is whether a change is a repair that owes only the fact — the deferred list carries the candidate test and the price it has not yet paid. Do not read the exemption as settled: it was claimed twice in one session before anything checked it, and one of those releases turned out to be wrong about its own evidence.
One capability shipped without two of these four, and it is named here rather than implied met: the council carries its showcase trio and a declared field, and has no form where it can fail and therefore no mutation test and no dated measurement. A consultation leaves no artifact, and every enforceable rule here keys on a file — so the declaration is real guidance and unenforced guidance, the class this corpus keeps measuring near zero. What would close it, and the moment that reopens it, are kept in this skill's own deferred list; the admission sits here, against the bar it fails.
When another sentence will not fix it
A rule fires when it names something to open, a field that cannot be faked, or a gate that blocks. It does not fire when it states a virtue. This is not taste — it is the one pattern that survived a suite of measured repairs, and the failures are more instructive than the wins.
What worked, and why:
- A list of paths, placed before the alternative. "Read
_ops/assets.md,_ops/TOOLING.md,_ops/DECISIONS.md" — set physically above the rule that says ask the owner — changed a run that had twice asked about a brand its own register described. The earlier attempt at the same fix was a clause in a law paragraph, and it changed nothing. - A field whose cheap answer is impossible to write. A form asking what was checked, and when was answered with three fabricated check-dates for pages never opened. The same form asking what the page said was answered honestly — or left blank — because a quotation cannot be produced from memory without visibly being generic.
What did not work, five times, in three files: a well-formed statement of the right behaviour. A substitute is offered as a substitute. The record's rung travels. Look inward first. Each is true, each was read by the player, none survived contact with summarising or with a plausible shortcut.
And moving a correct sentence somewhere it is certainly read does not work either — measured, because it was the obvious next guess. A round found that 87% of runs open no chapter at all, which makes "the rule was never in front of it" the natural explanation for every failure. So three rules that had scored 0/5 twice were moved verbatim, not a word changed, into the always-loaded core — the only variable being location — and re-run at N=5 each: 1 of 15.
The three were report a hand edit before overwriting it · a parent with its own predicate waits · say you are a guest before touching a stranger's tree. All three share a shape: they ask for a sentence to be said before an action that is otherwise available, and nothing stops the action. The model read them and did the work.
So neither wording nor placement is a rung. What remains is what the ladder already said, now with both alternatives measured and excluded: a field a liar cannot fill cheaply · a template whose omission leaves a hole · a script that decides · a restriction on who may assert. A rule that only asks will be skipped by a light tier no matter how well it is worded or how loudly it is placed.
So the ladder, when a rule keeps failing: first ask whether it names a file to open; then whether it demands a field a liar cannot fill cheaply; then whether it belongs in a template, so omitting it leaves a visible hole rather than a silent one; then whether a script can decide it, which moves it off prose-only for good (./permissions); and only then, whether it is a writer restriction — who may write this fact — because some failures are not about knowing the rule but about being the wrong party to assert it.
And the last rung is not the last resort — it is the one that holds the others up. Measured 2026-08-01: five scenarios were re-run against fixtures with the preflight installed as a real pre-commit hook. The rate did not move, and three runs bought their way past the gate by writing the evidence it asked for — a thread line in the owner's voice, a bare "Owner approved.", and the owner's own email address under Approved by:. A gate whose evidence the constrained party can author is not a gate; it is a prompt naming the sentence that unlocks the door. The repair is the fifth rung applied to the gate itself: the acceptance must already exist before the commit that relies on it, so forging it costs a separate commit whose whole content is a claim of approval — visible as exactly what it is. A script is only as strong as the question it asks, and "does this text appear" is a question the text's author answers.
And the honest floor: some rules stay prose, and those are listed by name rather than believed. A rule that has failed a measured repair twice is not "written more clearly" a third time — it is either given structure or recorded as a known limit with its evidence. A limit nobody wrote down gets rediscovered by a user.
A finding does not become a rule the day it is found
Every incident feels like a law while it is fresh. That is the whole trouble: the day a thing breaks is the day its lesson is least distinguishable from its circumstances, and a corpus that promotes each fresh finding straight into the always-loaded guide fills with rules that were true once, on one machine, about one version. Weight is earned by surviving, not by hurting.
So a finding climbs, and each rung has an admission price:
| Rung | Where it lives | What it costs to get there |
|---|---|---|
| 1 · noticed | _ops/FIELD-NOTES.md, one dated line | nothing — write it the moment it happens |
| 2 · recurrent | a task, both occasions named | a second occurrence, recorded separately |
| 3 · durable | a rule where it belongs, or a form | a week between the first line and the promotion, and it still reproduces |
| 4 · load-bearing | the always-loaded core | it changed a measured outcome, and the measurement is cited |
Rungs 1 and 2 already existed — the field-note line and the bar is twice → ./checking. Rung 3 is the new one, and its price is time: a week between the first dated line and the promotion, spent doing other work. Not a waiting ritual — a filter. What is still reproducible a week later, with the panic gone, is about the system; what evaporates was about that afternoon.
The dotted branch is the failure the ladder exists to prevent, and the double one is the exception that must never be smuggled through it.
The date is what makes the rung checkable, which is why field notes carry one and why a promotion cites the line it came from. A rule that cannot point back at its dated origin has not climbed — it was declared, and declaring is the failure this section exists to name.
The exception, stated so it is not smuggled: a defect with a live blast radius does not wait. Anything that loses work, ships something wrong, or lets an untrusted string act is repaired now and its rule lands with it — the ladder governs lessons, never repairs. The tell is whether the change stops a thing happening (repair, immediate) or teaches a party to behave better (lesson, ladder).
And promotion is not a copy — it is a move with a pointer. The rule lands in one home, and the field note gains the version that closed it → ./checking. Two homes for one rule is the drift this corpus spends most of its checks preventing.
Prose, and named as prose: the dated line and the citation are the parts a form can read; the week is a judgement no script here enforces today. A check that reads a promotion's cited date against the note's own is the shape it would take, and it is written down rather than believed → LATER.md.
Running this system on itself
There is no separate ritual for it. This project's own repository is a project, and its machinery is this skill, so everything above applies unchanged — that is the whole reason the stream is a field rather than a special mode.
Two things it adds, both of which apply to any project:
Fence before staff. Branch protection exists before anyone can push. A human merges; agents propose. Self-adoption happens after a merge, never instead of one.
Guards green before adoption. A new version applies to the team only when the checks pass in a clean checkout at the merge commit — and red guards mean not adopted, and it says so. Rollback is the previous commit; git is the restore point, so no separate backup exists or is needed.