leos-agent 6.3.0 → 10.1.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 (84) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +547 -24
  3. package/commands/handoff.md +11 -0
  4. package/commands/handon.md +10 -0
  5. package/commands/leo-doctor.md +22 -0
  6. package/commands/leo-install.md +9 -0
  7. package/commands/review-pr.md +9 -0
  8. package/commands-claude/watch-review.md +9 -0
  9. package/index.js +12 -0
  10. package/package.json +30 -18
  11. package/payload/codex-agents/leo-executor.toml +36 -0
  12. package/payload/codex-agents/leo-runner.toml +28 -0
  13. package/rules/preferences.md +97 -0
  14. package/scripts/check.py +244 -0
  15. package/scripts/ghreview.py +24 -6
  16. package/scripts/handoff.py +183 -0
  17. package/scripts/leo-install.py +509 -0
  18. package/scripts/measure_context.py +113 -0
  19. package/scripts/publish-npm.py +138 -0
  20. package/scripts/resolve_attach_target.py +45 -13
  21. package/scripts/watch_review.py +169 -0
  22. package/skills/doctor/SKILL.md +73 -96
  23. package/skills/doctor/agents/openai.yaml +5 -0
  24. package/skills/handoff/SKILL.md +99 -0
  25. package/skills/handoff/agents/openai.yaml +5 -0
  26. package/skills/handon/SKILL.md +61 -0
  27. package/skills/install/SKILL.md +79 -0
  28. package/skills/install/agents/openai.yaml +5 -0
  29. package/skills/review-pr/SKILL.md +59 -308
  30. package/skills/review-pr/reference/lenses.md +67 -0
  31. package/skills/review-pr/reference/procedure.md +348 -0
  32. package/skills-claude/attach-pr/SKILL.md +178 -0
  33. package/skills-claude/watch-review/SKILL.md +91 -0
  34. package/adapters/cursor/agents/executor.md +0 -17
  35. package/adapters/cursor/agents/expert.md +0 -70
  36. package/adapters/cursor/agents/explore.md +0 -16
  37. package/adapters/cursor/agents/implementer.md +0 -18
  38. package/adapters/cursor/agents/investigator.md +0 -18
  39. package/adapters/cursor/agents/planner.md +0 -28
  40. package/adapters/cursor/agents/reviewer.md +0 -34
  41. package/adapters/opencode/agents.json +0 -66
  42. package/adapters/opencode/plugin.js +0 -288
  43. package/config/models.json +0 -408
  44. package/hooks/bash-guard.py +0 -541
  45. package/hooks/cursor-guard.py +0 -84
  46. package/hooks/hooks-cursor.json +0 -11
  47. package/hooks/hooks.json +0 -20
  48. package/hooks/session-start.py +0 -148
  49. package/roles/executor.md +0 -15
  50. package/roles/expert.md +0 -67
  51. package/roles/explore.md +0 -13
  52. package/roles/implementer.md +0 -16
  53. package/roles/investigator.md +0 -15
  54. package/roles/planner.md +0 -25
  55. package/roles/reviewer.md +0 -31
  56. package/scripts/doctor.py +0 -284
  57. package/scripts/memory.py +0 -705
  58. package/scripts/render_adapters.py +0 -473
  59. package/scripts/setup.py +0 -161
  60. package/settings.json +0 -7
  61. package/skills/.gitkeep +0 -0
  62. package/skills/brainstorming/SKILL.md +0 -109
  63. package/skills/debugging/SKILL.md +0 -98
  64. package/skills/delegation/SKILL.md +0 -141
  65. package/skills/executing-plans/SKILL.md +0 -116
  66. package/skills/finishing-a-branch/SKILL.md +0 -123
  67. package/skills/freshness/SKILL.md +0 -118
  68. package/skills/memory/SKILL.md +0 -144
  69. package/skills/resolve-ticket/SKILL.md +0 -269
  70. package/skills/setup/SKILL.md +0 -85
  71. package/skills/test-first/SKILL.md +0 -90
  72. package/skills/using-leo/SKILL.md +0 -96
  73. package/skills/using-leo/references/claude-mapping.md +0 -32
  74. package/skills/using-leo/references/codex-mapping.md +0 -34
  75. package/skills/using-leo/references/cursor-mapping.md +0 -34
  76. package/skills/using-leo/references/hermes-mapping.md +0 -36
  77. package/skills/using-leo/references/opencode-mapping.md +0 -36
  78. package/skills/verification/SKILL.md +0 -109
  79. package/skills/visual-verification/SKILL.md +0 -114
  80. package/skills/watch-review/SKILL.md +0 -125
  81. package/skills/worktrees/SKILL.md +0 -129
  82. package/skills/writing-plans/SKILL.md +0 -96
  83. package/skills/writing-skills/SKILL.md +0 -134
  84. package/workflows/cost-tiered-fix.js +0 -259
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Leo Liang
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,43 +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.1.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 agent operating policy: cost-tiered model routing, specialist subagent roles, process skills, execute-then-review discipline, and a narrow catastrophic-command guard.
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
- This npm package is the **OpenCode** distribution. Claude Code, Codex, Cursor, and Hermes each install it through their own plugin system — see [the repository](https://github.com/foxhatleo/leos-agent) for those.
16
+ ## What it ships
8
17
 
9
- ## Install
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 `/leo-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.1.0">
53
+ ...the payload...
54
+ </leos-agent>
55
+ ```
56
+
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.
81
+
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
13
97
  ```
14
98
 
15
- On builds without the `plugin` subcommand, add it to `~/.config/opencode/opencode.json` (or `opencode.jsonc`) by hand:
99
+ Then, in a Claude Code session, run `/leo-install` (or ask it to use the `install`
100
+ skill). That writes the block into `~/.claude/CLAUDE.md`.
16
101
 
17
- ```json
18
- { "$schema": "https://opencode.ai/config.json", "plugin": ["leos-agent"] }
102
+ **Upgrade**
103
+
104
+ ```bash
105
+ claude plugin marketplace update leos-agent
19
106
  ```
20
107
 
21
- Start a new OpenCode session. The plugin registers the skills directory, the 6 subagent roles, and the operating policy, and installs the bash deletion tripwire.
108
+ ```bash
109
+ claude plugin install leos-agent@leos-agent --scope user
110
+ ```
22
111
 
23
- If the skills do not appear, run `opencode debug skill` each one should list a `location` inside this package. The plugin resolves its own install path and registers it, so none needs to be written by hand.
112
+ Re-run `/leo-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.
24
115
 
25
- ## Model tiers
116
+ **Uninstall**
26
117
 
27
- 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:
28
119
 
29
- | Tier | Model | Effort |
30
- |---|---|---|
31
- | Fable | `moonshotai/kimi-k3` | native default |
32
- | Opus | `moonshotai/kimi-k3` | native default |
33
- | Sonnet | `z-ai/glm-5.2` | native default |
34
- | Haiku | `z-ai/glm-5.2` | native default |
120
+ ```bash
121
+ python3 ~/.claude/plugins/cache/leos-agent/leos-agent/10.1.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.1.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**
35
175
 
36
- 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`.
176
+ ```bash
177
+ python3 ~/.codex/plugins/cache/leos-agent/leos-agent/10.1.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
+ ---
37
230
 
38
- ## Links
231
+ ## Hermes
39
232
 
40
- - [Repository and full documentation](https://github.com/foxhatleo/leos-agent)
41
- - [Operating policy](https://github.com/foxhatleo/leos-agent/blob/main/plugins/leo/skills/using-leo/SKILL.md)
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
+ ```
284
+
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.1.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 skill and command into
363
+ `~/.config/opencode/skills/leo-install/` and `~/.config/opencode/commands/`. From
364
+ then on `/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.
491
+
492
+ ## Development
493
+
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.1.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
+ ```
42
565
 
43
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,22 @@
1
+ ---
2
+ description: Diagnose Leo's agent setup in this harness — injection, global context, and local checkout.
3
+ ---
4
+
5
+ Run the leos-agent diagnosis for **this harness only**. Read-only; change
6
+ nothing unless asked.
7
+
8
+ Determine which harness you are running in (`claude`, `codex`, `cursor`,
9
+ `hermes`, `pi`, or `opencode`), locate the plugin root — the directory
10
+ containing `rules/preferences.md`, available as `$LEOS_AGENT_ROOT`,
11
+ `$CLAUDE_PLUGIN_ROOT`, or `$PLUGIN_ROOT` on most harnesses — and follow the
12
+ `doctor` skill:
13
+
14
+ 1. `python3 <plugin-root>/scripts/leo-install.py <harness> --check`, plus a read
15
+ of the harness's global file to confirm one current `<leos-agent>` block.
16
+ 2. Audit the rest of this harness's always-loaded context: the global
17
+ instruction file outside the block, memory files and their index, global
18
+ settings, skills, commands, and plugins.
19
+ 3. If the plugin root is a git checkout, `python3 <plugin-root>/scripts/check.py`.
20
+
21
+ Report findings grouped by section, worst first, one line each, then a one-line
22
+ verdict.
@@ -0,0 +1,9 @@
1
+ ---
2
+ description: Install or update Leo's global agent preferences in this harness's instruction file.
3
+ ---
4
+
5
+ Use the leos-agent `install` skill.
6
+
7
+ Install **this harness only** — never the others. Pass `--dry-run` to preview the
8
+ change, or `--uninstall` to remove the block and any installed payload files.
9
+ Report the script's per-target status lines verbatim, including any warning.
@@ -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.