ops
Skill1 starsChanged 3 months agoMITView on GitHub
Execute a milestone's interactive π§ Operational and π Investigation tasks β the judgment-bound work that is NOT auto-dispatched. Two modes in one pass: Operational changes production/environment state through a sanctioned surface (config/catalog/entity authoring, backfills, alarm config, dependency installs, session/machine setup); Investigation produces a defensible decision from live data (diagnoses, spikes, zero/anomaly triage) and files follow-on tasks. Enforces: autonomous runs STAGE (never verdicts, never β Done), read-only diagnosis before any write, falsify every "it's fine", audited read-modify-write, reconcile+capture, "Done β deployed β seeded β working". Records durable research to a staging journal. Use when the user says "work the ops tasks", "run ops/tooling for milestone X", "work the operational/investigation tasks", or starts an overnight or interactive ops run on a project's task board.
17 other projects use a version of this.
Adopted by
Most recently taken up by
- holon-run/holontheir own version, first seen Nov 8, 2026
- guaardvark/guaardvarktheir own version, first seen Nov 5, 2026
- jthingelstad/elixir-mcptheir own version, first seen Nov 4, 2026
- tandregbg/core-claude-skillstheir own version, first seen Nov 4, 2026
- aya-taleb/biz-ready-skillstheir own version, first seen Nov 1, 2026
- vivekschaudhary/compasstheir own version, first seen Oct 25, 2026
Used with
Projects with it also use status, plan and 2 more.
Other files people use alongside this one.
Files found in the same public projects as a version of this one, more often than they turn up anywhere else. Each project counts once, large collections count for less, and this file's own repository is left out.
AnthropicSkillstatus
Case status summary by audience β client-facing (plain language), internal (for the professor), or court-ready (formal caption format per local rules). Same facts, different framing and depth. Use when a student needs to update the client, brief the professor, or prepare a court status report.
Also in 3 projects that use this
BlockSkillplan
Draft a TDD, PRD, or lightweight plan in the conversation without committing it.
Also in 3 projects that use this
SentrySkillreview
Fixture review skill.
Also in 3 projects that use this
VercelSkillsetup
Set up Vercel CLI and project configuration. Use when the user says "set up Vercel", "configure Vercel", "link to Vercel", or "vercel init".
Also in 3 projects that use this
Other versions17 projects use a version of this.
Word for word Β· 0
None found.
Edited Β· 0
None found.
Wrote their own version Β· 17
- guaardvark/guaardvarkβ 306same name
- holon-run/holonβ 194same name
- drafthq/draftβ 40same name
- tandregbg/core-claude-skillsβ 4same name
- vivekschaudhary/compassβ 2same name
- vlting/claude-skillsβ 2same name
- aya-taleb/biz-ready-skillsβ 1same name
- Frutzmann/claude-code-setupβ 1same name
- harshsinghmp/muse-skillsβ 1same name
- HDHNezherParking-cum-Y638-Intl-Ltd/titanβ 1same name
7 more not listed
How matches are found. Word for word: the exact same text. Edited: shares passages with this file (β99% sameβ means 99% of its five-word phrases also appear here; 10% or more counts). Their own version: similar meaning, or, weakest, the same name. We canβt tell which project had it first. Projects are counted among the 200 most-starred candidates, and mentions are links to the repository we found, up to 50 per site, so both counts are a floor.
In this repository10 other files it gives its agents.
- deploySkill
- designSkill
- docsSkill
- gateSkill
- groomSkill
- investigateSkill
- milestone-seedSkill
- milestone-wrapSkill
- sync-guidelinesSkill
- wrapSkill
The file
Show its rules and text
We split this skill into the rules it gives an agent
13 rules. 0 are common, 9 are distinctive, and 4 are very specific to this project.
0
Common
Most of the 14 edited versions we read keep these.
9
Distinctive
This author's own choices. Worth a look.
4
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Distinctive: line 114
Read-only diagnosis before any write: Never mutate to learn what you can read.
- Distinctive: line 136
BEFORE any restart β a restart destroys it.
- Distinctive: line 150
Don't build solo. Concretely:
- Distinctive: line 194
A committed live window stays watched: When a run names a future live window as the re-run or measurement target for a check, keep a watch β¦
- Distinctive: line 243
Before reporting any zero, confirm the comparison can be true at all: types match (an ISO string compared against epoch-ms columns matches β¦
- Distinctive: line 350
Find the precedent before proposing a mechanism: Search the same subsystem for how this shape of problem is already solved, and prefer β¦
- Very specific: line 435
Read it with node ~/.claude/scripts/ops-client.mjs journal --milestone <M> (wraps GET /api/ops-journal?milestone=<M>).
- Very specific: line 461
Multi-session durability: If even the interactive review runs long, unreached tasks stay staged for the next session.
- Very specific: line 483
autonomousβinteractive handoff: When a run is interactive from minute one (no autonomous pass to hand off), the journal is a live β¦
- Very specific: line 634
Spot-verify delegated first-pass reports: When the first-pass is delegated to subagents, every load-bearing claim in a returned report β¦
- Distinctive: line 673
No execution and no new investigation inside the walk.
- Distinctive: line 688
Not stop conditions: a write, a daemon command, a seed application, filing a follow-on, moving to the next task, or an anomaly (an anomaly β¦
- Distinctive: line 729
A harness / permission-guardrail block is not a menu prompt: When the auto-mode classifier or a permission hook blocks an β¦
βCommonβ is measured: kept by at least 6 in 10 of the 14 edited versions of this file we could read. βVery specificβ is our guess from the words: it names a file, a command, a setting or the project itself.
Files
ops β execute a milestone's Operational & Investigation tasks
Companion to groom (backlogβReady) and design (design tasks): this skill works the
π§ Operational and π Investigation tasks β the interactive, judgment-bound ones that
are not auto-dispatched. Its whole value is a verification discipline that refuses to
trust premises, statuses, or convenient shortcuts, and that treats an unattended pass as
staging, never as conclusions. Follow it even when a task "looks like a one-liner."
This skill shares its planning-procedure core with /groom and /design β see
../_shared/reference/hard-rules.md (canonical source
packages/backend/src/planning/procedureCore.ts) for the rules this skill
also follows: deterministic load, not hand-fetch (Flow step 2 below), the
human/operator is the gate (see Β§ Status handling), and no silent writes
(verdicts land on the journal, never the task page, until the operator
confirms).
Scope: this skill runs π§ Operational + π Investigation, plus observational / E2E π§ͺ Testing folded in as an Investigation variant (run the system live β a disposition:
pass/blocked-pending-fix/pass-with-caveatβ there is no "fail"). Test-authoring π§ͺ Testing (writing test code, no live-data dependency) and π Docs stay out β the former is really π» Code, so reclassify it (the loader lists any it caught intest_authoring; flag the rest at triage). (Legacy π οΈ Tooling tasks that predate the split are grandfathered; treat a live one as whichever mode it actually is.)
The two modes
π§ Operational β change prod/environment state through a sanctioned surface, and verify it landed. The decision is already made; the work is the doing + verification. Uncertainty is in breadth / source / mechanics, never in whether or what. Failure mode = a bad write (wiped siblings, wrong source, a re-derive never run). Two flavors:
- Directed β fully-specified change: a backfill/re-derive from a known-good state, a dependency install, wiring a tool/MCP into sessions, a machine migration. Little/no research.
- Research-first β the what to author needs research (which teams/tournaments/streams/ aliases): governed by "research β present β author on confirmation; never apply before presenting."
π Investigation β produce a defensible decision about a live issue from production data. The decision is the deliverable. Output = filed follow-on tasks (Code / Operational / more Investigation) + an occasional inline change. Uncertainty is in the conclusion itself. Failure mode = a wrong conclusion. Includes spikes (verify an external surface before code depends on it). An Investigation may produce a Code task β that is a legitimate output, never a reason it should have been Code. It must never contain "implement module X" as its own acceptance criterion; that gets filed as a separate Code task.
Variant β observational / E2E π§ͺ Testing. A Testing task that runs the system live and observes is an Investigation whose deliverable is a
disposition(journal field). There is no "fail" state β the outcome is one of:
passβ completed: demonstrated by value (verified working, not a green-looking degenerate/zero result);blocked-pending-fixβ it surfaced an issue: file the fix task and set this task to ποΈ Ready +Depends Onthe fix (it re-runs after the fix lands). Carries the observed evidence
- the filed fix β same root-cause bar as any Investigation (name the mechanism, never "it broke"). This is not a dead end and not "Done" β it's a dependency.
pass-with-caveatβ done, with one aspect superseded/deferred and noted.Breadth before depth: run every check in the check table to at least a by-value first reading and present the table before deep-diving any single failing check β unless an incident freeze applies. Digging one family's outage while the other checks sit unrun is the failure.
Test-authoring (writing test code) is not this β it's π» Code.
Execution context β autonomous vs interactive (this replaces "Phase 1 / Phase 2")
The old two-phase framing conflated two orthogonal things. Keep them separate:
- Read-only diagnosis before any write is a safety ordering β it holds inside every run, every mode. Never mutate to learn something you can read.
- Who may commit a verdict or a write is the execution context β autonomous (overnight,
no operator:
--print/ no TTY) vs interactive (an operator is present). Context is auto-detected from the invocation; an operator may override it explicitly.
An autonomous run stages; it emits a staging report; a later interactive run resolves it. But the split governs what you may commit, not whether to do the first-pass. Every run β autonomous and interactive β does the full read-only first-pass over every task first (Flow step 3). An interactive run does not get to skip staging and jump straight to resolving: unless it is consuming a prior autonomous run's journal, it must run that first-pass itself before it walks any task. Skipping the first-pass is the single most common way this skill is mishandled β treat step 3 as a gate, not a suggestion.
Commit-authority matrix
| Autonomous (no operator) | Interactive (operator present) | |
| π Investigation | Read-only diagnose; record findings as provisional candidates; file follow-on tasks; freeze+capture incidents. No verdicts (no "VERIFIED", "not a bug", "root cause confirmed"); no status flip. | Earn the verdict with the operator (falsify it); make the call; occasional inline change; propose the status flip (operator confirms). |
| π§ Operational β research-first | Research + verify sources the project's way; stage a proposal (what to author, breadth, source). No write; no status flip. | Choose source/breadth; author via the audited path under the step-4 authorization; reconcile+capture; propose the flip. |
| π§ Operational β directed | May execute the well-defined change via the audited path iff low-risk + mechanically verifiable (read-modify-write; reconcile+capture); record "applied + verified". Not cleanly verifiable β stage. | Execute + verify + propose the flip. |
The load-bearing rule: in the autonomous column, nothing ever flips to β Done and nothing records a definitive verdict β not even a directed Operational change it successfully applied (that records "applied + verified, pending operator confirmation"). Status-flips and verdicts are always interactive. This lets a "run-only-from-known-good-state" backfill actually run unattended while still keeping a human on every close.
Disciplines
Universal β every run, every mode
- Read-only diagnosis before any write. Never mutate to learn what you can read.
- Acknowledgement is not compliance β the next action is what agreement looks like. Saying "you're right" and then proceeding with your own plan is a null response that costs the operator the correction twice. On accepting a correction: state what you are doing differently, then do that β not the plan you already had. A correction persists for the rest of the run; a rule conceded once does not need re-conceding each time it applies.
- Ambiguous input: resolve it before acting. If you call an input ambiguous, you may not act on
your interpretation in the same turn β ask, then act. Real run: a bare
+was read as approval, said aloud to be ambiguous, and acted on anyway. Flagging an ambiguity and then proceeding is worse than either asking cleanly or acting silently: it transfers the risk to the operator while keeping the action. This binds hardest on anything that writes or files. - The sanctioned read surface is the default β use it freely, no permission needed. The
analyst MCP + the
/opsHTTP read endpoints are the normal read path; reach for them without asking the operator. "Read by value" almost always means these, not raw SQL. Ad-hoc read-only SQL through the project's read-only role (direct PG) is a lighter, still-sanctioned fallback for what the endpoints don't cover; only a write (or the write DSN) is break-glass. - Never force blocked or prod-risky actions (deploys, fleet/DB restarts, dumping live credentials, instrumented prod deploys). Document, hand to the operator, move on. One blocker never stalls the run.
- Incidents: freeze β capture β classify β file β don't loop. A live prod incident gets the
incident sub-protocol β see
reference/incident.md. The one rule to remember without opening it: capture volatile evidence (a stack dump,pg_stat_activity, thread states) BEFORE any restart β a restart destroys it. Risky recovery (a fleet/daemon restart, a pgbouncer bounce) is the operator's call β but "operator's call" = their decision, your execution under phase auth. In a co-hosted interactive session the operator often has no server access; never hand a command back to an operator who can't run it β get the decision, then you run it. And don't recover-in-circles: killing a stuck session/backend to clear a lock is pointless while the root code bug is still live β it recurs and leaves the fleet in an unknown state. Capture + file the fix; don't loop on restarts. - Drill-budget / conversion tripwire β it caps fixing, never understanding. Diagnostic
depth has no budget: an Investigation digs until the root cause is proven (see Β§ π
Investigation). A diagnosis is never paused to ask whether to continue β carry it to the proven
root cause and report; the only legitimate stops are a genuine external / access blocker, or the
work turning from diagnosing to implementing. What the budget stops is open-ended doing solo β implementing a fix, building
a module, excavating a large change. The moment the work turns from diagnosing to implementing,
stop β file a Code task carrying the proven root cause, capture the state, and surface it.
Don't build solo. Concretely:
- An Operational task that can't be completed via a sanctioned surface without new code is blocked-pending-Code (or was mis-declared Investigation). Stop, file, surface β don't excavate a code change solo.
- A workaround that hands the operator code to run (a script, a patched copy, a one-off tool) is new code: file the fix as a π» task, wire Depends On, and wait. Never paste or ship an untracked copy, however well tested.
- An Investigation keeps diagnosing to root cause; it stops only to file (a Code / Operational task carrying the proven cause) when the remaining work is doing, not understanding. One that turns out to be a well-defined change dressed as a question β downgrade to Operational and do it (within the autonomous ceiling).
- The buck stops with this run β don't deflect your own work into a deferral ("it's not my problem"). The drill-budget above stops open-ended building solo; it does not license the opposite and more common failure β under-doing: reflexively reaching for "file a task / defer to a next session / satisfied by a future move / record it as deferred" for work that is this session's to do and executable now. The judgment-bound doing that IS the task β exercising the change, verifying execution by value (never "it'll be tested later / in prod"), triaging what you backfilled, closing every AC item β is yours, not a follow-on's. Before you defer or file anything, ask: is this genuinely blocked (a proven external / access / Code blocker), or am I defaulting to the easy option? A follow-on is for what's out of scope or genuinely blocked, never a place to offload the part of the task you'd rather not do. And when a deferral IS correct, it must be kept honest by a real forcing function (a one-time precondition at the point of resumption, a hard dependency) β never a rot-able backlog note, and never a standing per-run check that taxes every future execution to police a finite, shrinking condition.
- A throughput/latency cause is named only with its measured share β never as host contention.
"The host is IO-busy" is contention, not attribution. State the cause with its share of the
producer's own time: an idle-inclusive profile or a statement-time delta (e.g.
pg_stat_statements) on the producer's own process. Real run: a slow backlog drain was blamed on a busy host; the profile and statement deltas showed five distinct causes in the producer itself. - Point dumps locate a stuck thread; they do not rank costs. Rank costs with an idle-inclusive
recording over β₯ 60 s (e.g.
py-spy record --idle). Real run: 5/5 dumps named a function that the 60 s recording put at 4.6% while the real costs sat elsewhere (29%, 22%). - Recommend from the proven mechanism and the project's stated priorities β never a revert or an easy-out lever as the default. A rollback, or a lever that trades live freshness for correctness (e.g. capping a live watermark behind a backlog), is not offered as the recommendation, least of all under time pressure. Real run: "revert three commits" was proposed; investigating instead found two more proven defects the revert would have hidden. Live first, then historical, unless the project says otherwise.
- Every issue met during the run is this run's to investigate β on or off the task list. A live
anomaly, an alarm, a degenerate reading, an unexpected cost, a stated blocker: dig it in-session
to the proven root cause under Β§ Evidence law and file the follow-on carrying it. Deferring it
to
/investigateor "a later session", or noting it and moving on, is the failure mode β including for an unrelated daemon or a restart loop spotted in passing. Real run: a memory-thrash loop was pointed at/investigate; the dig proved the root cause and filed three tasks. - A committed live window stays watched. When a run names a future live window as the re-run or measurement target for a check, keep a watch armed for it β or state explicitly, in that same turn, that you are stopping and the window will be missed. Naming a window and then doing nothing leaves it silently unmeasured.
Evidence law β the claim shape dictates the admissible evidence
Wrong conclusions in an ops run share one mechanism: a cheap check returned a result consistent with the hypothesis, and the search stopped. Reciting "falsify before you assert" does not prevent it β the discipline gets recited and violated in the same session. What prevents it is mechanical. Before stating a claim β in a journal entry, a verdict, a filed task, or to the operator β find its shape here and confirm you ran that evidence, not the cheap substitute.
| Claim shape | Admissible evidence | The cheap substitute that fails |
| "X is absent / not wired / not running / 0" β any negative | A search or query whose scope you can state, run through the false-negative checklist (Β§ π Investigation, "read outputs by value") | Checking the one place you expect it. A livestats filter against a producer that writes source='lol' reads as "0 rows / dark" |
| "Session / daemon / job S did or didn't do Y" | S's own record β its transcript, its log, its event stream | Its artifacts or its status. Artifacts cannot show a failed call, a flail, or a silent abort |
| "At time T the state was Z" | Point-in-time rows: events, audit history, timestamped snapshots | A current-state column. The events under study are what mutated it β it can read zero by construction |
| "X is by design / intentional" | A quoted docstring, comment, commit message, or design doc | Inferring intent from a naming difference or an apparent symmetry. The docstring is usually directly above the code, and says the opposite |
| "S is abandoned / stuck / safe to terminate" | Its event stream β recency and volume β plus a second observation separated in time | A status field plus elapsed time. idle is not terminal (procedures.md Β§ Never recommend a terminal action against a session on status alone β a hard rule, not a preference) |
| "This behaviour is a bug" | The spec, docstring, or invariant it violates, quoted | It looked wrong. A correct guard refusing an invalid operation is not a bug, and "fixing" it makes things worse |
| "Task / design Y already owns this" | Y's quoted body | Y's title. A title compresses a task to a topic; two tasks on one topic routinely own different questions |
Row 2 is a gate, not a preference: no claim about what a session / daemon / job did β or why β before you have read its own record. State rows, intent rows, and artifacts describe the envelope; they cannot distinguish "it never supplied the value" from "it supplied the value and something downstream ate it." Real run: nine intent members all showed a null proposal field and the cause was reported as "the session didn't supply one"; the transcript showed a 3,272-character proposal supplied every time, silently discarded by the envelope. A supporting base rate does not corroborate a cause you have not read the record for β that wrong answer came decorated with 191/557 rows and looked well-evidenced.
Validate the instrument before trusting what it returns β state the coverage. A query is not a read of the record until you know what it dropped. Before concluding from any filtered, joined, or type-coerced query, state the fraction of the population it covers: rows returned vs rows that exist. A filter that drops more than ~20% of the population is not a read of the record β it is a sample, and must be described as one or widened until it isn't. Real failure: a transcript reader filtered to two event types, dropping 489 of 571 events, while the preceding command had already printed the type histogram proving it β the number was generated, then ignored, and the remainder was reported as complete.
A fraction is a claim about what the excluded part contains, not only how many. Stating "E only affects 9% of attribution segments" reads as low-impact until you check what's in that 9% β those 82 windows in a real run were exactly the stage-day parallel-stream slots, the live match chat, and the small percentage hid that entirely. Before citing a coverage/exclusion fraction as evidence of low impact, state what the excluded (or included) rows are, by value β never the count alone.
A zero or a thin result is a claim about the instrument before it is a claim about the world. Before reporting any zero, confirm the comparison can be true at all: types match (an ISO string compared against epoch-ms columns matches nothing, ever), the filter value equals what the producer writes, the id-space is the same. This is the false-negative checklist in Β§ π Investigation, applied one step earlier β to the instrument rather than the result.
Replicate a predicate exactly, or you are measuring a different question. When you reconstruct a
check the system performs β a budget, a capacity, a coverage count, an eligibility or backfill filter
β copy its predicate verbatim from the source. Every condition you add that the code lacks, and
every loosening you allow that it doesn't, changes the question while the number keeps looking
authoritative. Real run: a dispatch budget computed with an archived = 0 filter the code does not
have returned 9 where the true budget was 0, and that one added condition hid the root cause
across a dozen reads; a coverage scan reported 5 by prefix-matching and 22 by exact match.
Neither was bad arithmetic β both answered a question nobody asked. Paste the predicate, don't
paraphrase it; if you must diverge, say which condition you changed, in the same breath as the
number.
Column types vary per table β print one raw value before reading meaning into a filtered result.
The epoch-ms trap has an inverted twin: a started_at stored as ISO TEXT compared with
>= Date.now() - N returned rows from nine days earlier presented as "since this morning" β a
silent coercion producing plausible, wrong history. Never infer a timestamp column's type from a
sibling table: SELECT one row, read the literal value, confirm your comparison can be true against
it. And never conclude absence from truncated output β a head -40 on a list nearly became
"those rows were deleted." Truncation is your formatting, not the data's.
State the disconfirming test in the same clause as the claim β before the operator asks, not
after. "Not running β systemctl list-units across the host shows no matching unit, and the
supervisor config names none." A claim whose disconfirming test you cannot name in one clause is not
ready to state, let alone journal.
Timestamps spanning more than one day carry their date. Format YYYY-MM-DD HH:MM:SS. Bare
HH:MM:SS collapses a multi-day window into an apparent single day and inverts before/after
conclusions.
π§ Operational
- Writes only through the project's audited path (its config-CRUD / ops affordance), never raw SQL / hand-edits. Verify each write; prefer reversible, greppable-for-rollback changes.
- Read-modify-write any replace-semantics shared state (a binding/linkage/config row the CRUD replaces wholesale) β read current, merge, write the full set. Blindly creating wipes siblings.
- Verify the daemon reconciled AND actually captured β it heard the config change, built the actor, and a post/signal/record landed. Authoring a row is not ingesting.
- "Done β deployed β seeded β working." A merged task may be un-deployed; a deployed code path may have no operational seed applied (a recurring silent-degradation trap). Confirm the seed is present on prod, then that the behavior actually runs. When the task at hand is the milestone's config-seed task, work it via Β§ Milestone config-seed below, not by reading its task body as the worklist.
- No accepted gaps β every step closes or is filed. A multi-step Operational task is Done only when every step is completed or filed as a follow-on that closes the gap. "Accept the gap" is never an option to present β silently dropping the price side of a backfill and shipping trades-only is the exact failure this prevents. If a step can't be done now, file the follow-on that will and say so; never narrow the deliverable to what happened to work.
- Verification that must wait for a future event is a gate item, not a blocker. If a
reconcile/capture step can't be observed until a future event (a live match, a timer firing),
accrete it on the task via
gate-state-client.mjs accreteas an atomic item (classification usually Read-Only; text naming the exact query + the expected observable). It does not block proposing Done. Never a scheduled one-time self re-check, never a standing per-run check. - Research-first: research, decide, apply under the step-4 authorization. Pull authoritative per-entity data (the source's own page), verify each item exists the project's way, lay out what the task assumed vs. what you found, choose source/scope/breadth, and apply via the audited path; the walk records the choice. Stop before the write only at a Β§ Stop condition (an irreversible action, or a source/scope choice between materially different outcomes the task does not settle).
- Writes and the write-DSN are break-glass β deliberate, logged, not the default. (Reads are not β see the sanctioned-read-surface rule under Universal.) Never run session-level read-only GUCs over a pooled connection (they leak to other clients); for ad-hoc read SQL use the project's read-only role over the direct/unpooled path, and route every write through the audited CRUD.
- A service config reload goes through the deploy, not a hand restart. An env or config file change to a long-running service takes effect through the project's deploy path, which rolls the service. Record it as pending the next deploy rather than restarting the service by hand. A hand restart is break-glass, needs explicit operator approval, and must first confirm from source which unit the restart verb actually targets.
- Operational execution is a phase, not per-action break-glass. The break-glass framing above is for one-off actions; a task's execution is a sustained burst of them (one run: a price backfill + 8 per-market trade backfills + a re-match β 10 prod actions). Metered one approval-prompt at a time, that's death-by-a-thousand-prompts β an operator had to abandon a run, flip to auto mode, and resume. So at the phase boundary, state the shape and request phase-level authorization once: "this phase is ~N prod actions via the audited path (writes / daemon restarts / secret-DSN reads); recommend auto/accept for the duration β I'll narrate each and stop at any real decision point." That converts N prompts into one decision + running narration. In an interactive run this is the Flow step 4 order sign-off β it is the authorization. It's safe because Operational writes are already required to be reversible + greppable-for-rollback (above) β and you still stop at the Β§ Stop conditions (anything irreversible, an outcome choice the task does not settle, a harness block).
π Investigation
- The buck stops here β dig to the proven root cause. An Investigation's job is to find the
mechanism β demonstrated by value + the exact code path/line (or config row / state), not
hypothesized. Keep asking "why, really?" until the cause is proven, not plausible. Stopping short
is legitimate only at a genuine external/access blocker (no read access to the evidence). Never
discharge the undug question into a "next fix" β a
lead_lagfamily got "fixed" while the realalign()root cause sat unfound for a whole milestone precisely because the investigation stopped at "a fix was filed." - A filed follow-on carries a proven root cause β never another investigation of the same question. If your follow-on title starts with "Investigateβ¦", you haven't finished investigating β you punted. File a Code / Operational task that names the proven cause and the fix, not a re-run of the diagnosis.
- Run every claim through Β§ Evidence law before stating it. For any conclusion β "it's fine", "no bug", "will self-heal", "the numbers say X" β find the claim's shape in the table and confirm you ran the admissible evidence, not the cheap substitute; then state the disconfirming test in the same clause. Ask "why, really?" and "would that actually fix it?" one level deeper than feels necessary β that flips the answer more than half the time.
- Read one instance of the data before proposing a mechanism. Structural reasoning about
carriers, fields, schemas, and where a value could live β with no payload read β produces
confident nothing. Real run: four turns proposing carriers for a payload (a new intent kind, a
group-level field, a designated bearer) without reading a single instance of the payload; one query
showed the required structure already existed, in a kind already in the set and already used for
exactly that. Before designing a mechanism,
SELECTone row and read it. - Find the precedent before proposing a mechanism. Search the same subsystem for how this shape of problem is already solved, and prefer extending that to inventing a parallel path. Real run: a fix was proposed for a broken auto-adjudication step when the answer was that the step should not exist β "replace a broken machinery by some extra broken machinery"; and a closure design anchored on the wrong precedent while the right one sat forty lines above code already read three times. Corollary β a deviation from a consistently-applied pattern is usually the defect, not a gap to fill with machinery. Where a system applies one rule everywhere (sessions stage, the operator disposes), the place that departs from it is the bug. Fix the deviation; don't build a second mechanism to service it.
- Silent-success paths β can the record tell "no work" from "blocked"? A component reporting
status=ok, items_processed=0is indistinguishable from one that is wedged, and reads as healthy everywhere. When you find one, ask whether the record separates the two cases β if it cannot, that is itself a finding, independent of which case is live. Same family as "deployed but inert", one layer out: the mechanism fires, does nothing, and says so in the voice of success. - When the operator holds the one instrument you lack, ask for a single scoped observation β never ask them to diagnose. Ask for one observation, and enumerate what each possible answer would mean, so their reply resolves the question instead of starting a discussion ("which of these four strings is in the panel?", "is the element present at height 0?"). That is using an instrument, not escalating. "Can you look and tell me what's wrong?" hands back the diagnosis that is yours.
- An explanation of why the system might be right is not a finding. On hitting something odd the reflex is "is this actually correct?" β not "here is why this might be intentional." A docstring, a naming convention, an apparent symmetry: each is a claim to check, and the check is usually thirty seconds of reading. When the operator rejects a rationale, drop it β do not re-offer a weaker one (latency, performance, "probably deliberate") to salvage the position. That spends the operator's scrutiny defending a guess.
- Treat a registered number as a claim to re-derive, never a fact. A prior task's stated figures, a "known" count β re-derive it from live data before you build on it.
- A degenerate/zero reading is attributed only after replicating the producer's own predicate
on one scope by value β never from the shape of the inputs. A plausible-sounding input-side
explanation ("thin prices", "the destroyed tag corpus", "sparse tags on outrights") is not a
finding until you have run the producer's own query on one concrete scope β its CTE (e.g. a
stage1
post_countsCTE), its funnel counters, its run-duration/crash record β and read what it says by value. Real run: three separate degenerate readings, each initially explained by a plausible input-side cause, each turned out to be something else entirely once the producer's own predicate was run β markets closed before the pairing window, a cohort fan-out that had replaced the channel scope, sub-horizon burst slices, and a 10-hour actor crash loop a deploy-health check reported as healthy. The tell that you're still guessing from input shape: you can name a cause but not the producer's own query/counter that shows it. - Read outputs by value, not by row-count/existence, and check provenance. N rows of
zero/degenerate output looks identical to real work; a row's presence never proves it's current
or correct (version + timestamp vs the relevant deploy). Before concluding 0 / dark / broken,
run the false-negative checklist: (a) does your filter value equal what the producer actually
writes β the exact
sourcestring, enum member, id-space? (two premise-inversions this way this run: alivestatsfilter vs the actualsource='lol'; an esportstournament_idfalse-negative); (b) is the scoping key a known false-negative (documented incontext.md/ the retrospective)?; (c) is provenance/version current? A "0" that's really a filter mismatch is the single most common wrong conclusion. - Verify a source the project's own way. A browser/WebFetch success β the daemon's success β fetch with the project's actual client/UA/auth; confirm a walled surface clears via the client the daemon uses.
- Consult the authoritative source-of-truth doc first β not optional. Before interpreting any zero, anomaly, or "this looks broken," read the relevant findings / retrospective / architecture page (surfaced by the loader / Flow step 2). It very often documents the exact case and the interpretation trap β skipping it flips real findings (it inverted a seed-verification finding this session). Do this at the moment of interpretation, before you record even a candidate.
- "Mirror the existing X" is the highest-risk sentence in a filed task. It reads as safe and
low-effort, which is why it ships unexamined β it delegates a semantics question to an implementer
who resolves it by pattern-match. Never write "mirror X" alone: name the exact helper, counter,
or guard, state what carries across, and state what does not. Two regressions from one run came
from this one sentence shape β a completion path mirrored across a type boundary where the
source's terminal state and the target's were different state machines (result: a record marked
β
Done with its required field
NULL), and a budget mirrored onto an unnamed counter whose DB-backed variant counted 104 archived idle corpses (result: the budget pinned at 0). Test before writing it: if the implementer resolves this mirror the most obvious way and the obvious way is wrong, does anything catch it? A mirror across a type boundary almost never transfers whole. - Output is filed tasks, not code. File π² Backlog tasks (Code / Operational / Investigation) for what you find. Accurate-the-first-time beats file-then-correct β run the one-level-deeper check before filing, and set priority from the verified severity, not the first impression. Interactive: file the follow-on under the step-4 authorization β no stop before filing unless a Β§ Stop condition applies (e.g. an outcome choice the task does not settle). Because it is filed unreviewed, the one-level-deeper check above is mandatory, and the consolidated close lists every filed follow-on so the operator can reframe, defer, or reject it there.
- Milestone routing for filed follow-ons: critical / blocks the current milestone β the current milestone; non-critical / needs-a-migration / a next-theme concern β the next milestone. (This run: the lock fix + windowing β M12; index-sargability + catchup-daemon β M13.)
The staging journal
Long ops runs must not discard expensive research, but must not persist unverified decisions either. Those reconcile only if research and verdicts live in different places with different durability rules.
The staging journal lives in the backend's ops_journal DB table β one row per
eligible task, pre-seeded and reconciled server-side by GET /api/ops-context
(Flow step 2; same reconcile job loadOpsContext always did, now the only path to it).
Read it with node ~/.claude/scripts/ops-client.mjs journal --milestone <M> (wraps
GET /api/ops-journal?milestone=<M>). Documented shape (one entry per task id):
mode(operational|investigation),flavor(directed|research-first|null),worked_in(autonomous|interactive)evidence[]β the durable, expensive part: probes/queries run, values observed with provenance (version + timestamp vs deploy). This is what survives context exhaustion.finding_or_proposalβ the candidate finding (Investigation) or staged authoring proposal (Operational)falsificationβ Investigation: "what I'd observe if false, and did I look."stateβ the provisional marker:pending(loader-seeded, not yet worked β the first-pass must advance every entry off this) |candidate|staged-proposal|applied-pending-confirm|blocked|incident-frozen|resolvedfiled_followons[],needs_from_operatorresolutionβ null until interactive; on operator confirmation,{ decision, by, at, persisted_to }(task page / follow-on / arch page)dispositionβ π§ͺ Testing variant only:pass|blocked-pending-fix|pass-with-caveat|null(loader-seeded null; no "fail" β a surfaced issue βblocked-pending-fix+ a filed fix + aDepends On). Set withops-client.mjs set-state β¦ --disposition <value>.
Rules that make it safe:
- Research persists in
evidence[], always tagged provisional bystate. A fresh interactive session (new process) reloads the journal and resumes without re-excavating. - Verdicts don't leak. The autonomous pass writes only to the journal β never to the
Notion task page. A decision reaches the task page only at
state: resolved(after interactive operator confirmation). - Multi-session durability. If even the interactive review runs long, unreached tasks stay
staged for the next session. A task becomes
resolvedonly when the operator confirms and its residue is persisted to its proper home. - Trimming β the journal holds open work, not history. Once an entry reaches
resolvedand its residue is persisted to its proper home, that home (the task page / follow-on / arch page) is the audit trail β so drop the entry. Trimming happens server-side, on everyGET /api/ops-contextcall: anyops_journalrow whose task is now β Done or no longer on the open board is deleted as part of that request's reconcile (the DB-backed twin of the old loader's job 3 β seereconcileJournalinpackages/backend/src/ops/opsJournal.ts). Never hand-edit the DB. On resolve, setstate: resolved+resolutionwithops-client.mjs set-state --task <id> --state resolved [--resolution '<json>'](wrapsPOST /api/ops-journal/:taskId/stateβ deterministic field write, validated against the allowed state-transition graph server-side); the nextops-contextcall trims it: deletion is the fragile part, not the write, and it's no longer yours to get wrong. A non-π Investigation βresolvedfrom any state other thanapplied-pending-confirm(e.g. a π§ͺ Testing task atcandidate) is rejected with 400 unless the call carries one of:--no-change-reason '<text>'(non-empty; nothing needed changing) or--reconciliation '{"description":"<what was reconciled>","passed":true|false}'(object with a stringdescriptionand booleanpassed).set-state's response on success is the updatedops_journalrow itself (same shape as one entry injournal --milestone <M>'sentries[]) β not{ entry }β andops-client.mjsalso prints a one-line<taskId> -> <state>confirmation to stderr. - Interactive-throughout is a lighter path. The full
pendingβcandidate/staged-proposal/applied-pending-confirmβresolvedvocabulary exists to protect the autonomousβinteractive handoff. When a run is interactive from minute one (no autonomous pass to hand off), the journal is a live scratchpad, not a handoff artifact β you may collapse the provisional states to justpendingβresolved, still recordingresolutionper task. Hereevidence[]can stay in-conversation and land on the task page (that's what worked) β by designops-client.mjs set-statewrites onlystate/resolution/disposition/reconciliation/noChangeReason, not evidence: a fragile evidence append isn't worth it when the operator is present and the task page is the durable home. Don't carry the full staging ceremony when there's no handoff to protect. - This is ops-native and distinct from
/wrap(which sweeps broad session residue).
Milestone config-seed β driven by the seed-state API
The milestone's one accreted config-seed task (config-template/task-writing.md Β§
Milestone config-seed) is orchestrator-tracked state, not a task-body checklist to read
top to bottom. Every seed a Code task contributed at grooming time lives as a seed_item
row β applyable once its min_deployed_commit is an ancestor of the target project's
current deploy SHA. Every apply attempt is a seed_item_event β that log is the
durable record, the operational twin of the gate's gate_item_event. Do not read the
config-seed task's body as the seed worklist β the live worklist is seed_item rows,
never a bulk load of the whole applyable set.
This is a thin human-driven loop over the seed-state API
(packages/backend/src/routes/seedState.ts, business logic in
packages/backend/src/seed/seedService.ts), called through the sanctioned node client:
node ~/.claude/scripts/seed-state-client.mjs <command> ...seed-state-client.mjs is the vendored sanctioned node client (see
packages/backend/scripts/seed-state-client.mjs, re-vendored via the
/sync-guidelines skill), using $ORCHESTRATOR_DEVICE_TOKEN (host/port
default to 127.0.0.1:3000, overridable via $ORCHESTRATOR_BACKEND_HOST /
$ORCHESTRATOR_BACKEND_PORT) the same way the other sanctioned session
clients (ops-client.mjs, gate-state-client.mjs) do.
- Readiness β
node ~/.claude/scripts/seed-state-client.mjs readiness --project <P> --milestone <M>β{status: 'green'|'blocked', blocking}.greenβ nothing left to apply this milestone; report and stop.blockedβ every unconfirmed seed with its project/state, as a worklist map only β pull the actual batch vianext, never disposition straight off this summary. - Pull one applyable batch at a time β
node ~/.claude/scripts/seed-state-client.mjs next --milestone <M> --deploySha <sha> [--limit <N>](default limit 1).deployShais the target project's currently-deployed commit β resolve it the project's own way (itscontext.mddocuments the deploy-tracking surface); never guess it. Applyability = deploy-included (the seed'smin_deployed_commitis an ancestor ofdeploySha) AND not yetconfirmed. Never bulk-load the milestone's full seed set. Apply through the target project's own audited config-CRUD, then record the outcome. For each pulled item: read
item.spec(node ~/.claude/scripts/seed-state-client.mjs detail <id>for sources + prior events before re-attempting one). The operator applies the seed via the target project's audited config-CRUD / ops affordance β never raw SQL, and the orchestrator never applies another project's config on its behalf (that's whynextrequires adeployShathe caller supplies rather than applying anything itself). Batch consent is fine here β one up-front "these N seeds, go" per pulled batch, the same phase-level authorization an Operational execution phase gets, not a prompt per seed. Then verify reconcile + capture the ops-native way ("Done β deployed β seeded β working" β confirm the row landed AND the consuming worker picked it up AND the mechanism actually emits) and record every attempt, not just resolving ones:node ~/.claude/scripts/seed-state-client.mjs event <seedItemId> \ '{"outcome":"applied","evidence":"<what was authored + how verified>"}'outcomeisapplied(authored, reconcile/capture not yet fully confirmed),confirmed(reconcile + capture verified β resolves the item), orblocked(could not apply β must carryfiledFollowon, the id of the follow-on filed for the blocker; the server rejects ablockedevent without one). Includeevidence(freeform) andoperatorwhen known.- Loop β repeat 2β3 until
readinessreportsgreen, or the operator stops for the session; remaining seeds staypending/appliedand nothing is lost, state persists server-side. Correcting a seed recorded
appliedin error βappliedis non-terminal (authored, reconcile/capture not yet confirmed), and recording it is the step most likely to be wrong (a session's own claim, ahead of actual verification). To return it topending:node ~/.claude/scripts/seed-state-client.mjs reopen <seedItemId> "<reason>" [operator]reasonis required when the item is currentlyapplied(the server rejects the reopen with a 400 otherwise) β an erroneousappliedis an operator correction and must say why. The resultingreopenedevent carries{reason, priorState: 'applied'}in its evidence, so the log shows what was undone.pendingitems cannot be reopened (no-op guard);confirmed/blocked/discardedreopen as before, withreasonoptional.
What this replaces: it does not fetch or parse the config-seed task's body as the seed worklist, and it does not bulk-load a milestone's full seed set.
Built, not activated. This ships in the skill now, and seed-state-client.mjs is
vendored to ~/.claude/scripts (via the /sync-guidelines skill), but the seed-activation
task still owns confirming it runs live end-to-end for a real milestone β do not fold
that actuation here.
Flow
- Invoke β detect context (autonomous vs interactive) and state which you're in. If
interactive and the run will enter an operational execution phase β a sustained burst of
audited-path prod actions β get phase-level authorization up front, not per-action (see Β§ π§
Operational β operational execution phase). It isn't only writes that trip the auto-mode
classifier β break-glass reads (fetching a DSN from
/etc/β¦secrets) and daemon restarts do too; scope the up-front authorization to all three. - Load context deterministically β call the ops-context backend route. It is the sanctioned
Flow-2 load, now served in-process by the backend instead of a vendored shell-out:
node ~/.claude/scripts/ops-client.mjs context --milestone <M> --project <dir>(wrapsGET /api/ops-context?milestone=<M>&project=<dir>; loopback + device-authed β setORCHESTRATOR_DEVICE_TOKENin the session env first). It deterministically (a) loads the fixed context pages β the master Project Context page + the source-of-truth docs (findings / retrospective / architecture / guidelines), returned in the response'scontextPages; (b) enumerates the π§ Operational / π Investigation tasks β plus observational / E2E π§ͺ Testing folded in as an Investigation variant (modeinvestigation, flavortesting), while excluding test-authoring Testing to theworklist.test_authoringtriage list (reclassify β π» Code) β intoworklist.executable/dep_blocked/needs_grooming/closed_not_done(worklist.newly_unblockedfurther flags which executable entries weredep_blockedon the previous ops-context load for this milestone and have since cleared every blocking dependency β call these out explicitly in step 4; they read identically to an always-ready task otherwise.); and (c) pre-seeds + reconciles theops_journalDB table server-side β one row per eligible (Ready / In-Progress) task atstate:"pending", preserving prior worked fields and trimming rows whose task is now Done / off-board (same job the old loader did to its on-disk journal, now done to the DB on every call β seereconcileJournalinpackages/backend/src/ops/opsLoad.ts/opsJournal.ts). Then alsoReadthe project'scontext.md(write paths, prod/deploy, operator read-surface & break-glass). Do not hand-load a partial subset β skipping the master page / source-of-truth docs is the #1 load failure this route exists to prevent. (If the route is truly unreachable, load all of the above by hand β and record what you loaded as acontext_loaded: [...]note for the run.) This load is a precondition: a successfulops-contextresponse β or a hand-load withcontext_loadedrecorded β MUST exist before you interpret any zero/anomaly. A failed call must never silently become a skipped load; that is exactly how the master Project Context + source-of-truth docs get skipped. First-pass β work every eligible task. Mandatory in every context, before resolving any one. Order doesn't matter here. Respect
Depends On(only β Done satisfies a dep; where it gates deployed behavior, confirm it's actually deployed). For each: re-derive the task's premise and blocker before working or blocking it β (a) is the deliverable already settled elsewhere (a sibling task / prior resolution)? (b) is the stated blocker actually the only path? The loader's Ready/blocked and a task's stated dependency are claims to check, not facts (81f3was already settled by81c7;81e4's Liquipedia wasn't the only source β Twitch was). Then read-only diagnose the premise the project's way, by value, checking provenance β and consult the source-of-truth doc before interpreting any zero/anomaly (Investigation discipline); then work it to its mode's autonomous ceiling (matrix above); journal the evidence +state. File Backlog tasks for gaps; freeze+capture incidents. Never let one blocker stall the run. Any "why only N rows?" / low-volume question is answered from the producer's own run record FIRST β run count, run-duration metrics, actor-crash/restart history (Β§ Evidence law, "S's own record") β before it gets classified as a property of the analyzer/query itself. Do this as the first move on the question, not as a check applied after a classification is already drafted: a real run walked pastlead_lag_v1 = 70 rowsas an analyzer property, with deploy-health reporting the service healthy, and only the run record (7 runs in 20h, a Postgres-restart wedge) showed the true cause.Spot-verify delegated first-pass reports. When the first-pass is delegated to subagents, every load-bearing claim in a returned report (counts,
file:line, "absent / not wired", "fresh") is re-checked by value by the parent before it is journaled or presented. Subagents have cited non-existent files and columns, concluded "no unbind path" when the deployed code had one, and reported row counts off by ~80Γ and a stale meta as "fresh".GATE β do not start step 5 (working tasks to end state) until step 3 has advanced every journal entry off
pending. The ops-context load seeds oneops_journalrow per eligible task atpending; the first-pass must move each offpendingviaops-client.mjs set-stateβ frompendingthe only legal targets arecandidate,blocked, orincident-frozen(the server rejectspending β staged-proposalwith 400).staged-proposal/applied-pending-confirmfollow fromcandidate(a secondset-stateonce the proposal/application exists). The dominant failure is grabbing the first interesting task and resolving it before the rest are diagnosed β resist it; the cost is an uninformed order and missed cross-task context. Anypendingentry means the first-pass isn't done.- Present the overview + a suggested review order. Open with the coverage line β "N eligible Β·
N advanced off
pending" (they must match; any entry stillpendinginops-client.mjs journal --milestone <M>'s output means step 3 isn't finished β go back). Summarize: what's staged, what's blocked and on what, what was filed, incidents frozen, and which tasks arenewly_unblocked(name them by id β a dependency just landed and they were stuck last run). Then propose a review order (likedesign), favoring in this priority:- Incidents / blockers β safety, first eyes.
- High-confidence items β cheap, mechanically-verified directed-Operational completions and clear-cut resolutions; bank the certain value before a long session risks not finishing.
- Thematic clusters β grouped by theme; within a cluster, Investigation before Operational (a diagnosis often gates whether the authoring change is even right). Get the operator's sign-off on the order. This sign-off is the one authorization point: it also grants phase authorization for the run's audited-path actions (writes, daemon commands, seed applications, filing Backlog follow-ons). After it, execute β do not ask per action or per task. Only the Β§ Stop conditions stop the run.
- Work every task to its end state β before the walk. For each task in the signed-off order:
execute via the audited path, reconcile and capture, file the gap-closing follow-ons, write the
task page notes, and set the journal to
applied-pending-confirmorblocked(with the filed blocker). Every task must reach one of those two states before step 6 starts. Work long lanes (backfills, seed passes, scoped runs) one command at a time and watch them; while one waits, work the next task β never idle. Every issue met on the way is dug in-session to a proven root cause (Β§ Universal β every issue is this run's to investigate). Never mark a task Done. - Walk = one consolidated confirmation pass per the Interactive walk protocol below: per task, what was done, what was filed, the proposed status; the operator confirms Done per task. No execution and no new investigation inside the walk.
Stop conditions
The run stops and asks only at these; everything else proceeds under the step-4 authorization. Lead with one recommendation (Β§ Interactive walk protocol).
- An irreversible action β anything the audited path cannot undo or roll back.
- An outcome choice the task does not settle β a choice between materially different outcomes (e.g. "Pairing after map_ended: defect or intended?"). Dig to the proven facts first; ask only for the choice itself.
- A harness / classifier block β follow the procedures.md escalation order: request explicit approval of that action, then an approval-mode change. State the single needed action and why it is blocked.
Not stop conditions: a write, a daemon command, a seed application, filing a follow-on, moving to the next task, or an anomaly (an anomaly is investigated, not asked about). Autonomous (no-operator) runs still only stage.
Interactive walk protocol
Step 6 (the walk) is where this skill is most often mishandled. Codified:
- The walk is a confirmation pass. It starts only after the first-pass (step 3), the order
sign-off (step 4) and the work-to-end-state step (step 5). Never walk from a cold board. The walk
confirms actions already taken; it executes nothing and opens no new investigation. A walk
question that needs a fresh query / DB read / write means step 5 was incomplete: stop walking,
finish the work, then resume. Execution-time discovery belongs in step 5 β applying a change
is exactly what surfaces the real bugs (a precision bug, a
/tradestruncation, aconfig.entitiesvsconfig.entityhot-reload mismatch). That's a legitimate output of Operational work: dig it to a proven root cause in-session, file the follow-on, keep going. - Never walk a dep-blocked task. The loader excludes any task whose hard dep isn't β
Done from
the walkable set (it lands in
dep_blocked, surfaced for re-groom β fix theDepends Onor wait for the dep, only β Done satisfies). Do not resurrect one into the walk because it "looks ready"; a ποΈ Ready or βοΈ Deferred dep still blocks. - One consolidated close; the operator confirms Done per task. The close lists, per task: the actions taken (ids, counts, before/after), the follow-ons filed (ids), and the proposed status. Every task keeps its own entry and the operator confirms (or reopens) each Done individually. Batching is the default, not an operator-requested exception; the operator may still ask to go task-by-task, in which case present one entry per message.
- Stop conditions are listed once, in Β§ Stop conditions below. Nothing else stops the run β no stop before each write, none per task, none before filing a follow-on.
- Open each task with context β never cold. Lead with (a) what the task is for and (b) what the read-only diagnosis found; then the decision / recommendation. The operator should be able to engage from your message alone, without re-reading the task body.
- One handle per task. Name a task by its short name + Notion ID once, then use that handle consistently. Don't interchange IDs, ordering numbers, and paraphrased names across turns. An ad-hoc grouping label ("cluster", "the sidecar batch") is a device for the review-order overview only β never refer to it as if it were a task or a unit of work.
- Lead with a recommendation, not a menu. At a stop condition (Β§ Stop conditions), state a single proposed change + its rationale, then stop and wait β not a menu-style option list ("your options: (a)β¦ (b)β¦ (c)β¦, which do you want?"). A prose menu pushes the framing and the decision-work back onto the operator and reads as hedging; form a view and state it. Genuinely load-bearing alternatives may be named in prose, but the default shape is "here's the change I need to make and why β authorize?", never "(a)/(b)/(c), your pick." This governs how a choice is framed, not whether you stop; whether to stop is decided by Β§ Stop conditions.
- A harness / permission-guardrail block is not a menu prompt. When the auto-mode classifier or a permission hook blocks an already-authorized action, state the single needed action + exactly why it is blocked, then stop β do not enumerate resolution options ("add a permission rule vs. run it yourself"). Surfacing the block is required; turning it into an option list is the same menu anti-pattern above and offloads a call that is the operator's to make however they choose.
- Background watches must not flood the operator. A Monitor / background watch emits only on a state change or terminal state β never a per-interval heartbeat or "still waiting" line.
- Check a task's current Status immediately before writing to it. Before any write to an existing task page, fetch its current Status in the same turn; never rely on the status seen when it was filed or loaded (it may have reached β Done in between β a filed task is read-only once past Backlog).
Status handling
The operator owns every status transition β including reopening or reverting. You propose; the operator disposes. Never change a task's status on your own reasoning β not to β Done, and just as importantly never reopen or revert a status either (reverting a task unprompted on a re-reading is the same violation as self-closing one).
- Autonomous: change no task's status. Staging is neither "in progress" (it awaits review) nor "in review" in the vocab's sense. The journal is the record; the board stays truthful.
- Interactive: set π In Progress when you actively open a task to resolve it, cleared on resolution. On operator confirmation, propose the terminal move β never self-mark β Done.
- Skip π In Review for these Types. Its meaning ("PR open / Notion changes formally proposed, awaiting merge-or-lock") doesn't fit an ops task whose resolution is usually filed follow-ons + a task-page note. Keep staged-ness in the journal.
Keep the explicit close turn β do not collapse it. The final "here's the outcome + filed follow-ups; propose Done" turn, and the operator's confirmation of it, is a deliberate review checkpoint β the last place the result and the follow-ons surface before the task is buried. Even when the operator's prior reply was a terse "LGTM" / "good," do not fast-forward it into "task done, on to the next": present the close, let them confirm. The operator wants that turn. The close is the consolidated confirmation (see Β§ Interactive walk protocol): per task, only that task's outcome + its filed follow-ons + proposed status β no next-task preview, no run-level narrative beyond the per-task entries. Each task's entry stays separate so the operator can confirm or reopen it individually. This also excludes arm-state / groom-mechanics narration β e.g. "groom is armed on M15, so this will be picked up on its own." Whether some other task gets auto-dispatched is neither this task's outcome nor one of its filed follow-ons; it is not this session's to assert in a close, the same way arm state is not this session's to pre-flight before filing a task.
When is a task Done? (propose it β the operator confirms.)
- π Investigation is Done only when the root cause is proven β the mechanism demonstrated by value + the exact code path/line (or config row / state), not merely hypothesized β with any inline fixes made and follow-on tasks filed (each carrying that proven cause, never another "investigateβ¦" task). It does not wait on those follow-ons landing; filing them is the deliverable. The only excuse to stop short of a proven root cause is a genuine external/access blocker (e.g. no read access to the evidence) β recorded as such, not as Done.
- π§ Operational is Done when the change is applied and reconcile + capture is verified on prod β not gated on anything downstream β and no step was silently dropped (every part of a multi-step task is closed or filed as a gap-closing follow-on; "accept the gap" is never offered). A reconcile/capture step that cannot be observed until a future event (a live match, a scheduled timer firing) does not block proposing Done: accrete it as an atomic gate item (see Β§ π§ Operational) and propose Done. Never keep the task In Progress to wait, and never schedule a self re-check.
- π§ͺ Testing (observational/E2E variant) reaches a
disposition, not a Done/fail verdict.pass(verified by value, not a degenerate/zero that looks green) orpass-with-caveatβ the task is Done.blocked-pending-fixis NOT Done β file the fix task and set this task to ποΈ Ready +Depends Onthe fix (it re-runs after). There is no "fail": a surfaced issue becomes a filed fix + a dependency, never a dead end.
Dispositions land on the board, not only the journal. The journal is evidence; the board is
truth. Any disposition that changes how a task should be groomed, worked, or run β supersede,
re-scope, defer, "don't run as-is" β must be written to the task page (body / Notes + the
proposed status) once confirmed. Recording it only in ops_journal is a silent loss: /groom
and future workers never read the journal. (Autonomous stages the disposition as a candidate in the
journal; the interactive pass lands it on the board.)
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

