agent-bios 0.9.8 → 0.9.9
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 +19 -19
- package/README.md +34 -11
- package/claude/CLAUDE.md +2 -1
- package/claude/guides/claude-prompting.md +1 -1
- package/claude/guides/cli-multi-model-workflow.md +19 -1
- package/claude/guides/coding-staged-workflow.md +32 -0
- package/claude/guides/gpt-prompting.md +1 -1
- package/claude/guides/learning-flow.md +5 -5
- package/claude/guides/llm-capability-boundary.md +6 -1
- package/claude/guides/session-distill-workflow.md +19 -9
- package/claude/guides/tooling-gotchas.md +16 -0
- package/claude/hooks/__pycache__/tooling-gotchas-hook.cpython-314.pyc +0 -0
- package/claude/hooks/tooling-gotchas-hook.py +7 -0
- package/codex/AGENTS.md +2 -1
- package/codex/guides/claude-prompting.md +1 -1
- package/codex/guides/cli-multi-model-workflow.md +19 -1
- package/codex/guides/coding-staged-workflow.md +32 -0
- package/codex/guides/gpt-prompting.md +1 -1
- package/codex/guides/learning-flow.md +5 -5
- package/codex/guides/llm-capability-boundary.md +6 -1
- package/codex/guides/session-distill-workflow.md +19 -9
- package/codex/guides/tooling-gotchas.md +16 -0
- package/{scripts → compose}/assemble.py +184 -16
- package/{scripts → compose}/canary.sh +14 -5
- package/{scripts → compose}/check-domains.py +9 -3
- package/{config → compose}/domains.json +1 -0
- package/{scripts → compose}/pkgid.py +8 -1
- package/compose/prune-backups.py +204 -0
- package/{scripts → compose}/register-hooks.py +3 -3
- package/{scripts/install.sh → install.sh} +401 -104
- package/launch/agent-launch.py +5294 -0
- package/launch/agent-launch.toml +376 -0
- package/{scripts → launch}/check-prompting-targets.sh +1 -1
- package/{scripts → launch}/provision-venv.sh +1 -1
- package/{scripts → learn}/check-learning.py +7 -7
- package/{scripts → learn}/collect-learning.py +10 -10
- package/{config → learn}/learning.schema.json +3 -3
- package/{scripts → learn}/migrate-learnings.py +95 -54
- package/{scripts → learn}/redact.py +4 -4
- package/package.json +25 -24
- package/wrappers/claude-run.sh +162 -0
- package/{scripts → wrappers}/codex-run.sh +62 -6
- package/config/agent-launch.toml +0 -143
- package/scripts/agent-launch.py +0 -2350
- package/scripts/check-parity.sh +0 -2003
- /package/{shell → launch}/agent-launch.zsh +0 -0
- /package/{config → learn}/promotions.json +0 -0
- /package/{scripts/session-cost.py → session-cost.py} +0 -0
- /package/{scripts → wrappers}/codex-helm.sh +0 -0
|
@@ -0,0 +1,376 @@
|
|
|
1
|
+
schema_version = 1
|
|
2
|
+
|
|
3
|
+
[backends.codex]
|
|
4
|
+
command = "codex"
|
|
5
|
+
passthrough_args = []
|
|
6
|
+
|
|
7
|
+
[backends.claude]
|
|
8
|
+
command = "claude"
|
|
9
|
+
passthrough_args = ["--dangerously-skip-permissions"]
|
|
10
|
+
|
|
11
|
+
# Optional dependencies. `command` gates the route: unresolvable means the route
|
|
12
|
+
# is unavailable and the review setup degrades without it. `install` is the single
|
|
13
|
+
# source for both the one-line hint shown when it is missing and what
|
|
14
|
+
# `agent-bios install --with <name>` runs.
|
|
15
|
+
[capabilities.onto]
|
|
16
|
+
command = "onto"
|
|
17
|
+
install = "npm i -g onto-mcp"
|
|
18
|
+
# How this tool exposes an operation. The adapter is a protocol codec owned by core,
|
|
19
|
+
# never a method identity, so a second method reusing the tag is data-only.
|
|
20
|
+
# `evidence` names what this tool reports back about the dispatch it performed, and a
|
|
21
|
+
# receipt missing any of it is not credited. These three are what onto's override already
|
|
22
|
+
# returns on its warning channel. They are here because of a measured incident, not a
|
|
23
|
+
# guess: an override that reached no seat resolved to a default provider with a null model
|
|
24
|
+
# and did NOT fail, so a reporter with nothing to check would have called it a success.
|
|
25
|
+
offers = [{ operation = "structured-review", adapter = "mcp-stdio-v1", hosts = ["codex", "claude"], evidence = ["reached_seat", "billing_mode", "auth_defaulted"] }]
|
|
26
|
+
|
|
27
|
+
# ── dynamic workflow, one concept and two host-bound tools ─────────────────
|
|
28
|
+
# `ultracode` runs ON CLAUDE and `ultracode-for-codex` runs ON CODEX — the names say which,
|
|
29
|
+
# and getting them the wrong way round is the mistake to avoid: the package name is
|
|
30
|
+
# "ultracode, ported for codex", not "the codex one is the real one".
|
|
31
|
+
#
|
|
32
|
+
# What they are FOR, which is what a reader choosing between reviewers actually needs:
|
|
33
|
+
# both drive a dynamic workflow, used here as a flexible many-perspective check on an
|
|
34
|
+
# IMPLEMENTATION — does it function, does it survive an adversary, does the logic hold,
|
|
35
|
+
# does it hold under a real scenario, does it hold under stress. That makes them
|
|
36
|
+
# COMPLEMENTARY to onto rather than competing with it: onto looks hardest at whether
|
|
37
|
+
# authority, gates and harness are consistent with each other. The two are independently
|
|
38
|
+
# selectable, and both single-sided choices are legitimate — a thing whose whole point is
|
|
39
|
+
# that it WORKS can be reviewed by the workflow alone, and a logic-bearing document,
|
|
40
|
+
# ontology, harness or gate can be reviewed by onto alone.
|
|
41
|
+
|
|
42
|
+
[capabilities.ultracode]
|
|
43
|
+
# Not a separate tool: the Claude Code CLI's own dynamic workflow, opened by putting the
|
|
44
|
+
# keyword in the prompt (read in the installed 2.1.220 bundle —
|
|
45
|
+
# `workflowKeywordTriggerEnabled`: "including the keyword in a prompt opts that turn into
|
|
46
|
+
# the Workflow tool", default true). So the command IS the claude backend, and there is
|
|
47
|
+
# nothing extra to install.
|
|
48
|
+
# `${backend}` and not the literal token: this tool IS the configured claude CLI, so a
|
|
49
|
+
# duplicated default broke it for anyone whose backend is a wrapper or an absolute path —
|
|
50
|
+
# dispatch worked, the reviewer reported NOT INSTALLED, and the review went on without it.
|
|
51
|
+
# No `install`: that field is EXECUTED by `agent-bios install --with`, so prose there would
|
|
52
|
+
# be run as a shell command, and a missing claude CLI is a missing host, not a missing
|
|
53
|
+
# reviewer.
|
|
54
|
+
command = "${backend}"
|
|
55
|
+
# claude only: the keyword trigger is a Claude Code feature, so a codex seat cannot run it.
|
|
56
|
+
offers = [{ operation = "workflow-review", adapter = "host-workflow-v1", hosts = ["claude"] }]
|
|
57
|
+
|
|
58
|
+
[capabilities.ultracode-for-codex]
|
|
59
|
+
command = "ultracode-for-codex"
|
|
60
|
+
install = "npm i -g ultracode-for-codex"
|
|
61
|
+
# codex only, and this is the tool's nature rather than a policy: it drives the Codex
|
|
62
|
+
# app-server and takes its model catalog from there, so a reviewer seated on the
|
|
63
|
+
# claude host is a seat it cannot fill. Declaring both hosts made a codex-main launch
|
|
64
|
+
# emit "run ultracode-for-codex on claude-fable-5", which cannot work.
|
|
65
|
+
#
|
|
66
|
+
# Between the two, this review is available CROSS-FAMILY from either main — which the
|
|
67
|
+
# codex arm previously had no way to express, and so silently went without.
|
|
68
|
+
offers = [{ operation = "workflow-review", adapter = "host-workflow-v1", hosts = ["codex"] }]
|
|
69
|
+
|
|
70
|
+
# ── review methods (DESIGN.md §1) ───────────────────────────────────────────
|
|
71
|
+
# Data only. Adding a method here — including one this repo has never seen — must
|
|
72
|
+
# need no code change; gates/check_parity.py proves that with a runtime-named canary.
|
|
73
|
+
# `instructions` may use only the core slot vocabulary: command, model, effort,
|
|
74
|
+
# provider, host, service_tier, perspectives, trials, severities. An unknown slot is
|
|
75
|
+
# rejected at load, so this list going stale is an over-restriction with a real cost — a
|
|
76
|
+
# reviewer that needs one of them cannot be authored from what the config says. The
|
|
77
|
+
# launcher's own rejection message enumerates INSTRUCTION_SLOTS, which is the list to
|
|
78
|
+
# trust if the two ever differ.
|
|
79
|
+
|
|
80
|
+
[review_methods.panel]
|
|
81
|
+
label = "Isolated panel"
|
|
82
|
+
description = "The always-present base: an isolated multi-perspective panel, no install required."
|
|
83
|
+
instructions = "dispatch {command} as a fresh read-only process for {trials} isolated passes over the perspectives {perspectives}, each pinned to {model}/{effort}, and aggregate"
|
|
84
|
+
output = "review-v1"
|
|
85
|
+
perspectives = ["correctness", "security", "reproduction"]
|
|
86
|
+
trials = 3
|
|
87
|
+
order = "randomized"
|
|
88
|
+
swap_augmentation = true
|
|
89
|
+
aggregation = "majority"
|
|
90
|
+
# Our own subagents report on the canonical ladder itself. Stated rather than left
|
|
91
|
+
# implicit, because an identity map is exactly what a wrongly copied one looks like.
|
|
92
|
+
severity_emits = ["blocker", "high", "medium", "low", "info"]
|
|
93
|
+
severity_map = { blocker = "blocker", high = "high", medium = "medium", low = "low", info = "info" }
|
|
94
|
+
|
|
95
|
+
[review_methods.onto]
|
|
96
|
+
label = "onto structured lens review"
|
|
97
|
+
description = "Audits any target — code, a design doc, a whole repo — against the intent you state, looking hardest at whether authority, gates and harness are consistent with one another; complementary to the ultracode workflows rather than an alternative, and enough on its own for a logic-bearing document, ontology, harness or gate. Six lenses, cited issues, dissent kept as an artifact. Needs no diff. Returns a handle, not a result: poll 10+ min, and read record_status before believing a clean report."
|
|
98
|
+
capability = "onto"
|
|
99
|
+
operation = "structured-review"
|
|
100
|
+
# `effort` is sent and `auth` is deliberately NOT. onto's per-call override REPLACES
|
|
101
|
+
# a seat whose route differs, so what it omits is dropped rather than inherited —
|
|
102
|
+
# which is why effort must be stated: this binding IS the reviewer's pinned rigour.
|
|
103
|
+
# auth is the opposite case. onto selects the metered route only when a seat says so in
|
|
104
|
+
# writing — `auth = "api_key"` or an `api_key_env` naming the variable to call — and
|
|
105
|
+
# defaults to the subscription worker otherwise, so an omitted auth cannot land on
|
|
106
|
+
# metered and stating one buys nothing. It does cost something: switching a seat to
|
|
107
|
+
# oauth is a route change, so a user who deliberately chose metered loses both their
|
|
108
|
+
# auth and the api_key_env that carried it. Omitting it lets onto's default protect the
|
|
109
|
+
# unconfigured seat and its overlay preserve the configured one.
|
|
110
|
+
instructions = 'call onto_review/onto_prepare_review with llmOverride={{"provider":"{provider}","model":"{model}","effort":"{effort}"}} so onto runs on {provider} at {effort}'
|
|
111
|
+
output = "review-v1"
|
|
112
|
+
perspectives = ["axiology", "coverage", "evolution", "logic", "semantics", "structure"]
|
|
113
|
+
trials = 1
|
|
114
|
+
order = "fixed"
|
|
115
|
+
swap_augmentation = false
|
|
116
|
+
aggregation = "union"
|
|
117
|
+
# onto's own REVIEW_SEVERITY_ORDER is this same ladder — read in its source, not
|
|
118
|
+
# assumed. Identity is correct here for a different reason than the panel below.
|
|
119
|
+
severity_emits = ["blocker", "high", "medium", "low", "info"]
|
|
120
|
+
severity_map = { blocker = "blocker", high = "high", medium = "medium", low = "low", info = "info" }
|
|
121
|
+
|
|
122
|
+
[review_methods.ultracode-for-codex]
|
|
123
|
+
label = "Ultracode workflow review (Codex)"
|
|
124
|
+
# Named for the tool, not for the legacy layer. The legacy route token `ultracode` used to
|
|
125
|
+
# BE this capability's key, so naming the Claude tool `ultracode` silently repointed the
|
|
126
|
+
# legacy route at it — the golden caught that, and the fix was to bind the legacy token to
|
|
127
|
+
# a capability explicitly (`LEGACY_ULTRACODE_CAPABILITY`) rather than let a setup name and
|
|
128
|
+
# a tool id be the same string.
|
|
129
|
+
description = "The same dynamic workflow, ported to Codex — same use: things that have to WORK, checked from many angles rather than one. Fans dozens of Codex agents over your UNCOMMITTED working-tree changes for file:line defects, each candidate verified by its own agent. Its built-in code-review fails before spawning anything when the tree holds no reviewable change — clean, or only types it excludes such as .java, Dockerfile or dist/. Passing that gate is not the same as your files being reviewed. Detached: launching exits 0 even when the run dies."
|
|
130
|
+
capability = "ultracode-for-codex"
|
|
131
|
+
operation = "workflow-review"
|
|
132
|
+
instructions = "run {command} against a self-contained review packet on {model}/{effort}"
|
|
133
|
+
output = "review-v1"
|
|
134
|
+
perspectives = ["orchestration"]
|
|
135
|
+
trials = 1
|
|
136
|
+
order = "fixed"
|
|
137
|
+
swap_augmentation = false
|
|
138
|
+
aggregation = "union"
|
|
139
|
+
# P0..P3 plus a null severity, taken from the tool's own result contract. The mapping
|
|
140
|
+
# is the owner's call: the tool documents the vocabulary but not what each level
|
|
141
|
+
# means, so it cannot be derived. "null" keys a finding the tool reports with none.
|
|
142
|
+
severity_emits = ["P0", "P1", "P2", "P3", "null"]
|
|
143
|
+
severity_map = { P0 = "blocker", P1 = "high", P2 = "medium", P3 = "low", null = "info" }
|
|
144
|
+
|
|
145
|
+
[review_methods.ultracode]
|
|
146
|
+
label = "Ultracode workflow review (Claude)"
|
|
147
|
+
description = "Claude Code's own dynamic workflow, on Claude. Decomposes the request across many agents and adversarially verifies each candidate finding before it survives. Use it on things that have to WORK — functional, adversarial, logic, scenario and stress passes — where onto is the one to reach for when the question is whether authority, gates and harness agree. Reviews whatever packet you hand it, so it needs no working-tree state. The keyword in the prompt is what opens the workflow: without it the turn is an ordinary session that will answer, plausibly, alone. PRECONDITION this launcher cannot establish: the keyword trigger must be enabled (`workflowKeywordTriggerEnabled`, default true, verified in claude 2.1.220). A resolvable claude CLI proves the command exists, not that the workflow opens — with that setting off the review runs as an ordinary session and would report as though it were orchestrated."
|
|
148
|
+
capability = "ultracode"
|
|
149
|
+
operation = "workflow-review"
|
|
150
|
+
# The keyword is the whole mechanism, so it is stated as a literal rather than left to the
|
|
151
|
+
# dispatcher's memory. The severity ladder is stated too, and that is what makes the
|
|
152
|
+
# identity map below TRUE rather than copied: this reviewer has no vocabulary of its own —
|
|
153
|
+
# it reports on the ladder because the request tells it to. A gate asserts the instruction
|
|
154
|
+
# still names every value the descriptor claims, so the two cannot drift apart.
|
|
155
|
+
instructions = "dispatch {command} as a fresh read-only process whose prompt carries the keyword ultracode, so the turn runs as an orchestrated workflow over a self-contained review packet on {model}/{effort} (confirm the workflow actually opened — a disabled keyword trigger yields an ordinary session), and require every finding to carry one of {severities}"
|
|
156
|
+
output = "review-v1"
|
|
157
|
+
perspectives = ["orchestration"]
|
|
158
|
+
trials = 1
|
|
159
|
+
order = "fixed"
|
|
160
|
+
swap_augmentation = false
|
|
161
|
+
aggregation = "union"
|
|
162
|
+
severity_emits = ["blocker", "high", "medium", "low", "info"]
|
|
163
|
+
severity_map = { blocker = "blocker", high = "high", medium = "medium", low = "low", info = "info" }
|
|
164
|
+
|
|
165
|
+
[hosts.codex]
|
|
166
|
+
# The model family this host speaks for. A review binding names a provider, and
|
|
167
|
+
# the reverse map must be unique so it resolves to exactly one validatable seat.
|
|
168
|
+
provider = "openai"
|
|
169
|
+
models = ["gpt-5.6-sol", "gpt-5.6-terra", "gpt-5.6-luna"]
|
|
170
|
+
# onto review seat used when a CROSS-family main (Claude) routes onto review to
|
|
171
|
+
# this (gpt/codex) family; must be an onto review-role registered (provider, model).
|
|
172
|
+
onto_review = { provider = "openai", model = "gpt-5.6-sol" }
|
|
173
|
+
|
|
174
|
+
[hosts.codex.tiers.frontier]
|
|
175
|
+
model = "gpt-5.6-sol"
|
|
176
|
+
effort = "max"
|
|
177
|
+
|
|
178
|
+
[hosts.codex.tiers.helm]
|
|
179
|
+
model = "gpt-5.6-sol"
|
|
180
|
+
effort = "xhigh"
|
|
181
|
+
|
|
182
|
+
[hosts.codex.tiers.workhorse]
|
|
183
|
+
model = "gpt-5.6-terra"
|
|
184
|
+
effort = "high"
|
|
185
|
+
|
|
186
|
+
[hosts.codex.tiers.sweep]
|
|
187
|
+
model = "gpt-5.6-luna"
|
|
188
|
+
effort = "low"
|
|
189
|
+
|
|
190
|
+
[hosts.codex.agent_templates]
|
|
191
|
+
frontier = "${CODEX_HOME}/agents/frontier.toml"
|
|
192
|
+
workhorse = "${CODEX_HOME}/agents/workhorse.toml"
|
|
193
|
+
sweep = "${CODEX_HOME}/agents/sweep.toml"
|
|
194
|
+
|
|
195
|
+
# Model id -> the name the human-readable guides write. The guides' Environment Binding tables
|
|
196
|
+
# restate these bindings in prose that also carries policy the profile does not hold ("main Ultra
|
|
197
|
+
# requires explicit selection"), so those tables are not generatable — but the MODEL IDENTITY in
|
|
198
|
+
# them is this file's, and until this map existed the parity gate compared each table to display
|
|
199
|
+
# names written inside the gate. That made the gate a third author of the binding. With the map
|
|
200
|
+
# here, the gate compares two real surfaces and holds no copy of its own.
|
|
201
|
+
[model_display]
|
|
202
|
+
"claude-fable-5" = "Claude Fable 5"
|
|
203
|
+
"claude-opus-5" = "Claude Opus 5"
|
|
204
|
+
"claude-haiku-4-5" = "Claude Haiku 4.5"
|
|
205
|
+
"gpt-5.6-sol" = "GPT-5.6 Sol"
|
|
206
|
+
"gpt-5.6-terra" = "GPT-5.6 Terra"
|
|
207
|
+
"gpt-5.6-luna" = "GPT-5.6 Luna"
|
|
208
|
+
|
|
209
|
+
[hosts.claude]
|
|
210
|
+
provider = "anthropic"
|
|
211
|
+
models = ["claude-fable-5", "claude-opus-5", "claude-sonnet-5", "claude-haiku-4-5"]
|
|
212
|
+
# onto review seat used when a CROSS-family main (Codex) routes onto review to
|
|
213
|
+
# this (anthropic/claude) family; must be an onto review-role registered (provider, model).
|
|
214
|
+
onto_review = { provider = "anthropic", model = "claude-fable-5" }
|
|
215
|
+
|
|
216
|
+
[hosts.claude.tiers.frontier]
|
|
217
|
+
model = "claude-fable-5"
|
|
218
|
+
effort = "max"
|
|
219
|
+
|
|
220
|
+
[hosts.claude.tiers.helm]
|
|
221
|
+
model = "claude-opus-5"
|
|
222
|
+
effort = "xhigh"
|
|
223
|
+
|
|
224
|
+
[hosts.claude.tiers.workhorse]
|
|
225
|
+
model = "claude-opus-5"
|
|
226
|
+
effort = "medium"
|
|
227
|
+
|
|
228
|
+
[hosts.claude.tiers.sweep]
|
|
229
|
+
model = "claude-haiku-4-5"
|
|
230
|
+
effort = "low"
|
|
231
|
+
|
|
232
|
+
[presets.balanced]
|
|
233
|
+
label = "Balanced"
|
|
234
|
+
description = "HELM default for everyday work with native multi-perspective review."
|
|
235
|
+
mode = "builder"
|
|
236
|
+
main_tier = "helm"
|
|
237
|
+
frontier_effort = "max"
|
|
238
|
+
delegation = true
|
|
239
|
+
codex_execution_policy = "bypass"
|
|
240
|
+
claude_permission_mode = "bypassPermissions"
|
|
241
|
+
|
|
242
|
+
[presets.deep-review]
|
|
243
|
+
label = "Deep review"
|
|
244
|
+
description = "HELM with hybrid onto, native, and Ultracode review at deep FRONTIER effort."
|
|
245
|
+
mode = "builder"
|
|
246
|
+
main_tier = "helm"
|
|
247
|
+
frontier_effort = { codex = "ultra", claude = "max" }
|
|
248
|
+
delegation = true
|
|
249
|
+
codex_execution_policy = "bypass"
|
|
250
|
+
claude_permission_mode = "bypassPermissions"
|
|
251
|
+
|
|
252
|
+
[presets.fast-batch]
|
|
253
|
+
label = "Fast batch"
|
|
254
|
+
description = "WORKHORSE default for high-volume, cost-conscious execution."
|
|
255
|
+
mode = "builder"
|
|
256
|
+
main_tier = "workhorse"
|
|
257
|
+
frontier_effort = "max"
|
|
258
|
+
delegation = true
|
|
259
|
+
codex_execution_policy = "bypass"
|
|
260
|
+
claude_permission_mode = "bypassPermissions"
|
|
261
|
+
|
|
262
|
+
[presets.solo]
|
|
263
|
+
label = "Solo"
|
|
264
|
+
description = "Single-model session: delegation off (no tier fan-out; the standing spawn policy is lifted), review via the host's own command only."
|
|
265
|
+
mode = "builder"
|
|
266
|
+
main_tier = "helm"
|
|
267
|
+
frontier_effort = "max"
|
|
268
|
+
review_setup = "none"
|
|
269
|
+
delegation = false
|
|
270
|
+
codex_execution_policy = "bypass"
|
|
271
|
+
claude_permission_mode = "bypassPermissions"
|
|
272
|
+
|
|
273
|
+
[presets.vanilla]
|
|
274
|
+
label = "Vanilla"
|
|
275
|
+
description = "Plain CLI session: no launch contract, no tier bindings, standard permissions — exactly what the bare backend gives you."
|
|
276
|
+
mode = "software-engineer"
|
|
277
|
+
main_tier = "helm"
|
|
278
|
+
frontier_effort = "max"
|
|
279
|
+
review_setup = "none"
|
|
280
|
+
delegation = false
|
|
281
|
+
codex_execution_policy = "standard"
|
|
282
|
+
claude_permission_mode = "standard"
|
|
283
|
+
|
|
284
|
+
[presets.session-distill]
|
|
285
|
+
# Author-only: the workflow edits the agent-bios corpus and needs a checkout, so
|
|
286
|
+
# its mission names repo paths a packaged user does not have. Declaring it lets
|
|
287
|
+
# gates/check-package.sh judge the mission text. NOTE: this declaration is read by
|
|
288
|
+
# the gate, not yet by the launcher — the preset is still offered on a packaged
|
|
289
|
+
# install. Closing that route belongs with the package-based distill work.
|
|
290
|
+
audience = "author"
|
|
291
|
+
label = "Session distill"
|
|
292
|
+
description = "Dedicated session-distill run: mine recent sessions, verify, place, and apply per the session-distill workflow. Requires an agent-bios checkout."
|
|
293
|
+
mode = "distill"
|
|
294
|
+
main_tier = "helm"
|
|
295
|
+
frontier_effort = "max"
|
|
296
|
+
delegation = true
|
|
297
|
+
codex_execution_policy = "bypass"
|
|
298
|
+
claude_permission_mode = "bypassPermissions"
|
|
299
|
+
mission = "This is a session-distill initiative session, gated on a trigger. When the user enters the trigger command '{trigger}': read claude/guides/session-distill-workflow.md in the agent-bios checkout, then the initiative state in design/session-distill/ledger.json in that same checkout, and run the next mining window per that guide. Until the trigger arrives, respond normally and do not start the workflow. Every promotion passes through explicit user approval; nothing is applied to the corpus without it."
|
|
300
|
+
trigger = "distill!"
|
|
301
|
+
|
|
302
|
+
|
|
303
|
+
# ── review, per host (DESIGN.md Corrections C7) ─────────────────────────────
|
|
304
|
+
# A binding names a provider, which maps to one host, so cross-family review has to
|
|
305
|
+
# be stated per launch host. Both answers live here rather than being inferred, and
|
|
306
|
+
# the reviewer's tier now tracks the preset's intent instead of exposing the whole
|
|
307
|
+
# opposite tier table for the reader to pick from.
|
|
308
|
+
|
|
309
|
+
[presets.balanced.review.hosts.claude.base]
|
|
310
|
+
provider = "openai"
|
|
311
|
+
tier = "helm"
|
|
312
|
+
|
|
313
|
+
[presets.balanced.review.hosts.codex.base]
|
|
314
|
+
provider = "anthropic"
|
|
315
|
+
tier = "helm"
|
|
316
|
+
|
|
317
|
+
[presets.deep-review.review.hosts.claude.base]
|
|
318
|
+
provider = "openai"
|
|
319
|
+
tier = "frontier"
|
|
320
|
+
|
|
321
|
+
[presets.deep-review.review.hosts.claude.methods."onto"]
|
|
322
|
+
provider = "openai"
|
|
323
|
+
tier = "frontier"
|
|
324
|
+
|
|
325
|
+
[presets.deep-review.review.hosts.claude.methods."ultracode-for-codex"]
|
|
326
|
+
provider = "openai"
|
|
327
|
+
tier = "frontier"
|
|
328
|
+
|
|
329
|
+
[presets.deep-review.review.hosts.codex.base]
|
|
330
|
+
provider = "anthropic"
|
|
331
|
+
tier = "frontier"
|
|
332
|
+
|
|
333
|
+
[presets.deep-review.review.hosts.codex.methods."onto"]
|
|
334
|
+
provider = "anthropic"
|
|
335
|
+
tier = "frontier"
|
|
336
|
+
|
|
337
|
+
[presets.deep-review.review.hosts.codex.methods."ultracode"]
|
|
338
|
+
provider = "anthropic"
|
|
339
|
+
tier = "frontier"
|
|
340
|
+
|
|
341
|
+
[presets.fast-batch.review.hosts.claude.base]
|
|
342
|
+
provider = "openai"
|
|
343
|
+
tier = "workhorse"
|
|
344
|
+
|
|
345
|
+
[presets.fast-batch.review.hosts.codex.base]
|
|
346
|
+
provider = "anthropic"
|
|
347
|
+
tier = "workhorse"
|
|
348
|
+
|
|
349
|
+
[presets.session-distill.review.hosts.claude.base]
|
|
350
|
+
provider = "openai"
|
|
351
|
+
tier = "frontier"
|
|
352
|
+
|
|
353
|
+
[presets.session-distill.review.hosts.claude.methods."onto"]
|
|
354
|
+
provider = "openai"
|
|
355
|
+
tier = "frontier"
|
|
356
|
+
|
|
357
|
+
[presets.session-distill.review.hosts.claude.methods."ultracode-for-codex"]
|
|
358
|
+
provider = "openai"
|
|
359
|
+
tier = "frontier"
|
|
360
|
+
|
|
361
|
+
[presets.session-distill.review.hosts.codex.base]
|
|
362
|
+
provider = "anthropic"
|
|
363
|
+
tier = "frontier"
|
|
364
|
+
|
|
365
|
+
[presets.session-distill.review.hosts.codex.methods."onto"]
|
|
366
|
+
provider = "anthropic"
|
|
367
|
+
tier = "frontier"
|
|
368
|
+
|
|
369
|
+
[presets.session-distill.review.hosts.codex.methods."ultracode"]
|
|
370
|
+
provider = "anthropic"
|
|
371
|
+
tier = "frontier"
|
|
372
|
+
|
|
373
|
+
# Nudge baseline lives in ~/.local/share/agent-bios/session-distill-state.json,
|
|
374
|
+
# written by session-distill/update-state.py at window close.
|
|
375
|
+
[session_distill]
|
|
376
|
+
nudge_after = 250
|
|
@@ -11,7 +11,7 @@ cd "$(dirname "$0")/.." || exit 2
|
|
|
11
11
|
python3 - "$@" <<'PY'
|
|
12
12
|
import pathlib, re, sys, tomllib
|
|
13
13
|
|
|
14
|
-
config = pathlib.Path("
|
|
14
|
+
config = pathlib.Path("launch/agent-launch.toml")
|
|
15
15
|
hosts = tomllib.loads(config.read_text())["hosts"]
|
|
16
16
|
|
|
17
17
|
# host -> the guide that owns prompting guidance for that host's model family
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env bash
|
|
2
2
|
# Provision the managed virtualenv that backs the agent-launch Textual preflight.
|
|
3
3
|
#
|
|
4
|
-
# The interactive launcher re-execs into this venv (
|
|
4
|
+
# The interactive launcher re-execs into this venv (launch/agent-launch.py ->
|
|
5
5
|
# maybe_reexec_into_venv). It is an enhancement, not a hard dependency: when the
|
|
6
6
|
# venv is missing or broken, the launcher falls back to numbered prompts, and
|
|
7
7
|
# every direct / non-TTY / --no-tui path keeps running under the system
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
#!/usr/bin/env python3
|
|
2
2
|
"""Learning record gate + validator (collection loop, Phase 0).
|
|
3
3
|
|
|
4
|
-
|
|
4
|
+
learn/learning.schema.json is the SSOT for the learning record
|
|
5
5
|
(design/collection-loop/DESIGN.md); the dashboard mirrors only minimal
|
|
6
6
|
validation. Full client-side validity = JSON Schema conformance PLUS domain
|
|
7
|
-
membership in
|
|
7
|
+
membership in compose/domains.json domains ∪ 'unclassified' — membership is
|
|
8
8
|
checked here, not frozen in the schema, so vocabulary evolution never needs
|
|
9
9
|
a schema_version bump.
|
|
10
10
|
|
|
@@ -35,8 +35,8 @@ except ImportError:
|
|
|
35
35
|
"(pip install jsonschema; verified 4.26.0 in DEPENDENCIES.md)")
|
|
36
36
|
|
|
37
37
|
REPO = pathlib.Path(__file__).resolve().parent.parent
|
|
38
|
-
SCHEMA = REPO / "
|
|
39
|
-
DOMAINS = REPO / "
|
|
38
|
+
SCHEMA = REPO / "learn" / "learning.schema.json"
|
|
39
|
+
DOMAINS = REPO / "compose" / "domains.json"
|
|
40
40
|
FIXTURES = REPO / "design" / "collection-loop" / "fixtures"
|
|
41
41
|
|
|
42
42
|
# broken fixture -> field its single defect lives in; the reported errors
|
|
@@ -60,7 +60,7 @@ def load_json(path):
|
|
|
60
60
|
|
|
61
61
|
|
|
62
62
|
def valid_domain_values(path=DOMAINS):
|
|
63
|
-
"""The set a record's `domain` may take, drawn from
|
|
63
|
+
"""The set a record's `domain` may take, drawn from compose/domains.json.
|
|
64
64
|
|
|
65
65
|
Ledger-compatible (design/session-distill/ledger.json): the ledger's
|
|
66
66
|
`domain` field uses BOTH domain keys (builder-base, …) for
|
|
@@ -73,7 +73,7 @@ def valid_domain_values(path=DOMAINS):
|
|
|
73
73
|
manifest = load_json(path)
|
|
74
74
|
values = set(manifest["domains"]) | set(manifest["tiers"]) | {"unclassified"}
|
|
75
75
|
if len(values) <= 1:
|
|
76
|
-
sys.exit("FAIL:
|
|
76
|
+
sys.exit("FAIL: compose/domains.json registers no domains/tiers (vacuous gate)")
|
|
77
77
|
return values
|
|
78
78
|
|
|
79
79
|
|
|
@@ -88,7 +88,7 @@ def validate_record(record, validator, domain_values):
|
|
|
88
88
|
if isinstance(dom, str) and dom not in domain_values:
|
|
89
89
|
errors.append(
|
|
90
90
|
f"domain: {dom!r} is not a registered domain key, tier name, "
|
|
91
|
-
f"or 'unclassified' (
|
|
91
|
+
f"or 'unclassified' (compose/domains.json)")
|
|
92
92
|
return errors
|
|
93
93
|
|
|
94
94
|
|
|
@@ -7,8 +7,8 @@ optional criteria / classification / proposed_domain / context) plus its session
|
|
|
7
7
|
`--host`; THIS script owns every deterministic value and side effect:
|
|
8
8
|
|
|
9
9
|
* mints learning_id (a lowercase UUID) + created (ISO-8601) + schema_version;
|
|
10
|
-
* validates the full record against
|
|
11
|
-
validation source, reused from
|
|
10
|
+
* validates the full record against learn/learning.schema.json — the single
|
|
11
|
+
validation source, reused from learn/check-learning.py (no second schema);
|
|
12
12
|
* logs the JSON record to <home>/personal/learnings.jsonl — the durable,
|
|
13
13
|
append-only upload source that the Phase 2 watermark drain re-sends from;
|
|
14
14
|
* writes the lesson prose where THIS host loads it next session, and wires it:
|
|
@@ -16,7 +16,7 @@ optional criteria / classification / proposed_domain / context) plus its session
|
|
|
16
16
|
`@personal/learnings.md` import once in the entry CLAUDE.md;
|
|
17
17
|
- codex: appends into a preserved `agent-bios:personal-learnings` region
|
|
18
18
|
of <home>/AGENTS.md (Codex has no @import; AGENTS.md is always loaded).
|
|
19
|
-
The region lives OUTSIDE the central markers so
|
|
19
|
+
The region lives OUTSIDE the central markers so compose/assemble.py —
|
|
20
20
|
which only rewrites the central region — preserves it across re-assembly.
|
|
21
21
|
|
|
22
22
|
It REFUSES any script-owned field in the payload (deterministic values are never
|
|
@@ -61,7 +61,7 @@ HOSTS = {
|
|
|
61
61
|
CLAUDE_IMPORT_LINE = "@personal/learnings.md"
|
|
62
62
|
CLAUDE_CENTRAL_IMPORT = "@central/bundle.md"
|
|
63
63
|
|
|
64
|
-
# Codex AGENTS.md markers. The central pair is owned by
|
|
64
|
+
# Codex AGENTS.md markers. The central pair is owned by compose/assemble.py
|
|
65
65
|
# (kept in sync here); the personal-learnings pair is this tool's own region,
|
|
66
66
|
# placed outside the central pair so re-assembly preserves it.
|
|
67
67
|
CENTRAL_START = "<!-- agent-bios:central:start -->"
|
|
@@ -72,7 +72,7 @@ PERSONAL_END = "<!-- agent-bios:personal-learnings:end -->"
|
|
|
72
72
|
CLAUDE_LEARNINGS_HEADER = """# Personal learnings
|
|
73
73
|
|
|
74
74
|
<!-- Automation-owned: written by the session learning flow (`learn!`,
|
|
75
|
-
|
|
75
|
+
learn/collect-learning.py). Do NOT hand-edit — promote→migrate clears
|
|
76
76
|
applied items by learning_id when the org redistributes them. Your own
|
|
77
77
|
personal rules belong in the entry CLAUDE.md '## Personal' section, never
|
|
78
78
|
here. This file is pulled into context by the entry file's
|
|
@@ -81,15 +81,15 @@ CLAUDE_LEARNINGS_HEADER = """# Personal learnings
|
|
|
81
81
|
|
|
82
82
|
CODEX_REGION_HEADER = """## Personal learnings
|
|
83
83
|
<!-- Automation-owned: written by the session learning flow (`learn!`,
|
|
84
|
-
|
|
84
|
+
learn/collect-learning.py). Codex loads this via AGENTS.md (no @import).
|
|
85
85
|
Do NOT hand-edit — promote→migrate clears applied items by learning_id.
|
|
86
86
|
Kept outside the agent-bios central markers so re-assembly preserves it. -->
|
|
87
87
|
"""
|
|
88
88
|
|
|
89
89
|
|
|
90
90
|
def load_checker():
|
|
91
|
-
"""Reuse
|
|
92
|
-
path = REPO / "
|
|
91
|
+
"""Reuse learn/check-learning.py as the single validation source."""
|
|
92
|
+
path = REPO / "learn" / "check-learning.py"
|
|
93
93
|
spec = importlib.util.spec_from_file_location("check_learning", path)
|
|
94
94
|
module = importlib.util.module_from_spec(spec)
|
|
95
95
|
spec.loader.exec_module(module)
|
|
@@ -97,9 +97,9 @@ def load_checker():
|
|
|
97
97
|
|
|
98
98
|
|
|
99
99
|
def load_redactor():
|
|
100
|
-
"""Reuse
|
|
100
|
+
"""Reuse learn/redact.py as the single secret-redaction floor (loaded by
|
|
101
101
|
path so it works from the npm bin regardless of cwd, like load_checker)."""
|
|
102
|
-
path = REPO / "
|
|
102
|
+
path = REPO / "learn" / "redact.py"
|
|
103
103
|
spec = importlib.util.spec_from_file_location("redact", path)
|
|
104
104
|
module = importlib.util.module_from_spec(spec)
|
|
105
105
|
spec.loader.exec_module(module)
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
3
|
"$id": "urn:agent-bios:schema:learning:v1",
|
|
4
4
|
"title": "Learning record",
|
|
5
|
-
"description": "Per-session learning artifact produced by the session learning flow (trigger `learn!`; design/collection-loop/DESIGN.md). This file is the SSOT for the upload payload of POST /api/ingest/learnings and for the curator export; the dashboard mirrors only minimal validation from it. Field names stay ledger-compatible (design/session-distill/ledger.json). Identity is NEVER carried in the payload — the server derives it from X-Hook-Token. `domain` membership (
|
|
5
|
+
"description": "Per-session learning artifact produced by the session learning flow (trigger `learn!`; design/collection-loop/DESIGN.md). This file is the SSOT for the upload payload of POST /api/ingest/learnings and for the curator export; the dashboard mirrors only minimal validation from it. Field names stay ledger-compatible (design/session-distill/ledger.json). Identity is NEVER carried in the payload — the server derives it from X-Hook-Token. `domain` membership (compose/domains.json domains ∪ tier names ∪ 'unclassified') is enforced by learn/check-learning.py, not frozen here, so vocabulary evolution never requires a schema_version bump.",
|
|
6
6
|
"type": "object",
|
|
7
7
|
"additionalProperties": false,
|
|
8
8
|
"required": [
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
"learning_id": {
|
|
22
22
|
"type": "string",
|
|
23
23
|
"pattern": "^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$",
|
|
24
|
-
"description": "Client-generated UUID for this learning, lowercase canonical form (tooling must lowercase, e.g. macOS uuidgen emits uppercase). Owned by
|
|
24
|
+
"description": "Client-generated UUID for this learning, lowercase canonical form (tooling must lowercase, e.g. macOS uuidgen emits uppercase). Owned by learn/collect-learning.py, never hand-authored. Idempotency key for the pending-learnings.jsonl bounded retry in Phase 2. Distinct from the ledger's `id` (a curator-assigned short id like 'S3-07'); this is the light-flow record's own key.",
|
|
25
25
|
"$comment": "Ledger entries use `id`; the light-flow record's own key is `learning_id` (the artifact is a learning — LEXICON.md — so it is not `distill_id`, which would collide with the heavy session-distill pipeline)."
|
|
26
26
|
},
|
|
27
27
|
"lesson": {
|
|
@@ -33,7 +33,7 @@
|
|
|
33
33
|
"domain": {
|
|
34
34
|
"type": "string",
|
|
35
35
|
"pattern": "^[a-z][a-z0-9-]*$",
|
|
36
|
-
"description": "Curation join key, ledger-compatible: a D6 domain key from
|
|
36
|
+
"description": "Curation join key, ledger-compatible: a D6 domain key from compose/domains.json for a domain-specific lesson, OR a tier name (core, infra, …) for a cross-cutting lesson (4 real ledger entries carry core/infra), OR 'unclassified' (refinement B — users are never blocked at capture time; the curator assigns later; kept distinct from 'core', which asserts a genuinely cross-cutting lesson). Membership is validated by learn/check-learning.py against compose/domains.json (single source), not frozen in this pattern. When the model proposes a NOT-yet-registered domain, this stays 'unclassified' and the name goes in `proposed_domain`."
|
|
37
37
|
},
|
|
38
38
|
"created": {
|
|
39
39
|
"type": "string",
|