claude-code-swarm 0.3.23 → 0.3.25
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/.claude-plugin/marketplace.json +1 -1
- package/.claude-plugin/plugin.json +1 -1
- package/docs/loadout-consumer-design.md +469 -0
- package/e2e/tier7-loadout-live.test.mjs +221 -0
- package/package.json +3 -3
- package/scripts/map-sidecar.mjs +34 -0
- package/scripts/scope-check.mjs +132 -0
- package/skills/swarm-mcp/SKILL.md +116 -0
- package/src/__tests__/cognitive-core-loadout-e2e.test.mjs +260 -0
- package/src/__tests__/e2e-loadout-demo.test.mjs +150 -0
- package/src/__tests__/fixtures/loadout-compile-team/loadouts/base-reviewer.yaml +16 -0
- package/src/__tests__/fixtures/loadout-compile-team/loadouts/extended-security.yaml +10 -0
- package/src/__tests__/fixtures/loadout-compile-team/roles/auditor.yaml +4 -0
- package/src/__tests__/fixtures/loadout-compile-team/roles/inline-extender.yaml +10 -0
- package/src/__tests__/fixtures/loadout-compile-team/roles/reviewer.yaml +4 -0
- package/src/__tests__/fixtures/loadout-compile-team/team.yaml +15 -0
- package/src/__tests__/loadout-materializer.test.mjs +578 -0
- package/src/__tests__/loadout-schema-bridge.test.mjs +177 -0
- package/src/__tests__/loadout-skilltree-compile-e2e.test.mjs +444 -0
- package/src/__tests__/loadout-template-shape.test.mjs +102 -0
- package/src/__tests__/mcp-health-checker.test.mjs +327 -0
- package/src/__tests__/scope-check.test.mjs +210 -0
- package/src/__tests__/skilltree-client.test.mjs +185 -1
- package/src/agent-generator.mjs +135 -8
- package/src/context-output.mjs +32 -0
- package/src/loadout-materializer.mjs +315 -0
- package/src/mcp-health-checker.mjs +237 -0
- package/src/opentasks-bridge.mjs +140 -0
- package/src/skilltree-client.mjs +135 -24
- package/src/template.mjs +158 -2
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "claude-code-swarm",
|
|
3
3
|
"description": "Spin up Claude Code agent teams from openteams YAML topologies with optional MAP (Multi-Agent Protocol) observability and coordination. Provides hooks for session lifecycle, agent spawn/complete tracking, and a /swarm skill to launch team configurations.",
|
|
4
|
-
"version": "0.3.
|
|
4
|
+
"version": "0.3.25",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "alexngai"
|
|
7
7
|
},
|
|
@@ -0,0 +1,469 @@
|
|
|
1
|
+
# Loadout Consumer Design
|
|
2
|
+
|
|
3
|
+
**Status:** Proposed — scope locked, implementation pending.
|
|
4
|
+
**Author:** Iterative design session (openhive + claude-code-swarm + openteams)
|
|
5
|
+
**Date:** 2026-04-21
|
|
6
|
+
**Scope:** claude-code-swarm's consumer integration for openteams loadouts.
|
|
7
|
+
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
## TL;DR
|
|
11
|
+
|
|
12
|
+
openteams 0.3 introduced **loadouts** — reusable bundles of skills, capabilities, MCP servers, permissions, and prompt material that bind to roles on a team. claude-code-swarm materializes loadouts into per-role Claude Code sub-agent definitions.
|
|
13
|
+
|
|
14
|
+
The materialization is **fully non-invasive by default**: claude-code-swarm writes only to `.claude/agents/` (for sub-agent discovery) and `.swarm/claude-swarm/` (its own namespace). It never modifies `.mcp.json`, `.claude/settings.json`, or any user-global config without an explicit user command.
|
|
15
|
+
|
|
16
|
+
Per-role MCP scope and permissions enforcement lives in the sub-agent frontmatter (`mcpServers:`, `tools:`, `disallowedTools:`, `hooks:`). A bundled PreToolUse hook provides fine-grained scope enforcement without modifying session-level settings.
|
|
17
|
+
|
|
18
|
+
---
|
|
19
|
+
|
|
20
|
+
## Motivation
|
|
21
|
+
|
|
22
|
+
### What loadouts give us
|
|
23
|
+
|
|
24
|
+
Before loadouts, agent capabilities, MCP servers, permissions, and skill loadouts were all configured in disparate places — some in team YAML, some in plugin.json, some implicitly via capability manual lists. Users had no single place to customize what an agent could do, and no way to share that configuration across teams.
|
|
25
|
+
|
|
26
|
+
Loadouts collapse these concerns into a single first-class primitive with inheritance, scope declarations, and install specs separated cleanly. See the openteams `design.md` for the canonical shape.
|
|
27
|
+
|
|
28
|
+
### What claude-code-swarm must do
|
|
29
|
+
|
|
30
|
+
claude-code-swarm is the runtime consumer that translates loadouts into Claude Code's sub-agent mechanism. Its job:
|
|
31
|
+
|
|
32
|
+
1. Read the resolved loadout for each role from openteams.
|
|
33
|
+
2. Materialize per-role `AGENT.md` files with the right frontmatter and body.
|
|
34
|
+
3. Surface MCP install requirements without auto-installing.
|
|
35
|
+
4. Enforce per-role scope (which MCP tools a role may call) without touching global settings.
|
|
36
|
+
5. Provide explicit opt-in commands for users who want the traditional "install to `.mcp.json`" path.
|
|
37
|
+
|
|
38
|
+
### What we want to avoid
|
|
39
|
+
|
|
40
|
+
The prior approach would have been to auto-write `.mcp.json` and `.claude/settings.json` from every loadout. This is invasive:
|
|
41
|
+
|
|
42
|
+
- User-owned config gets mutated every team spawn.
|
|
43
|
+
- Two teams with overlapping MCP declarations create install conflicts.
|
|
44
|
+
- Permissions accumulated from many roles are hard to audit.
|
|
45
|
+
- Reversing the changes is manual and error-prone.
|
|
46
|
+
|
|
47
|
+
The non-invasive model is a deliberate tradeoff: we give up some convenience (no automatic runtime install) in exchange for predictability and user trust.
|
|
48
|
+
|
|
49
|
+
---
|
|
50
|
+
|
|
51
|
+
## Design Principles
|
|
52
|
+
|
|
53
|
+
1. **Zero invasive writes by default.** claude-code-swarm never modifies `.mcp.json`, `.claude/settings.json`, or user-global config unless the user explicitly requests it via a slash command.
|
|
54
|
+
2. **Sub-agent definitions are artifacts, not config.** Writing `.claude/agents/<team>-<role>.md` is an output of claude-code-swarm, namespaced per team. These files are markered, cleanable, and gitignore-friendly.
|
|
55
|
+
3. **All scope enforcement lives in sub-agent frontmatter.** `mcpServers:`, `tools:`, `disallowedTools:`, and `hooks:` handle per-agent restriction without session-level mutation.
|
|
56
|
+
4. **Install specs are advisory.** Team-declared `mcp_providers` are cached and reported, never auto-installed.
|
|
57
|
+
5. **Explicit opt-in for invasive writes.** `/swarm mcp install <name>` and `/swarm permissions sync` exist for users who want the traditional path — always with confirmation and diff preview.
|
|
58
|
+
6. **Health check as feedback, not gatekeeping.** SessionStart reports missing MCPs without blocking; PreToolUse hooks block individual out-of-scope calls with actionable error messages.
|
|
59
|
+
|
|
60
|
+
---
|
|
61
|
+
|
|
62
|
+
## Architecture
|
|
63
|
+
|
|
64
|
+
```
|
|
65
|
+
┌──────────────────────────────────────────────────────────────┐
|
|
66
|
+
│ /swarm <template> │
|
|
67
|
+
│ │
|
|
68
|
+
│ scripts/team-loader.mjs │
|
|
69
|
+
│ ↓ │
|
|
70
|
+
│ src/template.mjs : loadTeam() │
|
|
71
|
+
│ ↓ openteams TemplateLoader.load() │
|
|
72
|
+
│ → ResolvedTemplate { mcpProviders, loadouts, ... } │
|
|
73
|
+
│ ↓ cache artifacts to .swarm/claude-swarm/tmp/teams/<t>/ │
|
|
74
|
+
│ ├── mcp-providers.json │
|
|
75
|
+
│ ├── loadouts/<role>.json │
|
|
76
|
+
│ ├── scope/<role>.json ← per-role scope file │
|
|
77
|
+
│ └── missing-mcp.json │
|
|
78
|
+
│ ↓ │
|
|
79
|
+
│ src/loadout-materializer.mjs │
|
|
80
|
+
│ ↓ generateAgentFrontmatter(role, loadout, template) │
|
|
81
|
+
│ ↓ │
|
|
82
|
+
│ src/agent-generator.mjs : generateAgentMd() │
|
|
83
|
+
│ ↓ writes to .claude/agents/<team>-<role>.md │
|
|
84
|
+
│ (or ~/.claude/agents/ with --scope=user) │
|
|
85
|
+
│ │
|
|
86
|
+
│ SessionStart hook │
|
|
87
|
+
│ ↓ src/mcp-health-checker.mjs │
|
|
88
|
+
│ → prints report: active / declared / missing │
|
|
89
|
+
│ │
|
|
90
|
+
│ Runtime │
|
|
91
|
+
│ ↓ Claude Code spawns agent via Agent() tool │
|
|
92
|
+
│ ↓ Agent loads frontmatter (mcpServers, tools, hooks) │
|
|
93
|
+
│ ↓ PreToolUse hook scope-check.mjs gates MCP calls │
|
|
94
|
+
│ via per-role scope file │
|
|
95
|
+
└──────────────────────────────────────────────────────────────┘
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
### Components
|
|
99
|
+
|
|
100
|
+
- **loadout-materializer** — pure function, loadout → frontmatter YAML
|
|
101
|
+
- **mcp-scope-resolver** — pure function, normalized scope → `mcpServers` / `tools` / `disallowedTools` lists
|
|
102
|
+
- **mcp-health-checker** — pure function, providers ∩ active set → report
|
|
103
|
+
- **scope-check hook** — generic PreToolUse, reads per-role scope JSON, gates tool calls
|
|
104
|
+
- **swarm-mcp skill** — slash commands for user-initiated operations
|
|
105
|
+
|
|
106
|
+
---
|
|
107
|
+
|
|
108
|
+
## Materialized Artifacts
|
|
109
|
+
|
|
110
|
+
### AGENT.md frontmatter (example)
|
|
111
|
+
|
|
112
|
+
```yaml
|
|
113
|
+
---
|
|
114
|
+
name: loadout-demo-reviewer
|
|
115
|
+
description: Reviewer role for loadout-demo team
|
|
116
|
+
team_name: loadout-demo
|
|
117
|
+
role: reviewer
|
|
118
|
+
generated_by: claude-code-swarm
|
|
119
|
+
generated_at: 2026-04-21T14:30:00Z
|
|
120
|
+
project_path: /absolute/path/to/project
|
|
121
|
+
|
|
122
|
+
# Native Claude Code tools — explicit allowlist
|
|
123
|
+
tools:
|
|
124
|
+
- Read
|
|
125
|
+
- Grep
|
|
126
|
+
- Glob
|
|
127
|
+
- Bash
|
|
128
|
+
|
|
129
|
+
# Per-agent MCP scope (string refs for session-level servers; inline for ephemeral)
|
|
130
|
+
mcpServers:
|
|
131
|
+
- ast-grep
|
|
132
|
+
- chrome-devtools
|
|
133
|
+
|
|
134
|
+
# MCP tool denies (from loadout exclude lists)
|
|
135
|
+
disallowedTools:
|
|
136
|
+
- mcp__ast-grep__dangerous_replace
|
|
137
|
+
|
|
138
|
+
# Fine-grained scope enforcement via per-agent hook
|
|
139
|
+
hooks:
|
|
140
|
+
PreToolUse:
|
|
141
|
+
- matcher: "mcp__.*"
|
|
142
|
+
hooks:
|
|
143
|
+
- type: command
|
|
144
|
+
command: ${CLAUDE_PLUGIN_ROOT}/hooks/scope-check.mjs
|
|
145
|
+
env:
|
|
146
|
+
SCOPE_FILE: .swarm/claude-swarm/tmp/teams/loadout-demo/scope/reviewer.json
|
|
147
|
+
|
|
148
|
+
# Loadout capabilities (informational to Claude Code; consumed by macro-agent)
|
|
149
|
+
capabilities:
|
|
150
|
+
- file.read
|
|
151
|
+
- git.diff
|
|
152
|
+
- codebase.search
|
|
153
|
+
- exec.test
|
|
154
|
+
- task.update
|
|
155
|
+
---
|
|
156
|
+
|
|
157
|
+
# Reviewer — loadout-demo team
|
|
158
|
+
|
|
159
|
+
[role prompt body]
|
|
160
|
+
|
|
161
|
+
## Review Mindset
|
|
162
|
+
[loadout.promptAddendum from inheritance chain]
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
### Per-role scope file
|
|
166
|
+
|
|
167
|
+
```json
|
|
168
|
+
{
|
|
169
|
+
"role": "reviewer",
|
|
170
|
+
"team": "loadout-demo",
|
|
171
|
+
"scope": [
|
|
172
|
+
{ "server": "ast-grep", "exclude": ["dangerous_replace"] },
|
|
173
|
+
{ "server": "chrome-devtools", "tools": ["navigate", "screenshot", "get_page_text"] }
|
|
174
|
+
],
|
|
175
|
+
"permissions": {
|
|
176
|
+
"allow": ["Read(**)", "Bash(git diff:*)"],
|
|
177
|
+
"deny": ["Bash(git push:*)", "Bash(rm -rf:*)"]
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
The hook reads this file (path injected via `SCOPE_FILE` env var in the frontmatter hook declaration), parses the incoming tool name, and exits with code 2 if the tool is out of scope.
|
|
183
|
+
|
|
184
|
+
### Scope → frontmatter translation rules
|
|
185
|
+
|
|
186
|
+
Implemented in `mcp-scope-resolver.mjs`:
|
|
187
|
+
|
|
188
|
+
| Loadout scope entry | Frontmatter emission |
|
|
189
|
+
|---|---|
|
|
190
|
+
| `{ server: "opentasks" }` (bare) | `mcpServers: [opentasks]` — full server access; no explicit tool list |
|
|
191
|
+
| `{ server: "chrome-devtools", tools: ["navigate"] }` | `mcpServers: [chrome-devtools]` + per-agent hook narrows to `navigate` |
|
|
192
|
+
| `{ server: "ast-grep", exclude: ["dangerous"] }` | `mcpServers: [ast-grep]` + `disallowedTools: [mcp__ast-grep__dangerous]` |
|
|
193
|
+
| Install spec (`{ name, command, args }`) | `mcpServers: [{ inline install spec }]` — per-agent subprocess (advisory) |
|
|
194
|
+
| Symbolic ref (`{ ref: "@..." }`) | Skip (warn) unless resolved via bundled registry or hive DB |
|
|
195
|
+
|
|
196
|
+
When tools are specified as an allowlist (`tools: [...]`) rather than a denylist (`exclude: [...]`), we cannot use `tools:` frontmatter wildcards. Instead, the hook enforces the allowlist via the scope file. This keeps the materializer simple at the cost of one more hook invocation per tool call.
|
|
197
|
+
|
|
198
|
+
---
|
|
199
|
+
|
|
200
|
+
## The Non-Invasive Contract
|
|
201
|
+
|
|
202
|
+
### What claude-code-swarm writes (by default)
|
|
203
|
+
|
|
204
|
+
| Path | Contents | Invasiveness |
|
|
205
|
+
|---|---|---|
|
|
206
|
+
| `.swarm/claude-swarm/tmp/teams/<t>/` | Artifact cache (providers, loadouts, scope, missing-mcp) | Low — swarm namespace |
|
|
207
|
+
| `.claude/agents/<team>-<role>.md` | Generated sub-agent definitions | Low — namespaced, markered, cleanable |
|
|
208
|
+
| `~/.claude/agents/<project-slug>-<team>-<role>.md` | User-scoped variant (opt-in) | Low — same treatment, user-scoped |
|
|
209
|
+
|
|
210
|
+
### What claude-code-swarm never writes (by default)
|
|
211
|
+
|
|
212
|
+
| Path | Reason |
|
|
213
|
+
|---|---|
|
|
214
|
+
| `.mcp.json` | User-owned session config. Only written on `/swarm mcp install` with confirmation. |
|
|
215
|
+
| `.claude/settings.json` | User-owned session config. Committed to version control. Never modified. |
|
|
216
|
+
| `.claude/settings.local.json` | User-owned local override. Only written on `/swarm permissions sync` with confirmation. |
|
|
217
|
+
| `~/.claude/settings.json` | User-global. Never touched. |
|
|
218
|
+
| `~/.claude/mcp.json` | User-global. Never touched. |
|
|
219
|
+
|
|
220
|
+
### Markers on generated files
|
|
221
|
+
|
|
222
|
+
Every AGENT.md written by claude-code-swarm includes:
|
|
223
|
+
|
|
224
|
+
```yaml
|
|
225
|
+
generated_by: claude-code-swarm
|
|
226
|
+
generated_at: <ISO timestamp>
|
|
227
|
+
team_name: <template>
|
|
228
|
+
project_path: <absolute>
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
`/swarm clean` only removes files matching these markers — never touches hand-authored agents in `.claude/agents/`.
|
|
232
|
+
|
|
233
|
+
---
|
|
234
|
+
|
|
235
|
+
## Explicit Opt-In Commands
|
|
236
|
+
|
|
237
|
+
For users who want the traditional "install everything automatically" experience, four slash commands exist. All require confirmation and show a diff before writing.
|
|
238
|
+
|
|
239
|
+
### `/swarm mcp check`
|
|
240
|
+
|
|
241
|
+
Dry-run health report. Prints missing/extra/conflicting MCP servers; no filesystem changes.
|
|
242
|
+
|
|
243
|
+
### `/swarm mcp install <name>`
|
|
244
|
+
|
|
245
|
+
Writes the named provider (from `template.mcpProviders`) into project `.mcp.json`. Strips openteams-specific fields (`ref`, `description`, `disabled`). Confirms before writing. `--all` installs every declared provider not already active.
|
|
246
|
+
|
|
247
|
+
### `/swarm permissions sync`
|
|
248
|
+
|
|
249
|
+
Merges the union of all roles' permissions (loadout `permissions.{allow,deny,ask}` + scope-translated MCP patterns) into `.claude/settings.local.json`. Uses a clearly-namespaced block:
|
|
250
|
+
|
|
251
|
+
```jsonc
|
|
252
|
+
// .claude/settings.local.json
|
|
253
|
+
{
|
|
254
|
+
"permissions": {
|
|
255
|
+
"allow": [
|
|
256
|
+
/* swarm:loadout-demo:start */
|
|
257
|
+
"Read(**)",
|
|
258
|
+
"Bash(git diff:*)",
|
|
259
|
+
"mcp__opentasks__*",
|
|
260
|
+
"mcp__chrome-devtools__navigate"
|
|
261
|
+
/* swarm:loadout-demo:end */
|
|
262
|
+
]
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
The markers let the command surgically update the block on subsequent runs without disturbing user-authored permissions.
|
|
268
|
+
|
|
269
|
+
### `/swarm clean`
|
|
270
|
+
|
|
271
|
+
Removes generated AGENT.md files and cached artifacts for the current team (or all teams with `--all`). Respects markers — never removes hand-authored agents.
|
|
272
|
+
|
|
273
|
+
### `/swarm mcp resolve-ref <ref>`
|
|
274
|
+
|
|
275
|
+
Resolves a symbolic ref against bundled registries or user-provided resolvers. Optional for PR 3; refs are skipped with a warning by default until this is implemented.
|
|
276
|
+
|
|
277
|
+
---
|
|
278
|
+
|
|
279
|
+
## Agent Scope Configuration
|
|
280
|
+
|
|
281
|
+
Default: **project-scoped** at `<project>/.claude/agents/<team>-<role>.md`.
|
|
282
|
+
|
|
283
|
+
### Rationale
|
|
284
|
+
|
|
285
|
+
- Team definitions are typically chosen for a specific project.
|
|
286
|
+
- `.swarm/claude-swarm/tmp/` is already project-scoped; keeping agents there matches.
|
|
287
|
+
- Name collisions between projects are impossible.
|
|
288
|
+
- Cleanup is trivial (`rm <project>`).
|
|
289
|
+
- Claude Code only sees the project's agents when running in that project.
|
|
290
|
+
|
|
291
|
+
### Opt-in: user-scoped
|
|
292
|
+
|
|
293
|
+
```jsonc
|
|
294
|
+
// .swarm/claude-swarm/config.json
|
|
295
|
+
{ "agentScope": "user" }
|
|
296
|
+
```
|
|
297
|
+
|
|
298
|
+
Or per-invocation: `/swarm <template> --scope=user`.
|
|
299
|
+
|
|
300
|
+
User-scoped behavior:
|
|
301
|
+
- Filenames get a project-slug prefix: `~/.claude/agents/<project-slug>-<team>-<role>.md`
|
|
302
|
+
- Frontmatter records `project_path:` to trace origin.
|
|
303
|
+
- `/swarm clean --scope=user` only removes files traceable to the current project.
|
|
304
|
+
- Same-named agents in both scopes: project-scoped wins (Claude Code precedence).
|
|
305
|
+
|
|
306
|
+
### Cleanup across scopes
|
|
307
|
+
|
|
308
|
+
- `/swarm clean` — defaults to the currently configured scope
|
|
309
|
+
- `/swarm clean --scope=project|user|all` — explicit
|
|
310
|
+
|
|
311
|
+
---
|
|
312
|
+
|
|
313
|
+
## SessionStart Health Check
|
|
314
|
+
|
|
315
|
+
A SessionStart hook invokes `mcp-health-checker.mjs` at team launch. Output is informational — never blocks session start.
|
|
316
|
+
|
|
317
|
+
```
|
|
318
|
+
╭─ loadout-demo team MCP status ──────────────────────╮
|
|
319
|
+
│ │
|
|
320
|
+
│ ✓ opentasks (plugin) │
|
|
321
|
+
│ ✓ agent-inbox (plugin) │
|
|
322
|
+
│ ✓ ast-grep (user ~/.claude/mcp.json) │
|
|
323
|
+
│ ⚠ chrome-devtools (declared, not active) │
|
|
324
|
+
│ → /swarm mcp install chrome-devtools │
|
|
325
|
+
│ ⚠ secrets-scanner (ref deferred) │
|
|
326
|
+
│ → /swarm mcp resolve-ref @openhive/secrets... │
|
|
327
|
+
│ │
|
|
328
|
+
│ Agents generated: 3 (at .claude/agents/) │
|
|
329
|
+
│ Scope files: 3 (at .swarm/.../scope/) │
|
|
330
|
+
╰─────────────────────────────────────────────────────╯
|
|
331
|
+
```
|
|
332
|
+
|
|
333
|
+
Discovery sources for the "active set":
|
|
334
|
+
- Plugin `.claude-plugin/plugin.json:mcpServers`
|
|
335
|
+
- Project `.mcp.json` (if present)
|
|
336
|
+
- User `~/.claude/mcp.json` (if present)
|
|
337
|
+
- Future: OpenHive hive DB via IPC
|
|
338
|
+
|
|
339
|
+
---
|
|
340
|
+
|
|
341
|
+
## macro-agent Consideration
|
|
342
|
+
|
|
343
|
+
macro-agent is an orchestration layer above claude-code-swarm. For Claude workers, it delegates to claude-code-swarm for spawning. For Codex/Gemini workers, it materializes loadouts to its own runtime formats.
|
|
344
|
+
|
|
345
|
+
The claude-code-swarm work in this document is upstream of macro-agent; macro-agent consumes the materialized artifacts indirectly.
|
|
346
|
+
|
|
347
|
+
macro-agent's additional responsibilities (not covered here):
|
|
348
|
+
- Reads `role.loadout.capabilities` for runtime tool filtering via `isToolAllowedForRole`.
|
|
349
|
+
- Optionally installs MCP servers from `template.mcpProviders` before spawning (explicit, opt-in).
|
|
350
|
+
- Implements its own materializers for non-Claude runtimes.
|
|
351
|
+
|
|
352
|
+
Per-role loadout enforcement in macro-agent rides the same primitives — `role.loadout.mcpScope` drives filter policy identically whether the runtime is Claude Code, Codex, or Gemini.
|
|
353
|
+
|
|
354
|
+
---
|
|
355
|
+
|
|
356
|
+
## Alternatives Considered
|
|
357
|
+
|
|
358
|
+
### Alternative 1: Auto-write `.mcp.json` and `.claude/settings.json`
|
|
359
|
+
|
|
360
|
+
**Rejected.** Mutates user-owned config on every team spawn; creates conflicts between overlapping teams; reversal is manual. The convenience isn't worth the loss of user trust.
|
|
361
|
+
|
|
362
|
+
### Alternative 2: Inline all agent definitions via `Agent({ prompt: ... })`, never write `.claude/agents/`
|
|
363
|
+
|
|
364
|
+
**Rejected.** Loses access to per-agent `mcpServers:`, `hooks:`, `tools:`, `disallowedTools:` frontmatter. Scope enforcement collapses back to session-level, which forces us to mutate settings.json (the thing we're trying to avoid).
|
|
365
|
+
|
|
366
|
+
### Alternative 3: Plugin-distributed sub-agents via claude-code-swarm plugin
|
|
367
|
+
|
|
368
|
+
**Rejected.** Plugin sub-agents cannot use `mcpServers:` (Claude Code security restriction). Loses per-agent MCP scope, which is a core loadout feature.
|
|
369
|
+
|
|
370
|
+
### Alternative 4: Full tool enumeration in `tools:` frontmatter (no hook)
|
|
371
|
+
|
|
372
|
+
**Rejected.** Requires introspecting MCP servers at generation time or shipping a stale tool registry. Fragile under MCP server upgrades. The hook approach is slightly slower but survives server evolution.
|
|
373
|
+
|
|
374
|
+
### Alternative 5: Session-level settings with per-team namespace
|
|
375
|
+
|
|
376
|
+
**Rejected.** Claude Code has no concept of per-team settings; all settings are session-global. Union across teams works but loses per-role precision and mutates settings.json.
|
|
377
|
+
|
|
378
|
+
---
|
|
379
|
+
|
|
380
|
+
## Open Verifications
|
|
381
|
+
|
|
382
|
+
Three behaviors worth confirming before cutting the materializer:
|
|
383
|
+
|
|
384
|
+
1. **Does Claude Code recurse into `.claude/agents/` subdirectories?**
|
|
385
|
+
- If yes: use `.claude/agents/swarm/<team>/<role>.md` (cleaner namespacing, single gitignore rule).
|
|
386
|
+
- If no: flat `.claude/agents/<team>-<role>.md`.
|
|
387
|
+
|
|
388
|
+
2. **Does inline `mcpServers:` in AGENT.md spawn a subprocess per-agent, or is it pooled?**
|
|
389
|
+
- Affects viability of "inline everything" mode for advanced loadouts.
|
|
390
|
+
- Default is advisory-only; inline is a power-user opt-in via a loadout-level flag.
|
|
391
|
+
|
|
392
|
+
3. **Exact `hooks:` frontmatter schema for per-agent PreToolUse hooks with env vars?**
|
|
393
|
+
- Proposed shape in this doc is reasoned from research; need to confirm `env:` field is supported in sub-agent hook declarations specifically.
|
|
394
|
+
- Fallback: pass scope file path via command-line argument rather than env var.
|
|
395
|
+
|
|
396
|
+
Verification target: a focused follow-up query to the claude-code-guide agent or direct Claude Code docs before step 1 of execution.
|
|
397
|
+
|
|
398
|
+
---
|
|
399
|
+
|
|
400
|
+
## Execution Plan
|
|
401
|
+
|
|
402
|
+
Order chosen to build pure functions first (easy to test), then integrate.
|
|
403
|
+
|
|
404
|
+
1. **`src/loadout-materializer.mjs`** + unit tests — loadout → frontmatter (pure function).
|
|
405
|
+
2. **`src/mcp-scope-resolver.mjs`** + unit tests — scope → mcpServers/tools/disallowedTools (pure function).
|
|
406
|
+
3. **`src/mcp-health-checker.mjs`** + unit tests — providers ∩ active set → report (pure function).
|
|
407
|
+
4. **`hooks/scope-check.mjs`** + integration tests — PreToolUse hook, runs as subprocess.
|
|
408
|
+
5. **Integrate into `src/template.mjs:loadTeam()`** — cache new artifacts alongside existing skill-loadouts.json.
|
|
409
|
+
6. **Update `src/agent-generator.mjs:generateAgentMd()`** — emit rich frontmatter via materializer.
|
|
410
|
+
7. **Update `src/skilltree-client.mjs`** — read `role.loadout.skills` before legacy path.
|
|
411
|
+
8. **Add `skills/swarm-mcp/SKILL.md`** with slash commands.
|
|
412
|
+
9. **SessionStart hook integration** — invoke health checker, print report.
|
|
413
|
+
10. **E2E manual test** against `examples/loadout-demo` from openteams.
|
|
414
|
+
|
|
415
|
+
### Go/no-go checkpoints
|
|
416
|
+
|
|
417
|
+
- **After step 1** — show generated frontmatter for loadout-demo, confirm shape.
|
|
418
|
+
- **After step 6** — inspect AGENT.md files on disk, confirm they're clean and markered.
|
|
419
|
+
- **After step 8** — walk through slash commands end-to-end.
|
|
420
|
+
|
|
421
|
+
---
|
|
422
|
+
|
|
423
|
+
## Future Work
|
|
424
|
+
|
|
425
|
+
### Deferred from PR 3
|
|
426
|
+
|
|
427
|
+
- **Symbolic ref registry** — bundled map for `@openhive/*` and other well-known refs. Current: warn-and-skip.
|
|
428
|
+
- **Tool introspection at session start** — enumerate MCP tools dynamically to enrich `tools:` frontmatter allowlists. Current: hook-based enforcement only.
|
|
429
|
+
- **Symlink mode opt-in** — `.claude/agents/*` → `.swarm/...` symlinks for users who want single-source-of-truth. Current: direct writes to both (project scope) or prefixed writes (user scope).
|
|
430
|
+
- **Plugin MCP conflict resolution** — detect plugin vs project MCP name collisions and warn. Current: silent (Claude Code handles via priority rules).
|
|
431
|
+
|
|
432
|
+
### Openhive integration (later)
|
|
433
|
+
|
|
434
|
+
- OpenHive hive DB becomes authoritative for MCP providers + ref resolution.
|
|
435
|
+
- `resolveExternalLoadout` hook lets OpenHive supply hive-stored loadout overrides.
|
|
436
|
+
- `findMissingMcpReferences` cross-references against hive-managed MCP registry.
|
|
437
|
+
|
|
438
|
+
### macro-agent integration (follow-on)
|
|
439
|
+
|
|
440
|
+
- Read `role.loadout.capabilities` for runtime tool filtering (no claude-code-swarm change).
|
|
441
|
+
- Own materializers for Codex/Gemini runtimes.
|
|
442
|
+
- Optional explicit MCP server lifecycle management at boot.
|
|
443
|
+
|
|
444
|
+
### Federation
|
|
445
|
+
|
|
446
|
+
- Multi-template consumption — how do cross-template MCP provider overlaps resolve?
|
|
447
|
+
- Current answer: consumer-layer policy decision; openteams permits overlap.
|
|
448
|
+
- Future consideration as openteams `federation.yaml` matures.
|
|
449
|
+
|
|
450
|
+
---
|
|
451
|
+
|
|
452
|
+
## References
|
|
453
|
+
|
|
454
|
+
- **openteams design** — `references/openteams/design.md`
|
|
455
|
+
- **openteams Loadout spec** — `references/openteams/schema/loadout.schema.json`
|
|
456
|
+
- **Claude Code sub-agent docs** — https://code.claude.com/docs/en/subagents
|
|
457
|
+
- **Claude Code MCP docs** — https://code.claude.com/docs/en/mcp-servers
|
|
458
|
+
- **Claude Code permissions docs** — https://code.claude.com/docs/en/permissions
|
|
459
|
+
- **loadout-demo example** — `references/openteams/examples/loadout-demo/`
|
|
460
|
+
|
|
461
|
+
---
|
|
462
|
+
|
|
463
|
+
## Changelog
|
|
464
|
+
|
|
465
|
+
- **2026-04-21** — Initial design captured from iterative session. Scope locked: fully non-invasive, project-scoped default with user-scope opt-in, hook-based scope enforcement.
|
|
466
|
+
- **2026-04-21** — Verifications complete.
|
|
467
|
+
1. **No subdirectory recursion** in `.claude/agents/`. Decision: flat naming `<team>-<role>.md`.
|
|
468
|
+
2. **Inline `mcpServers:` spawns subprocess per-agent-invocation** ("connected when subagent starts, disconnected when it finishes"). Decision: default to string refs (session-level servers); inline install specs become a power-user advisory with an explicit warning.
|
|
469
|
+
3. **`hooks:` frontmatter supported** for `PreToolUse`/`PostToolUse`/`Stop`, with `matcher:`, `type: command`, stdin JSON, exit code 2 to block. `env:` field behavior in subagent hooks is unverified; materializer will use `env:` and fall back to CLI argument injection at step 4 if empirical testing fails.
|