loadouts 0.2.3 → 0.2.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/builtins/agent-transforms.d.ts +9 -0
- package/dist/builtins/agent-transforms.d.ts.map +1 -0
- package/dist/builtins/agent-transforms.js +231 -0
- package/dist/builtins/agent-transforms.js.map +1 -0
- package/dist/builtins/index.d.ts.map +1 -1
- package/dist/builtins/index.js +7 -0
- package/dist/builtins/index.js.map +1 -1
- package/dist/builtins/kinds/agent.d.ts +3 -0
- package/dist/builtins/kinds/agent.d.ts.map +1 -0
- package/dist/builtins/kinds/agent.js +8 -0
- package/dist/builtins/kinds/agent.js.map +1 -0
- package/dist/builtins/tools/claude-code.d.ts.map +1 -1
- package/dist/builtins/tools/claude-code.js +7 -1
- package/dist/builtins/tools/claude-code.js.map +1 -1
- package/dist/builtins/tools/codex.d.ts.map +1 -1
- package/dist/builtins/tools/codex.js +10 -1
- package/dist/builtins/tools/codex.js.map +1 -1
- package/dist/builtins/tools/cursor.d.ts.map +1 -1
- package/dist/builtins/tools/cursor.js +7 -1
- package/dist/builtins/tools/cursor.js.map +1 -1
- package/dist/builtins/tools/opencode.d.ts.map +1 -1
- package/dist/builtins/tools/opencode.js +7 -0
- package/dist/builtins/tools/opencode.js.map +1 -1
- package/dist/cli/commands/activate.d.ts.map +1 -1
- package/dist/cli/commands/activate.js +2 -0
- package/dist/cli/commands/activate.js.map +1 -1
- package/dist/cli/commands/docs.d.ts.map +1 -1
- package/dist/cli/commands/docs.js +2 -1
- package/dist/cli/commands/docs.js.map +1 -1
- package/dist/cli/commands/doctor.d.ts.map +1 -1
- package/dist/cli/commands/doctor.js +10 -0
- package/dist/cli/commands/doctor.js.map +1 -1
- package/dist/cli/commands/init.d.ts.map +1 -1
- package/dist/cli/commands/init.js +5 -0
- package/dist/cli/commands/init.js.map +1 -1
- package/dist/cli/commands/install.d.ts.map +1 -1
- package/dist/cli/commands/install.js +15 -3
- package/dist/cli/commands/install.js.map +1 -1
- package/dist/cli/commands/migrate.d.ts +31 -0
- package/dist/cli/commands/migrate.d.ts.map +1 -0
- package/dist/cli/commands/migrate.js +223 -0
- package/dist/cli/commands/migrate.js.map +1 -0
- package/dist/cli/commands/render-engine.d.ts +1 -0
- package/dist/cli/commands/render-engine.d.ts.map +1 -1
- package/dist/cli/commands/render-engine.js +10 -35
- package/dist/cli/commands/render-engine.js.map +1 -1
- package/dist/cli/commands/runtime.d.ts +21 -0
- package/dist/cli/commands/runtime.d.ts.map +1 -0
- package/dist/cli/commands/runtime.js +100 -0
- package/dist/cli/commands/runtime.js.map +1 -0
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli/index.js +4 -0
- package/dist/cli/index.js.map +1 -1
- package/dist/core/agent-migration.d.ts +13 -0
- package/dist/core/agent-migration.d.ts.map +1 -0
- package/dist/core/agent-migration.js +397 -0
- package/dist/core/agent-migration.js.map +1 -0
- package/dist/core/import-discovery.d.ts.map +1 -1
- package/dist/core/import-discovery.js +27 -0
- package/dist/core/import-discovery.js.map +1 -1
- package/dist/core/kindLoader.d.ts +10 -4
- package/dist/core/kindLoader.d.ts.map +1 -1
- package/dist/core/kindLoader.js +22 -10
- package/dist/core/kindLoader.js.map +1 -1
- package/dist/core/registry.d.ts +4 -2
- package/dist/core/registry.d.ts.map +1 -1
- package/dist/core/registry.js.map +1 -1
- package/dist/core/render.d.ts.map +1 -1
- package/dist/core/render.js +14 -6
- package/dist/core/render.js.map +1 -1
- package/dist/core/resolve.d.ts +17 -1
- package/dist/core/resolve.d.ts.map +1 -1
- package/dist/core/resolve.js +50 -27
- package/dist/core/resolve.js.map +1 -1
- package/dist/core/runtime.d.ts +79 -0
- package/dist/core/runtime.d.ts.map +1 -0
- package/dist/core/runtime.js +345 -0
- package/dist/core/runtime.js.map +1 -0
- package/dist/lib/artifact-paths.d.ts.map +1 -1
- package/dist/lib/artifact-paths.js +4 -0
- package/dist/lib/artifact-paths.js.map +1 -1
- package/dist/lib/artifact-table.d.ts.map +1 -1
- package/dist/lib/artifact-table.js +13 -1
- package/dist/lib/artifact-table.js.map +1 -1
- package/dist/lib/gitignore.d.ts.map +1 -1
- package/dist/lib/gitignore.js +2 -0
- package/dist/lib/gitignore.js.map +1 -1
- package/docs/authoring.md +66 -1
- package/docs/commands.md +30 -0
- package/docs/compatibility.md +15 -8
- package/docs/concepts.md +8 -7
- package/docs/examples/opencode-runtime-plugin.ts +143 -0
- package/docs/index.md +1 -0
- package/docs/runtime.md +72 -0
- package/package.json +1 -1
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:
|
package/docs/commands.md
CHANGED
|
@@ -46,6 +46,18 @@ 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 --json # Output RuntimeBundle JSON only
|
|
56
|
+
loadouts runtime base --system-block # Output renderRuntimeSystemBlock(bundle) only
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
See `docs/runtime.md` for architecture, OpenCode-first integration flow, and per-tool capability flags.
|
|
60
|
+
|
|
49
61
|
### `loadouts diff [name]`
|
|
50
62
|
Preview what would change if a loadout were applied.
|
|
51
63
|
```bash
|
|
@@ -73,10 +85,26 @@ loadouts install ./rule.mdc # Import a single rule file
|
|
|
73
85
|
loadouts install --dry-run # Preview
|
|
74
86
|
loadouts install -i # Interactive
|
|
75
87
|
loadouts install --rules # Rules only
|
|
88
|
+
loadouts install --kinds agent # Import and canonicalize agents
|
|
76
89
|
loadouts install --from cursor # From specific tool
|
|
77
90
|
loadouts install --keep # Don't delete originals
|
|
78
91
|
```
|
|
79
92
|
|
|
93
|
+
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.
|
|
94
|
+
|
|
95
|
+
### `loadouts migrate agents [source]`
|
|
96
|
+
Migrate native harness agent definitions that already live in a loadout tree into canonical `.loadouts/agents/*.md` files.
|
|
97
|
+
|
|
98
|
+
```bash
|
|
99
|
+
loadouts migrate agents # Scan legacy agent paths in current loadout
|
|
100
|
+
loadouts migrate agents --dry-run # Preview migration
|
|
101
|
+
loadouts migrate agents --keep # Keep old native files
|
|
102
|
+
loadouts migrate agents --force # Overwrite existing canonical agents
|
|
103
|
+
loadouts migrate agents ./agents --from opencode
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
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.
|
|
107
|
+
|
|
80
108
|
### `loadouts create <name>`
|
|
81
109
|
Create a new loadout definition.
|
|
82
110
|
```bash
|
|
@@ -196,6 +224,8 @@ Most state commands (`activate`, `deactivate`, `sync`, `status`, `clear`, `list`
|
|
|
196
224
|
| `-g, --global` | Global scope only |
|
|
197
225
|
| `-a, --all` | Both scopes |
|
|
198
226
|
|
|
227
|
+
`runtime` supports `-l/--local` and `-g/--global` only (no `--all`).
|
|
228
|
+
|
|
199
229
|
When omitted, commands auto-detect scope based on context. Use `--dry-run` to preview behavior before destructive operations.
|
|
200
230
|
|
|
201
231
|
---
|
package/docs/compatibility.md
CHANGED
|
@@ -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 |
|
|
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` |
|
|
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
|
-
-
|
|
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,6 +74,7 @@ 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 |
|
|
@@ -83,13 +84,13 @@ include:
|
|
|
83
84
|
|
|
84
85
|
## Supported Tools
|
|
85
86
|
|
|
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/` |
|
|
87
|
+
| Tool | Rules | Skills | Agents | Instructions | Extra Artifacts |
|
|
88
|
+
|------|-------|--------|--------|--------------|-----------------|
|
|
89
|
+
| Claude Code | `.claude/rules/*.md` | `.claude/skills/` | `.claude/agents/*.md` | `CLAUDE.md` | — |
|
|
90
|
+
| Cursor | `.cursor/rules/*.mdc` | `.cursor/skills/` | `.cursor/agents/*.md` | `AGENTS.md` | — |
|
|
91
|
+
| OpenCode | `.opencode/rules/*.md` | `.opencode/skills/` | `.opencode/agents/*.md` | `AGENTS.md` | `opencode.json(c)`, `.opencode/plugins/` |
|
|
92
|
+
| Codex | — | `.agents/skills/` | `.codex/agents/*.toml` | `AGENTS.md` | — |
|
|
93
|
+
| Pi | `.pi/rules/*.md` | `.pi/skills/` | — | `AGENTS.md` | `.pi/extensions/`, `.pi/themes/` |
|
|
93
94
|
|
|
94
95
|
## Sources (Cross-Project Config)
|
|
95
96
|
|
|
@@ -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
|
package/docs/runtime.md
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
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
|
+
## Tool Capability Matrix (Runtime v1)
|
|
47
|
+
|
|
48
|
+
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.
|
|
49
|
+
|
|
50
|
+
| Tool | Runtime mode | Instruction/rule model injection | Skill path discovery | Native skill hot-swap |
|
|
51
|
+
|------|--------------|----------------------------------|----------------------|-----------------------|
|
|
52
|
+
| OpenCode | `experimental-runtime` | Yes | Yes | No |
|
|
53
|
+
| Pi | `native-runtime` | Yes | Yes | No |
|
|
54
|
+
| Codex | `experimental-runtime` | Yes | Yes | No |
|
|
55
|
+
| Claude Code | `filesystem-activation` | No | No | No |
|
|
56
|
+
| Cursor | `filesystem-activation` | No (not native) | No | No |
|
|
57
|
+
|
|
58
|
+
For filesystem-first tools, use standard `activate/sync` as the primary path and treat runtime output as inspection/debugging data.
|
|
59
|
+
|
|
60
|
+
## Runtime v1 Limits
|
|
61
|
+
|
|
62
|
+
- Supported kinds: `instruction`, `rule`, `skill`.
|
|
63
|
+
- Agents are filesystem-rendered native definitions for supported harnesses; they are not injected through runtime v1.
|
|
64
|
+
- Unsupported kinds are reported as diagnostics, not hard failures.
|
|
65
|
+
- Skills require a `SKILL.md` entrypoint for runtime discovery metadata.
|
|
66
|
+
- Runtime v1 does not implement native skill hot-swap.
|
|
67
|
+
|
|
68
|
+
## Reference Scaffold
|
|
69
|
+
|
|
70
|
+
- Example OpenCode plugin scaffold: `docs/examples/opencode-runtime-plugin.ts`
|
|
71
|
+
- Core compiler implementation: `src/core/runtime.ts`
|
|
72
|
+
- CLI command surface: `src/cli/commands/runtime.ts`
|