agent-bios 0.13.0 → 0.15.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (36) hide show
  1. package/README.md +2 -2
  2. package/claude/CLAUDE.md +8 -8
  3. package/claude/guides/claude-prompting.md +59 -7
  4. package/claude/guides/cli-multi-model-workflow.md +6 -1
  5. package/claude/guides/coding-staged-workflow.md +12 -0
  6. package/claude/guides/gpt-prompting.md +60 -4
  7. package/claude/guides/learning-flow.md +4 -1
  8. package/claude/guides/llm-capability-boundary-patterns.md +8 -0
  9. package/claude/guides/review-request.md +13 -0
  10. package/claude/guides/session-distill-workflow.md +21 -9
  11. package/claude/guides/tooling-gotchas.md +181 -14
  12. package/claude/guides/verification-discipline.md +71 -3
  13. package/claude/hooks/tooling-gotchas-hook.py +50 -0
  14. package/codex/AGENTS.md +8 -8
  15. package/codex/guides/claude-prompting.md +59 -7
  16. package/codex/guides/cli-multi-model-workflow.md +6 -1
  17. package/codex/guides/coding-staged-workflow.md +12 -0
  18. package/codex/guides/gpt-prompting.md +60 -4
  19. package/codex/guides/learning-flow.md +4 -1
  20. package/codex/guides/llm-capability-boundary-patterns.md +8 -0
  21. package/codex/guides/review-request.md +13 -0
  22. package/codex/guides/session-distill-workflow.md +21 -9
  23. package/codex/guides/tooling-gotchas.md +181 -14
  24. package/codex/guides/verification-discipline.md +71 -3
  25. package/compose/corpus-state.py +1170 -0
  26. package/compose/write-update-cache.py +53 -0
  27. package/install.sh +198 -11
  28. package/launch/agent-launch.py +112 -6
  29. package/launch/agent-launch.zsh +109 -6
  30. package/launch/i18n/en.toml +1 -0
  31. package/launch/i18n/ja.toml +1 -0
  32. package/launch/i18n/ko.toml +1 -0
  33. package/learn/collect-learning.py +593 -62
  34. package/learn/redact.py +2 -1
  35. package/package.json +4 -2
  36. package/provenance.json +1 -1
@@ -40,28 +40,47 @@ depends on it, pin it explicitly instead of trusting the environment.
40
40
  shells resolve functions/aliases first, programmatic spawns resolve raw
41
41
  PATH, and a same-named package can shadow a system tool with silent empty
42
42
  output. Before trusting a result across execution contexts, confirm the
43
- resolved target (`type -a`, absolute path).
43
+ resolved target (`type -a`, absolute path). A missing prefix wrapper fails
44
+ the same silent way — GNU `timeout` is routinely absent on BSD-derived
45
+ systems — so confirm the wrapper too.
44
46
  - **Cloud CLI context**: gcloud/aws/kubectl/terraform carry mutable ambient
45
47
  context (active project, profile, cluster) that drifts between sessions.
46
48
  Before the first environment-affecting command — or right after a resume —
47
49
  verify it against intent, then pin the target explicitly on every command
48
50
  (`--project`, `--profile`, `--context`) rather than fixing the global
49
- default once.
51
+ default once. A forge CLI (`gh`/`glab`) reads its repository from the
52
+ checkout's remotes too: with a fork plus an upstream it can answer for the
53
+ wrong repo, so pass `--repo` wherever the answer feeds a decision.
50
54
  - **Installed is not running**: a live process keeps its old code until
51
55
  restarted or reloaded. When confirming an update, config change, or
52
56
  dependency bump took effect, don't stop at the on-disk artifact — confirm
53
57
  the running process's actual version/behavior or force a restart.
58
+ - **Producer newer than consumer**: when a deployed binary validates an
59
+ artifact you produce (a signed config or manifest), produce and verify it
60
+ with the producer tooling checked out at the exact commit that binary was
61
+ built from — a local verify with current-tree tooling proves only that
62
+ newer tooling accepts it. Confirm the consumer's build commit from image
63
+ provenance, not the current branch; any version mismatch is a release
64
+ blocker. A consumer rebuilt from the same commit needs only ordinary
65
+ verification.
66
+ - **A dev-labelled datastore target is a claim**: a localhost URL or
67
+ exported override is no evidence of a non-production target — a local port
68
+ can proxy into the only real instance, and a tool's config loader can
69
+ re-load a dotenv over your exported value. Before the first writing
70
+ command (migration, seeder), print what the connection reaches from inside
71
+ the tool's own path and assert it is the intended target; where the loader
72
+ is untrustworthy, extract the DDL and apply it yourself.
54
73
 
55
74
  ## Shell execution traps
56
75
 
57
76
  - **Pipe exit masking**: `$?` after a pipeline reflects only the last stage;
58
- a real failure in the command under test is masked by a successful
59
- `tail`/`grep`/`jq` and reads as a false green. Capture the tested stage's
60
- own status: run it unpiped, store `$?` immediately, or use
61
- `set -o pipefail`/`PIPESTATUS` noting pipefail breaks legitimate
62
- early-exit consumers (`cmd | head -1` → SIGPIPE 141), so it is a per-command
63
- choice, not a global default. Does not apply when the final stage IS the
64
- assertion (`cmd | grep -q pattern`).
77
+ a real failure upstream is masked by a successful `tail`/`grep`/`jq`,
78
+ reading green. Capture the tested stage's own status: run it unpiped,
79
+ store `$?` immediately, or use `set -o pipefail`/`PIPESTATUS` — a
80
+ per-command choice, since pipefail breaks early-exit consumers (`cmd |
81
+ head -1`, `grep -q` on a long producer → SIGPIPE 141). The
82
+ final-stage-assertion exemption (`cmd | grep -q pattern`) holds only
83
+ without pipefail; under it, capture output and check its status first.
65
84
  - **Passthrough arguments in a CLI you author**: an option meant to carry
66
85
  another command's own flags cannot use a greedy-but-dash-stopping arity —
67
86
  Python's `nargs="+"` ends at the first token starting with `-`, so the
@@ -71,6 +90,13 @@ depends on it, pin it explicitly instead of trusting the environment.
71
90
  second, separate trap: argparse consumes it as its own positional marker
72
91
  before the remainder sees it, so the form every caller reaches for first is
73
92
  the one that breaks — normalize it out of `argv` before parsing.
93
+ - **CLI flag probes that execute**: probe a CLI only with invocations that
94
+ cannot do real work — a help form, or the candidate flag paired with a
95
+ control flag that forbids execution (dry-run, an invalid required
96
+ argument). Never run a subcommand bare, and assume a value after a flag
97
+ may be read as positional input: a boolean flag does not consume it, so it
98
+ falls through and runs. Tell a boolean from an unregistered flag by the
99
+ parser's error, not by the run succeeding.
74
100
  - **Reserved parameter names**: assigning to reserved shell names (`UID`,
75
101
  `EUID`, `GID`, `PPID`) can invoke the bound system behavior instead of
76
102
  storing a value — silently changing process credentials mid-script. Use
@@ -105,6 +131,14 @@ depends on it, pin it explicitly instead of trusting the environment.
105
131
  timestamp resolution (mutation testing). Clear the cache or run no-cache
106
132
  per iteration, and re-confirm the unmutated baseline still passes after a
107
133
  cache clear.
134
+ - **Transport limits are measured on the wire payload, in the provider's
135
+ unit**: take the unit and value from the provider's rejection or a live
136
+ probe, never from docs or a variable's name, and measure the serialized
137
+ payload the consumer receives — after encoding and wrappers — not the
138
+ object you assembled. A character count against a byte limit undercounts
139
+ multibyte text, hiding while inputs are ASCII; an item count bounds no
140
+ size. Enforce at one dispatch chokepoint, deriving every budget from that
141
+ constant.
108
142
 
109
143
  ## Git operations
110
144
 
@@ -131,12 +165,31 @@ depends on it, pin it explicitly instead of trusting the environment.
131
165
  restore from that. The same asymmetry makes the restore step fragile: if the
132
166
  probe can time out or abort, the restore must not be the next command in the
133
167
  same invocation — put it where a failure cannot skip it.
168
+ - **An ignore rule can swallow a durable record**: before treating a path as
169
+ durable — a new ledger, a cited authority — run `git check-ignore -v
170
+ <path>` and `git ls-files --error-unmatch <path>`. Broad runtime-state
171
+ patterns (`*.jsonl`, `runs/`, `out/`) absorb a new file, and a tracked
172
+ file pointing at an ignored path is an authority that exists in one
173
+ checkout only. Fix with a negation rule proven by a sibling that stays
174
+ ignored; genuinely ephemeral output stays ignored.
134
175
  - **Dirty-worktree pulls**: before pulling into a worktree with
135
176
  staged/unstaged/untracked changes, fetch first and compare incoming paths
136
177
  against every dirty path; on overlap or a non-fast-forward, stop and clear
137
178
  the conflict risk (stash, commit, ask). Otherwise pull `--ff-only`, confirm
138
179
  dirty changes survived, and regenerate any local derived artifacts whose
139
180
  inputs were updated.
181
+ - **A split series is proven commit by commit**: order them by dependency
182
+ and check each out into a throwaway worktree to run the build, tests, and
183
+ gates before pushing. Green only at the tip hides a broken bisect point
184
+ and a commit that cannot be reverted alone — usually a rename or shared
185
+ hunk in the wrong commit. If a handoff cites the branch's hashes, merge
186
+ with a merge commit: squash and rebase rewrite every hash.
187
+ - **A shared tree holds other operators' work**: a commit you did not make, a file the
188
+ editor reports changed on disk, a staged path you never added, one more field than
189
+ your predicted post-state — treat an unexplained delta as someone else's work, not
190
+ noise. Before a sweeping write (`git add -A`/`.`, `commit -a`, `stash`, `clean`,
191
+ `reset --hard`), attribute it (`git status`, reflog timestamps, other live sessions)
192
+ and then act only on what you can prove is yours — add by name.
140
193
 
141
194
  ## Config, secrets, and managed services
142
195
 
@@ -151,6 +204,13 @@ depends on it, pin it explicitly instead of trusting the environment.
151
204
  leaving stale, unreferenced definitions live. After updating, re-read the
152
205
  resource, check definitions and active references separately, and remove
153
206
  the orphans explicitly.
207
+ - **Derive a new revision from the live one, not from a template**: a
208
+ replace-semantics update drops every field the command does not restate,
209
+ and wrappers commonly default mounted secrets to off. Render the exact set
210
+ the command will send, derived from the live resource, and diff it field
211
+ by field; a field that disappears, or an operational value that moves
212
+ backward, is a blocker to explain, not a default to accept. Re-read the
213
+ resource afterwards, since a command rarely labels its semantics.
154
214
  - **A new revision is not live traffic**: on a runtime that pins traffic to a
155
215
  named revision (e.g. Cloud Run with a fixed split), `gcloud run deploy` (or
156
216
  the equivalent) creates the new revision but shifts no traffic to it — the
@@ -158,23 +218,101 @@ depends on it, pin it explicitly instead of trusting the environment.
158
218
  update-traffic`. Read the "deploy succeeded" message as "a revision exists",
159
219
  not "the new code is serving"; verify the live traffic split before
160
220
  concluding the deploy took effect.
161
- - **Perimeter controls need the enforcement point's own logs**: an agent-side
162
- fetch is not an independent external observer its egress IP and caching
163
- path are opaque, and it may share the protected network or serve a stale
164
- cached response. Verify allow AND deny directions from the load balancer /
165
- firewall's own logs, and check for a front-side cache/CDN separately.
221
+ - **Job logs outlive the execution**: a managed job that has run more than
222
+ once under one name including one deleted and recreated with the same
223
+ name returns the earlier incarnations' output when its logs are read by
224
+ job name. Scope every read to the execution id you received at launch and
225
+ confirm the timestamp window covers that run. An unscoped read merges
226
+ prior runs into the present and yields confident false diagnoses that a
227
+ scoped read reverses.
228
+ - **Dispatch status is not execution**: a CLI `--wait` returning or timing
229
+ out, a scheduler reporting success, a trigger accepted without error —
230
+ each reports what the dispatcher saw, not whether the target ran or what
231
+ state it reached. Before retrying or declaring done, re-derive the state
232
+ from the target's own record (its execution describe, the handler's logs),
233
+ matched to the run by id, and keep a manual probe distinguishable from the
234
+ scheduled one. A blind re-launch is a duplicate execution with side
235
+ effects.
236
+ - **An apply cut off before confirmation is unconfirmed** — neither done nor
237
+ un-run: when a multi-statement side-effecting apply (migration, batch
238
+ write) loses its confirmation channel, enumerate which target objects
239
+ already exist in the store, and plan the rerun from that partial state; a
240
+ naive rerun half-fails on "already exists" and leaves a second partial
241
+ state. Where the runner surfaces only exit status, route the object list
242
+ out through a deliberate failure. A transactional or provably idempotent
243
+ apply needs only the confirmation.
244
+ - **A traffic rollback is not a config rollback**: on a revision-pinned
245
+ runtime, sending traffic back to the previous revision restores behavior
246
+ but leaves the added env var or secret binding in the service template,
247
+ where the next deploy re-enables it silently. Count a rollback complete
248
+ only when the traffic split and the service spec are both back to the
249
+ prior state — re-read the spec and remove the change explicitly. Runtimes
250
+ that redeploy the prior spec itself (immutable-artifact, GitOps) have no
251
+ such gap.
252
+ - **Perimeter controls need the enforcement point's own logs**: an
253
+ agent-side fetch is not an independent observer — its egress IP and
254
+ caching path are opaque, and it may share the protected network or serve a
255
+ stale cached response. Verify allow AND deny directions from those logs,
256
+ and check for a front-side cache/CDN separately. Aim the probe at an
257
+ in-unit sentinel the app answers without credentials: a denial the app
258
+ produces anyway passes with the control off, and a redirect into it is a
259
+ bypass.
260
+ - **Tightening exposure is a behavior change for external clients**: switching
261
+ ingress mode, adding an allowlist, or requiring auth is not safe when
262
+ callers live outside your redeploy. Enumerate which clients reach the
263
+ endpoint and by which hostname, verify from a client's vantage, and
264
+ confirm inbound volume did not fall to zero — clients you cut off raise no
265
+ error on your side, so enforcement-point logs alone can sever ingestion
266
+ silently. Callers you redeploy in the same change need only the ordinary
267
+ deploy check.
166
268
  - **Smoke limits outlive the smoke test**: item caps, sample sizes, and row
167
269
  limits left in env vars/flags/config make a later "full-scale" run silently
168
270
  succeed on a slice. Clearing or explicitly verifying their absence is a
169
271
  precondition of declaring a full run.
272
+ - **A remote handle is valid only when it was read**: a row index in a sheet
273
+ that auto-sorts, a downloaded copy of a hosted file — each moves between
274
+ your read and your write. Before writing, re-establish the target from the
275
+ live source: re-locate the row by its key column, not a remembered
276
+ position, and assert the key matches after the write; compare the remote's
277
+ version against the copy you edited, re-downloading and reapplying on a
278
+ move. Local single-writer files need none of this.
279
+ - **Packaging and ignore rules are judged against paths and environments, not your tree**: before
280
+ a release, pack the real tarball, install it clean with lifecycle scripts
281
+ ON, and smoke it — a postinstall hook fine in the repo can delete the
282
+ shipped runtime where the build toolchain is absent. After moving or
283
+ renaming a directory, every ignore rule is void for the new paths:
284
+ re-check there and read the staged diff's file count, since old-path
285
+ patterns stop matching and excluded data enters the stage.
170
286
  - **Shared live config has concurrent writers**: before concluding your edit
171
287
  to a shared state/config file was lost or corrupting, rule out concurrent
172
288
  writers with a short live observation (mtime plus the fields you changed),
173
289
  and scope merge/union operations to the intended fields only.
290
+ - **Uniform failure is structural — read the persisted reason, then check the built artifact**: when
291
+ every item in a batch fails and the per-item error is persisted outside
292
+ the log (a status column, a result record), read it before blaming keys,
293
+ quota, or model availability. And when code reads sibling files from its
294
+ working directory, prove they exist inside the built image by listing or
295
+ hashing them there: a selective copy passes every repo-side check and
296
+ fails only at runtime.
174
297
  - **Production probes expose data**: default diagnostic queries against
175
298
  production stores to read-only server-side aggregation (counts, types,
176
299
  presence, hashes) — never pull raw payloads into logs, prompts, or
177
300
  transcripts — and delete scratch probe resources after the decision.
301
+ - **Build-context ignore patterns anchor at the root**: in a `.dockerignore`
302
+ or any root-anchored filter, a bare filename matches only at the context
303
+ root and never in a subdirectory, and an extension glob misses the
304
+ same-purpose credential file carrying another extension. Never conclude a
305
+ shipped image is secret-free from the patterns — list the built artifact's
306
+ own filesystem for credential-shaped files (env files, keys,
307
+ service-account JSON) as a named negative control, repeated whenever the
308
+ build context or ignore file changes.
309
+ - **A revoke is grant-wide, not token-wide**: revoking anything issued under
310
+ a client id the user's live sessions share invalidates those sessions too,
311
+ and the failure surfaces later, elsewhere, with no re-auth prompt. A probe
312
+ may clean up only what it alone owns — use minimum scopes and a dedicated
313
+ client id, and let a probe token expire rather than revoking it. Where a
314
+ revoke on a shared grant is unavoidable, state the blast radius and time
315
+ it with the user.
178
316
 
179
317
  ## Own what you spawn
180
318
 
@@ -186,3 +324,32 @@ Instance of the global rule: own the full lifecycle of what you create.
186
324
  orphans the real child), and await exit. An unref'd child handle or open
187
325
  stdin pipe keeps the parent's event loop alive and hangs otherwise-complete
188
326
  commands.
327
+ - **A handle issued to a human is a commitment**: once a consent URL is
328
+ handed over, the listener behind it must not be restarted, re-ported, or
329
+ replaced while the person may still act — keep it alive until the callback
330
+ lands, or say plainly that the link is dead. The handler captures the
331
+ credential write-once and ignores later hits, since a browser's favicon
332
+ request clears a naive one. Before asking a human to click again, drive
333
+ the handler with a simulated callback.
334
+ - **A stop is confirmed at the sink, not in the process list**: a kill that
335
+ misses one descendant lets that stage finish and publish, and the process
336
+ list looks clean either way. After stopping a multi-stage run, list the
337
+ output sink for anything written after the stop instant and roll it back
338
+ as contaminated. Read the rollback path's retention — noncurrent-version
339
+ expiry is a recovery window, not a backup — and snapshot before a risky
340
+ run, choosing the restore point by timestamp.
341
+ - **Detach what must outlive the call**: a process started inside a harness
342
+ tool call belongs to that call's process group: a trailing `&` is reaped
343
+ when the call returns, and the harness may signal the group when another
344
+ background task finishes. Launch anything meant to outlive one call
345
+ through the harness's background facility or fully detached
346
+ (nohup/setsid), writing progress to durable files a resume can read. A
347
+ zero-byte output file means it never survived. Detached still means owned
348
+ — PID file and stop path.
349
+ - **Name-substring lookup is not a liveness check**: `pgrep -f <name>` and
350
+ `ps | grep <name>` match the argv of the shell running the query itself,
351
+ and match unrelated processes carrying the same name — another session, a
352
+ sibling dispatch, the launcher's own plan text. To decide whether a
353
+ dispatched job is alive, use the PID or handle captured at launch, its
354
+ process-group state, or growth of its own output artifact. Substring
355
+ lookup is for discovery only, confirmed against one of those first.
@@ -34,11 +34,21 @@ the depth first:
34
34
  over persisted real artifacts rather than re-running the whole pipeline to observe it.
35
35
  - Probe at N=1 with the inputs precondition-checked. A single well-chosen case that reaches the
36
36
  real path outranks a hundred that stop short of it.
37
+ - Bound the N=1 probe to reachability. One case settles whether a path works — never how often a
38
+ stochastic behavior holds. Before quoting a rate-shaped property (determinism, flake rate, an
39
+ A/B effect), confirm the mechanism honors your controls, establish the noise floor from runs on
40
+ hand, then sample enough to bound the rate against a no-treatment control on the real path. A
41
+ floor larger than the effect breaks the premise — record it before redesigning.
37
42
  - Reserve the full design-review-plus-live-verification treatment for first-of-kind work and for
38
43
  changes that move authority — who may decide, who may write, what is irreversible.
39
44
  - Proportion assurance to the deployment context. A single-user tool operating on its owner's own
40
45
  data does not warrant production-grade assurance, and treating it as if it did buys nothing
41
46
  while delaying delivery. Prefer shipping.
47
+ - Census the population before a costed or irreversible batch. Read its current state cheaply and
48
+ deterministically — status distribution, version, presence of the artifacts the plan expects —
49
+ and compare that against the premise the batch rests on, halting to re-diagnose when the
50
+ distribution contradicts it. A probe validates the path; only the census validates that the
51
+ population is what the plan assumes. A cheap idempotent batch over a few items needs none.
42
52
 
43
53
  The failure this prevents is not under-testing. It is spending the verification budget on the
44
54
  cheap half of the risk and having nothing left for the part that could actually hurt.
@@ -62,10 +72,14 @@ cheapest one to write.
62
72
  - Config or data: real parsers, schema checks, fixture validation, and sample transformations.
63
73
  - Spreadsheets: static workbook checks, fixture-based output checks, cross-sheet flow checks, visual/layout checks, and real Microsoft Excel engine recalculation for formula-dependent results.
64
74
  - Docs: links, terminology, current behavior alignment, and references to isolated historical notes.
75
+ - Multi-subject prose: when deliverables draw on material about different people, companies, or cases, bind every captured item to its subject and confirmation status at capture, and narrate nothing under a subject until that binding is confirmed. Cross-check subject-specific proper nouns and figures across all outputs before delivery — one subject's term under another is the signature of context bleed. Keep a figure in the same sentence as its composition, since a detached number is read at its worst.
65
76
  - Release or distribution: after publishing to multiple independently writable channels (signed manifest, object storage, release host, embedded updater), digest-verify every referenced object against the staging original per channel — publish success and upload order are not evidence — and run the real installer/updater through its default path.
66
77
  - A/B or on/off measurements: before accepting a null result, verify the arms actually received different treatment in the mechanism under test — a shared default or unconditional upstream step can silently apply the treatment to both arms.
78
+ - Multi-stage pipelines with nondeterministic stages: a final-output diff cannot attribute an effect or a regression to a stage — it conflates the change with run-to-run variance. Persist every stage's output, tabulate what each creates, may edit, and only guards, restrict the suspects to the stages that edit the content in question, and find the first stage where the intended effect disappears or the defect appears. Fix there, preferring a structural recheck over another prompt-level instruction that already failed.
79
+ - Before/after comparisons: pin the input to an immutable copy — a snapshot or versioned artifact — and run both arms against it, because a live artifact (a growing log, a regenerated upstream stage) drifts between runs and any diff over it, a matching one included, is evidence of nothing; when the arms are metered, restore the baseline's exact upstream inputs and re-run only the changed stage. This is input identity, not the separate unit-and-denominator basis rule.
67
80
  - Model-behavior guardrails: verify by changed behavior, not recitation — a staged battery from named-trigger cases through disguised, deconfounded, category-wide, and single-variable framings; a clean pass means "no known defect", so re-run the battery when the model changes.
68
81
  - Branch/version test builds against real data: explicitly separate every state sink the app touches (files, DB, OS-level stores that ignore env overrides), confirm the launch path propagates the isolation to child processes, and back up live data before the first run — a mismatched schema that drops unknown fields on write is data loss, not a no-op.
82
+ - Sandbox, replay, or re-adjudication runs on production-derived config: enumerate every outbound channel the stage can reach — publish, upload, notify, external write — and disable or redirect each one before the run, proving each disarm fires as you would prove a path guard; a guard on the input or target path alone leaves egress armed. Fingerprint every external destination before the run and diff it after, so an escaped write is caught by the run rather than by a recipient.
69
83
  - Irreversible capture switches: when activation itself has unreproducible cost (a capture window that cannot be replayed), prove the downstream consumption path against existing samples before enabling — reversibility of the code path alone is not enough.
70
84
 
71
85
  ## Deriving the case space
@@ -108,6 +122,12 @@ someone typed once.
108
122
  interrupted, a restore sitting after it never runs and the plant survives into a
109
123
  commit. Plant in a copy where the shape allows it, and when it must be in place, snapshot
110
124
  first and restore from the snapshot as its own step rather than trusting the probe to finish.
125
+ - Attribute a fault by a controlled contrast before choosing a remedy. Hold everything constant —
126
+ principal, path, input — vary only the candidate variable, and read a countable difference
127
+ (element dimensions, request count, status-code family). A missing error report is not
128
+ exoneration: channels can be suppressed, unobserved, or unwired from the mechanism at fault, so
129
+ "no violations logged" rules a cause out only when the contrast shows none either. Read the
130
+ contrast the evidence already holds before proposing a policy loosening.
111
131
 
112
132
  ## When a green means nothing
113
133
 
@@ -121,17 +141,65 @@ produce a green with no evidence behind it:
121
141
  confirm its inputs satisfy the live branch's entry guard. A copied fixture that fails the new
122
142
  guard routes silently into the about-to-be-deleted dead branch and stays green after the real
123
143
  behavior breaks.
144
+ - **The fixture the producer never emits.** A test's input is evidence only when the thing that
145
+ produces it in production produced it. A wire fixture must be a raw response captured through
146
+ the same client that will parse it, never a rendered listing or a hand-written payload; a gated
147
+ feature's E2E must run with the gate in its production setting, on the state its real upstream
148
+ leaves. Replay against the live producer once, then probe every sibling built the same way.
124
149
  - **The permissive fallback in the checker.** A `a || b` inside a gate absorbs a wrong assumption
125
150
  and keeps passing. Checker code must assert the shape it expects and fail loud.
126
151
  - **The suspiciously fast or empty run.** When a check goes green unexpectedly quickly, or reports
127
152
  nothing at all, dump what it actually ran over before believing it. A harness that crashed early
128
153
  and one that found nothing produce the same exit code.
154
+ - **The control that failed by crashing.** A negative control is evidence only when it fails
155
+ through the assertion it names: a traceback and a caught violation share an exit code, and an
156
+ early crash can pre-empt every control after it. Treat each traceback in a control run as a
157
+ defect until the run reports one named failure per planted violation. Run any unattended gate
158
+ with stdin closed, so a path reaching a prompt fails at once instead of hanging.
129
159
  - **The control that went quiet.** A negative control indexing a live list stops testing when that
130
160
  list empties, and says nothing about it. New controls build their own subject; resolving an item
131
161
  means re-reading the controls for ones that have gone silent.
132
-
133
- The discipline that covers all five: after adding a check, revert the fix it guards and watch the
134
- check fail. A control that survives a faithful revert was never testing the thing it names.
162
+ - **The silent log.** Absence of activity is not evidence of non-use. Before retiring an
163
+ identity, key, or endpoint on a quiet log, show that the queried field is the one recording the
164
+ subject delegated actions are attributed to the caller, with the target in another field, so
165
+ the wrong field returns clean silence — and that no live binding still references it, since a
166
+ reference proves use while emitting no traffic. Only a demonstrated "this use would have been
167
+ logged" evidences non-use.
168
+ - **The population that shrank.** A gate scanning an explicit list of files sees only "listed but
169
+ empty": a subject that migrates to an unlisted surface leaves the scanned set smaller yet
170
+ non-empty, so the empty-subject guard never fires while coverage erodes. Retarget the gate in
171
+ the same change that moves the code, and pin a floor so any decrease fails loudly — proved by
172
+ moving one subject out. A floor is a ratchet: never lower it to pass a run.
173
+ - **The mutant that never ran.** A mutation verdict counts only if the mutant is valid: it
174
+ compiled, sits on a path the exercised test traverses, and changes the guarded behavior, not
175
+ healed downstream or coinciding with a default. The runner must report build failure,
176
+ unreachable, and equivalent distinctly from KILLED and SURVIVED, and halt on a moved anchor.
177
+ More tests red than the mutation should touch indicts it; classify a survivor (rebuild,
178
+ discard, genuine gap) before writing a test.
179
+ - **The probe that measured the original.** A copied script that derives its root or targets from
180
+ its own location (`$0`, `BASH_SOURCE`, a `cd` to its parent) scans the original tree, not the
181
+ copy, so its verdict says nothing about the mutation you planted. Pin the subject in the copy,
182
+ copy the whole tree, or plant in place with a snapshot-restore. The tell is a result identical
183
+ to the unmutated run; a script taking its subject as an argument is safe to copy.
184
+
185
+ The discipline that covers every shape above: after adding a check, revert the fix it guards and
186
+ watch the check fail. A control that survives a faithful revert was never testing the thing it
187
+ names. Prove the plant landed: assert the altered input differs from the original and that the
188
+ control's cases reach the mutated branch before asserting rejection. Construct corruption
189
+ deterministically: scanning for a flip site yields no-op mutations reporting a rejection nothing
190
+ exercised.
191
+
192
+ ## Before blaming code for a metric change
193
+
194
+ When a live metric collapses or crosses a pre-declared threshold, localize the change in time
195
+ before diagnosing the feature: confirm every inbound source is alive, compare only
196
+ contemporaneous cohorts, never re-processed rows, then bracket the transition to the finest unit
197
+ available and read the deploy log around that instant.
198
+
199
+ A change landing seconds from the last-good point is the prime suspect; a step in a window with
200
+ no deploys is an input-population shift, fixed by scoping the measured population, not the model
201
+ or the code. Declare the threshold before looking, and confirm a failure from the fleet's vantage
202
+ rather than your own — this does not replace fixing the comparison basis, which comes first.
135
203
 
136
204
  ## Keeping E2E honest
137
205
 
@@ -53,6 +53,31 @@ RULES = [
53
53
  "Reverting a path discards ALL uncommitted edits in that file, not just the one "
54
54
  f"you planted — check `git diff <path>` first, or restore from a copy ({GUIDE}).",
55
55
  "Reverting a path is not undoing your edit"),
56
+ # A sweeping write treats every delta in the tree as the caller's own. Named paths
57
+ # (`git add src/x.py`) are exempt: naming is the attribution the rule asks for.
58
+ ("shared-tree-sweep",
59
+ # The commit flag must be its own token: a path like /x/-agent/msg.txt after -F carries
60
+ # "-a" too, and the first version of this rule fired on exactly that.
61
+ re.compile(r"\bgit\s+(add\s+(-A|--all|\.)(\s|$)|commit\s+(?:[^|;&]*\s)?(?:-[a-zA-Z]*a[a-zA-Z]*|--all)(?=\s|$)|stash\b(?!\s+(pop|apply|list|show))|clean\b|reset\s+--hard)"),
62
+ "A shared tree may hold another operator's work — attribute every delta you did not "
63
+ f"make (git status, reflog, live sessions) before sweeping it; add by name ({GUIDE}).",
64
+ "A shared tree holds other operators' work"),
65
+ ("job-logs-by-execution",
66
+ re.compile(r"\bgcloud\s+(?:alpha\s+|beta\s+)?(?:logging\s+read|run\s+jobs)\b"),
67
+ "Job-level logs retain earlier executions (even a job deleted and recreated under the "
68
+ f"same name) — scope the read to the execution id you launched ({GUIDE}).",
69
+ "Job logs outlive the execution"),
70
+ ("name-substring-liveness",
71
+ re.compile(r"\bpgrep\s+(?:-\w+\s+)*-\w*f|\bps\b[^|\n]*\|[^|\n]*\bgrep\b"),
72
+ "A name-substring process lookup matches the querying shell's own argv and unrelated "
73
+ f"same-named processes — confirm liveness by PID, handle, or output growth ({GUIDE}).",
74
+ "Name-substring lookup is not a liveness check"),
75
+ # Not a search for the word: a grep/rg over sources mentions revoke without revoking.
76
+ ("revoke-grant-blast-radius",
77
+ re.compile(r"^(?!.*\b(?:rg|grep|ag|git\s+log)\b).*\brevoke\b"),
78
+ "A revoke is grant-wide: everything issued under a shared client id, including the "
79
+ f"user's live sessions, goes with it — confirm the scope before revoking ({GUIDE}).",
80
+ "A revoke is grant-wide, not token-wide"),
56
81
  ("grep-binary-heuristic",
57
82
  # Applied per extracted STAGE by matches(), not to the raw line. The stage's
58
83
  # COMMAND WORD must be grep — after optional reserved words (`if ! grep -q`
@@ -265,8 +290,33 @@ def self_test() -> int:
265
290
  "metachar-inline-arg": 'codex exec "$(cat packet.md)"',
266
291
  "pipe-exit-masking": "make build | tail -1; echo $?",
267
292
  "git-checkout-path": "git checkout src/thing.py",
293
+ "shared-tree-sweep": "git add -A && git commit -m x",
294
+ "job-logs-by-execution": "gcloud logging read 'resource.labels.job_name=probe' --limit 50",
295
+ "name-substring-liveness": "pgrep -f codex",
296
+ "revoke-grant-blast-radius": "gcloud auth revoke probe@example.com",
268
297
  "grep-binary-heuristic": "grep needle haystack.md",
269
298
  }
299
+ # Naming the path IS the attribution the sweep rule asks for, so a named add, a
300
+ # plain commit, and stash pop must not draw the reminder — or it fires on every commit.
301
+ for quiet_cmd in ("git add src/thing.py", "git commit -m 'fix'", "git stash pop", "git add -p",
302
+ "git commit -F /tmp/claude-501/-Users-someone-Documents-agent-bios/scratch/msg.txt"):
303
+ if "shared-tree-sweep" in [h for h, _ in matches(quiet_cmd, limit=None)]:
304
+ problems.append(f"shared-tree-sweep: fired on a non-sweeping command ({quiet_cmd!r})")
305
+ for sweep_cmd in ("git add .", "git commit -am 'wip'", "git commit --all -m x", "git stash", "git reset --hard HEAD"):
306
+ if "shared-tree-sweep" not in [h for h, _ in matches(sweep_cmd, limit=None)]:
307
+ problems.append(f"shared-tree-sweep: did not fire on a sweeping command ({sweep_cmd!r})")
308
+ for quiet_cmd in ("gcloud run services list", "docker logs probe", "kill -0 12345",
309
+ "grep -rn pgrep claude/guides/", "ls | grep foo", "rg revoke src/",
310
+ "git log --grep revoke"):
311
+ hit = [h for h, _ in matches(quiet_cmd, limit=None)]
312
+ for rule in ("job-logs-by-execution", "name-substring-liveness", "revoke-grant-blast-radius"):
313
+ if rule in hit:
314
+ problems.append(f"{rule}: fired on a non-matching command ({quiet_cmd!r})")
315
+ for rule, cmd in (("job-logs-by-execution", "gcloud beta run jobs executions list --job probe"),
316
+ ("name-substring-liveness", "ps aux | grep codex"),
317
+ ("revoke-grant-blast-radius", "vault token revoke s.f3b9c2")):
318
+ if rule not in [h for h, _ in matches(cmd, limit=None)]:
319
+ problems.append(f"{rule}: did not fire on ({cmd!r})")
270
320
  # A pipeline-stage grep must reach the rule too — the fixture alone exercises only
271
321
  # command-start grep, and the reminder is most needed mid-pipeline.
272
322
  if "grep-binary-heuristic" not in [h for h, _ in matches("cat payload | grep needle", limit=None)]:
package/codex/AGENTS.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  ## Global Preferences
4
4
 
5
- - Prefer concise Korean responses with polite speech unless the user asks otherwise.
5
+ - Prefer concise Korean responses with polite speech unless the user asks otherwise. (private)
6
6
  - Keep file changes within the requested scope.
7
7
 
8
8
  ## Problem Solving
@@ -10,7 +10,7 @@
10
10
  - First identify the goal, scope, ambiguities, and likely completion condition.
11
11
  - Resolve ambiguity from context when safe; ask only when ambiguity blocks progress or creates risky outcomes.
12
12
  - For simple requests, choose the most direct low-risk method and proceed.
13
- - For non-trivial requests, compare 2-4 methods by goal fit, time, cost, risk, benefit, and "done when".
13
+ - For non-trivial requests, compare 2-4 methods by goal fit, time, cost, risk, benefit, and "done when", and portability — take a host-, model-, or tool-specific mechanism (hook, skill, host-owned directory) only after a portable route is shown absent and its per-host cost is judged worth it.
14
14
  - Mark one default method. If the user is silent and the default is safe, proceed with it.
15
15
  - Execute the chosen method accurately and stay within scope.
16
16
  - Return to understanding if a discovery breaks the user's premise.
@@ -21,7 +21,7 @@
21
21
 
22
22
  ## Decision Framing
23
23
 
24
- - Ask decision questions in outcome terms, not jargon terms.
24
+ - Ask decision questions in outcome terms, not jargon terms: before ending a turn on a decision request, check that it gives the situation in one plain sentence, what changes for the user under each option, and a default — and where a structured question channel exists, route the ask through it so its fields force that shape.
25
25
  - When the user may not know the domain, explain choices by resulting behavior, tradeoffs, time, cost, risk, reversibility, and recommended default.
26
26
  - Present 2-4 meaningful options. Ask about implementation details only when they directly affect the decision.
27
27
  - For each option, state what changes for the user or product, what it costs, what risk it carries, and when it is the right choice.
@@ -29,7 +29,7 @@
29
29
  - Ask for the user's goal or constraint when that determines the answer; otherwise choose the safest default and proceed.
30
30
  - Evaluate user suggestions for goal fit, risk, complexity, and verification before turning them into implementation plans; if a suggestion does not fit the user's goal, say so clearly and recommend a better path.
31
31
  - Distinguish implementation feasibility from recommendation.
32
- - Do not default to a restrictive lens (security, masking, capability limits) when the system's purpose is sharing or utilization; confirm the purpose framing first, and restrict only on concrete, named risk.
32
+ - Do not default to a restrictive lens (security, masking, capability limits) when the system's purpose is sharing or utilization; confirm the purpose framing first, and restrict only on concrete, named risk — and size every control (gate, cap, rule, review lens, success criterion, clarifying question) to that risk: a target is a direction, not an absolute, and prefer a warning plus a recovery path over a prohibition.
33
33
  - Treat user suggestions, inherited premises, prior diagnoses, handoff and design claims, reviewer findings, and your own earlier conclusions as hypotheses, not facts; re-derive each load-bearing claim from real code or data before building on it, and record a dated correction in the source doc or memory when a finding overturns it.
34
34
 
35
35
  ## LLM And Capability Boundary
@@ -53,7 +53,7 @@
53
53
  ## Concept Economy
54
54
 
55
55
  - When adding, changing, renaming, splitting, or exposing anything lasting or shared — a feature, entity, type, field, config key, CLI flag, enum value, failure kind, artifact, or documentation term — read and use `${CODEX_HOME:-$HOME/.codex}/guides/concept-economy.md` as a scoped extension of this section.
56
- - Before fixing a review finding or test failure, classify the fix as reducing, preserving, or increasing the active concept surface.
56
+ - Before fixing a review finding or test failure, name its cause — a finding is a symptom — then classify the fix as reducing, preserving, or increasing the active concept surface, and fix the cause completely now: a scope-minimal patch that leaves the cause in place is not a fix.
57
57
 
58
58
  ## Coding Guidelines
59
59
 
@@ -61,7 +61,7 @@
61
61
  - For development work, read and use `${CODEX_HOME:-$HOME/.codex}/guides/coding-staged-workflow.md` as a scoped extension of these Coding Guidelines — a change too narrow to need it is what its lightweight path decides, not a reason to skip the read.
62
62
  - For mock, fixture, fake, stub, simulated-provider, or test-realization design, read and use `${CODEX_HOME:-$HOME/.codex}/guides/mock-realization-boundary.md` as a scoped extension of these Coding Guidelines.
63
63
  - Own the full lifecycle of what you create — spawned processes and handles through teardown, artifacts out of tool-managed temp locations into a durable home — and keep differently-owned state separate: never colocate deploy-managed and user-owned data in one overwrite-managed file.
64
- - Land risky or behavior-changing work behind a default-off path that preserves current behavior when off (proven by diff) and is enabled by an explicit opt-in, so the change stays reversible and the on/off difference is isolated. When a request would weaken a security or authority posture — removing or loosening an authentication/authorization check or access scope, or lowering a protective value such as session/token lifetime, password/crypto strength, rate limit, lockout threshold, or audit retention — treat it as a decision, not a rote edit, even when it is a one-line change and nothing in the code labels the value as security-relevant: state the consequence and at least one safer path to the real goal, and do not apply the weakening in the same turn — proceed only after the user confirms they accept the tradeoff.
64
+ - Land risky or behavior-changing work behind a default-off path that preserves current behavior when off (proven by diff) and is enabled by an explicit opt-in, so the change stays reversible and the on/off difference is isolated — the switch lands a fix reversibly and never substitutes for one. When a request would weaken a security or authority posture — removing or loosening an authentication/authorization check or access scope, or lowering a protective value such as session/token lifetime, password/crypto strength, rate limit, lockout threshold, or audit retention — treat it as a decision, not a rote edit, even when it is a one-line change and nothing in the code labels the value as security-relevant: state the consequence and at least one safer path to the real goal, and do not apply the weakening in the same turn — proceed only after the user confirms they accept the tradeoff.
65
65
 
66
66
  ## Verification Discipline
67
67
 
@@ -77,7 +77,7 @@
77
77
  - For concrete shell/CLI traps — pipe exit codes, output rendering, git range/pull semantics, config and managed-service pitfalls — read and use `${CODEX_HOME:-$HOME/.codex}/guides/tooling-gotchas.md` as a scoped extension of this section.
78
78
  - Ambient state — the active shell, cloud CLI project/context, command-name resolution, 'latest'-style pointers, version-bearing paths — drifts silently; where an outcome depends on it, pin it explicitly (a pinned interpreter, --project/--context flags, exact handles, resolved paths) instead of trusting the environment.
79
79
  - Before relying on any model id, tool flag, API capability, dependency version, or runtime constraint, confirm it empirically against the live or installed artifact (a minimal probe, the binary's registered options, the installed package version) rather than docs, memory, or a version string.
80
- - Scope destructive actions (kill, rm, force-push, reset --hard) to targets you own, identified by PID, path, or ancestry — never a broad command-line substring or blanket match — and diagnose the actual state before any irreversible git, remote, or process operation; snapshot the last good state before any in-place resume or overwrite of a completed run, and gate irreversible identity-tied actions (revoke, delete, grant, consent) on a live identity check — never auto-open a browser for a non-default identity (hand the operator the URL).
80
+ - Scope destructive actions (kill, rm, force-push, reset --hard) to targets you own, by PID, path, or ancestry — never a broad command-line substring or blanket match — and diagnose actual state before any irreversible git, remote, or process operation; snapshot the last good state before any in-place resume or overwrite of a completed run, and gate irreversible identity-tied actions (revoke, delete, grant, consent, account-bound creation) on a live identity check — never auto-open a browser for a non-default identity (hand the operator the URL).
81
81
  - Never accept secrets through transcript- or history-logged channels.
82
82
  - When a secret must be supplied, provide a gitignored env slot, read the value only from the environment, verify its presence and format without echoing it, and advise rotating anything already pasted; assume a resource-creating call may echo the secret back in its success output — suppress or discard the response body, and treat an echoed secret as pasted (rotate).
83
83
  - Treat a coarse runtime signal — a failure label, a `ps`/process-inspection result, idle CPU with no output — as a hypothesis, and confirm the cause against the authoritative low-level evidence the mechanism emits before attributing blame or intervening: read the raw provider/skill log payload (e.g. `input_tokens:0` proves a pre-dispatch rejection that exonerates your content and your change), and confirm a config/env toggle reached a subprocess via a cheap artifact the gated branch emits rather than an unreliable `ps` env read. A multi-minute LLM or subprocess call at ~0% CPU with an output gap is the normal signature of I/O wait, not a hang — check process state and the call trace's in-flight duration before acting, so you do not abort healthy long-running work.
@@ -85,7 +85,7 @@
85
85
  ## Multi-Model Workflow
86
86
 
87
87
  - Codex-only standing authorization: on root/main local tasks, ordinary subagent dispatch is authorized when the `When To Spawn` gates fire. Explicit no-fan-out wins. Delegated agents may re-delegate only when their role allows. This grants no destructive, remote, credential, install, OAuth, push, live-network-expanding, or broader-sandbox authority.
88
- - Standing spawn policy: check the spawn gates at every work-unit boundary — judgment latitude applies inside a gate, never to whether the gates are checked. Independence: verifying or reviewing your own work always spawns. Parallelism: two or more independent items spawn in parallel — SWEEP when each item applies one explicit rule and returns ambiguity as an exception, else WORKHORSE. Residual context: work whose log dwarfs the conclusion the main needs spawns with a bounded report contract. Escalation: an irreversible or authority-changing action ahead, two failed attempts, or two persisting design alternatives spawns a bounded FRONTIER judgment with a blind packet (evidence, constraints, rubric, neutral alternatives — never your draft conclusion) and a pre-noted change condition. Specifiability/de-minimis: work needing your live context, or whose verification would repeat the reasoning, or whose packet outweighs the work, stays inline.
88
+ - Standing spawn policy: check the spawn gates at every work-unit boundary — judgment latitude applies inside a gate, never to whether the gates are checked. Independence: verifying or reviewing your own work always spawns, and you raise it yourself — before presenting a load-bearing conclusion or taking an irreversible step, propose the cross-check unprompted; the user should never have to ask for it. Parallelism: two or more independent items spawn in parallel — SWEEP when each item applies one explicit rule and returns ambiguity as an exception, else WORKHORSE. Residual context: work whose log dwarfs the conclusion the main needs spawns with a bounded report contract. Escalation: an irreversible or authority-changing action ahead, two failed attempts, or two persisting design alternatives spawns a bounded FRONTIER judgment with a blind packet (evidence, constraints, rubric, neutral alternatives — never your draft conclusion) and a pre-noted change condition. Specifiability/de-minimis: work needing your live context, or whose verification would repeat the reasoning, or whose packet outweighs the work, stays inline.
89
89
  - Down-spawns carry a machine-checkable done-when on decision-complete work with staged output (no external irreversible actions) and briefing-plus-verifying clearly cheaper than doing. Record one line per gate decision — `SpawnGate: <gate> <tier> spawn|inline — <why>` — and for FRONTIER record the disposition afterward (what changed, or why nothing did). A launch contract's `Delegation=off` lifts the spawn obligation, not the records; explicit user no-fan-out always wins.
90
90
  - For work spanning multiple models or CLI agents, context resets and handoffs, unattended LLM batches (including orchestrated subagent fleets), or parallel worktree branches, read and use `${CODEX_HOME:-$HOME/.codex}/guides/cli-multi-model-workflow.md` as a scoped extension of this section.
91
91
  - For composing a prompt, packet, or tool description aimed at a specific model family — including cross-family review dispatch, porting a prompt written for an older model, or choosing a reasoning-effort level for a model family — read and use `${CODEX_HOME:-$HOME/.codex}/guides/gpt-prompting.md` for gpt-family targets and `${CODEX_HOME:-$HOME/.codex}/guides/claude-prompting.md` for claude-family targets as scoped extensions of this section.