loadouts 0.2.3 → 0.3.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 (244) hide show
  1. package/bundled/embedded/opencode/loadouts-runtime.tsx +14461 -0
  2. package/bundled/embedded/pi/loadouts-runtime.ts +14638 -0
  3. package/bundled/extensions/loadouts-runtime/index.ts +14638 -0
  4. package/bundled/extensions/loadouts-runtime/package.json +6 -0
  5. package/bundled/loadouts/opencode-runtime.yaml +7 -0
  6. package/bundled/loadouts/pi-runtime.yaml +5 -0
  7. package/bundled/opencode/commands/loadouts.md +3 -0
  8. package/bundled/opencode/plugins/loadouts-runtime-tui.tsx +14461 -0
  9. package/bundled/opencode/plugins/loadouts-runtime.ts +533 -0
  10. package/bundled/opencode/tui.jsonc +5 -0
  11. package/dist/builtins/agent-transforms.d.ts +9 -0
  12. package/dist/builtins/agent-transforms.d.ts.map +1 -0
  13. package/dist/builtins/agent-transforms.js +232 -0
  14. package/dist/builtins/agent-transforms.js.map +1 -0
  15. package/dist/builtins/index.d.ts.map +1 -1
  16. package/dist/builtins/index.js +13 -0
  17. package/dist/builtins/index.js.map +1 -1
  18. package/dist/builtins/kinds/agent.d.ts +3 -0
  19. package/dist/builtins/kinds/agent.d.ts.map +1 -0
  20. package/dist/builtins/kinds/agent.js +8 -0
  21. package/dist/builtins/kinds/agent.js.map +1 -0
  22. package/dist/builtins/kinds/extension-dir.d.ts +3 -0
  23. package/dist/builtins/kinds/extension-dir.d.ts.map +1 -0
  24. package/dist/builtins/kinds/extension-dir.js +8 -0
  25. package/dist/builtins/kinds/extension-dir.js.map +1 -0
  26. package/dist/builtins/kinds/opencode-command.d.ts +3 -0
  27. package/dist/builtins/kinds/opencode-command.d.ts.map +1 -0
  28. package/dist/builtins/kinds/opencode-command.js +8 -0
  29. package/dist/builtins/kinds/opencode-command.js.map +1 -0
  30. package/dist/builtins/kinds/opencode-plugin.js +1 -1
  31. package/dist/builtins/kinds/opencode-plugin.js.map +1 -1
  32. package/dist/builtins/kinds/opencode-tui-config.d.ts +3 -0
  33. package/dist/builtins/kinds/opencode-tui-config.d.ts.map +1 -0
  34. package/dist/builtins/kinds/opencode-tui-config.js +8 -0
  35. package/dist/builtins/kinds/opencode-tui-config.js.map +1 -0
  36. package/dist/builtins/tools/claude-code.d.ts.map +1 -1
  37. package/dist/builtins/tools/claude-code.js +7 -1
  38. package/dist/builtins/tools/claude-code.js.map +1 -1
  39. package/dist/builtins/tools/codex.d.ts.map +1 -1
  40. package/dist/builtins/tools/codex.js +10 -1
  41. package/dist/builtins/tools/codex.js.map +1 -1
  42. package/dist/builtins/tools/cursor.d.ts.map +1 -1
  43. package/dist/builtins/tools/cursor.js +7 -1
  44. package/dist/builtins/tools/cursor.js.map +1 -1
  45. package/dist/builtins/tools/opencode.d.ts.map +1 -1
  46. package/dist/builtins/tools/opencode.js +16 -0
  47. package/dist/builtins/tools/opencode.js.map +1 -1
  48. package/dist/builtins/tools/pi.d.ts.map +1 -1
  49. package/dist/builtins/tools/pi.js +2 -1
  50. package/dist/builtins/tools/pi.js.map +1 -1
  51. package/dist/cli/commands/activate.d.ts.map +1 -1
  52. package/dist/cli/commands/activate.js +9 -0
  53. package/dist/cli/commands/activate.js.map +1 -1
  54. package/dist/cli/commands/diff.d.ts +10 -0
  55. package/dist/cli/commands/diff.d.ts.map +1 -1
  56. package/dist/cli/commands/diff.js +71 -30
  57. package/dist/cli/commands/diff.js.map +1 -1
  58. package/dist/cli/commands/docs.d.ts.map +1 -1
  59. package/dist/cli/commands/docs.js +2 -1
  60. package/dist/cli/commands/docs.js.map +1 -1
  61. package/dist/cli/commands/doctor.d.ts.map +1 -1
  62. package/dist/cli/commands/doctor.js +10 -0
  63. package/dist/cli/commands/doctor.js.map +1 -1
  64. package/dist/cli/commands/info.d.ts +10 -0
  65. package/dist/cli/commands/info.d.ts.map +1 -1
  66. package/dist/cli/commands/info.js +45 -1
  67. package/dist/cli/commands/info.js.map +1 -1
  68. package/dist/cli/commands/init.d.ts.map +1 -1
  69. package/dist/cli/commands/init.js +5 -0
  70. package/dist/cli/commands/init.js.map +1 -1
  71. package/dist/cli/commands/install.d.ts.map +1 -1
  72. package/dist/cli/commands/install.js +15 -3
  73. package/dist/cli/commands/install.js.map +1 -1
  74. package/dist/cli/commands/list.d.ts +18 -0
  75. package/dist/cli/commands/list.d.ts.map +1 -1
  76. package/dist/cli/commands/list.js +27 -0
  77. package/dist/cli/commands/list.js.map +1 -1
  78. package/dist/cli/commands/migrate.d.ts +31 -0
  79. package/dist/cli/commands/migrate.d.ts.map +1 -0
  80. package/dist/cli/commands/migrate.js +223 -0
  81. package/dist/cli/commands/migrate.js.map +1 -0
  82. package/dist/cli/commands/render-engine.d.ts +1 -0
  83. package/dist/cli/commands/render-engine.d.ts.map +1 -1
  84. package/dist/cli/commands/render-engine.js +10 -35
  85. package/dist/cli/commands/render-engine.js.map +1 -1
  86. package/dist/cli/commands/runtime.d.ts +21 -0
  87. package/dist/cli/commands/runtime.d.ts.map +1 -0
  88. package/dist/cli/commands/runtime.js +100 -0
  89. package/dist/cli/commands/runtime.js.map +1 -0
  90. package/dist/cli/commands/status.d.ts +10 -0
  91. package/dist/cli/commands/status.d.ts.map +1 -1
  92. package/dist/cli/commands/status.js +100 -2
  93. package/dist/cli/commands/status.js.map +1 -1
  94. package/dist/cli/commands/sync.d.ts.map +1 -1
  95. package/dist/cli/commands/sync.js +6 -0
  96. package/dist/cli/commands/sync.js.map +1 -1
  97. package/dist/cli/commands/tui.d.ts +3 -0
  98. package/dist/cli/commands/tui.d.ts.map +1 -0
  99. package/dist/cli/commands/tui.js +20 -0
  100. package/dist/cli/commands/tui.js.map +1 -0
  101. package/dist/cli/index.d.ts.map +1 -1
  102. package/dist/cli/index.js +6 -0
  103. package/dist/cli/index.js.map +1 -1
  104. package/dist/core/agent-migration.d.ts +13 -0
  105. package/dist/core/agent-migration.d.ts.map +1 -0
  106. package/dist/core/agent-migration.js +397 -0
  107. package/dist/core/agent-migration.js.map +1 -0
  108. package/dist/core/import-discovery.d.ts.map +1 -1
  109. package/dist/core/import-discovery.js +27 -0
  110. package/dist/core/import-discovery.js.map +1 -1
  111. package/dist/core/kindLoader.d.ts +10 -4
  112. package/dist/core/kindLoader.d.ts.map +1 -1
  113. package/dist/core/kindLoader.js +22 -10
  114. package/dist/core/kindLoader.js.map +1 -1
  115. package/dist/core/registry.d.ts +4 -2
  116. package/dist/core/registry.d.ts.map +1 -1
  117. package/dist/core/registry.js.map +1 -1
  118. package/dist/core/render.d.ts.map +1 -1
  119. package/dist/core/render.js +62 -13
  120. package/dist/core/render.js.map +1 -1
  121. package/dist/core/resolve.d.ts +18 -2
  122. package/dist/core/resolve.d.ts.map +1 -1
  123. package/dist/core/resolve.js +50 -27
  124. package/dist/core/resolve.js.map +1 -1
  125. package/dist/core/runtime.d.ts +79 -0
  126. package/dist/core/runtime.d.ts.map +1 -0
  127. package/dist/core/runtime.js +345 -0
  128. package/dist/core/runtime.js.map +1 -0
  129. package/dist/core/types.d.ts.map +1 -1
  130. package/dist/integrations/opencode-runtime/bridge.d.ts +17 -0
  131. package/dist/integrations/opencode-runtime/bridge.d.ts.map +1 -0
  132. package/dist/integrations/opencode-runtime/bridge.js +60 -0
  133. package/dist/integrations/opencode-runtime/bridge.js.map +1 -0
  134. package/dist/integrations/opencode-runtime/command.d.ts +4 -0
  135. package/dist/integrations/opencode-runtime/command.d.ts.map +1 -0
  136. package/dist/integrations/opencode-runtime/command.js +200 -0
  137. package/dist/integrations/opencode-runtime/command.js.map +1 -0
  138. package/dist/integrations/opencode-runtime/index.d.ts +6 -0
  139. package/dist/integrations/opencode-runtime/index.d.ts.map +1 -0
  140. package/dist/integrations/opencode-runtime/index.js +5 -0
  141. package/dist/integrations/opencode-runtime/index.js.map +1 -0
  142. package/dist/integrations/opencode-runtime/plugin.d.ts +59 -0
  143. package/dist/integrations/opencode-runtime/plugin.d.ts.map +1 -0
  144. package/dist/integrations/opencode-runtime/plugin.js +238 -0
  145. package/dist/integrations/opencode-runtime/plugin.js.map +1 -0
  146. package/dist/integrations/opencode-runtime/state.d.ts +8 -0
  147. package/dist/integrations/opencode-runtime/state.d.ts.map +1 -0
  148. package/dist/integrations/opencode-runtime/state.js +27 -0
  149. package/dist/integrations/opencode-runtime/state.js.map +1 -0
  150. package/dist/integrations/opencode-runtime/types.d.ts +38 -0
  151. package/dist/integrations/opencode-runtime/types.d.ts.map +1 -0
  152. package/dist/integrations/opencode-runtime/types.js +2 -0
  153. package/dist/integrations/opencode-runtime/types.js.map +1 -0
  154. package/dist/lib/artifact-paths.d.ts.map +1 -1
  155. package/dist/lib/artifact-paths.js +4 -0
  156. package/dist/lib/artifact-paths.js.map +1 -1
  157. package/dist/lib/artifact-table.d.ts.map +1 -1
  158. package/dist/lib/artifact-table.js +13 -1
  159. package/dist/lib/artifact-table.js.map +1 -1
  160. package/dist/lib/gitignore.d.ts.map +1 -1
  161. package/dist/lib/gitignore.js +4 -0
  162. package/dist/lib/gitignore.js.map +1 -1
  163. package/dist/tui/core/actions.d.ts +9 -0
  164. package/dist/tui/core/actions.d.ts.map +1 -0
  165. package/dist/tui/core/actions.js +70 -0
  166. package/dist/tui/core/actions.js.map +1 -0
  167. package/dist/tui/core/data.d.ts +41 -0
  168. package/dist/tui/core/data.d.ts.map +1 -0
  169. package/dist/tui/core/data.js +150 -0
  170. package/dist/tui/core/data.js.map +1 -0
  171. package/dist/tui/core/host.d.ts +21 -0
  172. package/dist/tui/core/host.d.ts.map +1 -0
  173. package/dist/tui/core/host.js +2 -0
  174. package/dist/tui/core/host.js.map +1 -0
  175. package/dist/tui/core/intent.d.ts +80 -0
  176. package/dist/tui/core/intent.d.ts.map +1 -0
  177. package/dist/tui/core/intent.js +2 -0
  178. package/dist/tui/core/intent.js.map +1 -0
  179. package/dist/tui/core/keymap.d.ts +15 -0
  180. package/dist/tui/core/keymap.d.ts.map +1 -0
  181. package/dist/tui/core/keymap.js +36 -0
  182. package/dist/tui/core/keymap.js.map +1 -0
  183. package/dist/tui/core/model.d.ts +53 -0
  184. package/dist/tui/core/model.d.ts.map +1 -0
  185. package/dist/tui/core/model.js +33 -0
  186. package/dist/tui/core/model.js.map +1 -0
  187. package/dist/tui/core/theme.d.ts +15 -0
  188. package/dist/tui/core/theme.d.ts.map +1 -0
  189. package/dist/tui/core/theme.js +11 -0
  190. package/dist/tui/core/theme.js.map +1 -0
  191. package/dist/tui/core/update.d.ts +8 -0
  192. package/dist/tui/core/update.d.ts.map +1 -0
  193. package/dist/tui/core/update.js +192 -0
  194. package/dist/tui/core/update.js.map +1 -0
  195. package/dist/tui/core/view.d.ts +4 -0
  196. package/dist/tui/core/view.d.ts.map +1 -0
  197. package/dist/tui/core/view.js +150 -0
  198. package/dist/tui/core/view.js.map +1 -0
  199. package/dist/tui/core/viewspec.d.ts +44 -0
  200. package/dist/tui/core/viewspec.d.ts.map +1 -0
  201. package/dist/tui/core/viewspec.js +2 -0
  202. package/dist/tui/core/viewspec.js.map +1 -0
  203. package/dist/tui/hosts/_probe/embed-entry.d.ts +5 -0
  204. package/dist/tui/hosts/_probe/embed-entry.d.ts.map +1 -0
  205. package/dist/tui/hosts/_probe/embed-entry.js +8 -0
  206. package/dist/tui/hosts/_probe/embed-entry.js.map +1 -0
  207. package/dist/tui/hosts/pi/embed-entry.d.ts +3 -0
  208. package/dist/tui/hosts/pi/embed-entry.d.ts.map +1 -0
  209. package/dist/tui/hosts/pi/embed-entry.js +219 -0
  210. package/dist/tui/hosts/pi/embed-entry.js.map +1 -0
  211. package/dist/tui/hosts/pi/inject.d.ts +32 -0
  212. package/dist/tui/hosts/pi/inject.d.ts.map +1 -0
  213. package/dist/tui/hosts/pi/inject.js +53 -0
  214. package/dist/tui/hosts/pi/inject.js.map +1 -0
  215. package/dist/tui/hosts/standalone.d.ts +2 -0
  216. package/dist/tui/hosts/standalone.d.ts.map +1 -0
  217. package/dist/tui/hosts/standalone.js +145 -0
  218. package/dist/tui/hosts/standalone.js.map +1 -0
  219. package/dist/tui/skins/pi-tui/input.d.ts +5 -0
  220. package/dist/tui/skins/pi-tui/input.d.ts.map +1 -0
  221. package/dist/tui/skins/pi-tui/input.js +38 -0
  222. package/dist/tui/skins/pi-tui/input.js.map +1 -0
  223. package/dist/tui/skins/pi-tui/pi-theme-adapter.d.ts +4 -0
  224. package/dist/tui/skins/pi-tui/pi-theme-adapter.d.ts.map +1 -0
  225. package/dist/tui/skins/pi-tui/pi-theme-adapter.js +27 -0
  226. package/dist/tui/skins/pi-tui/pi-theme-adapter.js.map +1 -0
  227. package/dist/tui/skins/pi-tui/render.d.ts +35 -0
  228. package/dist/tui/skins/pi-tui/render.d.ts.map +1 -0
  229. package/dist/tui/skins/pi-tui/render.js +154 -0
  230. package/dist/tui/skins/pi-tui/render.js.map +1 -0
  231. package/dist/tui/skins/pi-tui/theme.d.ts +10 -0
  232. package/dist/tui/skins/pi-tui/theme.d.ts.map +1 -0
  233. package/dist/tui/skins/pi-tui/theme.js +58 -0
  234. package/dist/tui/skins/pi-tui/theme.js.map +1 -0
  235. package/docs/authoring.md +119 -2
  236. package/docs/commands.md +34 -0
  237. package/docs/compatibility.md +15 -8
  238. package/docs/concepts.md +10 -7
  239. package/docs/examples/opencode-runtime-plugin.ts +143 -0
  240. package/docs/index.md +1 -0
  241. package/docs/runtime.md +107 -0
  242. package/docs/troubleshooting.md +18 -1
  243. package/docs/tui-architecture.md +501 -0
  244. package/package.json +11 -2
package/docs/authoring.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Authoring Artifacts
2
2
 
3
- This guide covers creating rules, skills, and instructions. The typical workflow:
3
+ This guide covers creating agents, rules, skills, and instructions. The typical workflow:
4
4
 
5
5
  1. **Create** an artifact (`loadouts rule add`, `loadouts skill add`, etc.)
6
6
  2. **Include** it in a loadout (`loadouts add-to <loadout> <artifact>`)
@@ -9,6 +9,71 @@ This guide covers creating rules, skills, and instructions. The typical workflow
9
9
 
10
10
  ---
11
11
 
12
+ ## Agents
13
+
14
+ Agents are self-contained Markdown files under `.loadouts/agents/`. The body is the agent prompt. Top-level frontmatter holds portable fields, while `targets.<tool>` holds harness-specific fields.
15
+
16
+ ```markdown
17
+ ---
18
+ name: code-reviewer
19
+ description: Reviews code for correctness, security, and missing tests.
20
+ model: inherit
21
+ readonly: true
22
+ background: false
23
+
24
+ targets:
25
+ opencode:
26
+ mode: subagent
27
+ steps: 8
28
+ color: accent
29
+ permission:
30
+ bash:
31
+ "*": ask
32
+ "git diff*": allow
33
+
34
+ cursor:
35
+ is_background: false
36
+
37
+ claude-code:
38
+ tools: Read, Glob, Grep, Bash
39
+ maxTurns: 8
40
+
41
+ codex:
42
+ sandbox_mode: read-only
43
+ model_reasoning_effort: high
44
+ ---
45
+
46
+ Review code like an owner. Prioritize real bugs, behavior regressions,
47
+ security issues, and missing tests.
48
+ ```
49
+
50
+ Project scope renders agents to:
51
+
52
+ - OpenCode: `.opencode/agents/<name>.md`
53
+ - Cursor: `.cursor/agents/<name>.md`
54
+ - Claude Code: `.claude/agents/<name>.md`
55
+ - Codex: `.codex/agents/<name>.toml`
56
+
57
+ Markdown targets are symlinked only when the source frontmatter is already native-safe for that harness. If the file contains `targets:` overlays, Loadouts writes a cleaned managed copy for each Markdown harness. Codex always gets generated TOML, with the Markdown body mapped to `developer_instructions`.
58
+
59
+ After creating an agent manually, add it to a loadout:
60
+
61
+ ```bash
62
+ loadouts add-to backend agents/code-reviewer.md
63
+ ```
64
+
65
+ **Import or migrate existing agents:**
66
+
67
+ ```bash
68
+ loadouts install .opencode/agents/reviewer.md --kinds agent --keep
69
+ loadouts migrate agents --dry-run
70
+ loadouts migrate agents
71
+ ```
72
+
73
+ `install --kinds agent` imports native harness files from outside the target loadout. `migrate agents` converts native files already inside a loadout, such as `opencode/agents/*.md`, `cursor/agents/*.md`, `.claude/agents/*.md`, or `.codex/agents/*.toml`.
74
+
75
+ ---
76
+
12
77
  ## Rules
13
78
 
14
79
  Rules are scoped advisory files with YAML frontmatter:
@@ -154,7 +219,7 @@ include:
154
219
 
155
220
  ---
156
221
 
157
- ## OpenCode Config And Plugins
222
+ ## OpenCode Config, Commands, And Plugins
158
223
 
159
224
  OpenCode-specific artifacts live under `.loadouts/opencode/` and only render when included in a loadout that targets `opencode`.
160
225
 
@@ -169,6 +234,16 @@ OpenCode-specific artifacts live under `.loadouts/opencode/` and only render whe
169
234
 
170
235
  Project scope renders this to `opencode.jsonc`. Global scope renders it to `~/.config/opencode/opencode.jsonc`. This is whole-file ownership; if you do not include this artifact, loadouts does not touch your OpenCode config file.
171
236
 
237
+ **Slash commands:**
238
+ ```md
239
+ <!-- .loadouts/opencode/commands/loadouts.md -->
240
+ # /loadouts
241
+
242
+ Arguments: `$ARGUMENTS`
243
+ ```
244
+
245
+ Project scope renders this to `.opencode/commands/loadouts.md`. Global scope renders it to `~/.config/opencode/commands/loadouts.md`.
246
+
172
247
  **Local plugins:**
173
248
  ```ts
174
249
  // .loadouts/opencode/plugins/notify.ts
@@ -187,11 +262,53 @@ Project scope renders this to `.opencode/plugins/notify.ts`. Global scope render
187
262
  ```yaml
188
263
  include:
189
264
  - opencode/opencode.jsonc
265
+ - opencode/commands/loadouts.md
190
266
  - opencode/plugins/notify.ts
191
267
  ```
192
268
 
193
269
  NPM plugins belong in the managed `opencode.json(c)` `plugin` array. Local plugin source files belong in `.loadouts/opencode/plugins/`.
194
270
 
271
+ **TUI plugins:**
272
+
273
+ OpenCode TUI plugins are local plugin modules loaded from `tui.json(c)`. They are useful for user-facing UI that should not be added to chat or model-visible prompt context.
274
+
275
+ ```tsx
276
+ // .loadouts/opencode/plugins/status-popup.tsx
277
+ /** @jsxImportSource @opentui/solid */
278
+
279
+ import type { TuiPlugin, TuiPluginModule } from "@opencode-ai/plugin/tui";
280
+
281
+ const tui: TuiPlugin = async (api) => {
282
+ api.keymap.registerLayer({
283
+ commands: [
284
+ {
285
+ name: "status_popup_open",
286
+ title: "Open status popup",
287
+ category: "Plugin",
288
+ namespace: "palette",
289
+ slashName: "status-popup",
290
+ run() {
291
+ api.ui.dialog.setSize("medium");
292
+ api.ui.dialog.replace(() => <box border paddingLeft={2}>TUI-only popup</box>);
293
+ },
294
+ },
295
+ ],
296
+ });
297
+ };
298
+
299
+ export default { id: "status-popup", tui } satisfies TuiPluginModule & { id: string };
300
+ ```
301
+
302
+ ```jsonc
303
+ // .loadouts/opencode/tui.jsonc
304
+ {
305
+ "$schema": "https://opencode.ai/tui.json",
306
+ "plugin": ["./plugins/status-popup.tsx"]
307
+ }
308
+ ```
309
+
310
+ Project scope renders this config to `.opencode/tui.jsonc`. Global scope renders it to `~/.config/opencode/tui.jsonc`. This is whole-file ownership; if you already manage `tui.jsonc`, add the plugin entry there instead of including this artifact.
311
+
195
312
  ---
196
313
 
197
314
  ## Custom Kinds
package/docs/commands.md CHANGED
@@ -46,6 +46,22 @@ loadouts info # Active loadout(s)
46
46
  loadouts info backend # Specific loadout
47
47
  ```
48
48
 
49
+ ### `loadouts runtime [names...]`
50
+ Compile a runtime bundle for inspection (no filesystem activation). Defaults to the root `default` loadout (or `base`).
51
+ ```bash
52
+ loadouts runtime # Compile default loadout
53
+ loadouts runtime base backend # Compile multiple loadouts
54
+ loadouts runtime base --tool cursor # Target a different tool
55
+ loadouts runtime base -l # Force local/project scope
56
+ loadouts runtime base -g # Force global scope
57
+ loadouts runtime base --json # Output RuntimeBundle JSON only
58
+ loadouts runtime base --system-block # Output renderRuntimeSystemBlock(bundle) only
59
+ ```
60
+
61
+ See `docs/runtime.md` for architecture, OpenCode-first integration flow, and per-tool capability flags.
62
+
63
+ For OpenCode runtime plugin integrations, this is exposed as `/loadouts activate|a|use ...`, `/loadouts list|ls`, `/loadouts info`, and `/loadouts clear`. The bundled fallback command omits `$ARGUMENTS` to reduce model-visible command noise, and runtime JSON/intermediate plugin output should stay hidden. User-visible slash command acknowledgment text may still be model-mediated by OpenCode even when plugin state handling is deterministic.
64
+
49
65
  ### `loadouts diff [name]`
50
66
  Preview what would change if a loadout were applied.
51
67
  ```bash
@@ -73,10 +89,26 @@ loadouts install ./rule.mdc # Import a single rule file
73
89
  loadouts install --dry-run # Preview
74
90
  loadouts install -i # Interactive
75
91
  loadouts install --rules # Rules only
92
+ loadouts install --kinds agent # Import and canonicalize agents
76
93
  loadouts install --from cursor # From specific tool
77
94
  loadouts install --keep # Don't delete originals
78
95
  ```
79
96
 
97
+ Native agent files are converted to canonical `.loadouts/agents/*.md` during import. OpenCode, Cursor, Claude Code, and Codex fields are preserved under `targets.<tool>` overlays where needed.
98
+
99
+ ### `loadouts migrate agents [source]`
100
+ Migrate native harness agent definitions that already live in a loadout tree into canonical `.loadouts/agents/*.md` files.
101
+
102
+ ```bash
103
+ loadouts migrate agents # Scan legacy agent paths in current loadout
104
+ loadouts migrate agents --dry-run # Preview migration
105
+ loadouts migrate agents --keep # Keep old native files
106
+ loadouts migrate agents --force # Overwrite existing canonical agents
107
+ loadouts migrate agents ./agents --from opencode
108
+ ```
109
+
110
+ When migrating from a harness-specific source path such as `opencode/agents/reviewer.md`, loadout includes are updated to `agents/reviewer.md` with `tools: [opencode]` to preserve existing behavior. The canonical file still receives compatible fields for other harnesses where Loadouts can infer them.
111
+
80
112
  ### `loadouts create <name>`
81
113
  Create a new loadout definition.
82
114
  ```bash
@@ -196,6 +228,8 @@ Most state commands (`activate`, `deactivate`, `sync`, `status`, `clear`, `list`
196
228
  | `-g, --global` | Global scope only |
197
229
  | `-a, --all` | Both scopes |
198
230
 
231
+ `runtime` supports `-l/--local` and `-g/--global` only (no `--all`).
232
+
199
233
  When omitted, commands auto-detect scope based on context. Use `--dry-run` to preview behavior before destructive operations.
200
234
 
201
235
  ---
@@ -4,13 +4,13 @@ Current built-in rendering targets for canonical artifacts.
4
4
 
5
5
  ## Artifact Paths (Project Scope)
6
6
 
7
- | Tool | Rule | Skill | Instruction |
8
- |------|------|-------|-------------|
9
- | Claude Code | `.claude/rules/<name>.md` | `.claude/skills/<name>/` | `CLAUDE.md` (generated wrapper to `AGENTS.md`) |
10
- | Cursor | `.cursor/rules/<name>.mdc` | `.cursor/skills/<name>/` | `AGENTS.md` |
11
- | OpenCode | `.opencode/rules/<name>.md` | `.opencode/skills/<name>/` | `AGENTS.md` |
12
- | Codex | - (no rule target) | `.agents/skills/<name>/` | `AGENTS.md` |
13
- | Pi | - (no native rule target) | `.pi/skills/<name>/` | `AGENTS.md` |
7
+ | Tool | Rule | Skill | Agent | Instruction | Extra Artifacts |
8
+ |------|------|-------|-------|-------------|-----------------|
9
+ | Claude Code | `.claude/rules/<name>.md` | `.claude/skills/<name>/` | `.claude/agents/<name>.md` | `CLAUDE.md` (generated wrapper to `AGENTS.md`) | - |
10
+ | Cursor | `.cursor/rules/<name>.mdc` | `.cursor/skills/<name>/` | `.cursor/agents/<name>.md` | `AGENTS.md` | - |
11
+ | OpenCode | `.opencode/rules/<name>.md` | `.opencode/skills/<name>/` | `.opencode/agents/<name>.md` | `AGENTS.md` | `.opencode/commands/<name>.md`, `.opencode/plugins/<name>.{ts,tsx,js}`, `.opencode/tui.json(c)`, `opencode.json(c)` |
12
+ | Codex | - (no rule target) | `.agents/skills/<name>/` | `.codex/agents/<name>.toml` | `AGENTS.md` | - |
13
+ | Pi | - (no native rule target) | `.pi/skills/<name>/` | - | `AGENTS.md` | - |
14
14
 
15
15
  Global scope uses each tool's configured global base path. Instruction files may render to home-level `AGENTS.md` or `CLAUDE.md` paths depending on the tool.
16
16
 
@@ -18,17 +18,24 @@ Global scope uses each tool's configured global base path. Instruction files may
18
18
 
19
19
  - Canonical rule fields: `description`, `paths`, `activation` (`always` or `scoped`).
20
20
  - Canonical skill fields: `name`, `description`, `user-invocable`, `model-invocable`.
21
+ - Canonical agent files are Markdown under `.loadouts/agents/<name>.md`; use top-level portable fields plus `targets.<tool>` overlays for harness-specific config.
21
22
 
22
23
  Rendered aliases for compatibility:
23
24
 
24
25
  - Cursor/OpenCode rules: `paths` is mirrored to `globs`.
25
26
  - Cursor/OpenCode rules: `activation` is mirrored to `alwaysApply` (`always -> true`, `scoped -> false`).
26
27
  - OpenCode skills: `model-invocable` is mirrored to `disable-model-invocation` (inverted boolean).
28
+ - Agent overlays are rendered into each harness' native frontmatter. Codex agents are generated as TOML with the Markdown body mapped to `developer_instructions`.
27
29
 
28
30
  Transforms add aliases when canonical fields are present and alias fields are not already set.
29
31
 
32
+ Agent Markdown targets use symlinks only when the source frontmatter is already native-safe for that harness. Files with `targets:` overlays are rendered as managed copies so tool-specific fields do not leak into other harnesses.
33
+
34
+ Agent import and migration canonicalize native harness definitions. Compatible fields are inferred when possible: read-only native settings become canonical `readonly: true`, Cursor/Claude background settings become canonical `background`, OpenCode/Codex/Claude reasoning effort settings are mirrored across compatible target overlays, and OpenCode `steps` / Claude `maxTurns` are mirrored between those harnesses.
35
+
30
36
  ## Known Limitations
31
37
 
32
38
  - Codex and Pi do not currently have a built-in rule output target.
33
- - Frontmatter aliasing is only applied on transformed targets (currently Cursor/OpenCode rules and OpenCode skills).
39
+ - Pi does not currently have a built-in agent output target.
40
+ - Frontmatter aliasing is only applied on transformed targets.
34
41
  - If both canonical and alias fields are set by hand, existing alias values are preserved.
package/docs/concepts.md CHANGED
@@ -74,22 +74,25 @@ include:
74
74
  |------|--------|-------------|
75
75
  | `rule` | file | Scoped advisory rules (`.md`) |
76
76
  | `skill` | directory | On-demand capabilities with `SKILL.md` |
77
+ | `agent` | file | Specialized agents and subagents |
77
78
  | `instruction` | file | Always-on project instructions |
78
79
  | `prompt` | file | Slash command templates |
79
80
  | `extension` | directory | Runtime code extensions |
80
81
  | `theme` | file | UI theme configuration |
82
+ | `opencode-command` | file | OpenCode slash command markdown |
81
83
  | `opencode-config` | file | Whole-file OpenCode runtime configuration |
84
+ | `opencode-tui-config` | file | Whole-file OpenCode TUI configuration |
82
85
  | `opencode-plugin` | file | Local OpenCode plugin modules |
83
86
 
84
87
  ## Supported Tools
85
88
 
86
- | Tool | Rules | Skills | Instructions | Extra Artifacts |
87
- |------|-------|--------|--------------|-----------------|
88
- | Claude Code | `.claude/rules/*.md` | `.claude/skills/` | `CLAUDE.md` | — |
89
- | Cursor | `.cursor/rules/*.mdc` | `.cursor/skills/` | `AGENTS.md` | — |
90
- | OpenCode | `.opencode/rules/*.md` | `.opencode/skills/` | `AGENTS.md` | `opencode.json(c)`, `.opencode/plugins/` |
91
- | Codex | — | `.agents/skills/` | `AGENTS.md` | — |
92
- | Pi | `.pi/rules/*.md` | `.pi/skills/` | `AGENTS.md` | `.pi/extensions/`, `.pi/themes/` |
89
+ | Tool | Rules | Skills | Agents | Instructions | Extra Artifacts |
90
+ |------|-------|--------|--------|--------------|-----------------|
91
+ | Claude Code | `.claude/rules/*.md` | `.claude/skills/` | `.claude/agents/*.md` | `CLAUDE.md` | — |
92
+ | Cursor | `.cursor/rules/*.mdc` | `.cursor/skills/` | `.cursor/agents/*.md` | `AGENTS.md` | — |
93
+ | OpenCode | `.opencode/rules/*.md` | `.opencode/skills/` | `.opencode/agents/*.md` | `AGENTS.md` | `opencode.json(c)`, `.opencode/tui.json(c)`, `.opencode/plugins/`, `.opencode/commands/*.md` |
94
+ | Codex | — | `.agents/skills/` | `.codex/agents/*.toml` | `AGENTS.md` | — |
95
+ | Pi | — | `.pi/skills/` | — | `AGENTS.md` | `.pi/prompts/*.md`, `.pi/extensions/`, `.pi/themes/` |
93
96
 
94
97
  ## Sources (Cross-Project Config)
95
98
 
@@ -0,0 +1,143 @@
1
+ /**
2
+ * OpenCode runtime integration scaffold (reference implementation).
3
+ *
4
+ * This is intentionally conservative and uses the current CLI JSON bridge:
5
+ * loadouts runtime <names...> --tool opencode --json
6
+ *
7
+ * Notes:
8
+ * - API shapes below are placeholders where OpenCode plugin APIs are uncertain.
9
+ * - This scaffold does not claim native skill hot-swap.
10
+ * - Skills are exposed as path-discovery references only.
11
+ */
12
+
13
+ import { spawn } from "node:child_process";
14
+
15
+ interface RuntimeBundle {
16
+ tool: string;
17
+ fingerprint: string;
18
+ injection: {
19
+ instructions: Array<{ relativePath: string; content: string }>;
20
+ rules: Array<{ relativePath: string; content: string }>;
21
+ skills: Array<{ name: string; path: string; sourcePath: string }>;
22
+ };
23
+ capabilities: {
24
+ runtimeMode: "native-runtime" | "experimental-runtime" | "filesystem-activation";
25
+ modelInjection: { instructions: boolean; rules: boolean };
26
+ skillPathDiscovery: boolean;
27
+ nativeSkillHotSwap: boolean;
28
+ };
29
+ }
30
+
31
+ type SessionRuntimeState = {
32
+ fingerprint?: string;
33
+ bundle?: RuntimeBundle;
34
+ };
35
+
36
+ // Placeholder/uncertain plugin API. Replace with actual OpenCode interfaces.
37
+ interface OpenCodePluginApi {
38
+ // Possible session lifecycle hook (name/signature may differ).
39
+ onSessionStart?: (handler: (ctx: { cwd: string; state: SessionRuntimeState }) => Promise<void>) => void;
40
+ // Possible system prompt composition hook (name/signature may differ).
41
+ onSystemPrompt?: (handler: (ctx: { state: SessionRuntimeState }) => string | Promise<string>) => void;
42
+ // Possible skill discovery registration hook (name/signature may differ).
43
+ registerSkillDiscoveryPath?: (path: string) => void;
44
+ }
45
+
46
+ export function registerLoadoutsRuntimeScaffold(api: OpenCodePluginApi): void {
47
+ if (!api.onSessionStart || !api.onSystemPrompt) {
48
+ return;
49
+ }
50
+
51
+ api.onSessionStart(async ({ cwd, state }) => {
52
+ const names = ["base"]; // Replace with user/session-selected runtime loadouts.
53
+ const bundle = await compileRuntimeBundleViaCli(names, cwd);
54
+
55
+ state.bundle = bundle;
56
+ state.fingerprint = bundle.fingerprint;
57
+
58
+ if (bundle.capabilities.skillPathDiscovery && api.registerSkillDiscoveryPath) {
59
+ for (const skill of bundle.injection.skills) {
60
+ api.registerSkillDiscoveryPath(skill.path);
61
+ }
62
+ }
63
+ });
64
+
65
+ api.onSystemPrompt(({ state }) => {
66
+ const bundle = state.bundle;
67
+ if (!bundle) return "";
68
+
69
+ // Either render your own system block from bundle fields,
70
+ // or call `loadouts runtime ... --system-block` in environments that prefer text passthrough.
71
+ return renderRuntimeSystemBlockText(bundle);
72
+ });
73
+ }
74
+
75
+ async function compileRuntimeBundleViaCli(names: string[], cwd: string): Promise<RuntimeBundle> {
76
+ const args = ["runtime", ...names, "--tool", "opencode", "--json", "--local"];
77
+ const { stdout } = await execFile("loadouts", args, cwd);
78
+ return JSON.parse(stdout) as RuntimeBundle;
79
+ }
80
+
81
+ function renderRuntimeSystemBlockText(bundle: RuntimeBundle): string {
82
+ const lines: string[] = [];
83
+ lines.push("[loadout-runtime:v1]");
84
+ lines.push(`tool: ${bundle.tool}`);
85
+ lines.push(`fingerprint: ${bundle.fingerprint}`);
86
+ lines.push("");
87
+ lines.push("## Instructions (Model Injected)");
88
+
89
+ if (bundle.injection.instructions.length === 0) {
90
+ lines.push("(none)");
91
+ } else {
92
+ for (const item of bundle.injection.instructions) {
93
+ lines.push(`### ${item.relativePath}`);
94
+ lines.push(item.content);
95
+ lines.push("");
96
+ }
97
+ }
98
+
99
+ lines.push("## Rules (Model Injected)");
100
+ if (bundle.injection.rules.length === 0) {
101
+ lines.push("(none)");
102
+ } else {
103
+ for (const item of bundle.injection.rules) {
104
+ lines.push(`### ${item.relativePath}`);
105
+ lines.push(item.content);
106
+ lines.push("");
107
+ }
108
+ }
109
+
110
+ lines.push("## Skills (Path Discovery Only)");
111
+ lines.push("Native skill hot-swap is not available in runtime v1.");
112
+ for (const skill of bundle.injection.skills) {
113
+ lines.push(`- ${skill.name}`);
114
+ lines.push(` path: ${skill.path}`);
115
+ }
116
+
117
+ return lines.join("\n").trimEnd() + "\n";
118
+ }
119
+
120
+ function execFile(command: string, args: string[], cwd: string): Promise<{ stdout: string; stderr: string }> {
121
+ return new Promise((resolve, reject) => {
122
+ const child = spawn(command, args, { cwd, stdio: ["ignore", "pipe", "pipe"] });
123
+
124
+ let stdout = "";
125
+ let stderr = "";
126
+
127
+ child.stdout.on("data", (chunk) => {
128
+ stdout += String(chunk);
129
+ });
130
+ child.stderr.on("data", (chunk) => {
131
+ stderr += String(chunk);
132
+ });
133
+
134
+ child.on("error", reject);
135
+ child.on("close", (code) => {
136
+ if (code === 0) {
137
+ resolve({ stdout, stderr });
138
+ return;
139
+ }
140
+ reject(new Error(`loadouts runtime failed (${code}): ${stderr || stdout}`));
141
+ });
142
+ });
143
+ }
package/docs/index.md CHANGED
@@ -53,6 +53,7 @@ loadouts check # Validate configuration
53
53
  loadouts docs quickstart # Get started in 60 seconds
54
54
  loadouts docs concepts # Loadouts, artifacts, scopes, tools
55
55
  loadouts docs commands # Full command reference
56
+ loadouts docs runtime # Runtime activation architecture and capabilities
56
57
  loadouts docs authoring # Creating rules, skills, instructions
57
58
  loadouts docs compatibility # Tool paths, frontmatter aliases, limits
58
59
  loadouts docs workflows # Team setup, git, CI/CD
@@ -0,0 +1,107 @@
1
+ # Runtime Activation (OpenCode First)
2
+
3
+ `loadouts runtime` compiles loadouts into a session-time bundle without touching activated outputs on disk. Runtime v1 is designed as an OpenCode-first integration path and a reference surface for other tools.
4
+
5
+ ## Why Runtime Exists
6
+
7
+ - Keep activation side-effect free for agent sessions.
8
+ - Reuse the existing resolver and include semantics from standard loadout compilation.
9
+ - Make instruction/rule injection explicit and auditable in one JSON payload.
10
+ - Expose skill directories as references (path discovery only), without claiming native skill hot-swap.
11
+
12
+ ## Architecture
13
+
14
+ Runtime activation follows a resolver-backed bundle compiler:
15
+
16
+ 1. Resolve loadouts exactly like normal activation (`include`, source imports, bundled/global fallback, tool filtering).
17
+ 2. Compile supported artifacts into a `RuntimeBundle`.
18
+ 3. Return bundle JSON (`--json`) or a model-ready block (`--system-block`).
19
+
20
+ Key properties:
21
+
22
+ - Session-local state: caller owns lifecycle in memory/process state.
23
+ - No persistent activation changes: runtime commands do not mutate `.loadouts/.state.json`.
24
+ - No output rendering: runtime does not write `.opencode/`, `AGENTS.md`, or other tool target files.
25
+ - Deterministic fingerprinting: `fingerprint` is stable across `generatedAt` changes for equivalent content.
26
+
27
+ ## OpenCode-First Flow
28
+
29
+ Use OpenCode as the primary runtime consumer in v1:
30
+
31
+ ```bash
32
+ # JSON bridge for plugin/session adapters
33
+ loadouts runtime base backend --tool opencode --json
34
+
35
+ # Pre-rendered system block text
36
+ loadouts runtime base backend --tool opencode --system-block
37
+ ```
38
+
39
+ Recommended integration pattern:
40
+
41
+ - Compile once when a session starts or active runtime loadouts change.
42
+ - Cache by `fingerprint`.
43
+ - Inject `instructions` and `rules` into model/system context.
44
+ - Register `skills[*].path` for discovery only.
45
+
46
+ ### Slash Command UX (`/loadouts`)
47
+
48
+ The OpenCode runtime path is designed around a deterministic plugin-backed slash command:
49
+
50
+ ```text
51
+ /loadouts activate base
52
+ /loadouts a base -l
53
+ /loadouts a release -g
54
+ /loadouts list
55
+ /loadouts info base
56
+ /loadouts clear
57
+ ```
58
+
59
+ Expected behavior:
60
+
61
+ - The server plugin maps `/loadouts activate|a|use <names...>` to `loadouts runtime ...` (or equivalent runtime adapter path) and computes session runtime state deterministically.
62
+ - The TUI plugin listens for server plugin events and renders status/results in a TUI-only dialog that is not appended to chat and is not visible to the assistant.
63
+ - `-l/--local` and `-g/--global` are supported as direct scope selectors for runtime compilation.
64
+ - Runtime JSON and intermediate plugin outputs stay hidden from the model-facing response.
65
+ - The server and TUI plugins share persisted runtime state through `~/.cache/loadouts/opencode-runtime/<cwd-hash>.json`; the server plugin uses that state during system-message injection.
66
+ - A bundled scaffold loadout (`opencode-runtime`) renders `.opencode/plugins/loadouts-runtime.ts`, `.opencode/plugins/loadouts-runtime-tui.tsx`, and `.opencode/tui.jsonc`.
67
+
68
+ ### Known OpenCode Runtime Semantics
69
+
70
+ - The runtime plugin's `command.execute.before` hook is deterministic for parsing `/loadouts` arguments and updating runtime state.
71
+ - In interactive OpenCode, the server plugin owns `/loadouts` command handling and the TUI plugin owns user-visible feedback. If the TUI plugin is not loaded, the server plugin remains the headless/fallback path.
72
+ - OpenCode may still route server slash command text through model-facing flows when the TUI plugin is absent. Treat user-visible server acknowledgment text as host-dependent.
73
+ - OpenCode loads server plugins and TUI plugins at startup. Restart OpenCode after changing or activating runtime plugin or TUI config artifacts.
74
+ - The plugin bridge shells out to `loadouts runtime ...`. Ensure the `loadouts` binary available on OpenCode's `PATH` includes runtime support.
75
+ - The bundled TUI config is whole-file managed like other Loadouts config artifacts. Existing unmanaged `.opencode/tui.jsonc` files are protected by normal shadowing; add `./plugins/loadouts-runtime-tui.tsx` to your existing TUI config if needed.
76
+
77
+ ## Tool Capability Matrix (Runtime v1)
78
+
79
+ The bundle always includes resolved instructions, rules, and skill references. Capability flags tell consumers what should be treated as native runtime behavior for each tool.
80
+
81
+ | Tool | Runtime mode | Instruction/rule model injection | Skill path discovery | Native skill hot-swap |
82
+ |------|--------------|----------------------------------|----------------------|-----------------------|
83
+ | OpenCode | `experimental-runtime` | Yes | Yes | No |
84
+ | Pi | `native-runtime` | Yes | Yes | No |
85
+ | Codex | `experimental-runtime` | Yes | Yes | No |
86
+ | Claude Code | `filesystem-activation` | No | No | No |
87
+ | Cursor | `filesystem-activation` | No (not native) | No | No |
88
+
89
+ For filesystem-first tools, use standard `activate/sync` as the primary path and treat runtime output as inspection/debugging data.
90
+
91
+ ## Runtime v1 Limits
92
+
93
+ - Supported kinds: `instruction`, `rule`, `skill`.
94
+ - Agents are filesystem-rendered native definitions for supported harnesses; they are not injected through runtime v1.
95
+ - Unsupported kinds are reported as diagnostics, not hard failures.
96
+ - Skills require a `SKILL.md` entrypoint for runtime discovery metadata.
97
+ - Runtime v1 does not implement native skill hot-swap.
98
+
99
+ ## Reference Scaffold
100
+
101
+ - Bundled OpenCode server runtime plugin: `bundled/opencode/plugins/loadouts-runtime.ts`
102
+ - Bundled OpenCode TUI runtime plugin: `bundled/opencode/plugins/loadouts-runtime-tui.tsx`
103
+ - Bundled OpenCode TUI config: `bundled/opencode/tui.jsonc`
104
+ - Bundled scaffold loadout: `bundled/loadouts/opencode-runtime.yaml`
105
+ - Historical/reference plugin scaffold: `docs/examples/opencode-runtime-plugin.ts`
106
+ - Core compiler implementation: `src/core/runtime.ts`
107
+ - CLI command surface: `src/cli/commands/runtime.ts`
@@ -51,7 +51,24 @@ loadouts sync # Re-render if needed
51
51
 
52
52
  **Cursor:** Rules need `.mdc` extension — loadouts handles this automatically. Restart Cursor if rules don't appear immediately.
53
53
 
54
- **OpenCode:** Rules render to `.opencode/rules/`. Local plugins render to `.opencode/plugins/`, and NPM plugins are configured with the `plugin` array in `opencode.json(c)`.
54
+ **OpenCode:** Rules render to `.opencode/rules/`, commands to `.opencode/commands/`, local plugins to `.opencode/plugins/`, and NPM plugins are configured with the `plugin` array in `opencode.json(c)`.
55
+
56
+ ### `/loadouts` not working in OpenCode runtime
57
+
58
+ If `/loadouts` exists but does not activate runtime behavior, verify the full chain:
59
+
60
+ 1. Runtime artifacts are rendered in the expected scope:
61
+ - Local server plugin: `.opencode/plugins/loadouts-runtime.ts`
62
+ - Local TUI plugin/config: `.opencode/plugins/loadouts-runtime-tui.tsx` and `.opencode/tui.jsonc`
63
+ - Global server plugin: `~/.config/opencode/plugins/loadouts-runtime.ts`
64
+ - Global TUI plugin/config: `~/.config/opencode/plugins/loadouts-runtime-tui.tsx` and `~/.config/opencode/tui.jsonc`
65
+ 2. Runtime scaffold is active in the same scope (`loadouts info -l` or `loadouts info -g`).
66
+ 3. Restart OpenCode after activation or plugin/TUI config changes (startup-time plugin loading).
67
+ 4. Check the `loadouts` binary on OpenCode's `PATH` supports runtime:
68
+ ```bash
69
+ loadouts runtime base --tool opencode --json
70
+ ```
71
+ 5. In interactive OpenCode, the server plugin owns `/loadouts` and the TUI plugin listens for server events to render a user-only dialog. If command acknowledgment text looks model-generated, the TUI plugin is probably not loaded; the deterministic fallback is still server plugin state update and runtime system injection.
55
72
 
56
73
  **Claude Code:** Verify rules exist in `.claude/rules/`. May require restarting the session.
57
74