agent-bios 0.9.9 → 0.11.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.
- package/DEPENDENCIES.md +3 -3
- package/README.md +10 -2
- package/claude/CLAUDE.md +4 -41
- package/claude/guides/cli-multi-model-workflow.md +7 -7
- package/claude/guides/coding-staged-workflow.md +51 -49
- package/claude/guides/concept-economy.md +187 -0
- package/claude/guides/documentation-hygiene.md +112 -0
- package/claude/guides/review-request.md +9 -7
- package/claude/guides/session-distill-workflow.md +3 -3
- package/claude/guides/tooling-gotchas.md +10 -0
- package/claude/guides/verification-discipline.md +166 -0
- package/claude/hooks/tooling-gotchas-hook.py +323 -13
- package/codex/AGENTS.md +4 -41
- package/codex/guides/cli-multi-model-workflow.md +7 -7
- package/codex/guides/coding-staged-workflow.md +51 -49
- package/codex/guides/concept-economy.md +187 -0
- package/codex/guides/documentation-hygiene.md +112 -0
- package/codex/guides/review-request.md +9 -7
- package/codex/guides/session-distill-workflow.md +3 -3
- package/codex/guides/tooling-gotchas.md +10 -0
- package/codex/guides/verification-discipline.md +166 -0
- package/compose/assemble.py +10 -1
- package/compose/check-domains.py +882 -6
- package/compose/domains.json +10 -44
- package/install.sh +176 -16
- package/launch/agent-launch.py +790 -173
- package/launch/agent-launch.toml +56 -107
- package/launch/i18n/en.toml +66 -0
- package/launch/i18n/ja.toml +63 -0
- package/launch/i18n/ko.toml +63 -0
- package/package.json +9 -4
- package/provenance.json +1 -0
- package/wrappers/codex-run.sh +1 -1
- package/claude/hooks/__pycache__/tooling-gotchas-hook.cpython-314.pyc +0 -0
|
@@ -12,53 +12,159 @@ import sys
|
|
|
12
12
|
|
|
13
13
|
GUIDE = "guides/tooling-gotchas.md"
|
|
14
14
|
|
|
15
|
-
# (name, compiled trigger, one-line reminder). Priority order; max 2 injected.
|
|
15
|
+
# (name, compiled trigger, one-line reminder, guide anchor). Priority order; max 2 injected.
|
|
16
|
+
#
|
|
17
|
+
# The anchor is the heading in tooling-gotchas.md this rule compresses. It exists because the
|
|
18
|
+
# hook is Claude-only and the guide is what a Codex reader gets instead: a rule admitted here
|
|
19
|
+
# with no counterpart there would silently give the two hosts different guidance. The mapping
|
|
20
|
+
# is declared rather than matched, because a rule name and a guide heading do not share a
|
|
21
|
+
# string. --self-test checks every anchor against the guide AND its codex mirror.
|
|
16
22
|
RULES = [
|
|
17
23
|
("reserved-shell-names",
|
|
18
24
|
re.compile(r"\b(UID|EUID|GID|PPID)="),
|
|
19
25
|
"Assigning reserved shell names (UID/EUID/GID/PPID) can invoke the bound "
|
|
20
|
-
f"system behavior instead of storing a value — use unreserved names ({GUIDE})."
|
|
26
|
+
f"system behavior instead of storing a value — use unreserved names ({GUIDE}).",
|
|
27
|
+
"Reserved parameter names"),
|
|
21
28
|
("git-diff-two-dot",
|
|
22
29
|
re.compile(r"git\s+diff\s+[^|;&]*(?<!\.)\.\.(?!\.)"),
|
|
23
30
|
"git diff A..B is a direct snapshot comparison, not a range exclusion — "
|
|
24
|
-
f"for PR/review diffs use three-dot origin/base...HEAD ({GUIDE})."
|
|
31
|
+
f"for PR/review diffs use three-dot origin/base...HEAD ({GUIDE}).",
|
|
32
|
+
"Two-dot diff semantics"),
|
|
25
33
|
("git-pull-dirty",
|
|
26
34
|
re.compile(r"\bgit\s+pull\b"),
|
|
27
35
|
"Before pulling into a worktree with local changes: fetch first, compare "
|
|
28
|
-
f"incoming paths against dirty paths, prefer --ff-only ({GUIDE})."
|
|
36
|
+
f"incoming paths against dirty paths, prefer --ff-only ({GUIDE}).",
|
|
37
|
+
"Dirty-worktree pulls"),
|
|
29
38
|
("metachar-inline-arg",
|
|
30
39
|
re.compile(r"(codex-run|codex-helm|codex\s+exec|claude\s+-p)\b[^|;&]*[\"'][^\"']*(\$\(|`)"),
|
|
31
40
|
"Values with shell metacharacters must reach the target via stdin or a "
|
|
32
|
-
f"file, not inline arguments — the shell expands them first ({GUIDE})."
|
|
41
|
+
f"file, not inline arguments — the shell expands them first ({GUIDE}).",
|
|
42
|
+
"Metacharacter-bearing values"),
|
|
33
43
|
("pipe-exit-masking",
|
|
34
44
|
re.compile(r"\$\?"),
|
|
35
45
|
"A pipeline's $? reflects only the last stage — capture the tested "
|
|
36
|
-
f"stage's own status (unpiped run, PIPESTATUS, per-command pipefail) ({GUIDE})."
|
|
46
|
+
f"stage's own status (unpiped run, PIPESTATUS, per-command pipefail) ({GUIDE}).",
|
|
47
|
+
"Pipe exit masking"),
|
|
37
48
|
# Path-shaped argument only: `git checkout main` is a branch switch and needs no
|
|
38
49
|
# warning, while `git checkout src/x.py` silently discards every uncommitted edit in
|
|
39
50
|
# that file — including ones the caller did not put there.
|
|
40
51
|
("git-checkout-path",
|
|
41
52
|
re.compile(r"\bgit\s+(checkout|restore)\b[^|;&]*(--\s|[\w.-]*[./][\w./-]*)"),
|
|
42
53
|
"Reverting a path discards ALL uncommitted edits in that file, not just the one "
|
|
43
|
-
f"you planted — check `git diff <path>` first, or restore from a copy ({GUIDE})."
|
|
54
|
+
f"you planted — check `git diff <path>` first, or restore from a copy ({GUIDE}).",
|
|
55
|
+
"Reverting a path is not undoing your edit"),
|
|
44
56
|
("grep-binary-heuristic",
|
|
45
|
-
|
|
57
|
+
# Applied per extracted STAGE by matches(), not to the raw line. The stage's
|
|
58
|
+
# COMMAND WORD must be grep — after optional reserved words (`if ! grep -q`
|
|
59
|
+
# is the assert-absence idiom) and per-command assignments (`LC_ALL=C grep`
|
|
60
|
+
# — locale pinning is what our own guides recommend); bare, path-prefixed,
|
|
61
|
+
# or the DIRECT git subcommand (git grep shares the binary heuristic). A
|
|
62
|
+
# stage that merely passes the word along (`echo grep needle`) runs no grep
|
|
63
|
+
# and gets no reminder. Greps reached through any other prefix — sudo,
|
|
64
|
+
# xargs, git global options between git and the subcommand (`git -C repo
|
|
65
|
+
# grep`), env, timeout, and their successors — are accepted residual by
|
|
66
|
+
# decision: each is one rung of an endless prefix ladder, and a missed
|
|
67
|
+
# reminder is the failure mode this advisory-only hook tolerates.
|
|
68
|
+
re.compile(r"\s*(?:(?:!|if|elif|else|then|do|while|until|time)\s+)*"
|
|
69
|
+
r"(?:\w+=\S*\s+)*(?:\S+/)?(?:git\s+)?grep\s"),
|
|
46
70
|
"grep can misread text with heavy non-ASCII/NUL as binary and return a "
|
|
47
|
-
f"false no-match — prefer the Grep tool (ripgrep) or grep -a ({GUIDE})."
|
|
71
|
+
f"false no-match — prefer the Grep tool (ripgrep) or grep -a ({GUIDE}).",
|
|
72
|
+
"grep binary heuristic"),
|
|
48
73
|
]
|
|
49
74
|
MAX_INJECT = 2
|
|
50
75
|
|
|
51
76
|
|
|
52
|
-
def matches(command: str):
|
|
77
|
+
def matches(command: str, limit: int | None = MAX_INJECT):
|
|
78
|
+
"""Rules this command trips. `limit` is a DELIVERY policy — at most two reminders are
|
|
79
|
+
worth injecting at once — not a judgement about which rules matched, so the self-test
|
|
80
|
+
asks for the untruncated list rather than re-deriving the matching itself."""
|
|
53
81
|
hits = []
|
|
54
|
-
for name, rx, msg in RULES:
|
|
82
|
+
for name, rx, msg, _ in RULES:
|
|
55
83
|
if name == "pipe-exit-masking" and "|" not in command:
|
|
56
84
|
continue
|
|
57
|
-
if name == "grep-binary-heuristic"
|
|
85
|
+
if name == "grep-binary-heuristic":
|
|
86
|
+
# Per STAGE, not per command: -a on an upstream grep does nothing for a
|
|
87
|
+
# downstream one (`git grep -a foo | grep bar` leaves bar's stage on the
|
|
88
|
+
# binary heuristic), so the exemption holds only when EVERY grep stage
|
|
89
|
+
# carries its own text-mode flag.
|
|
90
|
+
# Every separator starts a new stage: a single & (background) and a newline
|
|
91
|
+
# join commands as surely as ; and | — `grep -a foo a & grep bar b` left the
|
|
92
|
+
# -a covering a stage it never touches.
|
|
93
|
+
# A command substitution executes regardless of the quotes around it:
|
|
94
|
+
# `echo "$(grep needle payload)"` runs that grep, and quote-blanking was
|
|
95
|
+
# hiding it from the stage list so an outer -a covered it. Substitution
|
|
96
|
+
# bodies are lifted out (innermost-first, to a fixpoint) and judged as
|
|
97
|
+
# stages of their own.
|
|
98
|
+
scan = command
|
|
99
|
+
seen_subs = set()
|
|
100
|
+
while True:
|
|
101
|
+
subs = [s2 for s2 in re.findall(r"\$\(([^()]*)\)", scan)
|
|
102
|
+
+ re.findall(r"`([^`]*)`", scan)
|
|
103
|
+
if s2 not in seen_subs]
|
|
104
|
+
if not subs:
|
|
105
|
+
break
|
|
106
|
+
seen_subs.update(subs)
|
|
107
|
+
scan = scan + "\n" + "\n".join(subs)
|
|
108
|
+
# Quotes are blanked BEFORE splitting: a separator inside a quoted pattern
|
|
109
|
+
# (`grep 'grep -a;foo'`) manufactured a pseudo-stage carrying a text-mode
|
|
110
|
+
# flag that exists only as pattern content. Blanked to a placeholder TOKEN,
|
|
111
|
+
# not to nothing: `grep -e "needle" -a file` blanked to whitespace left -e
|
|
112
|
+
# to consume the -a as its argument, and the real text-mode flag vanished
|
|
113
|
+
# with the operand's token boundary.
|
|
114
|
+
blanked = re.sub(r"'[^']*'|\"(?:\\\\.|[^\"\\\\])*\"", "0", scan)
|
|
115
|
+
# Comments go after the quotes: with quoted text blanked, any remaining # is
|
|
116
|
+
# a real comment, and `grep needle payload # use -a next time` was exempting
|
|
117
|
+
# itself with advice bash never passes to grep.
|
|
118
|
+
blanked = re.sub(r"#[^\n]*", "", blanked)
|
|
119
|
+
# Parens split as the old line-shaped trigger's [;&(|] class did: a
|
|
120
|
+
# subshell or group opener starts a command (`(grep needle)` runs grep),
|
|
121
|
+
# and dropping ( from the boundaries regressed exactly that form.
|
|
122
|
+
stages = [st for st in re.split(r"\|\||&&|[|;&\n()]", blanked)
|
|
123
|
+
if rx.match(st)]
|
|
124
|
+
# The STAGES are the trigger: a grep whose only appearance is inside a
|
|
125
|
+
# lifted substitution (`echo "\`grep needle payload\`"`) never matched a
|
|
126
|
+
# line-shaped regex, and a quoted assignment value (`FILTER='two words'
|
|
127
|
+
# grep ...`) hid the command word from it. The rule's regex judges each
|
|
128
|
+
# stage in COMMAND-WORD position — `echo grep needle` passes the word as
|
|
129
|
+
# an argument, runs no grep, and stays quiet.
|
|
130
|
+
if not stages:
|
|
131
|
+
continue
|
|
132
|
+
# Options end at `--`: after it, `-a` is the PATTERN operand (grep's usage is
|
|
133
|
+
# [OPTION]... PATTERNS [FILE]...), so `grep -- -a payload` is still on the
|
|
134
|
+
# binary heuristic and must keep its reminder.
|
|
135
|
+
# And `-e <pattern>` consumes its argument: in `grep -e -a payload` the -a
|
|
136
|
+
# is the PATTERN (grep --help: -e, --regexp=PATTERNS), so it must not read
|
|
137
|
+
# as text mode. The pattern-taking options are blanked before the flag scan.
|
|
138
|
+
# -f/--file consumes its argument the same way (-f, --file=FILE): every
|
|
139
|
+
# pattern-taking option is blanked, or its argument reads as a flag.
|
|
140
|
+
# Quoted text is pattern content, never options: `grep 'foo -a bar'` has no
|
|
141
|
+
# text-mode flag, and the unquoted scan read the -a inside the pattern.
|
|
142
|
+
# Quotes are blanked first, then the -- operand split, then pattern-taking
|
|
143
|
+
# option arguments.
|
|
144
|
+
opts = [re.sub(r"(^|\s)(?:-e|--regexp|-f|--file)(?:=\S+|\s+\S+)", " ",
|
|
145
|
+
st.split(" -- ", 1)[0])
|
|
146
|
+
for st in stages]
|
|
147
|
+
|
|
148
|
+
# Bundled short options count too: `grep -qa` enables text mode (grep
|
|
149
|
+
# --help: -a, --text), and requiring a whitespace-delimited -a warned
|
|
150
|
+
# about binary data on a grep that reads it as text. A letter that takes
|
|
151
|
+
# an argument (-e -f -m -A -B -C -d -D) consumes the REST of the bundle,
|
|
152
|
+
# so in `-ea` the a is the PATTERN, not a flag — an `a` reads as text
|
|
153
|
+
# mode only when every letter before it is argument-free.
|
|
154
|
+
def text_mode(o):
|
|
155
|
+
if re.search(r"(^|\s)(-a\b|--text\b|--binary-files(?:=|\s+)text\b)", o):
|
|
156
|
+
return True
|
|
157
|
+
return any(len(halves) == 2 and not set(halves[0]) & set("efmABCdD")
|
|
158
|
+
for tok in re.findall(r"(?:^|\s)-([A-Za-z0-9]+)", o)
|
|
159
|
+
for halves in [tok.split("a", 1)])
|
|
160
|
+
|
|
161
|
+
if all(text_mode(o) for o in opts):
|
|
162
|
+
continue
|
|
163
|
+
hits.append((name, msg))
|
|
58
164
|
continue
|
|
59
165
|
if rx.search(command):
|
|
60
166
|
hits.append((name, msg))
|
|
61
|
-
return hits[:
|
|
167
|
+
return hits if limit is None else hits[:limit]
|
|
62
168
|
|
|
63
169
|
|
|
64
170
|
def main() -> int:
|
|
@@ -82,5 +188,209 @@ def main() -> int:
|
|
|
82
188
|
return 0
|
|
83
189
|
|
|
84
190
|
|
|
191
|
+
def self_test() -> int:
|
|
192
|
+
"""Two halves, because this hook serves two hosts differently.
|
|
193
|
+
|
|
194
|
+
Claude gets the injection, so the first half runs the real entry point over real stdin and
|
|
195
|
+
requires the message out. Codex gets nothing from a hook, so its equivalent is the guide —
|
|
196
|
+
and the second half is the only thing that keeps the two hosts saying the same thing.
|
|
197
|
+
"""
|
|
198
|
+
import pathlib, subprocess
|
|
199
|
+
|
|
200
|
+
here = pathlib.Path(__file__).resolve()
|
|
201
|
+
repo = here.parent.parent.parent
|
|
202
|
+
problems = []
|
|
203
|
+
assert RULES, "no rules: this self-test would pass over nothing"
|
|
204
|
+
|
|
205
|
+
# -- half 1: the hook runs, matches, and emits. A file that is copied and registered but
|
|
206
|
+
# crashes on every invocation satisfies every other check in this repository.
|
|
207
|
+
fires = "UID=0 echo hi"
|
|
208
|
+
payload = json.dumps({"tool_name": "Bash", "tool_input": {"command": fires}})
|
|
209
|
+
r = subprocess.run([sys.executable, str(here)], input=payload,
|
|
210
|
+
capture_output=True, text=True)
|
|
211
|
+
if r.returncode != 0:
|
|
212
|
+
problems.append(f"hook exited {r.returncode} on a matching command: {r.stderr.strip()[:120]}")
|
|
213
|
+
elif "additionalContext" not in r.stdout:
|
|
214
|
+
problems.append(f"hook emitted no context for {fires!r}; got {r.stdout.strip()[:80]!r}")
|
|
215
|
+
|
|
216
|
+
# A non-matching command must stay silent, or "it fired" proves nothing.
|
|
217
|
+
quiet = json.dumps({"tool_name": "Bash", "tool_input": {"command": "echo hello"}})
|
|
218
|
+
r2 = subprocess.run([sys.executable, str(here)], input=quiet, capture_output=True, text=True)
|
|
219
|
+
if r2.stdout.strip():
|
|
220
|
+
problems.append(f"hook injected on a command that matches nothing: {r2.stdout.strip()[:80]!r}")
|
|
221
|
+
|
|
222
|
+
# Every rule needs a command that must reach it. A nonempty pattern is not evidence: a
|
|
223
|
+
# trigger of `(?!)` can never match, and a rule suppressed by the special-case logic in
|
|
224
|
+
# matches() never reaches the caller either — both leave the rule inert while this file
|
|
225
|
+
# goes on reporting that all of them fire.
|
|
226
|
+
FIXTURES = {
|
|
227
|
+
"reserved-shell-names": "UID=0 echo hi",
|
|
228
|
+
"git-diff-two-dot": "git diff main..HEAD",
|
|
229
|
+
"git-pull-dirty": "git pull origin main",
|
|
230
|
+
"metachar-inline-arg": 'codex exec "$(cat packet.md)"',
|
|
231
|
+
"pipe-exit-masking": "make build | tail -1; echo $?",
|
|
232
|
+
"git-checkout-path": "git checkout src/thing.py",
|
|
233
|
+
"grep-binary-heuristic": "grep needle haystack.md",
|
|
234
|
+
}
|
|
235
|
+
# A pipeline-stage grep must reach the rule too — the fixture alone exercises only
|
|
236
|
+
# command-start grep, and the reminder is most needed mid-pipeline.
|
|
237
|
+
if "grep-binary-heuristic" not in [h for h, _ in matches("cat payload | grep needle", limit=None)]:
|
|
238
|
+
problems.append("grep-binary-heuristic: does not fire on a pipeline stage "
|
|
239
|
+
"('cat payload | grep needle')")
|
|
240
|
+
if "grep-binary-heuristic" not in [h for h, _ in matches("git grep -a foo | grep bar", limit=None)]:
|
|
241
|
+
problems.append("grep-binary-heuristic: an upstream -a cancelled the reminder for "
|
|
242
|
+
"a downstream grep that has no text-mode flag")
|
|
243
|
+
if "grep-binary-heuristic" in [h for h, _ in matches("git grep -a foo | grep -a bar", limit=None)]:
|
|
244
|
+
problems.append("grep-binary-heuristic: fired although every grep stage carries "
|
|
245
|
+
"its own text-mode flag")
|
|
246
|
+
if "grep-binary-heuristic" not in [h for h, _ in matches("grep -- -a payload", limit=None)]:
|
|
247
|
+
problems.append("grep-binary-heuristic: '-a' AFTER the -- marker is the pattern "
|
|
248
|
+
"operand, not a flag, and the reminder was suppressed")
|
|
249
|
+
if "grep-binary-heuristic" in [h for h, _ in matches("grep -a -- pattern file.md", limit=None)]:
|
|
250
|
+
problems.append("grep-binary-heuristic: fired although -a precedes the -- marker")
|
|
251
|
+
if "grep-binary-heuristic" not in [h for h, _ in matches("grep -e -a payload", limit=None)]:
|
|
252
|
+
problems.append("grep-binary-heuristic: '-a' as the ARGUMENT of -e is the pattern, "
|
|
253
|
+
"not text mode, and the reminder was suppressed")
|
|
254
|
+
if "grep-binary-heuristic" in [h for h, _ in matches("grep -a -e pattern file.md", limit=None)]:
|
|
255
|
+
problems.append("grep-binary-heuristic: fired although -a stands alone before -e")
|
|
256
|
+
if "grep-binary-heuristic" not in [h for h, _ in matches("grep -f -a payload", limit=None)]:
|
|
257
|
+
problems.append("grep-binary-heuristic: '-a' as the ARGUMENT of -f is a pattern "
|
|
258
|
+
"file, not text mode, and the reminder was suppressed")
|
|
259
|
+
if "grep-binary-heuristic" not in [h for h, _ in matches("grep 'foo -a bar' payload", limit=None)]:
|
|
260
|
+
problems.append("grep-binary-heuristic: a text-mode spelling INSIDE a quoted "
|
|
261
|
+
"pattern is pattern content, and the reminder was suppressed")
|
|
262
|
+
if "grep-binary-heuristic" in [h for h, _ in matches("grep -a 'foo bar' payload", limit=None)]:
|
|
263
|
+
problems.append("grep-binary-heuristic: fired although -a stands outside the "
|
|
264
|
+
"quoted pattern")
|
|
265
|
+
if "grep-binary-heuristic" not in [h for h, _ in matches("grep 'grep -a;foo' payload", limit=None)]:
|
|
266
|
+
problems.append("grep-binary-heuristic: a separator inside a quoted pattern "
|
|
267
|
+
"manufactured a pseudo-stage whose -a suppressed the reminder")
|
|
268
|
+
if "grep-binary-heuristic" in [h for h, _ in matches("grep -a 'x;y' payload", limit=None)]:
|
|
269
|
+
problems.append("grep-binary-heuristic: fired although the real stage carries -a "
|
|
270
|
+
"and the separator is only pattern content")
|
|
271
|
+
if "grep-binary-heuristic" not in [h for h, _ in
|
|
272
|
+
matches('echo "`grep needle payload`" | grep -a foo', limit=None)]:
|
|
273
|
+
problems.append("grep-binary-heuristic: a LEGACY backtick substitution's grep lost "
|
|
274
|
+
"its reminder to the outer stage's -a")
|
|
275
|
+
if "grep-binary-heuristic" not in [h for h, _ in
|
|
276
|
+
matches('echo "`grep needle payload`"', limit=None)]:
|
|
277
|
+
problems.append("grep-binary-heuristic: a grep whose ONLY appearance is a lifted "
|
|
278
|
+
"substitution never triggered")
|
|
279
|
+
if "grep-binary-heuristic" in [h for h, _ in
|
|
280
|
+
matches("grep -a needle payload # note", limit=None)]:
|
|
281
|
+
problems.append("grep-binary-heuristic: fired although the real invocation "
|
|
282
|
+
"carries -a and only the comment follows")
|
|
283
|
+
if "grep-binary-heuristic" not in [h for h, _ in
|
|
284
|
+
matches("grep needle payload # use -a next time", limit=None)]:
|
|
285
|
+
problems.append("grep-binary-heuristic: advice in a trailing comment exempted a "
|
|
286
|
+
"grep bash never passes it to")
|
|
287
|
+
if "grep-binary-heuristic" not in [h for h, _ in
|
|
288
|
+
matches("FILTER='two words' grep needle payload", limit=None)]:
|
|
289
|
+
problems.append("grep-binary-heuristic: a quoted assignment value hid the command "
|
|
290
|
+
"word from the trigger")
|
|
291
|
+
for argcmd in ("echo grep needle", "command -v grep"):
|
|
292
|
+
if "grep-binary-heuristic" in [h for h, _ in matches(argcmd, limit=None)]:
|
|
293
|
+
problems.append(f"grep-binary-heuristic: fired although grep is an ARGUMENT, "
|
|
294
|
+
f"not the stage's command word ({argcmd!r})")
|
|
295
|
+
if "grep-binary-heuristic" not in [h for h, _ in
|
|
296
|
+
matches("if ! grep -q needle payload; then echo none; fi",
|
|
297
|
+
limit=None)]:
|
|
298
|
+
problems.append("grep-binary-heuristic: reserved words and negation before the "
|
|
299
|
+
"command word suppressed the reminder")
|
|
300
|
+
if "grep-binary-heuristic" not in [h for h, _ in
|
|
301
|
+
matches("/usr/bin/grep needle payload", limit=None)]:
|
|
302
|
+
problems.append("grep-binary-heuristic: a path-prefixed grep is still grep, and "
|
|
303
|
+
"the reminder was suppressed")
|
|
304
|
+
for bundled in ("grep -qa needle payload", "grep -aH needle payload",
|
|
305
|
+
"cat payload | grep -qa needle"):
|
|
306
|
+
if "grep-binary-heuristic" in [h for h, _ in matches(bundled, limit=None)]:
|
|
307
|
+
problems.append(f"grep-binary-heuristic: fired although a bundled short "
|
|
308
|
+
f"option enables text mode ({bundled!r})")
|
|
309
|
+
for consumed in ("grep -ea payload", "grep -fa payload"):
|
|
310
|
+
if "grep-binary-heuristic" not in [h for h, _ in matches(consumed, limit=None)]:
|
|
311
|
+
problems.append(f"grep-binary-heuristic: an 'a' consumed as an option "
|
|
312
|
+
f"ARGUMENT read as text mode ({consumed!r})")
|
|
313
|
+
for grouped in ("(grep needle payload)", "if (grep needle payload); then echo found; fi"):
|
|
314
|
+
if "grep-binary-heuristic" not in [h for h, _ in matches(grouped, limit=None)]:
|
|
315
|
+
problems.append(f"grep-binary-heuristic: a subshell-grouped grep lost its "
|
|
316
|
+
f"reminder to the opening paren ({grouped!r})")
|
|
317
|
+
for qop in ('grep -e "needle" -a file', 'grep -f "patterns.txt" -a file'):
|
|
318
|
+
if "grep-binary-heuristic" in [h for h, _ in matches(qop, limit=None)]:
|
|
319
|
+
problems.append(f"grep-binary-heuristic: fired although -a stands after a "
|
|
320
|
+
f"QUOTED pattern operand — blanking ate the token boundary "
|
|
321
|
+
f"({qop!r})")
|
|
322
|
+
if "grep-binary-heuristic" not in [h for h, _ in
|
|
323
|
+
matches('grep -e "needle" file', limit=None)]:
|
|
324
|
+
problems.append("grep-binary-heuristic: a quoted pattern operand with no "
|
|
325
|
+
"text-mode flag was read as exempt")
|
|
326
|
+
for bf in ("grep --binary-files=text needle payload",
|
|
327
|
+
"grep --binary-files text needle payload"):
|
|
328
|
+
if "grep-binary-heuristic" in [h for h, _ in matches(bf, limit=None)]:
|
|
329
|
+
problems.append(f"grep-binary-heuristic: fired although --binary-files "
|
|
330
|
+
f"selects text handling ({bf!r})")
|
|
331
|
+
if "grep-binary-heuristic" not in [h for h, _ in
|
|
332
|
+
matches("grep --binary-files without-match needle payload",
|
|
333
|
+
limit=None)]:
|
|
334
|
+
problems.append("grep-binary-heuristic: a non-text --binary-files TYPE was "
|
|
335
|
+
"read as text mode")
|
|
336
|
+
if "grep-binary-heuristic" in [h for h, _ in matches("(grep -a needle payload)", limit=None)]:
|
|
337
|
+
problems.append("grep-binary-heuristic: fired although the subshell-grouped "
|
|
338
|
+
"grep carries its own text-mode flag")
|
|
339
|
+
for envcmd in ("LC_ALL=C grep needle payload", "cat payload | LC_ALL=C grep needle"):
|
|
340
|
+
if "grep-binary-heuristic" not in [h for h, _ in matches(envcmd, limit=None)]:
|
|
341
|
+
problems.append(f"grep-binary-heuristic: an env-assignment prefix hid the "
|
|
342
|
+
f"command word ({envcmd!r})")
|
|
343
|
+
if "grep-binary-heuristic" not in [h for h, _ in
|
|
344
|
+
matches('echo "$(grep needle payload)" | grep -a foo', limit=None)]:
|
|
345
|
+
problems.append("grep-binary-heuristic: a grep inside a command substitution lost "
|
|
346
|
+
"its reminder to the outer stage's -a")
|
|
347
|
+
if "grep-binary-heuristic" in [h for h, _ in
|
|
348
|
+
matches('echo "$(grep -a needle payload)" | grep -a foo', limit=None)]:
|
|
349
|
+
problems.append("grep-binary-heuristic: fired although every invocation, nested "
|
|
350
|
+
"included, carries its own text-mode flag")
|
|
351
|
+
if "grep-binary-heuristic" not in [h for h, _ in matches("grep -a foo a & grep bar b", limit=None)]:
|
|
352
|
+
problems.append("grep-binary-heuristic: a background-joined second grep with no "
|
|
353
|
+
"text-mode flag lost its reminder to the first stage's -a")
|
|
354
|
+
if "grep-binary-heuristic" not in [h for h, _ in matches("grep -a foo a\ngrep bar b", limit=None)]:
|
|
355
|
+
problems.append("grep-binary-heuristic: a newline-joined second grep with no "
|
|
356
|
+
"text-mode flag lost its reminder to the first stage's -a")
|
|
357
|
+
if "grep-binary-heuristic" not in [h for h, _ in
|
|
358
|
+
matches('grep "foo \\" -a bar" payload', limit=None)]:
|
|
359
|
+
problems.append("grep-binary-heuristic: an escaped quote inside the pattern closed "
|
|
360
|
+
"the blanking early and the embedded -a read as a flag")
|
|
361
|
+
uncovered = [n for n, _rx, _m, _a in RULES if n not in FIXTURES]
|
|
362
|
+
if uncovered:
|
|
363
|
+
problems.append(f"rules with no fixture, so nothing proves they fire: {uncovered}")
|
|
364
|
+
for name, _rx, _msg, _anchor in RULES:
|
|
365
|
+
cmd = FIXTURES.get(name)
|
|
366
|
+
if cmd is None:
|
|
367
|
+
continue
|
|
368
|
+
if name not in [hit for hit, _ in matches(cmd, limit=None)]:
|
|
369
|
+
problems.append(f"{name}: its own fixture {cmd!r} does not reach it — the rule is inert")
|
|
370
|
+
|
|
371
|
+
# -- half 2: the Codex fallback. SURFACES.md admits a hook rule only with a guide
|
|
372
|
+
# counterpart, because the guide is what the other host receives.
|
|
373
|
+
for tree in ("claude", "codex"):
|
|
374
|
+
g = repo / tree / "guides" / "tooling-gotchas.md"
|
|
375
|
+
if not g.is_file():
|
|
376
|
+
problems.append(f"{tree}/guides/tooling-gotchas.md missing — no fallback to check")
|
|
377
|
+
continue
|
|
378
|
+
body = g.read_text(encoding="utf-8")
|
|
379
|
+
for name, _rx, _msg, anchor in RULES:
|
|
380
|
+
if anchor not in body:
|
|
381
|
+
problems.append(f"{name}: anchor {anchor!r} absent from {tree}/guides/tooling-gotchas.md")
|
|
382
|
+
|
|
383
|
+
for p in problems:
|
|
384
|
+
print(f"self-test [FAIL] {p}")
|
|
385
|
+
if problems:
|
|
386
|
+
print(f"HOOK SELF-TEST FAIL: {len(problems)} problem(s)")
|
|
387
|
+
return 1
|
|
388
|
+
print(f"HOOK SELF-TEST OK: {len(RULES)} rules each fire on their own fixture, stay quiet "
|
|
389
|
+
f"when they should, and each has its guide counterpart on both hosts")
|
|
390
|
+
return 0
|
|
391
|
+
|
|
392
|
+
|
|
85
393
|
if __name__ == "__main__":
|
|
394
|
+
if "--self-test" in sys.argv[1:]:
|
|
395
|
+
sys.exit(self_test())
|
|
86
396
|
sys.exit(main())
|
package/codex/AGENTS.md
CHANGED
|
@@ -52,57 +52,25 @@
|
|
|
52
52
|
|
|
53
53
|
## Concept Economy
|
|
54
54
|
|
|
55
|
-
-
|
|
56
|
-
- Treat lasting or shared names as concept candidates: features, entities, variables, types, helper modules, artifacts, config keys, CLI flags, MCP/tool fields, public response fields, artifact fields, enum values, failure kinds, retry/recovery tokens, process names, and documentation terms.
|
|
57
|
-
- Before adding or changing a concept, find the nearest existing concept and choose one path explicitly: reuse, extend, rename, or split.
|
|
58
|
-
- Prefer broad, stable concepts with precise properties over narrow near-duplicates.
|
|
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.
|
|
59
56
|
- Before fixing a review finding or test failure, classify the fix as reducing, preserving, or increasing the active concept surface.
|
|
60
|
-
- Split or promote a concept when it changes runtime behavior, ownership, lifecycle, validation, failure mode, user-visible behavior, audit/replay requirements, authority, persistence, user control, or failure handling.
|
|
61
|
-
- Keep derived values as properties or projections of their source concept when tools/code can derive them from the source authority.
|
|
62
|
-
- Keep internal projections and helper outputs internal unless public exposure is required for user behavior, product contract, or artifact truth.
|
|
63
|
-
- Distinguish authority from visibility: public responses may expose bounded views, while the source concept or artifact remains the truth location.
|
|
64
|
-
- Reuse existing enum values, failure kinds, retry/recovery tokens, and result/failure surfaces before introducing new vocabulary.
|
|
65
|
-
- Use fallback paths, compatibility shims, and deprecated alias normalization when explicit migration compatibility is required.
|
|
66
|
-
- Keep comments and active docs aligned with runtime behavior, failure semantics, retry policy, ownership, and authority.
|
|
67
|
-
- When a split is necessary, name the parent concept, explain the reason for the split, and map aliases or variants back to the canonical concept.
|
|
68
|
-
- In ontology work, check existing entities and relations first, then keep the concept graph compact.
|
|
69
|
-
- In code work, follow existing naming patterns and consolidate variations introduced by the current change.
|
|
70
|
-
- Let the repository's shape mirror its concept graph: keep each shared, lasting concept's canonical name traceable across the layers it appears in — path, module, type/interface, field, and public API — so the structure is navigable by name (grep-findable, path-guessable) without a translation table. This binds shared concepts only; transient locals, generic containers, and framework- or tooling-imposed layout may diverge.
|
|
71
57
|
|
|
72
58
|
## Coding Guidelines
|
|
73
59
|
|
|
74
60
|
- For `.xlsx` editing, generation, reconciliation, validation, or connected spreadsheet processing, use the installed `spreadsheet-processing` skill when present — with plain tools/code as the fallback — and validate formula-dependent Excel results with the real Microsoft Excel engine.
|
|
75
|
-
- For
|
|
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.
|
|
76
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.
|
|
77
|
-
- When the user asks to "설계" or design, read the coding-staged-workflow guide and focus on high-level design and implementation-process design; move to implementation only after the user asks to implement or approves the plan.
|
|
78
|
-
- Think before coding: state key assumptions and surface ambiguity early.
|
|
79
|
-
- Build the smallest viable functional path that satisfies the qualitative completion criteria. Minimum limits surface area, configuration, abstractions, optional scope, and implementation spread; it must not reduce required behavior, runtime authority, evidence quality, or verification depth.
|
|
80
|
-
- Treat viability as real behavior against real inputs, real authority, and the intended runtime path. Use mocks only for tests, fixtures, or explicitly requested simulations; mock-backed paths support verification but do not count as product completion.
|
|
81
|
-
- Make surgical changes. Touch only what the request requires, preserve existing style, and avoid casual adjacent refactors.
|
|
82
|
-
- Clean up issues introduced by the current change. Mention unrelated dead code separately.
|
|
83
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.
|
|
84
|
-
- Define success criteria before multi-step coding work, then verify against them.
|
|
85
|
-
- For bugs, prefer a reproducing test before the fix when practical.
|
|
86
|
-
- Every changed line should trace back to the user's request.
|
|
87
|
-
- Fix the root cause at its authority rather than the visible symptom: when downstream patches keep compensating for bad inputs, fix upstream at the source; when each fix only exposes another instance of the same defect, single-source the value and fix the whole class instead of patching instances.
|
|
88
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.
|
|
89
65
|
|
|
90
66
|
## Verification Discipline
|
|
91
67
|
|
|
92
68
|
- For composing a review request, packet, or reviewer role — the evidence bar, the verdict shape, and why a review returned noise, nothing, or a clean bill of health — read and use `${CODEX_HOME:-$HOME/.codex}/guides/review-request.md` as a scoped extension of this section.
|
|
93
69
|
- After every meaningful code, ontology, config, data, spreadsheet, or documentation change, run a verification loop regardless of commit or handoff status.
|
|
94
|
-
-
|
|
95
|
-
- Add the narrowest reliable runtime or semantic test that proves the changed behavior, meaning, or contract.
|
|
96
|
-
- Pick each domain's verification mix (code, ontology, config/data, spreadsheets, docs) from the Verification Menus in the coding-staged-workflow guide.
|
|
97
|
-
- Let the LLM derive scenarios from the diff, user impact, concept impact, and failure modes; let tools/code execute and verify them. Where an artifact already defines the case space — a config, a schema, a route table — enumerate the cases from it rather than from judgment, and record real output as the expectation instead of typing one: a hand-listed set of cases silently stops covering as the artifact grows past it.
|
|
98
|
-
- Keep E2E stable with deterministic data, resilient selectors, isolated external dependencies, and explicit waits.
|
|
70
|
+
- For choosing verification depth, the per-domain mix, the case space, what makes a completion criterion falsifiable, how to keep an E2E stable, or what a green result is worth, read and use `${CODEX_HOME:-$HOME/.codex}/guides/verification-discipline.md` as a scoped extension of this section — its Verification Menus carry the per-domain mixes.
|
|
99
71
|
- Report the checks run, results, and any unverified risk before calling the work done.
|
|
100
72
|
- Trust a green check only when it traversed the actual changed code through the real dispatch and real calls (not a mock, dry-run, or bypass), and remember that "it ran" is not "quality met" — a fallback, floor, or mock run is not done; treat a zero-findings verdict as suspect until you confirm the harness ran rather than silently crashed, and make PASS mean concrete assertions on real output from the real path.
|
|
101
|
-
- Make completion criteria falsifiable: prefer signals that fail when the mechanism is wrong (negative or contrast controls), and if no existing gate can judge a criterion, build the executable judge or do not claim the criterion met.
|
|
102
73
|
- Before comparing two of anything (cost, performance, quality, frequency), fix a common basis — units, denominators, population, measurement surface — compare on equivalent output, and exclude or flag non-representative data (promotions, outages, smoke slices).
|
|
103
|
-
- For non-trivial designs or high-risk changes, run independent adversarial review across distinct lenses, ideally on the design before implementation, and re-verify each finding against real code before acting on it. Apply the convergence heuristic by reviewer kind (detailed in the multi-model guide): same-kind convergence is high confidence but same-kind reviewers share blind spots — their shared "clean" is not verification; different-kind divergence is the expected signal — act on the union. Never accept an orchestrated workflow's self-reported all-green as sufficient; independently re-run the diff inspection and verification suite yourself.
|
|
104
|
-
- Proportion verification to cost, risk, and information gain: before expensive or slow live runs, diagnose in code and replay the changed deterministic logic over persisted real artifacts, probe at N=1 with inputs precondition-checked, and reserve full design-review-plus-live verification for first-of-kind or authority-changing work; proportion assurance to the deployment context — a single-user, own-data tool does not warrant production-grade assurance; prefer delivery.
|
|
105
|
-
- Trust a green / zero-findings verdict only if the check could have failed over a real, non-empty subject: assert the entity-under-test set has cardinality > 0 before any "no bad X" or "all X satisfy P" claim (an empty subject set passes vacuously and proves nothing), and for any test touching a branch you add or delete, confirm its inputs satisfy the live branch's entry guard — a copied fixture that fails the new guard silently routes into the about-to-be-deleted dead branch and stays green even after the real behavior breaks. When a check goes green unexpectedly fast or empty, dump what it actually ran over. Checker code itself must assert the expected shape and fail loud — a permissive fallback (`a || b`) inside a gate absorbs wrong assumptions and keeps passing.
|
|
106
74
|
|
|
107
75
|
## Tooling and Operational Safety
|
|
108
76
|
|
|
@@ -113,7 +81,6 @@
|
|
|
113
81
|
- Never accept secrets through transcript- or history-logged channels.
|
|
114
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).
|
|
115
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.
|
|
116
|
-
- Before reasoning about what a branch contains or opening a PR, run `git fetch` and compute the range as `origin/<base>..HEAD`, never `<base>..HEAD` against the local tracking ref — on a shared repo the local base drifts behind the remote until you pull, silently inflating the diff with already-merged work; if the range is surprisingly large, suspect a stale base before suspecting the branch. Platform "mergeable" flags are computed against the base only — sibling PRs can each look clean yet conflict; before picking a merge order, diff their changed-file sets and simulate the sequence.
|
|
117
84
|
|
|
118
85
|
## Multi-Model Workflow
|
|
119
86
|
|
|
@@ -131,11 +98,7 @@
|
|
|
131
98
|
## Documentation Hygiene
|
|
132
99
|
|
|
133
100
|
- Keep runtime code, active docs, and execution-facing docs focused on current behavior, current decisions, current contracts, current authority, and current failure handling.
|
|
134
|
-
-
|
|
135
|
-
- Put backward-compatibility notes, deprecated behavior, migration rationale, historical alternatives, change narratives, and handoff logs in isolated documentation paths such as `docs/`, `design/`, `archive/`, or `deprecated/`.
|
|
136
|
-
- Link from active docs or code to isolated notes only when the current task needs that history or the reference helps future maintainers.
|
|
137
|
-
- Phrase guidelines as desired behavior and preferred patterns.
|
|
138
|
-
- Prefer established docs such as `CHANGELOG.md`, `IMPLEMENTATION_MAP.html`, or handoff notes for change history and implementation context.
|
|
101
|
+
- For where a comment, a compatibility note, deprecated behavior, a rejected alternative, a migration rationale, a change narrative, or a handoff log belongs — how to phrase a rule others will follow, and whether active docs should link to history — read and use `${CODEX_HOME:-$HOME/.codex}/guides/documentation-hygiene.md` as a scoped extension of this section.
|
|
139
102
|
|
|
140
103
|
## Visual Explanations
|
|
141
104
|
|
|
@@ -57,7 +57,7 @@ Delegate execution, not decisions. A unit is delegable only when it is decision-
|
|
|
57
57
|
- Use a resident teammate only for dependent slices in one burst. Verify that the CLI preserves its model and context; resume-after-completion may silently change both. Retire after the burst or cache TTL, and persist durable knowledge in files.
|
|
58
58
|
- After a discard or direction change, respawn once a routine round costs about as much as a fresh slice. Recover unique in-flight state to files first.
|
|
59
59
|
- Redirects to busy workers may queue rather than preempt. Check artifacts before destructive redirects, phrase them conditionally, and stop an actively harmful worker by scoped PID/worktree authority.
|
|
60
|
-
- Idle/progress notifications are hypotheses; verify repo artifacts before re-dispatch. Cross-reset state belongs in files, not task boards or transcripts. When polling concurrent async jobs, pin the exact id/handle received at dispatch — a "latest" convenience selector can silently point at a sibling job and return plausible-but-wrong results.
|
|
60
|
+
- Idle/progress notifications are hypotheses; verify repo artifacts before re-dispatch. An idle signal is liveness decoupled from the report: a subagent can go idle without ever delivering its result, so idle-without-report is not done — request the report explicitly rather than waiting. Cross-reset state belongs in files, not task boards or transcripts. When polling concurrent async jobs, pin the exact id/handle received at dispatch — a "latest" convenience selector can silently point at a sibling job and return plausible-but-wrong results.
|
|
61
61
|
- Give reviewers/subagents a read-only diff, snapshot, or isolated worktree — not the live tree the main is editing — and forbid destructive git ops (checkout --, reset --hard, stash, clean) on any tree with uncommitted work; re-verify tree integrity before trusting results produced mid-edit.
|
|
62
62
|
- Review cost scales with the diff, so layered review preserves delegation savings. Lower reviewer tier before dropping a review kind.
|
|
63
63
|
|
|
@@ -127,9 +127,9 @@ How much independence a review actually bought, as an ordinal grade per reviewer
|
|
|
127
127
|
|
|
128
128
|
## Dual-Provider Design Drafts
|
|
129
129
|
|
|
130
|
-
- Trigger: the task is design
|
|
130
|
+
- Trigger: the task is design — high-level shape and implementation process, before any code — AND two or more providers are reachable at frontier tier. Reachability via an OAuth session is subscription-covered — no marginal spend, so no approval and no question: if a non-main-context OAuth frontier provider exists, proceed with the dual-provider design directly. The consent gate applies ONLY to a provider reachable solely via a metered API key: dispatching to it needs the user's explicit per-request approval of that spend (per-request, not standing — an old approval does not carry to the next design). If the only way to reach a second provider is un-approved metered API spend, stay single-provider rather than blocking the design.
|
|
131
131
|
- Mechanics: compose ONE blind packet (evidence, constraints, rubric, neutral alternatives — the escalation-gate packet shape) and dispatch it unchanged to one frontier-tier model per provider; drafts stay independent — neither sees the other's output. Then adjudicate: compare the two dual-provider frontier design drafts against the rubric, take the winner as the skeleton, graft the loser's superior parts, and record what differed and why the synthesis chose as it did (FRONTIER disposition line).
|
|
132
|
-
- Packet injection: a dispatched designer is hermetic — it reads only its packet and never loads this corpus. Inject the design principles the corpus would have supplied: concept economy (reuse/extend/rename/split, compact concept graph), the LLM/tools-code capability boundary, the staged
|
|
132
|
+
- Packet injection: a dispatched designer is hermetic — it reads only its packet and never loads this corpus. Inject the design principles the corpus would have supplied: concept economy (reuse/extend/rename/split, compact concept graph), the LLM/tools-code capability boundary, the staged design rules (smallest viable path, falsifiable done-when), and any domain-specific principles the design touches. A draft produced without the principles is not comparable to one produced with them.
|
|
133
133
|
|
|
134
134
|
## Unattended Batch Safety
|
|
135
135
|
|
|
@@ -173,7 +173,7 @@ Write for the next agent and re-verification, not narrative. Required content:
|
|
|
173
173
|
|
|
174
174
|
This is the human-readable projection of concrete models/tools; `launch/agent-launch.toml` is the machine launch authority and parity checks keep them aligned. Re-probe when the binding is older than ~8 weeks or a newer observable model/tool changes the surface. `agent-bios install` overwrites deployed bindings, so edit the repo copy.
|
|
175
175
|
|
|
176
|
-
Binding (2026-
|
|
176
|
+
Binding (2026-08-10):
|
|
177
177
|
|
|
178
178
|
| Slot | Binding | Notes |
|
|
179
179
|
|---|---|---|
|
|
@@ -181,13 +181,13 @@ Binding (2026-07-25):
|
|
|
181
181
|
| HELM | Claude Opus 5 (xhigh) · GPT-5.6 Sol (xhigh main; main Ultra requires explicit selection; bounded FRONTIER Ultra allowed) | standing main; Codex defaults bypass, explicit sandbox narrows |
|
|
182
182
|
| WORKHORSE | Claude Opus 5 (medium) · GPT-5.6 Terra (high) | implementation and per-item judgment |
|
|
183
183
|
| SWEEP | Claude Haiku 4.5 · GPT-5.6 Luna (low) | clear repeatable scans and mechanical work |
|
|
184
|
-
| VERIFIER-A |
|
|
185
|
-
| VERIFIER-B |
|
|
184
|
+
| VERIFIER-A | plain `codex exec` deep pass — GPT-5.6 Sol at ultra effort, packet on stdin (`-c service_tier="fast"` as explicit fast opt-in) | strongest single reader; cross-family from a Claude main |
|
|
185
|
+
| VERIFIER-B | Claude Code ultracode workflow (keyword-opened, many-agent) | code/execution kind; fan-out counterpart |
|
|
186
186
|
| INDEPENDENT-PR-REVIEWER | Codex CLI | adversarial `gh pr diff` review |
|
|
187
187
|
| Claude relocation | EnterWorktree, `/cd`, `--worktree`; resume is directory-scoped | verified 2.1.207 |
|
|
188
188
|
| Codex relocation | `codex resume` (cwd-filtered; `--all` lifts), fork | verified 0.144.1 |
|
|
189
189
|
| Claude teammate | named mailbox continuation; completed-agent message may cold-rerun on main model | keep resident; avoid completed resume |
|
|
190
|
-
| Rate-limit fallback | OpenAI limited → VERIFIER-
|
|
190
|
+
| Rate-limit fallback | OpenAI limited → VERIFIER-B (Anthropic workflow); Claude limited → VERIFIER-A (Codex exec) | record family collapse |
|
|
191
191
|
|
|
192
192
|
Codex direct-drive (verified 0.144.1, 2026-07-12):
|
|
193
193
|
|