leos-agent 7.0.0 → 10.2.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 (96) hide show
  1. package/README.md +544 -28
  2. package/commands/handoff.md +11 -0
  3. package/commands/handon.md +10 -0
  4. package/commands/review-pr.md +9 -0
  5. package/commands-claude/watch-review.md +9 -0
  6. package/index.js +12 -0
  7. package/package.json +29 -14
  8. package/payload/codex-agents/leo-executor.toml +36 -0
  9. package/payload/codex-agents/leo-runner.toml +28 -0
  10. package/rules/preferences.md +97 -0
  11. package/scripts/check.py +244 -0
  12. package/scripts/ghreview.py +17 -3
  13. package/scripts/handoff.py +183 -0
  14. package/scripts/leo-install.py +509 -0
  15. package/scripts/measure_context.py +113 -0
  16. package/scripts/publish-npm.py +138 -0
  17. package/scripts/watch_review.py +169 -0
  18. package/skills/doctor/SKILL.md +73 -115
  19. package/skills/doctor/agents/openai.yaml +5 -0
  20. package/skills/handoff/SKILL.md +99 -0
  21. package/skills/handoff/agents/openai.yaml +5 -0
  22. package/skills/handon/SKILL.md +61 -0
  23. package/skills/install/SKILL.md +79 -0
  24. package/skills/install/agents/openai.yaml +5 -0
  25. package/skills/review-pr/SKILL.md +59 -318
  26. package/skills/review-pr/reference/lenses.md +67 -0
  27. package/skills/review-pr/reference/procedure.md +348 -0
  28. package/skills-claude/attach-pr/SKILL.md +178 -0
  29. package/skills-claude/watch-review/SKILL.md +91 -0
  30. package/adapters/cursor/agents/executor.md +0 -17
  31. package/adapters/cursor/agents/expert.md +0 -70
  32. package/adapters/cursor/agents/explore.md +0 -16
  33. package/adapters/cursor/agents/implementer.md +0 -18
  34. package/adapters/cursor/agents/investigator.md +0 -18
  35. package/adapters/cursor/agents/planner.md +0 -28
  36. package/adapters/cursor/agents/review-lens.md +0 -22
  37. package/adapters/cursor/agents/reviewer.md +0 -34
  38. package/adapters/opencode/agents.json +0 -105
  39. package/adapters/opencode/plugin.js +0 -576
  40. package/config/MCP_PINS.md +0 -17
  41. package/config/models.json +0 -676
  42. package/hooks/bash-guard.py +0 -583
  43. package/hooks/cursor-guard.py +0 -84
  44. package/hooks/hooks-cursor.json +0 -11
  45. package/hooks/hooks.json +0 -20
  46. package/hooks/session-start.py +0 -148
  47. package/roles/executor.md +0 -15
  48. package/roles/expert.md +0 -67
  49. package/roles/explore.md +0 -13
  50. package/roles/implementer.md +0 -16
  51. package/roles/investigator.md +0 -15
  52. package/roles/planner.md +0 -25
  53. package/roles/review-lens.md +0 -20
  54. package/roles/reviewer.md +0 -31
  55. package/scripts/doctor.py +0 -520
  56. package/scripts/jsonc_bridge.cjs +0 -23
  57. package/scripts/memory.py +0 -744
  58. package/scripts/render_adapters.py +0 -508
  59. package/scripts/setup.py +0 -1753
  60. package/settings.json +0 -7
  61. package/skills/.gitkeep +0 -0
  62. package/skills/brainstorming/SKILL.md +0 -111
  63. package/skills/debugging/SKILL.md +0 -100
  64. package/skills/delegation/SKILL.md +0 -143
  65. package/skills/executing-plans/SKILL.md +0 -117
  66. package/skills/finishing-a-branch/SKILL.md +0 -125
  67. package/skills/freshness/SKILL.md +0 -131
  68. package/skills/memory/SKILL.md +0 -154
  69. package/skills/resolve-ticket/SKILL.md +0 -275
  70. package/skills/setup/SKILL.md +0 -199
  71. package/skills/setup/agents/openai.yaml +0 -5
  72. package/skills/test-first/SKILL.md +0 -92
  73. package/skills/using-leo/SKILL.md +0 -101
  74. package/skills/using-leo/references/claude-mapping.md +0 -33
  75. package/skills/using-leo/references/codex-mapping.md +0 -33
  76. package/skills/using-leo/references/cursor-mapping.md +0 -35
  77. package/skills/using-leo/references/hermes-mapping.md +0 -37
  78. package/skills/using-leo/references/opencode-mapping.md +0 -39
  79. package/skills/verification/SKILL.md +0 -110
  80. package/skills/visual-verification/SKILL.md +0 -115
  81. package/skills/watch-review/SKILL.md +0 -128
  82. package/skills/watch-review/agents/openai.yaml +0 -5
  83. package/skills/worktrees/SKILL.md +0 -131
  84. package/skills/writing-plans/SKILL.md +0 -97
  85. package/skills/writing-skills/SKILL.md +0 -141
  86. package/vendor/jsonc-parser-3.3.1/LICENSE.md +0 -21
  87. package/vendor/jsonc-parser-3.3.1/README.md +0 -26
  88. package/vendor/jsonc-parser-3.3.1/lib/umd/impl/edit.js +0 -201
  89. package/vendor/jsonc-parser-3.3.1/lib/umd/impl/format.js +0 -275
  90. package/vendor/jsonc-parser-3.3.1/lib/umd/impl/parser.js +0 -682
  91. package/vendor/jsonc-parser-3.3.1/lib/umd/impl/scanner.js +0 -456
  92. package/vendor/jsonc-parser-3.3.1/lib/umd/impl/string-intern.js +0 -42
  93. package/vendor/jsonc-parser-3.3.1/lib/umd/main.d.ts +0 -351
  94. package/vendor/jsonc-parser-3.3.1/lib/umd/main.js +0 -194
  95. package/vendor/jsonc-parser-3.3.1/package.json +0 -37
  96. package/workflows/cost-tiered-fix.js +0 -287
package/README.md CHANGED
@@ -1,50 +1,566 @@
1
- <!-- Generated by scripts/render_adapters.py; do not edit. -->
1
+ # leos-agent
2
2
 
3
- # Leo's Agent
3
+ Leo's portable agent operating policy, version **10.2.0**, installable on Claude
4
+ Code, Codex, Cursor, Hermes, Pi, and OpenCode through each harness's own plugin
5
+ system.
4
6
 
5
- Leo's Agent is a portable operating policy with cost-tiered routing, specialist roles, process skills, review discipline, and a narrow command guard. This npm package is the **OpenCode** distribution; use the [repository](https://github.com/foxhatleo/leos-agent) for Claude Code, Codex, Cursor, and Hermes instructions.
7
+ The policy it carries is short: **the main thread is an orchestrator.**
8
+ Investigation, brainstorming, debugging, execution, testing, and mechanical work
9
+ all run in briefed subagents, so the main thread never fills up with the files,
10
+ retries, and logs that produced an answer — only the answer. Work runs at one of two
11
+ named tiers: **standard**, the model you are already using, for thinking and
12
+ judging; **economical**, the cheapest sufficient profile where the harness can
13
+ select one. Narrow search, reading, testing, and mechanical work use the runner
14
+ profile; well-specified implementation uses the executor profile.
6
15
 
7
- Supported hosts are macOS, Linux, and WSL with Python 3.9+; native Windows is unsupported.
16
+ ## What it ships
8
17
 
9
- ## Install and update
18
+ Beyond the preferences payload: a setup diagnostic, a session handoff pair, and
19
+ three GitHub skills. The GitHub ones need `gh`, authenticated.
10
20
 
11
- ```sh
12
- opencode plugin leos-agent --global
21
+ | Skill | What it does | Where |
22
+ |---|---|---|
23
+ | `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 |
24
+ | `watch-review` | Arms a watcher that streams new direct review requests into the session, one notification per pull request, for `review-pr` to handle. 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 |
25
+ | `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 |
26
+ | `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 |
27
+ | `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 |
28
+ | `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 |
29
+
30
+ The Claude-only pair live in `skills-claude/` and `commands-claude/`, listed in
31
+ `.claude-plugin/plugin.json` and nowhere else. Hermes receives the preferences
32
+ payload but no skills — it has no skill loader.
33
+
34
+ The watcher records each reviewed pull request under `~/.leos-agent-local/`
35
+ (override with `$LEOS_AGENT_LOCAL_PATH`), so it never surfaces the same one
36
+ twice; `watch_review.py forget <n>` puts one back in play.
37
+
38
+ Handoffs live in the same place, under `handoffs/`. Nothing there is ever pruned
39
+ automatically: `handoff.py list [--all]` shows what exists and `handoff.py rm
40
+ <name>` is the only way one goes away. The directory is deliberately outside
41
+ the plugin, so upgrading or reinstalling can never take state with it.
42
+
43
+ ## How it works
44
+
45
+ The payload lives in exactly one file: [`rules/preferences.md`](rules/preferences.md).
46
+
47
+ Cursor reads that file natively as an always-apply rule. Every other harness
48
+ gets it through its global instruction file, written by
49
+ [`scripts/leo-install.py`](scripts/leo-install.py) into a marker block:
50
+
51
+ ```
52
+ <leos-agent version="10.2.0">
53
+ ...the payload...
54
+ </leos-agent>
13
55
  ```
14
56
 
15
- On builds without that subcommand, add `leos-agent` to the `plugin` array in `~/.config/opencode/opencode.json` or `opencode.jsonc`:
57
+ Updating replaces that block and nothing else, so anything you wrote in those
58
+ files by hand survives an upgrade untouched. The script writes only when the
59
+ bytes actually differ, so running it twice is a no-op, and it writes through a
60
+ temporary file and an atomic rename, so an interrupted run cannot leave a
61
+ half-written instruction file behind.
62
+
63
+ If it ever finds markers it cannot pair — an opener with no closer, a stray
64
+ closer, two blocks — it refuses to touch that file and tells you what to fix.
65
+ Guessing there would mean deleting whatever sits between the markers, which is
66
+ exactly the content it exists to protect.
67
+
68
+ | Harness | Global file the installer writes |
69
+ |---|---|
70
+ | Claude Code | `~/.claude/CLAUDE.md` |
71
+ | Codex | `~/.codex/AGENTS.md` (plus `~/.codex/agents/leo-runner.toml` and `leo-executor.toml`) |
72
+ | Cursor | none — the plugin's always-apply rule delivers it |
73
+ | Hermes | `~/.hermes/SOUL.md` (edited only if it already exists) |
74
+ | Pi | `~/.pi/agent/AGENTS.md` |
75
+ | OpenCode | `~/.config/opencode/AGENTS.md` (plus copied skills and commands) |
76
+
77
+ **The installer is per-harness and manual.** Running it inside Codex installs Codex and
78
+ nothing else; it never writes to another harness's files behind your back, and
79
+ it never runs on its own at session start. Install the plugin, then run the
80
+ installer once in that harness.
16
81
 
17
- ```json
18
- { "$schema": "https://opencode.ai/config.json", "plugin": ["leos-agent"] }
82
+ Requires Python 3.9+ and macOS, Linux, or WSL. No symlinks are used anywhere —
83
+ installs are real clones and copies.
84
+
85
+ ---
86
+
87
+ ## Claude Code
88
+
89
+ **Install**
90
+
91
+ ```bash
92
+ claude plugin marketplace add foxhatleo/leos-agent
93
+ ```
94
+
95
+ ```bash
96
+ claude plugin install leos-agent@leos-agent --scope user
19
97
  ```
20
98
 
21
- Run `opencode auth login` and choose OpenRouter before using the mapped models; Leo never writes provider credentials. Update with `opencode plugin leos-agent --global --force`, then start a new session. OpenCode currently has no plugin removal command; remove the `leos-agent` configuration entry to uninstall.
99
+ Then, in a Claude Code session, run `/install` (or ask it to use the `install`
100
+ skill). That writes the block into `~/.claude/CLAUDE.md`.
22
101
 
23
- The plugin registers generated shadow skills (`leo-<name>`) and namespaced `leo-<role>` agents (7 generated definitions) from `adapters/opencode/agents.json`, then injects the operating policy through OpenCode's configuration. Invoke its shadow skill as `leo-using-leo`. If a skill is absent, run `opencode debug skill`; its `location` should be an `opencode-skills-<hash>/leo-<name>/` directory under machine-local state, not a hand-written package path.
102
+ **Upgrade**
24
103
 
25
- ## MCP and durable state
104
+ ```bash
105
+ claude plugin marketplace update leos-agent
106
+ ```
26
107
 
27
- Use `leo-setup` to inspect or explicitly configure MCP services: `connectors` reports without writing, while `connect` and `apply` make only reviewed, harness-owned changes. Vendor connectors are never installed automatically and OAuth stays in OpenCode. Slack, Gmail, Drive, and providers without dynamic registration remain manual-only.
108
+ ```bash
109
+ claude plugin install leos-agent@leos-agent --scope user
110
+ ```
28
111
 
29
- Uninstall preserves `${LEOS_AGENT_LOCAL_PATH:-$HOME/.leos-agent-local}`. Before a full purge, export or copy that directory; only then explicitly remove it. For a 7.0 recovery, move old `LEOS_AGENT_PATH/local/` data there, rename the variable, restart, and run `leo-doctor`.
112
+ Re-run `/install` afterwards to refresh the block, then start a new session.
113
+ Both commands are safe to repeat; installing an already-current version reports
114
+ that it is already installed and changes nothing.
30
115
 
31
- ## Model tiers
116
+ **Uninstall**
32
117
 
33
- Tier names describe the kind of work, not a fixed provider model.
118
+ Run the installer's uninstall first, while the script is still on disk:
34
119
 
35
- | Tier | Model | Effort |
36
- |---|---|---|
37
- | Fable | `moonshotai/kimi-k3` | native default |
38
- | Opus | `moonshotai/kimi-k3` | native default |
39
- | Sonnet | `z-ai/glm-5.2` | native default |
40
- | Haiku | `z-ai/glm-5.2` | native default |
120
+ ```bash
121
+ python3 ~/.claude/plugins/cache/leos-agent/leos-agent/10.2.0/scripts/leo-install.py claude --uninstall
122
+ ```
123
+
124
+ ```bash
125
+ claude plugin uninstall leos-agent@leos-agent
126
+ ```
127
+
128
+ Optionally drop the marketplace too:
129
+
130
+ ```bash
131
+ claude plugin marketplace remove leos-agent
132
+ ```
133
+
134
+ ---
135
+
136
+ ## Codex
137
+
138
+ **Install**
139
+
140
+ ```bash
141
+ codex plugin marketplace add foxhatleo/leos-agent
142
+ ```
143
+
144
+ ```bash
145
+ codex plugin add leos-agent@leos-agent
146
+ ```
147
+
148
+ Then run the `install` skill in a Codex session (`$leos-agent`, then `install`), or
149
+ run the script directly:
150
+
151
+ ```bash
152
+ python3 ~/.codex/plugins/cache/leos-agent/leos-agent/10.2.0/scripts/leo-install.py codex
153
+ ```
154
+
155
+ This writes `~/.codex/AGENTS.md` and installs two economical agents:
156
+ `leo-runner` (`gpt-5.6-luna`, low effort) for narrow repeatable work and
157
+ `leo-executor` (`gpt-5.6-terra`, medium effort) for well-specified
158
+ implementation. Codex plugins cannot ship agent definitions themselves, which
159
+ is why the installer writes them.
160
+
161
+ **Upgrade**
162
+
163
+ ```bash
164
+ codex plugin marketplace upgrade leos-agent
165
+ ```
166
+
167
+ ```bash
168
+ codex plugin add leos-agent@leos-agent
169
+ ```
170
+
171
+ Re-run the installer, then start a new thread — Codex picks up plugin changes on new
172
+ threads only. Re-adding an already-installed plugin is idempotent.
173
+
174
+ **Uninstall**
175
+
176
+ ```bash
177
+ python3 ~/.codex/plugins/cache/leos-agent/leos-agent/10.2.0/scripts/leo-install.py codex --uninstall
178
+ ```
179
+
180
+ ```bash
181
+ codex plugin remove leos-agent@leos-agent
182
+ ```
183
+
184
+ ```bash
185
+ codex plugin marketplace remove leos-agent
186
+ ```
187
+
188
+ ---
189
+
190
+ ## Cursor
191
+
192
+ Cursor has no on-disk global rules file — its User Rules live in your synced
193
+ Cursor account — so there is nothing for the installer to write. The plugin ships the
194
+ payload as an always-apply rule instead, which takes effect as soon as the
195
+ plugin is installed.
196
+
197
+ **Install** — either through the UI, or as a local clone.
198
+
199
+ In the IDE: open the **Customize** sidebar, add the marketplace
200
+ `foxhatleo/leos-agent`, and install **Leo's Agent** at user scope.
201
+
202
+ Or clone it into Cursor's local plugin directory (a clone, not a symlink):
203
+
204
+ ```bash
205
+ git clone https://github.com/foxhatleo/leos-agent ~/.cursor/plugins/local/leos-agent
206
+ ```
207
+
208
+ Cursor does not currently expose a reliable non-interactive per-plugin install
209
+ command, so those two paths are the supported ones.
210
+
211
+ **Upgrade**
212
+
213
+ Refresh the marketplace from the Customize panel, or for a local clone:
214
+
215
+ ```bash
216
+ git -C ~/.cursor/plugins/local/leos-agent pull
217
+ ```
218
+
219
+ **Uninstall**
220
+
221
+ Remove the plugin from the Customize panel, or delete the clone:
222
+
223
+ ```bash
224
+ rm -rf ~/.cursor/plugins/local/leos-agent
225
+ ```
226
+
227
+ There is no block to remove — nothing was written outside the plugin directory.
228
+
229
+ ---
230
+
231
+ ## Hermes
232
+
233
+ **Install**
234
+
235
+ If the plugin resolves through the community index:
236
+
237
+ ```bash
238
+ hermes plugins install leos-agent
239
+ ```
240
+
241
+ Otherwise clone it into the Hermes plugin directory:
242
+
243
+ ```bash
244
+ git clone https://github.com/foxhatleo/leos-agent ~/.hermes/plugins/leos-agent
245
+ ```
246
+
247
+ Hermes plugins are opt-in, so enable it by adding `leos-agent` to
248
+ `plugins.enabled` in `~/.hermes/config.yaml`:
249
+
250
+ ```yaml
251
+ plugins:
252
+ enabled:
253
+ - leos-agent
254
+ ```
255
+
256
+ **Run Hermes once before installing.** The payload goes into `~/.hermes/SOUL.md`,
257
+ the agent's identity prompt, and Hermes writes its own starter version of that
258
+ file on first run. The installer deliberately never creates it — if `SOUL.md` is
259
+ missing it reports `skipped` and leaves Hermes' bootstrap alone. Once it exists:
260
+
261
+ ```bash
262
+ /leo-install
263
+ ```
264
+
265
+ **Upgrade**
266
+
267
+ ```bash
268
+ hermes plugins update leos-agent
269
+ ```
270
+
271
+ or, for a clone:
272
+
273
+ ```bash
274
+ git -C ~/.hermes/plugins/leos-agent pull
275
+ ```
276
+
277
+ Then re-run `/leo-install`.
278
+
279
+ **Uninstall**
280
+
281
+ ```bash
282
+ python3 ~/.hermes/plugins/leos-agent/scripts/leo-install.py hermes --uninstall
283
+ ```
41
284
 
42
- Fable is not a real rung here, so `expert` is not registered as an agent and escalation caps at Opus. Retier by editing `config/models.json` and re-running `scripts/render_adapters.py`.
285
+ ```bash
286
+ hermes plugins remove leos-agent
287
+ ```
288
+
289
+ Remove the `leos-agent` entry from `plugins.enabled`, and delete the clone if
290
+ you made one. Your own `SOUL.md` content is left intact — only the block goes.
291
+
292
+ **Note on model routing:** Hermes applies a single `delegation.model` to every
293
+ child of a `delegate_task` call, so it cannot vary the model per spawn. The
294
+ policy therefore routes all Hermes work to the current model.
295
+
296
+ ---
297
+
298
+ ## Pi
299
+
300
+ **Install**
301
+
302
+ ```bash
303
+ pi install git:github.com/foxhatleo/leos-agent
304
+ ```
305
+
306
+ Then run the install skill in a pi session:
307
+
308
+ ```
309
+ /skill:install
310
+ ```
311
+
312
+ Pi pins the git ref it installed and records the package in
313
+ `~/.pi/agent/settings.json`; re-running install is idempotent.
314
+
315
+ **Upgrade**
316
+
317
+ ```bash
318
+ pi update git:github.com/foxhatleo/leos-agent
319
+ ```
320
+
321
+ Pinned refs are reconciled, never silently advanced — to move to a new tag,
322
+ install it explicitly:
323
+
324
+ ```bash
325
+ pi install git:github.com/foxhatleo/leos-agent@v10.2.0
326
+ ```
327
+
328
+ Re-run `/skill:install` afterwards.
329
+
330
+ **Uninstall**
331
+
332
+ ```bash
333
+ python3 ~/.pi/agent/git/github.com/foxhatleo/leos-agent/scripts/leo-install.py pi --uninstall
334
+ ```
335
+
336
+ ```bash
337
+ pi remove git:github.com/foxhatleo/leos-agent
338
+ ```
339
+
340
+ ---
341
+
342
+ ## OpenCode
343
+
344
+ OpenCode loads plugins as npm packages, so this one is published to npm as
345
+ `leos-agent`.
346
+
347
+ **Install**
348
+
349
+ ```bash
350
+ opencode plugin leos-agent -g
351
+ ```
352
+
353
+ That adds the package to the `plugin` array in `~/.config/opencode/opencode.json`
354
+ (or `.jsonc`) and caches it. Bootstrap the installer once by running the script from
355
+ the cache — OpenCode's plugin API cannot register skills or commands, so the
356
+ first run has to come from the package itself:
357
+
358
+ ```bash
359
+ python3 ~/.cache/opencode/packages/leos-agent@latest/node_modules/leos-agent/scripts/leo-install.py opencode
360
+ ```
361
+
362
+ That writes `~/.config/opencode/AGENTS.md` and copies the skills and commands into
363
+ `~/.config/opencode/skills/` and `~/.config/opencode/commands/`. From then on
364
+ `/leo-install` works inside OpenCode.
365
+
366
+ **Upgrade**
367
+
368
+ ```bash
369
+ opencode plugin leos-agent -g -f
370
+ ```
371
+
372
+ If the cache holds a stale copy, clear it and let OpenCode refetch:
373
+
374
+ ```bash
375
+ rm -rf ~/.cache/opencode/packages/leos-agent@*
376
+ ```
377
+
378
+ Re-run the bootstrap install command above to refresh the copied files.
379
+
380
+ **Uninstall**
381
+
382
+ ```bash
383
+ python3 ~/.cache/opencode/packages/leos-agent@latest/node_modules/leos-agent/scripts/leo-install.py opencode --uninstall
384
+ ```
385
+
386
+ OpenCode has no plugin-remove command, so delete the `"leos-agent"` entry from
387
+ the `plugin` array in `~/.config/opencode/opencode.json` **by hand**. The installer
388
+ never edits that file: it is JSONC, with your comments in it, and rewriting it
389
+ would destroy them. Then clear the cache:
390
+
391
+ ```bash
392
+ rm -rf ~/.cache/opencode/packages/leos-agent@*
393
+ ```
394
+
395
+ ---
396
+
397
+ ## Migrating from v8
398
+
399
+ Version 10 renames the plugin from `leo` to `leos-agent`, so the old install
400
+ does not upgrade in place — remove it first. Most skills that were invoked
401
+ as `leo:<name>` are gone; v10 ships a deliberately lean payload plus the three
402
+ GitHub skills above, now unprefixed (`review-pr`, not `leo:review-pr`). The
403
+ watcher no longer runs under `/loop`: it is a shell process streaming into
404
+ Claude Code's Monitor tool, so idle polling costs nothing.
405
+
406
+ **Claude Code.** The old plugin will show as `failed to load` once the
407
+ marketplace points at v10 (`Plugin leo not found in marketplace leos-agent`).
408
+ Remove it:
409
+
410
+ ```bash
411
+ claude plugin uninstall leo@leos-agent
412
+ ```
413
+
414
+ **Codex.** The v8 marketplace entry is pinned to an old commit, and Codex
415
+ refuses to re-add a marketplace from a different source. Remove and re-add:
416
+
417
+ ```bash
418
+ codex plugin marketplace remove leos-agent && codex plugin marketplace add foxhatleo/leos-agent
419
+ ```
420
+
421
+ **OpenCode.** The existing `"leos-agent"` plugin entry stays valid; clear the
422
+ cache so it refetches v10.
423
+
424
+ **Leftover files.** v8 wrote `*.leo-backup` files next to the instruction files
425
+ it touched. v10 does not create backups — the block replacement is surgical, and
426
+ `--dry-run` shows you any change before it happens. These are safe to delete:
427
+
428
+ ```bash
429
+ rm -f ~/.claude/CLAUDE.md.leo-backup ~/.codex/AGENTS.md.leo-backup ~/.config/opencode/AGENTS.md.leo-backup
430
+ ```
431
+
432
+ ---
433
+
434
+ ## Extending it
435
+
436
+ The repo root is the plugin. Each harness reads its own manifest from the same
437
+ tree, and the three payload directories are shared between them.
438
+
439
+ **Skills** live in `skills/<name>/SKILL.md`, or `skills-claude/<name>/SKILL.md`
440
+ for one only Claude Code can use; commands mirror that with `commands/` and
441
+ `commands-claude/`. The two `-claude` directories are listed in
442
+ `.claude-plugin/plugin.json` and nowhere else. Keep the frontmatter of a
443
+ portable skill to `name` and `description`, plus
444
+ `disable-model-invocation: true` on a skill that must never fire on its own.
445
+ Codex uses the matching sibling `agents/openai.yaml` with
446
+ `policy.allow_implicit_invocation: false`; harnesses without a control for it
447
+ get the constraint stated in the description. That subset is what all five skill-loading harnesses accept, and
448
+ anything richer will parse on Claude Code and be ignored or rejected elsewhere.
449
+ Claude Code, Codex, Cursor, and Pi load `skills/` straight from their manifests;
450
+ OpenCode gets a copy from the installer.
451
+
452
+ **Commands** live in `commands/<name>.md`. Claude Code and Cursor read the
453
+ directory from their manifests; OpenCode gets a copy. Codex dropped custom
454
+ prompts in favour of skills, so add a skill there instead.
455
+
456
+ ### Two conventions, both enforced by `scripts/check.py`
457
+
458
+ **Progressive disclosure.** `SKILL.md` is the *dispatch contract* — what the
459
+ main thread does. The procedure a subagent follows goes in
460
+ `skills/<name>/reference/*.md`, which the brief points at by path. `review-pr`
461
+ is the worked example: the main thread loads a 3.2 KB contract, the reviewer
462
+ subagent reads `reference/procedure.md`, and the lens sub-subagents read
463
+ `reference/lenses.md` that the reviewer itself never loads. Before the split the
464
+ main thread and the reviewer each loaded the same 21 KB file, and every turn
465
+ after that re-read it. Split a file out only when some run genuinely does not
466
+ read it; moving prose around costs the same tokens.
467
+
468
+ **Invocation split.** A skill is either *user-invoked* — reached by typing its
469
+ slash command, and carrying `disable-model-invocation: true` — or *deliberately
470
+ model-invocable*, reached when the model decides the task fits. On Claude Code
471
+ the flag also drops the skill's description from the always-loaded skill
472
+ listing, which is the larger saving: a description is context in every session,
473
+ invoked or not. Only `review-pr` and `handon` are model-invocable here, because
474
+ they are the two you would phrase in words ("review PR 41", "pick up where I
475
+ left off") rather than by name; `check.py` fails the build on any other skill
476
+ that omits the flag. A user-invoked skill may invoke a model-invoked one, but
477
+ never chains another user-invoked skill.
478
+
479
+ A description says **when to reach for this** and **what it is not** — never how
480
+ the skill works. The mechanism is what the body is for, and every word of it in
481
+ the description is paid for in sessions that never invoke the skill.
482
+
483
+ **Hooks** live in `hooks/`, wired but empty — v10 enforces its policy through
484
+ the payload rather than by intercepting tool calls. There are two files because
485
+ the formats genuinely differ: `hooks.json` (PascalCase events) serves Claude
486
+ Code and Codex, which both auto-load it and must never name it in their
487
+ manifests, and `hooks-cursor.json` (camelCase, `version: 1`) serves Cursor,
488
+ which does name it. See [`hooks/README.md`](hooks/README.md) for how to add one,
489
+ including the Hermes, OpenCode, and Pi equivalents, which are code rather than
490
+ JSON.
43
491
 
44
- ## Links
492
+ ## Development
45
493
 
46
- - [Repository, contributing, and security policy](https://github.com/foxhatleo/leos-agent)
47
- - [GitHub Releases](https://github.com/foxhatleo/leos-agent/releases)
48
- - [Operating policy](https://github.com/foxhatleo/leos-agent/blob/main/plugins/leo/skills/using-leo/SKILL.md)
494
+ Run the checks:
495
+
496
+ ```bash
497
+ python3 scripts/check.py
498
+ ```
499
+
500
+ The structural check asserts that the version matches across every manifest,
501
+ the marketplace entry, and this README; that each manifest carries what its
502
+ harness requires and every declared path exists; that both hook files parse in
503
+ their own format; and that injection is idempotent, uninstall round-trips, and
504
+ malformed markers are refused.
505
+
506
+ Run the behavioral tests:
507
+
508
+ ```bash
509
+ python3 -m unittest discover -s tests -v
510
+ ```
511
+
512
+ Measure the repository-controlled static prompt footprint and enforce its
513
+ committed ceilings:
514
+
515
+ ```bash
516
+ python3 scripts/measure_context.py --check
517
+ ```
518
+
519
+ The measurement is a byte-based proxy for always-listed or dispatch-loaded
520
+ text. It deliberately does not claim to measure total task tokens or credits,
521
+ which also depend on conversation history, cache state, tool output, and the
522
+ number and model of spawned agents.
523
+
524
+ Preview any install without writing:
525
+
526
+ ```bash
527
+ python3 scripts/leo-install.py <harness> --dry-run
528
+ ```
529
+
530
+ **Both Claude Code and Codex cache a plugin by version**, so reinstalling while
531
+ the version is unchanged is a no-op and quietly leaves the old code in place —
532
+ you will be testing the previous build without being told. While iterating,
533
+ either uninstall and reinstall:
534
+
535
+ ```bash
536
+ claude plugin uninstall leos-agent@leos-agent && claude plugin install leos-agent@leos-agent --scope user
537
+ ```
538
+
539
+ or replace the cachebuster suffix in the Codex manifest with one in the form
540
+ `10.2.0+codex.local-YYYYMMDD-HHMMSS` and re-add. Either way, plugin changes only
541
+ reach a **new** session or thread.
542
+
543
+ `--check` exits non-zero when a file is out of date, and `--force` replaces a
544
+ copied file that something else has since overwritten.
545
+
546
+ To release: bump the version in `package.json`, the three `plugin.json` files,
547
+ `.claude-plugin/marketplace.json`, `plugin.yaml`, and every mention in this
548
+ README (the uninstall commands embed it in cache paths — `check.py` fails on any
549
+ stale one); run `scripts/check.py`; then push a `v`-prefixed tag.
550
+
551
+ Pushing that tag is the whole release. `.github/workflows/release.yml` runs the
552
+ tests and both checks, refuses a tag that disagrees with `package.json`,
553
+ inspects the tree npm would ship, and publishes to npm for OpenCode. It
554
+ authenticates by OIDC trusted publishing, so there is no token in the repository
555
+ — npm's configuration names this workflow by path, and renaming the file breaks
556
+ publishing until npm is updated to match. Publishing is idempotent: a version
557
+ already on the registry is a no-op, and a lookup that fails for any reason other
558
+ than a confirmed 404 aborts rather than assuming the version is absent.
559
+
560
+ Check what a publish would contain, without publishing:
561
+
562
+ ```bash
563
+ python3 scripts/publish-npm.py --dry-run
564
+ ```
49
565
 
50
566
  MIT licensed.
@@ -0,0 +1,11 @@
1
+ ---
2
+ description: Write this session's context to a leos-agent handoff document for a later session to resume.
3
+ argument-hint: "[what to emphasise]"
4
+ ---
5
+
6
+ Use the `handoff` skill. `$ARGUMENTS` says what to emphasise while writing — it
7
+ steers this document and is not stored.
8
+
9
+ Pick a slug naming the work, claim it with `scripts/handoff.py new`, write the
10
+ six sections against this session, and report the name plus `/handon <name>`.
11
+ Pointers, not contents; under about 100 lines.
@@ -0,0 +1,10 @@
1
+ ---
2
+ description: Resume work from a leos-agent handoff document written by an earlier session.
3
+ argument-hint: "[name]"
4
+ ---
5
+
6
+ Use the `handon` skill on `$ARGUMENTS`.
7
+
8
+ With no argument or an ambiguous one, list the handoffs and ask which — never
9
+ pick one unprompted. Read it, compare its frontmatter against the current
10
+ directory, branch, and HEAD, and report any drift before anything else.
@@ -0,0 +1,9 @@
1
+ ---
2
+ description: Stage a pending (unsubmitted) GitHub review on a pull request of this repository.
3
+ argument-hint: "[pr-number]"
4
+ ---
5
+
6
+ Use the leos-agent `review-pr` skill on `$ARGUMENTS`.
7
+
8
+ With no argument, review the pull request for the current branch. Comments are
9
+ staged as a PENDING review — never submitted, never made public.
@@ -0,0 +1,9 @@
1
+ ---
2
+ description: Arm the review-request watcher for this repository (Claude Code only).
3
+ argument-hint: "[repo-path]"
4
+ ---
5
+
6
+ Use the `watch-review` skill. Argument: `$ARGUMENTS`.
7
+
8
+ Arm it with the Monitor tool and let the notifications come — do not hand-poll
9
+ it turn after turn.
package/index.js ADDED
@@ -0,0 +1,12 @@
1
+ /**
2
+ * OpenCode plugin entry point for leos-agent.
3
+ *
4
+ * Deliberately does nothing at runtime. OpenCode's plugin API registers tools
5
+ * and hooks, not skills or commands, and the payload is installed to disk on
6
+ * demand rather than written at session start. This export exists so that
7
+ * `opencode plugin leos-agent -g` resolves and loads cleanly; the real work
8
+ * happens in scripts/leo-install.py, which the installed `install` skill runs.
9
+ */
10
+ export const LeosAgent = async () => ({});
11
+
12
+ export default LeosAgent;