leos-agent 10.7.2 → 12.2026090800.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 (63) hide show
  1. package/README.md +239 -670
  2. package/agents/leo-cheap.md +13 -0
  3. package/agents/leo-executor.md +13 -0
  4. package/agents/leo-parent.md +13 -0
  5. package/agents/leo-reviewer.md +12 -0
  6. package/agents/leo-runner.md +13 -0
  7. package/agents/leo-standard.md +13 -0
  8. package/hooks/README.md +43 -91
  9. package/hooks/hooks-codex.json +39 -0
  10. package/hooks/hooks-cursor.json +14 -2
  11. package/hooks/hooks.json +35 -1
  12. package/index.js +34 -108
  13. package/package.json +7 -4
  14. package/payload/codex-agents/leo-cheap.toml +4 -0
  15. package/payload/codex-agents/leo-executor.toml +3 -35
  16. package/payload/codex-agents/leo-parent.toml +4 -0
  17. package/payload/codex-agents/leo-reviewer.toml +5 -0
  18. package/payload/codex-agents/leo-runner.toml +3 -27
  19. package/payload/codex-agents/leo-standard.toml +4 -0
  20. package/payload/legacy-copy-hashes.json +21 -0
  21. package/payload/model-prices.json +2914 -0
  22. package/pi-extension.js +25 -0
  23. package/rules/preferences.md +29 -92
  24. package/scripts/bump.py +180 -0
  25. package/scripts/check.py +91 -18
  26. package/scripts/cursor_hook.py +58 -0
  27. package/scripts/dispatch_guard.py +87 -162
  28. package/scripts/dispatch_log.py +24 -25
  29. package/scripts/doctor.py +78 -0
  30. package/scripts/emit_payload.py +108 -0
  31. package/scripts/ghreview.py +176 -88
  32. package/scripts/handoff.py +25 -6
  33. package/scripts/harness_bridge.js +55 -0
  34. package/scripts/install_transaction.py +91 -0
  35. package/scripts/jsonc_edit.py +137 -0
  36. package/scripts/leo-install.py +323 -167
  37. package/scripts/measure_context.py +17 -19
  38. package/scripts/observe_agent.py +52 -0
  39. package/scripts/payload.py +99 -0
  40. package/scripts/pricing.py +321 -0
  41. package/scripts/publish-npm.py +12 -4
  42. package/scripts/routing.py +71 -82
  43. package/scripts/routing_engine.py +132 -0
  44. package/scripts/session_models.py +83 -0
  45. package/scripts/usage_scan.py +303 -278
  46. package/scripts/watch_review.py +153 -52
  47. package/skills/doctor/SKILL.md +45 -85
  48. package/skills/handoff/SKILL.md +3 -5
  49. package/skills/handon/SKILL.md +13 -21
  50. package/skills/install/SKILL.md +50 -74
  51. package/skills/review-pr/SKILL.md +27 -63
  52. package/skills/review-pr/reference/lenses.md +22 -56
  53. package/skills/review-pr/reference/procedure.md +128 -327
  54. package/skills/review-usage/SKILL.md +41 -91
  55. package/skills/review-usage/reference/sources.md +44 -80
  56. package/skills/tune-routing/SKILL.md +40 -109
  57. package/skills/tune-routing/reference/harnesses.md +25 -60
  58. package/skills-claude/attach-pr/SKILL.md +2 -2
  59. package/skills-claude/watch-review/SKILL.md +59 -108
  60. package/commands/handoff.md +0 -11
  61. package/commands/handon.md +0 -10
  62. package/commands/review-pr.md +0 -9
  63. package/commands-claude/watch-review.md +0 -9
package/README.md CHANGED
@@ -1,718 +1,287 @@
1
1
  # leos-agent
2
2
 
3
- Leo's portable agent operating policy, version **10.7.2**, installable on Claude
4
- Code, Codex, Cursor, Hermes, Pi, and OpenCode through each harness's own plugin
5
- system.
6
-
7
- The policy it carries is short: **the main thread is an orchestrator.**
8
- Investigation, brainstorming, debugging, and mechanical work all run in briefed
9
- subagents, so the main thread never fills up with the files, retries, and logs
10
- that produced an answer — only the answer. A single command you can filter at
11
- the shell stays inline. Work runs at one of two named tiers: **standard**, the
12
- model you are already using, for thinking and judging; **economical**, two
13
- named agent profiles — `leo-runner` for narrow search, reading, testing, and
14
- mechanical work, `leo-executor` for well-specified implementation — shipped as
15
- first-class agent definitions on both Claude Code (`agents/`, Haiku and Sonnet)
16
- and Codex (installed TOML profiles), so the cheaper model is baked into the
17
- agent type rather than chosen per dispatch. Every other harness inherits unless
18
- a machine-local [routing config](#per-machine-model-routing) names models for it.
19
-
20
- ## What it ships
21
-
22
- Beyond the preferences payload: the two economical-tier agent definitions
23
- (`agents/` for Claude Code, `payload/codex-agents/` for Codex), a setup
24
- diagnostic, a routing tuner, a session handoff pair, and three GitHub skills.
25
- The GitHub ones need `gh`, authenticated.
26
-
27
- | Skill | What it does | Where |
28
- |---|---|---|
29
- | `review-pr` | Reviews a pull request and stages inline comments as a **pending** review — visible only to you until you submit or discard on GitHub. Never submits. Resolves the originating ticket (Linear, Jira, GitHub issue) from the PR's title, body, or branch when one is named, and adds a spec lens that checks the diff against it. | every skill-loading harness |
30
- | `watch-review` | Arms a watcher that streams direct review requests into the session for `review-pr` to handle, and re-streams one when its head moves. Never surfaces a pull request someone else has approved. Polling is a shell script (`scripts/watch_review.py`), not a model loop: an idle tick is one `gh` call and zero tokens. | **Claude Code only** — built on its Monitor tool |
31
- | `doctor` | Diagnoses this harness's setup, read-only: whether the `<leos-agent>` block is injected and current, what else is loaded into every session (global instruction file, memories, settings, skills), and whether a local checkout passes `scripts/check.py`. Run it with `/doctor`. | every skill-loading harness |
32
- | `tune-routing` | Picks the concrete models behind `leo-runner` and `leo-executor` on this machine, writes them to `~/.leos-agent-local/routing.json`, re-renders the install, and proves the choice with one live dispatch — model strings are never checked against a known-model list, so a typo surfaces at dispatch time and nowhere earlier. Run it with `/tune-routing`. | every skill-loading harness |
33
- | `review-usage` | Reads many sessions across every harness on this machine — a time window, not one session — and reports where the tokens went and how well the policy actually held: routing compliance, guard blocks and whether they were re-dispatched, over- and under-delegation, cache health. The scan is a script, not a prompt, so it costs a second rather than a model's worth of transcript reading. Run it with `/review-usage`. | every skill-loading harness |
34
- | `handoff` | Writes this session's context — goal, what landed, what is next, key files, decisions, gotchas — to a markdown document under `~/.leos-agent-local/handoffs/`, so a later session can pick the work up. Pointers, not contents: it names files rather than pasting them. Run it with `/handoff`. | every skill-loading harness |
35
- | `handon` | Loads a handoff written earlier — in this harness or a different one — and resumes from it, reporting any drift first when the directory, branch, or HEAD has moved since. Loading never consumes a handoff. Run it with `/handon <name>`. | every skill-loading harness |
36
- | `attach-pr` | Attaches the current desktop session to an existing pull request so the app shows its PR card. Creates nothing and pushes nothing. | **Claude Code only** — it drives that app's card |
37
-
38
- The Claude-only pair live in `skills-claude/` and `commands-claude/`, listed in
39
- `.claude-plugin/plugin.json` and nowhere else. Hermes receives the preferences
40
- payload but no skills — it has no skill loader.
41
-
42
- The watcher records the **head commit** it reviewed each pull request at, under
43
- `~/.leos-agent-local/` (override with `$LEOS_AGENT_LOCAL_PATH`), so a pull
44
- request comes back when someone pushes to it and stays quiet otherwise;
45
- `watch_review.py forget <n>` puts one back in play at its current head. Two
46
- gates keep a continuous watch from being expensive: a pull request another user
47
- has already approved is never surfaced at all, and a new head must hold still
48
- for `--settle` seconds (default 120) before it is emitted, so a burst of pushes
49
- costs one review rather than one per commit.
50
-
51
- Handoffs live in the same place, at
52
- `~/.leos-agent-local/handoffs/<name>.md` — a fixed path that needs no plugin
53
- root, so `/handon` reads one with a single `cat` rather than going looking for
54
- it. Nothing there is ever pruned automatically: `handoff.py list [--all]` shows
55
- what exists and `handoff.py rm <name>` is the only way one goes away. The
56
- directory is deliberately outside the plugin, so upgrading or reinstalling can
57
- never take state with it.
58
-
59
- ## Per-machine model routing
60
-
61
- The economical tier only ever had teeth on Claude Code and Codex, because those
62
- are the two harnesses whose model names the payload could hardcode. Everywhere
63
- else, every fan-out ran at the current model — the most expensive shape the
64
- policy has. Which models a harness offers varies by machine and by what an IT
65
- department allows, so the mapping is machine-local config rather than something
66
- the plugin can ship:
67
-
68
- ```jsonc
69
- // ~/.leos-agent-local/routing.json (override the directory with $LEOS_AGENT_LOCAL_PATH)
70
- {
71
- "cursor": {"runner": "grok-code-fast-1", "executor": "claude-sonnet-4.6"},
72
- "opencode": {"runner": "anthropic/claude-haiku-4-5"},
73
- "codex": {"runner": {"model": "gpt-5.6-luna", "effort": "low"}}
74
- }
75
- ```
76
-
77
- Keys are harness names; each holds `runner` and/or `executor`, independently —
78
- configuring only `runner` is the common case, since it is the fan-out that
79
- costs. A bare string is shorthand for `{"model": ...}`. Model strings are
80
- free-form and never checked against a known-model list: whatever the harness
81
- accepts goes in verbatim. A misspelled *key*, though, is a hard error, because a
82
- typo that silently left a harness on the expensive model is the one failure this
83
- is here to prevent.
84
-
85
- **Nothing reads it at run time.** `leo-install.py` renders the result into the
86
- `<leos-agent>` block it already writes, so a session pays nothing to know its own
87
- routing — no config read, no extra turn. It costs *less* than before: each
88
- machine now carries only its own harness's dispatch line instead of all of them,
89
- which took the installed payload from 4497 bytes to 4315–4344 depending on the
90
- harness. `scripts/measure_context.py` prints the per-harness figure and fails if
91
- an unconfigured harness ever grows past the old one.
92
-
93
- Edit the file — by hand, or with `routing.py set --harness <h> --runner
94
- <model>`, which [`/tune-routing`](#what-it-ships) drives end to end — then
95
- re-run the installer to re-render; `leo-install.py <harness> --check` reports
96
- "out of date" until you do, and `/doctor` surfaces it. Installing is
97
- idempotent: same config, same version, same bytes, so a second run reports
98
- `unchanged`.
99
-
100
- **The config is yours, never the installer's.** `leo-install.py` only ever reads
101
- it, and never creates, migrates, rewrites, or removes it, including under
102
- `--uninstall`; it lives outside the plugin so an upgrade cannot take it. The one
103
- thing that writes it is `routing.py set` / `unset`, run because you asked: it
104
- creates the file if it is missing, replaces the one role you named, validates
105
- the whole document before writing, and leaves every other harness's entry —
106
- including the bare-string shorthand — exactly as you wrote it. `routing.py show`
107
- prints what is configured; with no file at all, every harness uses its shipped
108
- default and behaviour is exactly what it was before this existed.
109
-
110
- Delivery differs by harness only in the last mile: Claude Code gets a `model:`
111
- override alongside `subagent_type:` (the plugin-owned `agents/*.md` are never
112
- rewritten), Codex gets the models substituted into its installed profile TOMLs,
113
- Cursor gets its own `~/.cursor/rules/leos-agent-routing.mdc` because its rules
114
- come straight out of the plugin directory, and the rest get the rendered line in
115
- their global instruction file.
116
-
117
- ## The dispatch guard
118
-
119
- The payload has always said that a subagent dispatch must name a model. Prose
120
- alone did not hold: a forgotten dispatch inherits the parent's expensive model
121
- and pays a cold cache write per child, which is the single most expensive shape
122
- this policy has. From 10.7.2 that half of the rule is enforced by a hook instead,
123
- and the prose it replaced came out of the always-loaded payload — enforcement in
124
- code costs **zero** context per turn, so the guard paid for itself in bytes
125
- before saving a cent.
126
-
127
- `scripts/dispatch_guard.py` runs before a subagent dispatch and refuses exactly
128
- one thing: an agent selected with a brief, **no model named**, on a harness that
129
- can name one. Three ways to comply, all of them one word:
130
-
131
- | Instead of | Use | For |
132
- |---|---|---|
133
- | a generic agent, no model | `subagent_type: "leo-runner"` | reading, search, tests, logs, codemods, fan-out |
134
- | a generic agent, no model | `subagent_type: "leo-executor"` | an approved plan, a well-specified change |
135
- | a generic agent, no model | `model: "<name>"` | investigation and debugging — naming it *is* the stated reason |
136
-
137
- A plugin install namespaces the type — dispatch `leos-agent:leo-runner` rather
138
- than `leo-runner`; the guard accepts either.
139
-
140
- It never picks a model for you. It cannot force cheap work onto an expensive
141
- problem, so it cannot cause a quality regression — only an explicit choice. It
142
- is also deliberately narrow: a false block costs one re-dispatch, while a caught
143
- inherited fan-out saves the cold prefix of every child, so the margin only holds
144
- while the rule refuses to make judgment calls.
145
-
146
- Detection is by **argument shape**, not tool name: a dispatch is a call that
147
- selects an agent and carries a brief. A shape the guard does not recognise is
148
- left alone, so a harness it has never met keeps working. MCP tools are never
149
- guarded. Anything that goes wrong inside the guard allows the call and records
150
- `decision: "error"`, kept distinct from a decision to allow, because a guard
151
- that dies quietly is worse than no guard.
152
-
153
- ```
154
- LEOS_AGENT_DISPATCH_GUARD=on block (default)
155
- warn record, never block
156
- off disabled entirely
157
- verbose also put the over-delegation notice in front of the model
158
- LEOS_AGENT_DISPATCH_LOG_PROMPTS=1 debug only: keep 200 chars of brief text in the log
159
- ```
160
-
161
- **Per harness.** Claude Code dispatches `Agent` with `subagent_type`, and a
162
- plugin install namespaces it — both forms are tiers. Codex dispatches
163
- `spawn_agent`, which selects behaviour by `model` and `reasoning_effort` rather
164
- than by naming an agent, so there the guard requires `model`; its `message` is
165
- encrypted, so the over-delegation heuristic and block-conversion tracking do not
166
- apply on Codex. Hermes and OpenCode run the same policy in-process, blocking by
167
- directive and by throw respectively. Pi has no hook surface.
168
-
169
- **Codex hash-pins hooks.** A new version of the guard enforces nothing there
170
- until it is re-approved through `/hooks`, and the symptom is silence — zero
171
- Codex rows in `dispatch_log.py report`.
172
-
173
- ### What it records
174
-
175
- `~/.leos-agent-local/dispatch.jsonl`, one line per dispatch, mode `0600`,
176
- rotated at 1 MiB with one generation kept — bounded at 2 MiB forever.
177
-
178
- It stores **no prompt text and no paths.** Prompts, sessions and working
179
- directories are truncated SHA-256. The prompt hash is what makes the report
180
- meaningful: a blocked brief whose hash comes back naming a tier is a block that
181
- worked, and one that never returns was abandoned work rather than a saving.
182
- Delete it whenever you like — nothing depends on its history.
183
-
184
- ```bash
185
- python3 scripts/dispatch_log.py report
186
- python3 scripts/usage_scan.py --since 7d
187
- ```
188
-
189
- ## How it works
190
-
191
- The payload lives in exactly one file: [`rules/preferences.md`](rules/preferences.md).
192
-
193
- Cursor reads that file natively as an always-apply rule. Every other harness
194
- gets it through its global instruction file, written by
195
- [`scripts/leo-install.py`](scripts/leo-install.py) into a marker block:
196
-
197
- ```
198
- <leos-agent version="10.7.2">
199
- ...the payload...
200
- </leos-agent>
201
- ```
202
-
203
- Updating replaces that block and nothing else, so anything you wrote in those
204
- files by hand survives an upgrade untouched. The script writes only when the
205
- bytes actually differ, so running it twice is a no-op, and it writes through a
206
- temporary file and an atomic rename, so an interrupted run cannot leave a
207
- half-written instruction file behind.
208
-
209
- If it ever finds markers it cannot pair — an opener with no closer, a stray
210
- closer, two blocks — it refuses to touch that file and tells you what to fix.
211
- Guessing there would mean deleting whatever sits between the markers, which is
212
- exactly the content it exists to protect.
213
-
214
- | Harness | Global file the installer writes |
215
- |---|---|
216
- | Claude Code | `~/.claude/CLAUDE.md` (the `leo-runner` / `leo-executor` agents need no installer step — the plugin's `agents/` directory delivers them) |
217
- | Codex | `~/.codex/AGENTS.md` (plus `~/.codex/agents/leo-runner.toml` and `leo-executor.toml`) |
218
- | Cursor | none — the plugin's always-apply rule delivers it |
219
- | Hermes | `~/.hermes/SOUL.md` (edited only if it already exists) |
220
- | Pi | `~/.pi/agent/AGENTS.md` |
221
- | OpenCode | `~/.config/opencode/AGENTS.md` (plus copied skills and commands) |
222
-
223
- **The installer is per-harness and manual.** Running it inside Codex installs Codex and
224
- nothing else; it never writes to another harness's files behind your back, and
225
- it never runs on its own at session start. Install the plugin, then run the
226
- installer once in that harness.
227
-
228
- Requires Python 3.9+ and macOS, Linux, or WSL. No symlinks are used anywhere —
229
- installs are real clones and copies.
230
-
231
- ---
232
-
233
- ## Claude Code
234
-
235
- **Install**
236
-
237
- ```bash
3
+ Cost-aware delegation and portable workflows for Claude Code, Codex, Cursor,
4
+ OpenCode, Hermes, and Pi. Version **12.2026090800.0**.
5
+
6
+ The main agent handles small work directly and delegates substantial, bounded
7
+ work to the cheapest competent tier. The policy separates **whether to delegate**
8
+ from **which model to use**. Native adapters check model costs where the harness
9
+ exposes enough information, while skills load detailed procedures on demand.
10
+
11
+ This is a useful direction when expensive parents otherwise do large amounts of
12
+ routine work or spawn expensive children by inheritance. It can cost more when
13
+ briefing, duplicated context, verification, and retries exceed the work saved.
14
+ There is no claim of universal token reduction or measured savings without a
15
+ comparable task baseline. Optimizing dollars can mean spending more tokens on
16
+ a cheaper model while preserving quality.
17
+
18
+ ## Routing and cost
19
+
20
+ | Tier | Appropriate work | Claude default | Codex default |
21
+ |---|---|---|---|
22
+ | Cheap | Bounded factual checks, mechanical work, known procedures | Haiku | GPT-5.6 Luna |
23
+ | Standard | Investigation, implementation, diagnosis, ordinary review | Sonnet | GPT-5.6 Terra |
24
+ | Parent-level | Work requiring the parent's capability | Current parent | Current parent |
25
+
26
+ Native profiles are `leo-cheap`, `leo-standard`, `leo-parent`, and
27
+ `leo-reviewer`. `leo-runner` and `leo-executor` remain legacy aliases. Review
28
+ may use nested read-only lenses; ordinary workers do not delegate. Small
29
+ reviews run locally, and larger reviews divide independent areas rather than
30
+ requiring every lens to reread everything.
31
+
32
+ The tier name is not a price ordering. For example, the bundled reference
33
+ catalog prices Terra output above Sol output; the ceiling therefore replaces
34
+ that selection with the current parent where supported. Input/output crossover
35
+ rates, unknown IDs, and ambiguous catalog matches are allowed with diagnostics,
36
+ as configured by this project's policy. Thus the ceiling prevents **known**
37
+ overselection, not every possible billing outcome.
38
+
39
+ Prices come from the public [OpenRouter model catalog](https://openrouter.ai/docs/guides/overview/models),
40
+ including Claude, GPT, DeepSeek, Kimi, GLM, and Qwen families. Exact IDs and
41
+ recognized aliases are preferred. Nearby versions of the same variant can use
42
+ an explicitly labeled estimate; sizes, cheap/pro variants, and free endpoints
43
+ are not conflated. A price alias never changes the identifier sent to a harness.
44
+ Public prices do not establish account access, model availability, negotiated
45
+ rates, or subscription-credit accounting.
46
+
47
+ Refresh runs in ordinary code at installation/update and, when used, at most
48
+ daily. It is bounded and runs separately from dispatch. Failed refreshes keep
49
+ the last catalog and record a diagnostic. No dispatch performs network I/O or
50
+ asks a model to look up prices. Set `LEOS_AGENT_PRICE_REFRESH=off` for offline
51
+ operation.
52
+
53
+ ## Harness capabilities
54
+
55
+ | Harness | Policy delivery | Model control | Important limit |
56
+ |---|---|---|---|
57
+ | Claude Code | SessionStart, including forks | Agent/Task argument correction; native profiles | Forced settings and provider/org substitutions can affect execution; observe child transcripts. |
58
+ | Codex | Separate native SessionStart hook | Tier-enforcing explicit spawn selection; model-free native profiles | Hooks need native trust. Other/customized profiles can still override spawn settings. |
59
+ | Cursor | Native always-apply rule | Installed user agents; resolved subagentStart model ceiling | No invented Task model argument; hook diagnostics distinguish planned models from completion. |
60
+ | OpenCode | One registered rendered instruction | Native agent selection, confirmed through the SDK | Task has no model field; source/config paths must remain valid. |
61
+ | Hermes | Frozen system-prompt section | Global native delegation-model ceiling when parent/model are observable | Native delegation has one global model, not separate per-task tiers. |
62
+ | Pi | Extension caches rendered body per session | Advisory policy and extension-dependent dispatch checks | No native per-spawn model guarantee for third-party subagent tools. |
63
+
64
+ Portable skills are registered on all six. Native capability differences are
65
+ reported rather than presented as full enforcement parity. Policy, pricing,
66
+ routing decisions, and installation rendering share ordinary code; thin
67
+ adapters implement only supported controls. See [hook contracts](hooks/README.md).
68
+
69
+ ## Install and upgrade
70
+
71
+ Requires macOS or Linux, Python 3.9+, and a current public harness. GitHub workflows need
72
+ authenticated `gh`. JavaScript harnesses supply their own Node/Bun runtime.
73
+ No OpenAI or Anthropic marketplace submission is needed: use this repository
74
+ as your own plugin source or a local checkout.
75
+
76
+ Install **only the harness you intend to configure**. Native plugin discovery
77
+ and the integration installer are separate steps. Run the installer again
78
+ after upgrades or model-mapping changes, because native profiles and copied
79
+ OpenCode resources may need refreshing.
80
+
81
+ ### Claude Code
82
+
83
+ ```sh
238
84
  claude plugin marketplace add foxhatleo/leos-agent
239
- ```
240
-
241
- ```bash
242
85
  claude plugin install leos-agent@leos-agent --scope user
243
86
  ```
244
87
 
245
- Then, in a Claude Code session, run `/install` (or ask it to use the `install`
246
- skill). That writes the block into `~/.claude/CLAUDE.md`.
247
-
248
- **Upgrade**
249
-
250
- ```bash
251
- claude plugin marketplace update leos-agent
252
- ```
88
+ Then invoke the plugin's `install` skill in Claude. To upgrade, refresh the
89
+ marketplace and plugin through Claude's plugin manager, then run `install`
90
+ again and start a new session. Third-party marketplace auto-update settings may
91
+ be disabled; do not assume every client updates itself.
253
92
 
254
- ```bash
255
- claude plugin install leos-agent@leos-agent --scope user
256
- ```
257
-
258
- Re-run `/install` afterwards to refresh the block, then start a new session.
259
- Both commands are safe to repeat; installing an already-current version reports
260
- that it is already installed and changes nothing.
261
-
262
- **Uninstall**
263
-
264
- Run the installer's uninstall first, while the script is still on disk:
265
-
266
- ```bash
267
- python3 ~/.claude/plugins/cache/leos-agent/leos-agent/10.7.2/scripts/leo-install.py claude --uninstall
268
- ```
93
+ ### Codex
269
94
 
270
- ```bash
271
- claude plugin uninstall leos-agent@leos-agent
272
- ```
273
-
274
- Optionally drop the marketplace too:
275
-
276
- ```bash
277
- claude plugin marketplace remove leos-agent
278
- ```
279
-
280
- ---
281
-
282
- ## Codex
283
-
284
- **Install**
285
-
286
- ```bash
95
+ ```sh
287
96
  codex plugin marketplace add foxhatleo/leos-agent
288
- ```
289
-
290
- ```bash
291
- codex plugin add leos-agent@leos-agent
292
- ```
293
-
294
- Then run the `install` skill in a Codex session (`$leos-agent`, then `install`), or
295
- run the script directly:
296
-
297
- ```bash
298
- python3 ~/.codex/plugins/cache/leos-agent/leos-agent/10.7.2/scripts/leo-install.py codex
299
- ```
300
-
301
- This writes `~/.codex/AGENTS.md` and installs two economical agents:
302
- `leo-runner` (`gpt-5.6-luna`, low effort) for narrow repeatable work and
303
- `leo-executor` (`gpt-5.6-terra`, medium effort) for well-specified
304
- implementation. Codex plugins cannot ship agent definitions themselves, which
305
- is why the installer writes them.
306
-
307
- **Upgrade**
308
-
309
- ```bash
310
- codex plugin marketplace upgrade leos-agent
311
- ```
312
-
313
- ```bash
314
97
  codex plugin add leos-agent@leos-agent
315
98
  ```
316
99
 
317
- Re-run the installer, then start a new thread — Codex picks up plugin changes on new
318
- threads only. Re-adding an already-installed plugin is idempotent.
100
+ Invoke the plugin's `install` skill to install native agent TOMLs. Review the
101
+ current hook definitions in `/hooks`; enabling a plugin does not trust its
102
+ hooks automatically. On upgrade, refresh the marketplace/plugin, rerun
103
+ `install`, and review any changed hook definition. The project does not bypass
104
+ that native trust boundary.
319
105
 
320
- **Uninstall**
106
+ ### Cursor
321
107
 
322
- ```bash
323
- python3 ~/.codex/plugins/cache/leos-agent/leos-agent/10.7.2/scripts/leo-install.py codex --uninstall
324
- ```
108
+ Add this repository through Cursor's plugin UI, or use its local-plugin setup:
325
109
 
326
- ```bash
327
- codex plugin remove leos-agent@leos-agent
328
- ```
329
-
330
- ```bash
331
- codex plugin marketplace remove leos-agent
332
- ```
333
-
334
- ---
335
-
336
- ## Cursor
337
-
338
- Cursor has no on-disk global rules file — its User Rules live in your synced
339
- Cursor account — so there is nothing for the installer to write. The plugin ships the
340
- payload as an always-apply rule instead, which takes effect as soon as the
341
- plugin is installed.
342
-
343
- **Install** — either through the UI, or as a local clone.
344
-
345
- In the IDE: open the **Customize** sidebar, add the marketplace
346
- `foxhatleo/leos-agent`, and install **Leo's Agent** at user scope.
347
-
348
- Or clone it into Cursor's local plugin directory (a clone, not a symlink):
349
-
350
- ```bash
110
+ ```sh
351
111
  git clone https://github.com/foxhatleo/leos-agent ~/.cursor/plugins/local/leos-agent
112
+ python3 ~/.cursor/plugins/local/leos-agent/scripts/leo-install.py cursor
352
113
  ```
353
114
 
354
- Cursor does not currently expose a reliable non-interactive per-plugin install
355
- command, so those two paths are the supported ones.
356
-
357
- **Upgrade**
358
-
359
- Refresh the marketplace from the Customize panel, or for a local clone:
360
-
361
- ```bash
362
- git -C ~/.cursor/plugins/local/leos-agent pull
363
- ```
364
-
365
- **Uninstall**
366
-
367
- Remove the plugin from the Customize panel, or delete the clone:
368
-
369
- ```bash
370
- rm -rf ~/.cursor/plugins/local/leos-agent
371
- ```
372
-
373
- There is no block to remove — nothing was written outside the plugin directory.
374
-
375
- ---
376
-
377
- ## Hermes
378
-
379
- **Install**
380
-
381
- If the plugin resolves through the community index:
382
-
383
- ```bash
384
- hermes plugins install leos-agent
385
- ```
386
-
387
- Otherwise clone it into the Hermes plugin directory:
388
-
389
- ```bash
390
- git clone https://github.com/foxhatleo/leos-agent ~/.hermes/plugins/leos-agent
391
- ```
392
-
393
- Hermes plugins are opt-in, so enable it by adding `leos-agent` to
394
- `plugins.enabled` in `~/.hermes/config.yaml`:
395
-
396
- ```yaml
397
- plugins:
398
- enabled:
399
- - leos-agent
400
- ```
401
-
402
- **Run Hermes once before installing.** The payload goes into `~/.hermes/SOUL.md`,
403
- the agent's identity prompt, and Hermes writes its own starter version of that
404
- file on first run. The installer deliberately never creates it — if `SOUL.md` is
405
- missing it reports `skipped` and leaves Hermes' bootstrap alone. Once it exists:
406
-
407
- ```bash
408
- /leo-install
409
- ```
410
-
411
- **Upgrade**
115
+ Confirm the plugin in Customize and inspect Hooks diagnostics. Set explicit
116
+ models available to your Cursor account, then rerun the installer. Profiles
117
+ are written under `~/.cursor/agents`; `~/.cursor/rules` is not assumed to be a
118
+ supported global rule location. Upgrade a local clone with `git pull --ff-only`,
119
+ rerun the installer, and reload the plugin.
412
120
 
413
- ```bash
414
- hermes plugins update leos-agent
415
- ```
121
+ ### OpenCode
416
122
 
417
- or, for a clone:
123
+ A stable checkout avoids versioned package-cache paths:
418
124
 
419
- ```bash
420
- git -C ~/.hermes/plugins/leos-agent pull
125
+ ```sh
126
+ git clone https://github.com/foxhatleo/leos-agent ~/.local/share/leos-agent
127
+ python3 ~/.local/share/leos-agent/scripts/leo-install.py opencode
421
128
  ```
422
129
 
423
- Then re-run `/leo-install`.
130
+ The installer registers the checkout's plugin URI, one rendered instruction,
131
+ native agent profiles, and skill/reference copies. It preserves JSONC comments
132
+ and unrelated configuration. Upgrade that checkout with `git pull --ff-only`
133
+ and rerun the same command. The npm package is also published as `leos-agent`;
134
+ if using a package cache, resolve its actual root and rerun the installer when
135
+ that path changes. Do not assume a fixed cache directory layout.
424
136
 
425
- **Uninstall**
137
+ ### Hermes
426
138
 
427
- ```bash
428
- python3 ~/.hermes/plugins/leos-agent/scripts/leo-install.py hermes --uninstall
429
- ```
430
-
431
- ```bash
432
- hermes plugins remove leos-agent
433
- ```
139
+ Use Hermes's local-plugin directory under your active HERMES_HOME/profile to
140
+ install this repository as `plugins/leos-agent`, then enable it through Hermes's
141
+ plugin manager. Run the registered `leo-install` command. The native plugin
142
+ registers portable skills, one frozen policy section, and dispatch diagnostics.
143
+ Hermes supports the policy for deciding whether to delegate, but not per-task
144
+ model tiers. The installer preserves its native delegation-model setting;
145
+ saved cheap/standard mappings are not applied. The guard can still check known
146
+ child/parent prices when both models are observable.
434
147
 
435
- Remove the `leos-agent` entry from `plugins.enabled`, and delete the clone if
436
- you made one. Your own `SOUL.md` content is left intact — only the block goes.
148
+ ### Pi
437
149
 
438
- **Note on model routing:** Hermes applies a single `delegation.model` to every
439
- child of a `delegate_task` call, so it cannot vary the model per spawn. A
440
- routing config still renders a stanza for it, and the stanza says to inherit and
441
- say so where a per-spawn model is not available.
442
-
443
- ---
444
-
445
- ## Pi
446
-
447
- **Install**
448
-
449
- ```bash
150
+ ```sh
450
151
  pi install git:github.com/foxhatleo/leos-agent
451
152
  ```
452
153
 
453
- Then run the install skill in a pi session:
454
-
455
- ```
456
- /skill:install
457
- ```
458
-
459
- Pi pins the git ref it installed and records the package in
460
- `~/.pi/agent/settings.json`; re-running install is idempotent.
461
-
462
- **Upgrade**
463
-
464
- ```bash
465
- pi update git:github.com/foxhatleo/leos-agent
466
- ```
467
-
468
- Pinned refs are reconciled, never silently advanced — to move to a new tag,
469
- install it explicitly:
470
-
471
- ```bash
472
- pi install git:github.com/foxhatleo/leos-agent@v10.7.2
473
- ```
474
-
475
- Re-run `/skill:install` afterwards.
476
-
477
- **Uninstall**
478
-
479
- ```bash
480
- python3 ~/.pi/agent/git/github.com/foxhatleo/leos-agent/scripts/leo-install.py pi --uninstall
481
- ```
482
-
483
- ```bash
484
- pi remove git:github.com/foxhatleo/leos-agent
485
- ```
486
-
487
- ---
488
-
489
- ## OpenCode
154
+ Invoke the installed `install` skill for `pi`, then start a new session.
155
+ Package metadata provides skill discovery once; the extension does not register
156
+ the same skills a second time. Upgrade through Pi's package manager and rerun
157
+ `install`. A subagent extension is required for delegation; this project does
158
+ not pretend that every such extension accepts model overrides.
490
159
 
491
- OpenCode loads plugins as npm packages, so this one is published to npm as
492
- `leos-agent`.
160
+ ### Installer controls
493
161
 
494
- **Install**
495
-
496
- ```bash
497
- opencode plugin leos-agent -g
498
- ```
499
-
500
- That adds the package to the `plugin` array in `~/.config/opencode/opencode.json`
501
- (or `.jsonc`) and caches it. Bootstrap the installer once by running the script from
502
- the cache — OpenCode's plugin API cannot register skills or commands, so the
503
- first run has to come from the package itself:
504
-
505
- ```bash
506
- python3 ~/.cache/opencode/packages/leos-agent@latest/node_modules/leos-agent/scripts/leo-install.py opencode
507
- ```
162
+ From the resolved plugin root:
508
163
 
509
- That writes `~/.config/opencode/AGENTS.md` and copies the skills and commands into
510
- `~/.config/opencode/skills/` and `~/.config/opencode/commands/`. From then on
511
- `/leo-install` works inside OpenCode. The copies are installed with the plugin
512
- root already resolved to an absolute path — OpenCode sets no resolution env var,
513
- and the copies live apart from the scripts they invoke — so re-run the installer
514
- after clearing or moving the package cache to point them at the new location.
515
-
516
- **Upgrade**
517
-
518
- ```bash
519
- opencode plugin leos-agent -g -f
520
- ```
521
-
522
- If the cache holds a stale copy, clear it and let OpenCode refetch:
523
-
524
- ```bash
525
- rm -rf ~/.cache/opencode/packages/leos-agent@*
526
- ```
527
-
528
- Re-run the bootstrap install command above to refresh the copied files.
529
-
530
- **Uninstall**
531
-
532
- ```bash
533
- python3 ~/.cache/opencode/packages/leos-agent@latest/node_modules/leos-agent/scripts/leo-install.py opencode --uninstall
534
- ```
535
-
536
- OpenCode has no plugin-remove command, so delete the `"leos-agent"` entry from
537
- the `plugin` array in `~/.config/opencode/opencode.json` **by hand**. The installer
538
- never edits that file: it is JSONC, with your comments in it, and rewriting it
539
- would destroy them. Then clear the cache:
540
-
541
- ```bash
542
- rm -rf ~/.cache/opencode/packages/leos-agent@*
164
+ ```sh
165
+ python3 scripts/leo-install.py <harness> --dry-run
166
+ python3 scripts/leo-install.py <harness> --check
167
+ python3 scripts/leo-install.py <harness> --rollback
168
+ python3 scripts/leo-install.py <harness> --uninstall
543
169
  ```
544
170
 
545
- ---
171
+ Normal installation stages and validates all changes first, writes a private
172
+ backup, and rolls back earlier writes if an operation fails. Rollback refuses
173
+ intervening edits and can recover a partially applied installation. Only owned
174
+ entries/files are managed. Unchanged legacy copies are recognized by complete
175
+ content hashes; edited or unrelated files are preserved. `--force` is for a
176
+ specific conflict you explicitly intend to replace.
546
177
 
547
- ## Migrating from v8
178
+ Run `--uninstall` before removing the native plugin/source. It removes owned
179
+ integration artifacts, not routing preferences, handoffs, or logs. Supported
180
+ config overrides include CODEX_HOME, CLAUDE_CONFIG_DIR, HERMES_HOME,
181
+ PI_CODING_AGENT_DIR, OPENCODE_CONFIG_DIR, OPENCODE_CONFIG, and XDG_CONFIG_HOME.
548
182
 
549
- Version 10 renames the plugin from `leo` to `leos-agent`, so the old install
550
- does not upgrade in place — remove it first. Most skills that were invoked
551
- as `leo:<name>` are gone; v10 ships a deliberately lean payload plus the three
552
- GitHub skills above, now unprefixed (`review-pr`, not `leo:review-pr`). The
553
- watcher no longer runs under `/loop`: it is a shell process streaming into
554
- Claude Code's Monitor tool, so idle polling costs nothing.
183
+ ## Per-machine model routing
555
184
 
556
- **Claude Code.** The old plugin will show as `failed to load` once the
557
- marketplace points at v10 (`Plugin leo not found in marketplace leos-agent`).
558
- Remove it:
185
+ Data lives in `~/.leos-agent-local`, or LEOS_AGENT_LOCAL_PATH, outside versioned
186
+ plugin caches. Configure concrete provider/harness IDs rather than assuming
187
+ that a familiar alias exists everywhere:
559
188
 
560
- ```bash
561
- claude plugin uninstall leo@leos-agent
189
+ ```sh
190
+ python3 scripts/routing.py set --harness claude --cheap haiku --standard sonnet
191
+ python3 scripts/routing.py set --harness codex --cheap gpt-5.6-luna --standard gpt-5.6-terra
192
+ python3 scripts/routing.py show
193
+ python3 scripts/leo-install.py <harness>
562
194
  ```
563
195
 
564
- **Codex.** The v8 marketplace entry is pinned to an old commit, and Codex
565
- refuses to re-add a marketplace from a different source. Remove and re-add:
196
+ `routing.json` accepts `cheap` and `standard` as strings or objects containing
197
+ `model` and optional `effort`. Legacy `runner`/`executor` keys remain readable.
198
+ Unknown model identifiers are retained and diagnosed, not silently corrected
199
+ to a different dispatch ID. Parent-level always means the current parent.
566
200
 
567
- ```bash
568
- codex plugin marketplace remove leos-agent && codex plugin marketplace add foxhatleo/leos-agent
569
- ```
570
-
571
- **OpenCode.** The existing `"leos-agent"` plugin entry stays valid; clear the
572
- cache so it refetches v10.
201
+ Guard modes are `LEOS_AGENT_DISPATCH_GUARD=on` (default), `warn` (log proposed
202
+ corrections/blocks), and `off`. Unrelated tools and third-party MCP tools are
203
+ not routed. Failures are logged distinctly and fail open; this is not a
204
+ security boundary. Native or organization-level model substitutions may still
205
+ require investigation of actual execution.
573
206
 
574
- **Leftover files.** v8 wrote `*.leo-backup` files next to the instruction files
575
- it touched. v10 does not create backups — the block replacement is surgical, and
576
- `--dry-run` shows you any change before it happens. These are safe to delete:
207
+ ## Workflows and diagnostics
577
208
 
578
- ```bash
579
- rm -f ~/.claude/CLAUDE.md.leo-backup ~/.codex/AGENTS.md.leo-backup ~/.config/opencode/AGENTS.md.leo-backup
580
- ```
581
-
582
- ---
583
-
584
- ## Extending it
585
-
586
- The repo root is the plugin. Each harness reads its own manifest from the same
587
- tree, and the three payload directories are shared between them.
588
-
589
- **Skills** live in `skills/<name>/SKILL.md`, or `skills-claude/<name>/SKILL.md`
590
- for one only Claude Code can use; commands mirror that with `commands/` and
591
- `commands-claude/`. The two `-claude` directories are listed in
592
- `.claude-plugin/plugin.json` and nowhere else. Keep the frontmatter of a
593
- portable skill to `name` and `description`, plus
594
- `disable-model-invocation: true` on a skill that must never fire on its own.
595
- Codex uses the matching sibling `agents/openai.yaml` with
596
- `policy.allow_implicit_invocation: false`; harnesses without a control for it
597
- get the constraint stated in the description. That subset is what all five skill-loading harnesses accept, and
598
- anything richer will parse on Claude Code and be ignored or rejected elsewhere.
599
- Claude Code, Codex, Cursor, and Pi load `skills/` straight from their manifests;
600
- OpenCode gets a copy from the installer.
601
-
602
- **Commands** live in `commands/<name>.md`. Claude Code and Cursor read the
603
- directory from their manifests; OpenCode gets a copy. Codex dropped custom
604
- prompts in favour of skills, so add a skill there instead.
605
-
606
- ### Two conventions, both enforced by `scripts/check.py`
607
-
608
- **Progressive disclosure.** `SKILL.md` is the *dispatch contract* — what the
609
- main thread does. The procedure a subagent follows goes in
610
- `skills/<name>/reference/*.md`, which the brief points at by path. `review-pr`
611
- is the worked example: the main thread loads a 3.2 KB contract, the reviewer
612
- subagent reads `reference/procedure.md`, and the lens sub-subagents read
613
- `reference/lenses.md` that the reviewer itself never loads. Before the split the
614
- main thread and the reviewer each loaded the same 21 KB file, and every turn
615
- after that re-read it. `tune-routing` does the same with its per-harness model
616
- discovery, in `reference/harnesses.md`, which only a run that actually tunes
617
- ever loads. Split a file out only when some run genuinely does not read it;
618
- moving prose around costs the same tokens.
619
-
620
- **Invocation split.** A skill is either *user-invoked* — reached by typing its
621
- slash command, and carrying `disable-model-invocation: true` — or *deliberately
622
- model-invocable*, reached when the model decides the task fits. On Claude Code
623
- the flag also drops the skill's description from the always-loaded skill
624
- listing, which is the larger saving: a description is context in every session,
625
- invoked or not. Only `review-pr` and `handon` are model-invocable here, because
626
- they are the two you would phrase in words ("review PR 41", "pick up where I
627
- left off") rather than by name; `check.py` fails the build on any other skill
628
- that omits the flag. A user-invoked skill may invoke a model-invoked one, but
629
- never chains another user-invoked skill.
630
-
631
- A description says **when to reach for this** and **what it is not** — never how
632
- the skill works. The mechanism is what the body is for, and every word of it in
633
- the description is paid for in sessions that never invoke the skill.
634
-
635
- **Hooks** live in `hooks/`, wired but empty — v10 enforces its policy through
636
- the payload rather than by intercepting tool calls. There are two files because
637
- the formats genuinely differ: `hooks.json` (PascalCase events) serves Claude
638
- Code and Codex, which both auto-load it and must never name it in their
639
- manifests, and `hooks-cursor.json` (camelCase, `version: 1`) serves Cursor,
640
- which does name it. See [`hooks/README.md`](hooks/README.md) for how to add one,
641
- including the Hermes, OpenCode, and Pi equivalents, which are code rather than
642
- JSON.
643
-
644
- ## Development
645
-
646
- Run the checks:
647
-
648
- ```bash
209
+ | Skill | Purpose |
210
+ |---|---|
211
+ | install | Configure this harness's native artifacts; preview/check/uninstall/rollback. |
212
+ | doctor | Check installation, pricing, model references, and runtime evidence without paid calls. |
213
+ | tune-routing | Configure tiers and diagnose actual native model selection. |
214
+ | review-usage | Mechanical usage scan with reference-cost estimates and explicit gaps. |
215
+ | review-pr | Review a pinned GitHub PR; stage comments/replies as pending. |
216
+ | handoff / handon | Save concise context pointers and resume after checking drift. |
217
+ | watch-review | Claude Monitor watcher: code polls GitHub; models run only for eligible reviews. |
218
+ | attach-pr | Claude-specific attachment of an existing PR to the desktop session. |
219
+
220
+ Only small routing instructions and necessary metadata are always present.
221
+ Detailed review procedures remain in deferred reference files. Duplicate
222
+ slash-command wrappers are removed; native skills provide invocation. Explicit
223
+ invocation controls do not universally imply hidden metadata—measure both.
224
+
225
+ ```sh
226
+ python3 scripts/doctor.py --harness claude --json
227
+ python3 scripts/usage_scan.py --since 7d --harness claude --json
228
+ python3 scripts/dispatch_log.py report
229
+ python3 scripts/measure_context.py --check
230
+ python3 scripts/pricing.py resolve claude-sonnet-5
231
+ ```
232
+
233
+ Default policy bodies are about 1.8–2.0 KB, with a 2.2 KB component budget.
234
+ Measurement counts metadata separately and treats bytes/4 only as a rough
235
+ prose-token proxy. Harness wrappers, history, tools, cache behavior, and child
236
+ work are outside that static measurement. No assertion is made that instruction
237
+ overhead always pays for itself.
238
+
239
+ Usage scanning handles Claude streaming duplicates, Codex cumulative/cache
240
+ accounting, and OpenCode message-time usage. Cursor/Hermes/Pi usage schemas are
241
+ currently unsupported and reported that way. Reference prices are not bills;
242
+ unknown cache/model costs remain explicit. Compaction pre-context counts are
243
+ not discarded tokens. Requested/corrected/blocked dispatches are distinct from
244
+ observed child models. Missing/rotated logs do not prove a broken install.
245
+
246
+ PR review pins the full head SHA; it never silently moves line anchors or
247
+ retries old findings against a new head. Replacing a pending review requires
248
+ an unchanged ownership receipt and saves recovery data. New comments/replies
249
+ remain pending. Only verified addressed threads rooted by the authenticated
250
+ user can be auto-resolved; resolution is public and requires SHA-bound evidence.
251
+ Watchers use cross-process leases, bounded retries, and completion reports;
252
+ emission alone never records a PR as reviewed.
253
+
254
+ Logs omit prompt text by default and rotate at 1 MiB plus one retained file.
255
+ `LEOS_AGENT_DISPATCH_LOG_PROMPTS=1` is an explicit debug option that retains
256
+ brief excerpts; avoid it for sensitive work. Installation backups and handoffs
257
+ stay local. Handoff names are validated, reservations avoid collisions, and
258
+ symlink escapes are refused by the helper.
259
+
260
+ ## Development and releases
261
+
262
+ ```sh
263
+ LEOS_AGENT_PRICE_REFRESH=off PYTHONDONTWRITEBYTECODE=1 python3 -m unittest discover -s tests
264
+ node --test tests/js/*.test.js
649
265
  python3 scripts/check.py
650
- ```
651
-
652
- The structural check asserts that the version matches across every manifest,
653
- the marketplace entry, and this README; that each manifest carries what its
654
- harness requires and every declared path exists; that both hook files parse in
655
- their own format; and that injection is idempotent, uninstall round-trips, and
656
- malformed markers are refused.
657
-
658
- Run the behavioral tests:
659
-
660
- ```bash
661
- python3 -m unittest discover -s tests -v
662
- ```
663
-
664
- Measure the repository-controlled static prompt footprint and enforce its
665
- committed ceilings:
666
-
667
- ```bash
668
266
  python3 scripts/measure_context.py --check
669
267
  ```
670
268
 
671
- The measurement is a byte-based proxy for always-listed or dispatch-loaded
672
- text. It deliberately does not claim to measure total task tokens or credits,
673
- which also depend on conversation history, cache state, tool output, and the
674
- number and model of spawned agents.
675
-
676
- Preview any install without writing:
677
-
678
- ```bash
679
- python3 scripts/leo-install.py <harness> --dry-run
680
- ```
681
-
682
- **Both Claude Code and Codex cache a plugin by version**, so reinstalling while
683
- the version is unchanged is a no-op and quietly leaves the old code in place —
684
- you will be testing the previous build without being told. While iterating,
685
- either uninstall and reinstall:
686
-
687
- ```bash
688
- claude plugin uninstall leos-agent@leos-agent && claude plugin install leos-agent@leos-agent --scope user
689
- ```
690
-
691
- or replace the cachebuster suffix in the Codex manifest with one in the form
692
- `10.7.2+codex.local-YYYYMMDD-HHMMSS` and re-add. Either way, plugin changes only
693
- reach a **new** session or thread.
694
-
695
- `--check` exits non-zero when a file is out of date, and `--force` replaces a
696
- copied file that something else has since overwritten.
697
-
698
- To release: bump the version in `package.json`, the three `plugin.json` files,
699
- `.claude-plugin/marketplace.json`, `plugin.yaml`, and every mention in this
700
- README (the uninstall commands embed it in cache paths — `check.py` fails on any
701
- stale one); run `scripts/check.py`; then push a `v`-prefixed tag.
702
-
703
- Pushing that tag is the whole release. `.github/workflows/release.yml` runs the
704
- tests and both checks, refuses a tag that disagrees with `package.json`,
705
- inspects the tree npm would ship, and publishes to npm for OpenCode. It
706
- authenticates by OIDC trusted publishing, so there is no token in the repository
707
- — npm's configuration names this workflow by path, and renaming the file breaks
708
- publishing until npm is updated to match. Publishing is idempotent: a version
709
- already on the registry is a no-op, and a lookup that fails for any reason other
710
- than a confirmed 404 aborts rather than assuming the version is absent.
711
-
712
- Check what a publish would contain, without publishing:
713
-
714
- ```bash
715
- python3 scripts/publish-npm.py --dry-run
716
- ```
717
-
718
- MIT licensed.
269
+ Tests use fixtures and mock provider events; CI makes no paid model calls.
270
+ Native live smoke tests are separate, explicitly authorized, and budgeted.
271
+ Static/adapter tests establish contracts, not complete end-to-end parity on
272
+ all six installed harnesses.
273
+
274
+ Commits run validation only. Release versions use `12.YYYYMMDDXX.0`, with a UTC
275
+ calendar date and a two-digit serial from 00 to 99. Run `scripts/bump.py` only
276
+ when preparing a release, validate all manifests/package contents, commit on
277
+ main, and publish the matching tag through the release workflow. npm publishing
278
+ uses its existing trusted-publishing workflow. An ordinary code commit never
279
+ automatically changes versions or stages unrelated files.
280
+
281
+ Native references: [Claude subagents](https://code.claude.com/docs/en/sub-agents),
282
+ [Codex subagents](https://learn.chatgpt.com/docs/agent-configuration/subagents),
283
+ [Codex hooks](https://learn.chatgpt.com/docs/hooks),
284
+ [Cursor plugins](https://cursor.com/docs/reference/plugins),
285
+ [OpenCode plugins](https://opencode.ai/docs/plugins/),
286
+ [Hermes hooks](https://github.com/NousResearch/hermes-agent/blob/main/website/docs/user-guide/features/hooks.md),
287
+ [Pi extensions](https://github.com/badlogic/pi-mono/blob/main/packages/coding-agent/docs/extensions.md).