@heretyc/subagent-mcp 2.9.0 → 2.9.2
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/README.md +193 -143
- package/directives/carryover-claude.md +2 -2
- package/directives/carryover-codex.md +2 -4
- package/dist/index.js +43 -12
- package/dist/init.js +1 -1
- package/dist/orchestration/hook-core.js +3 -1
- package/dist/orchestration/marker.js +99 -26
- package/dist/routing.js +10 -11
- package/package.json +17 -2
package/README.md
CHANGED
|
@@ -1,143 +1,193 @@
|
|
|
1
|
-
# subagent-mcp
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
-
|
|
19
|
-
-
|
|
20
|
-
- `
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
```
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
[
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
|
117
|
-
|
|
118
|
-
| `
|
|
119
|
-
| `
|
|
120
|
-
| `
|
|
121
|
-
| `
|
|
122
|
-
| `
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
1
|
+
# subagent-mcp
|
|
2
|
+
|
|
3
|
+
[](https://www.npmjs.com/package/@heretyc/subagent-mcp)
|
|
4
|
+
[](LICENSE)
|
|
5
|
+
[](https://www.npmjs.com/package/@heretyc/subagent-mcp)
|
|
6
|
+
[](https://github.com/Heretyc/subagent-mcp/actions/workflows/claude-routine.yml)
|
|
7
|
+
|
|
8
|
+
MCP server that launches and manages always-interactive Claude Code and Codex sub-agent sessions — on macOS, Linux, and Windows. No direct API calls. No API keys.
|
|
9
|
+
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
## Install
|
|
13
|
+
|
|
14
|
+
### Prerequisites (runtime)
|
|
15
|
+
|
|
16
|
+
To run the published CLI you need:
|
|
17
|
+
|
|
18
|
+
- Node.js >= 18 (`node --version`)
|
|
19
|
+
- `claude` CLI — globally installed and authenticated (`claude --version`)
|
|
20
|
+
- `codex` CLI — globally installed and authenticated (`codex --version`; optional if you only use Claude paths)
|
|
21
|
+
|
|
22
|
+
Building from source needs additional developer tooling — see [CONTRIBUTING.md § Prerequisites](CONTRIBUTING.md#prerequisites).
|
|
23
|
+
|
|
24
|
+
### npmjs (default)
|
|
25
|
+
|
|
26
|
+
No authentication, no `.npmrc` configuration, and no PAT required. The package is publicly available on [npmjs.com](https://www.npmjs.com/package/@heretyc/subagent-mcp).
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
npm install -g @heretyc/subagent-mcp
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
**Use this path for all standard installs.**
|
|
33
|
+
|
|
34
|
+
### GitHub Packages (org-internal pin / supply-chain auditing)
|
|
35
|
+
|
|
36
|
+
Use this path when your organization's `.npmrc` already routes the `@heretyc` scope through GitHub Packages, when you need supply-chain audit tracing against the org-internal artifact, or when you run inside a GitHub Actions workflow whose `GITHUB_TOKEN` carries `read:packages`. Otherwise prefer npmjs above — it is simpler and needs no credentials.
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
# One-time machine setup
|
|
40
|
+
echo "@heretyc:registry=https://npm.pkg.github.com" >> ~/.npmrc
|
|
41
|
+
echo "//npm.pkg.github.com/:_authToken=YOUR_GITHUB_PAT" >> ~/.npmrc
|
|
42
|
+
# PAT must be a classic PAT with the read:packages scope
|
|
43
|
+
|
|
44
|
+
npm install -g @heretyc/subagent-mcp
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
> **Note:** GitHub Packages requires authentication even for public packages. If you see `401 Unauthorized`, verify your PAT has the `read:packages` scope and has not expired. GitHub Packages does not render a README page — the live documentation appears on [npmjs.com](https://www.npmjs.com/package/@heretyc/subagent-mcp).
|
|
48
|
+
|
|
49
|
+
---
|
|
50
|
+
|
|
51
|
+
## Quick Start
|
|
52
|
+
|
|
53
|
+
**1. Install** (see [Install](#install) above):
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
npm install -g @heretyc/subagent-mcp
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
**2. Register the MCP server + orchestration hooks:**
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
subagent-mcp setup
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
Installing the package only ships the binary — it does **not** auto-wire anything. `subagent-mcp setup` auto-detects Claude Code / Codex and registers the MCP server plus the per-turn orchestration-mode hooks. Preview with `subagent-mcp setup --dry-run`.
|
|
66
|
+
|
|
67
|
+
**3. Restart your host.**
|
|
68
|
+
|
|
69
|
+
Restart your Claude Code or Codex session so it picks up the new binary. On Codex, run `/hooks` and trust the new hook.
|
|
70
|
+
|
|
71
|
+
**4. Initialize the orchestration invariant (recommended):**
|
|
72
|
+
|
|
73
|
+
```bash
|
|
74
|
+
subagent-mcp init --global
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
`init --global` writes the managed invariant block into the providers' official global user-config files — `~/.claude/CLAUDE.md`, `~/.codex/AGENTS.md`, `~/.gemini/GEMINI.md` — set up once, works across every project. For a single project instead, use `subagent-mcp init --root /path/to/project` to write into that project's instruction files. `--global` and `--root` are mutually exclusive.
|
|
78
|
+
|
|
79
|
+
For manual wiring, Gemini CLI, Claude Desktop, and developer install from source, see [docs/registration.md](docs/registration.md).
|
|
80
|
+
|
|
81
|
+
---
|
|
82
|
+
|
|
83
|
+
## Features
|
|
84
|
+
|
|
85
|
+
- Start Claude or Codex interactive sessions as managed sub-agents from any MCP host
|
|
86
|
+
- Poll status, stream stdout/stderr tails, and enqueue follow-up messages to live sessions
|
|
87
|
+
- Concurrency caps: 5 concurrent Claude + 5 concurrent Codex agents (only `processing` agents count toward the cap; `stalled` agents do not hold a slot)
|
|
88
|
+
- Liveness tracking via the visible provider stream (Claude SDK events, Codex app-server JSONL): agents with no parsed visible provider stream item for 10 minutes enter `stalled` state (still alive, just quiet — thinking or awaiting a temp-file handoff), and recover to `processing` if the visible stream resumes
|
|
89
|
+
- Ultracode mode for Opus 4.8 via `--settings {"ultracode":true}` — see [docs/usage.md](docs/usage.md)
|
|
90
|
+
- Cross-platform exe resolution (Windows: npm-prefix .exe paths; macOS/Linux: PATH + Homebrew/usr-local fallbacks); immediate `taskkill /t /f` (Windows) / `SIGKILL` (POSIX) force-kill; no graceful shutdown period
|
|
91
|
+
- stdio MCP transport; built with `@modelcontextprotocol/sdk` + `zod`
|
|
92
|
+
- `orchestration-mode` tool — toggles orchestrator directives injected by bundled Claude Code / Codex hooks; Claude also gets a deterministic `PreToolUse` gate
|
|
93
|
+
|
|
94
|
+
---
|
|
95
|
+
|
|
96
|
+
## Orchestration Mode
|
|
97
|
+
|
|
98
|
+
**ON:** the agent operates as an orchestrator — hook injection governs each session turn, preventing inline reads or writes, and all work is delegated through sub-agent tools.
|
|
99
|
+
|
|
100
|
+
**OFF:** the agent operates normally, with no orchestration constraints.
|
|
101
|
+
|
|
102
|
+
Toggle with the `orchestration-mode` tool. Desktop hosts toggle the mode but receive no hook injection. See [docs/spec/dev-loop/orchestration-directive-architecture.md](docs/spec/dev-loop/orchestration-directive-architecture.md) for full semantics.
|
|
103
|
+
|
|
104
|
+
---
|
|
105
|
+
|
|
106
|
+
## Auto Mode
|
|
107
|
+
|
|
108
|
+
Pass `task_category` to `launch_agent` and the server picks the best provider, model, and effort for that category, with automatic fallback.
|
|
109
|
+
|
|
110
|
+
`launch_agent` supports **auto mode**: pass `prompt` + `task_category` and the server picks the best provider/model/effort for that category from its routing table, silently falling back to the next-best candidate on any launch-time failure.
|
|
111
|
+
|
|
112
|
+
`provider`, `model`, and `effort` are optional overrides — omit them to get the auto-selected best combination. Rules: passing `model` requires `provider`; passing `effort` requires both `provider` and `model`.
|
|
113
|
+
|
|
114
|
+
**task_category** (required) — pick one:
|
|
115
|
+
|
|
116
|
+
| Category | What it is |
|
|
117
|
+
|---|---|
|
|
118
|
+
| `math_proof` | deliverable is a proof/derivation/formally-checkable result |
|
|
119
|
+
| `security_review` | security verdict, threat assessment, or demonstrated exploit |
|
|
120
|
+
| `debugging` | verified fix/root-cause; requires an observed failure as precondition |
|
|
121
|
+
| `quality_review` | evaluative verdict on existing artifact (review, A-vs-B, validate-vs-spec) |
|
|
122
|
+
| `architecture` | cross-module design/plan, no code, no execution loop |
|
|
123
|
+
| `agentic_execution` | end-state via act/observe/adapt loop (run/deploy/provision/browse) |
|
|
124
|
+
| `data_analysis` | empirical finding about structured dataset (query, stat, model) |
|
|
125
|
+
| `coding` | bounded runnable code artifact, one-pass (implement, test, refactor) |
|
|
126
|
+
| `knowledge_synthesis` | novel integrated prose over sources (synthesize, summarize, draft) |
|
|
127
|
+
| `mechanical` | deterministic single-pass transform, exact-match checkable (grep, rename, reformat) |
|
|
128
|
+
| `prompt_engineering` | designed/optimized prompt or prompt-system steering an LLM/agent (composite-inferred) |
|
|
129
|
+
| `vulnerability_research` | discovery + PoC of a novel vulnerability (composite-inferred) |
|
|
130
|
+
| `molecular_biology` | reasoned molecular/computational-biology result over sequences, structures, or -omics data (composite-inferred) |
|
|
131
|
+
| `ml_accelerator_design` | hardware/software design for ML acceleration — dataflow, kernel, roofline (composite-inferred) |
|
|
132
|
+
| `fallback_default` | no category matches with confidence; prefer splitting work instead |
|
|
133
|
+
|
|
134
|
+
The last four are **composite-inferred**: they carry no dedicated benchmark and their routing competency is composed from parent categories rather than measured directly.
|
|
135
|
+
|
|
136
|
+
**Atomic-split guidance:** if you are unsure which category fits, do NOT submit one large amorphous task. Break the work into smaller atomic steps each mapping to a single category and launch one agent per step.
|
|
137
|
+
|
|
138
|
+
---
|
|
139
|
+
|
|
140
|
+
## Tools
|
|
141
|
+
|
|
142
|
+
Eight tools are exposed over the stdio MCP transport.
|
|
143
|
+
|
|
144
|
+
| Tool | Description |
|
|
145
|
+
|---|---|
|
|
146
|
+
| `launch_agent` | Start a new sub-agent session with a prompt and optional task category / overrides |
|
|
147
|
+
| `poll_agent` | Check status and stream tail output for a running agent |
|
|
148
|
+
| `kill_agent` | Terminate a running or stalled agent |
|
|
149
|
+
| `send_message` | Enqueue a message into a running agent's stdin |
|
|
150
|
+
| `list_agents` | List all tracked agents and their current status |
|
|
151
|
+
| `wait` | Block until a specific agent reaches a terminal state |
|
|
152
|
+
| `orchestration-mode` | Toggle orchestration-mode ON/OFF; controls whether hook directives are injected into agent sessions |
|
|
153
|
+
| `model-selection-mode` | Control model selection: `smart` (auto-pick) or `user-approved-overrides` (30-min override window) |
|
|
154
|
+
|
|
155
|
+
Full parameters, return shapes, and the `alive` / `idle_seconds` / `hint` / `recent_stream` fields are in [docs/tools.md](docs/tools.md).
|
|
156
|
+
|
|
157
|
+
---
|
|
158
|
+
|
|
159
|
+
## Agent Lifecycle
|
|
160
|
+
|
|
161
|
+
Each agent transitions through these states:
|
|
162
|
+
|
|
163
|
+
| Status | Meaning |
|
|
164
|
+
|---|---|
|
|
165
|
+
| `processing` | Driver alive with a visible provider-stream heartbeat in the last 10 minutes — actively working. Launch time counts as the initial heartbeat |
|
|
166
|
+
| `stalled` | Driver STILL ALIVE but no parsed visible provider stream item for >= 10 minutes — working, thinking, or awaiting a temp-file handoff (not a failure). Recovers to `processing` if the visible stream resumes |
|
|
167
|
+
| `finished` | Current turn completed, or driver exited with code 0 |
|
|
168
|
+
| `errored` | Process exited with non-zero code |
|
|
169
|
+
| `stopped` | Terminated by `kill_agent` |
|
|
170
|
+
|
|
171
|
+
`processing` and `stalled` are live. `stalled` means the driver is alive but quiet (>= 10 min no visible stream); it recovers automatically and is never auto-killed — do not `kill_agent` a stalled agent. `wait` does not return on `stalled`. Full semantics: [docs/reference/status-lifecycle.md](docs/reference/status-lifecycle.md).
|
|
172
|
+
|
|
173
|
+
---
|
|
174
|
+
|
|
175
|
+
## Documentation
|
|
176
|
+
|
|
177
|
+
| Document | Contents |
|
|
178
|
+
|---|---|
|
|
179
|
+
| [docs/registration.md](docs/registration.md) | Per-platform setup: Claude Code, Codex, Gemini CLI, Claude Desktop; manual wiring; developer install from source |
|
|
180
|
+
| [docs/tools.md](docs/tools.md) | Full tool reference — all eight tools, parameters, return shapes |
|
|
181
|
+
| [docs/usage.md](docs/usage.md) | Model & effort matrix, ultracode mode, CLI invocations, usage examples |
|
|
182
|
+
| [docs/SPEC.md](docs/SPEC.md) | Full technical specification — architecture, schemas, status lifecycle, error catalogue |
|
|
183
|
+
| [docs/spec/interactive-drivers.md](docs/spec/interactive-drivers.md) | Always-interactive Claude/Codex driver model |
|
|
184
|
+
| [docs/release-notes.md](docs/release-notes.md) | Operator-facing release notes |
|
|
185
|
+
| [CONTRIBUTING.md](CONTRIBUTING.md) | Contributor guide — dev environment, build, test, publish |
|
|
186
|
+
|
|
187
|
+
---
|
|
188
|
+
|
|
189
|
+
## License
|
|
190
|
+
|
|
191
|
+
Apache-2.0 — Copyright 2026 Lexi Blackburn
|
|
192
|
+
|
|
193
|
+
See [LICENSE](LICENSE).
|
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
<subagent-mcp state="on" kind="carryover">
|
|
3
3
|
FIRST-LINE EXEMPTION: if this session's prompt's literal first line begins with "<this is a request from a parent process>", ignore this entire tag.
|
|
4
4
|
|
|
5
|
-
Orchestration ON carried over from a PRIOR session for this project (
|
|
5
|
+
Orchestration ON carried over from a PRIOR session for this project (per-session disable; next session resumes ON, or after a 2h backstop). Not enabled THIS session.
|
|
6
6
|
|
|
7
|
-
THIS turn, ONCE: (1) NOTIFY the user it carried over; (2) ASK via AskUserQuestion whether to
|
|
7
|
+
THIS turn, ONCE: (1) NOTIFY the user it carried over; (2) ASK via AskUserQuestion whether to REMAIN enabled; (3) ADVISE fit — long-horizon → remain enabled; bounded/interactive → disable this session. Decline → orchestration-mode enabled:false this session only; no mid-session re-enable. NEVER disable on your own initiative. After answer handshake done; do not re-raise.
|
|
8
8
|
|
|
9
9
|
While ON, follow the MOST RECENT <subagent-mcp state="on"> tag in context (directive or reminder/carrier); if none is in the current window, the CLAUDE/AGENTS/GEMINI INIT_BLOCK governs. This tag is co-supreme with safety-scope; conflict → ask the user.
|
|
10
10
|
</subagent-mcp>
|
|
@@ -2,9 +2,7 @@
|
|
|
2
2
|
<subagent-mcp state="on" kind="carryover">
|
|
3
3
|
FIRST-LINE EXEMPTION: if this session's prompt's literal first line begins with "<this is a request from a parent process>", ignore this entire tag.
|
|
4
4
|
|
|
5
|
-
Orchestration ON carried over from a PRIOR session for this project (
|
|
5
|
+
Orchestration ON carried over from a PRIOR session for this project (per-session disable only; the next new session resumes ON automatically or after a 2h backstop). Not enabled THIS session.
|
|
6
6
|
|
|
7
|
-
THIS turn, ONCE: (1) NOTIFY the user it carried over; (2) ASK via request-user-input whether to
|
|
8
|
-
|
|
9
|
-
While ON, follow the MOST RECENT <subagent-mcp state="on"> tag in context (directive or reminder/carrier); if none is in the current window, the CLAUDE/AGENTS/GEMINI INIT_BLOCK governs. This tag is co-supreme with safety-scope; conflict → ask the user.
|
|
7
|
+
THIS turn, ONCE: (1) NOTIFY the user it carried over; (2) ASK via request-user-input whether to REMAIN enabled; (3) ADVISE fit — long-horizon / context-filling → remain enabled; bounded / interactive → propose OFF. Decline → orchestration-mode enabled:false for this session only; no mid-session re-enable. NEVER disable on your own initiative. After the answer the handshake is done; do not re-raise.
|
|
10
8
|
</subagent-mcp>
|
package/dist/index.js
CHANGED
|
@@ -139,11 +139,11 @@ reconcileInterval.unref();
|
|
|
139
139
|
// test/mirror-fragments.test.mjs while ORCHESTRATION_INSTRUCTIONS below stays
|
|
140
140
|
// compressed under MCP metadata limits:
|
|
141
141
|
// READ-ESCALATION LADDER (the orchestrator's only read channels, in order): (1) subagent-mcp `poll_agent` TAIL; (2) if the tail is insufficient, dispatch ONE sub-agent to return a single summary of <=100 lines, trusted as-is (no separate verification step); (3) anything larger: the USER reads the document directly. No reads or writes occur outside these channels. An empty or stalled tail means the agent is ALIVE, not dead — do NOT busy-loop poll_agent; learn completion via `wait`. Large inter-agent data: the orchestrator assigns scratch-file paths (%TEMP% on Windows, /tmp on POSIX) in prompts; the producing sub-agent writes, the consuming sub-agent reads; the orchestrator NEVER reads those files.
|
|
142
|
-
const ORCHESTRATION_INSTRUCTIONS = "subagent-mcp - CANONICAL OPERATING MODEL (full spec: docs/spec/dev-loop/orchestration-directive-architecture.md).\n\nPRECEDENCE. The latest <subagent-mcp state=\"...\"> hook tag and repo/system safety rules are co-supreme; genuine conflict => STOP and ask the user. Only the hook state changes ON/OFF.\n\nSOLE CHANNEL. Every sub-agent launch uses launch_agent; never harness Task/Agent or shell-spawned agents.\n\nORCHESTRATION ON. You are a delegate-ONLY orchestrator. Use only the structured-question tool (AskUserQuestion on Claude / request-user-input on Codex), subagent-mcp, and the /workflows tool. No direct reads/writes; inline-by-right does not exist. Non-delegable atomic step: ask for a one-time exception, do only that step, then resume delegating.\n\nREAD LADDER. poll_agent tail -> one <=100-line summarizer sub-agent, trusted as-is -> else the USER reads it. Large handoffs use scratch-file paths; producer writes, consumer reads; orchestrator never reads those files. Empty/stalled tail means ALIVE; use wait.\n\nORCHESTRATION OFF. If total context footprint since last upgrade ask exceeds 200 lines, after that turn STOP and ask whether to
|
|
142
|
+
const ORCHESTRATION_INSTRUCTIONS = "subagent-mcp - CANONICAL OPERATING MODEL (full spec: docs/spec/dev-loop/orchestration-directive-architecture.md).\n\nPRECEDENCE. The latest <subagent-mcp state=\"...\"> hook tag and repo/system safety rules are co-supreme; genuine conflict => STOP and ask the user. Only the hook state changes ON/OFF.\n\nSOLE CHANNEL. Every sub-agent launch uses launch_agent; never harness Task/Agent or shell-spawned agents.\n\nORCHESTRATION ON. You are a delegate-ONLY orchestrator. Use only the structured-question tool (AskUserQuestion on Claude / request-user-input on Codex), subagent-mcp, and the /workflows tool. No direct reads/writes; inline-by-right does not exist. Non-delegable atomic step: ask for a one-time exception, do only that step, then resume delegating.\n\nREAD LADDER. poll_agent tail -> one <=100-line summarizer sub-agent, trusted as-is -> else the USER reads it. Large handoffs use scratch-file paths; producer writes, consumer reads; orchestrator never reads those files. Empty/stalled tail means ALIVE; use wait.\n\nORCHESTRATION OFF. If total context footprint since last upgrade ask exceeds 200 lines, after that turn STOP and ask whether to remain enabled; reset count only when you ask.\n\nDROPOUT WHILE ON: HALT and ask; stay halted until restored. SUB-AGENT EXEMPTION: a prompt whose literal FIRST LINE begins \"<this is a request from a parent process>\" skips this regime.\n\nMODEL SELECTION MODE. Default smart rejects provider/model/effort selectors; launch_agent auto-picks. user-approved-overrides lasts 30 minutes, expires lazily on launch_agent, and must be enabled only after explicit user authorization via AskUserQuestion/request-user-input.";
|
|
143
143
|
const SUBAGENT_INSTRUCTIONS = "SUB-AGENT SESSION: you are a child process launched by subagent-mcp. Follow the parent prompt. Do not treat yourself as the orchestrator, do not re-trigger orchestration carryover, and do not launch further sub-agents unless the parent prompt explicitly assigns that.\n\nMODEL SELECTION MODE (parallel to orchestration-mode, set via the model-selection-mode tool). DEFAULT is \"smart\" and is used whenever unset: in smart, launch_agent REJECTS any call supplying provider/model/effort selectors and the server auto-picks the best model. \"user-approved-overrides\" opens a 30-MINUTE window where selectors are HONORED, enforced LAZILY (the mode reverts to smart on the next launch_agent call after 30 minutes) and re-enabling does NOT extend an active window. HONOR-BASED: you MUST NOT set \"user-approved-overrides\" without explicit interactive USER authorization via the structured-question tool (AskUserQuestion on Claude / request-user-input on Codex); never enable it on your own initiative.";
|
|
144
144
|
const server = new McpServer({
|
|
145
145
|
name: "subagent-mcp",
|
|
146
|
-
version: "2.9.
|
|
146
|
+
version: "2.9.2",
|
|
147
147
|
description: "Launches always-interactive local Claude and Codex sub-agent sessions. Claude uses the Claude Agent SDK over the local Claude Code executable; Codex uses `codex app-server` over stdio. The server does not call Anthropic or OpenAI HTTP APIs directly.",
|
|
148
148
|
}, {
|
|
149
149
|
instructions: process.env.SUBAGENT_MCP_SUBAGENT === "1"
|
|
@@ -1004,24 +1004,52 @@ server.tool("wait", "Blocks until one or more sub-agents reach a reportable stat
|
|
|
1004
1004
|
};
|
|
1005
1005
|
});
|
|
1006
1006
|
// Tool 7: orchestration-mode
|
|
1007
|
-
server.tool("orchestration-mode", "Toggle or query per-project ORCHESTRATION MODE. `enabled`: true = ON, false = OFF, omit = query current state. SOLE CHANNEL: the subagent MCP is the ONLY sanctioned channel for launching sub-agents whether this mode is ON or OFF — toggling OFF does not lift that obligation. When OFF, run the per-turn upgrade check: a long-horizon task = any whose TOTAL context footprint (input read + output produced) exceeds 200 lines, measured CUMULATIVELY since your last upgrade ask; after EVERY user turn, if it qualifies, STOP and ask the user whether to
|
|
1007
|
+
server.tool("orchestration-mode", "Toggle or query per-project ORCHESTRATION MODE. `enabled`: true = ON, false = OFF for THIS session only, omit = query current state. SOLE CHANNEL: the subagent MCP is the ONLY sanctioned channel for launching sub-agents whether this mode is ON or OFF — toggling OFF does not lift that obligation. When OFF, run the per-turn upgrade check: a long-horizon task = any whose TOTAL context footprint (input read + output produced) exceeds 200 lines, measured CUMULATIVELY since your last upgrade ask; after EVERY user turn, if it qualifies, STOP and ask the user whether to remain enabled (ask every qualifying turn; a decline does not latch; reset the count only when you actually ask). The FULL operating model + governance is carried in this server's MCP `instructions` (read once at initialize) — this is the operational summary only; do not act on the mode without that detail. WHAT: a default-ON orchestration mode for LONG-HORIZON work that would fill the context window if run to completion inline; when ON, act as a delegate-ONLY orchestrator: delegate every step; inline-by-right does not exist; a non-delegable atomic step requires a one-time user-approved exception via the structured-question tool (state which + why). PERSISTENCE: orchestration is DEFAULT ON; a permitted disable applies to THIS session only, resumes ON next new session (or after the 2h backstop), and cannot be re-enabled mid-session. CARRYOVER: if ON was inherited from a PRIOR session (provenance = carried-over, not user-enabled this session), the bundled hook prepends a ONE-TIME notice (once per marker, never per turn) — you MUST then notify the user it auto-activated and confirm whether to keep it ON. DISABLE: never on your own initiative; you MAY PROPOSE turning it OFF on task-fit mismatch, but only EXPLICIT user permission (AskUserQuestion on Claude, request-user-input on Codex) may set enabled:false. Per-turn injection fires only in CLI hosts that load the bundled hook; desktop hosts toggle the marker but inject nothing (documented degradation).", {
|
|
1008
1008
|
enabled: z.boolean().optional(),
|
|
1009
1009
|
}, async (params) => {
|
|
1010
1010
|
const cwd = process.cwd();
|
|
1011
|
+
const key = orchestrationMarker.readCurrentSession(cwd);
|
|
1011
1012
|
if (params.enabled === true) {
|
|
1012
|
-
orchestrationMarker.
|
|
1013
|
+
if (!orchestrationMarker.isActive(cwd, key)) {
|
|
1014
|
+
return errorResult("orchestration already disabled for this session, cannot re-enable mid-session; resumes ON automatically next new session (or after the 2h backstop).");
|
|
1015
|
+
}
|
|
1016
|
+
return {
|
|
1017
|
+
content: [
|
|
1018
|
+
{
|
|
1019
|
+
type: "text",
|
|
1020
|
+
text: JSON.stringify({
|
|
1021
|
+
orchestration_mode: "ON",
|
|
1022
|
+
message: "orchestration is ON by default.",
|
|
1023
|
+
}),
|
|
1024
|
+
},
|
|
1025
|
+
],
|
|
1026
|
+
};
|
|
1013
1027
|
}
|
|
1014
1028
|
else if (params.enabled === false) {
|
|
1015
|
-
|
|
1029
|
+
if (key)
|
|
1030
|
+
orchestrationMarker.writeDisable(key);
|
|
1031
|
+
else
|
|
1032
|
+
orchestrationMarker.writeDisableCwd(cwd);
|
|
1033
|
+
return {
|
|
1034
|
+
content: [
|
|
1035
|
+
{
|
|
1036
|
+
type: "text",
|
|
1037
|
+
text: JSON.stringify({
|
|
1038
|
+
orchestration_mode: "disabled-this-session",
|
|
1039
|
+
message: "orchestration disabled for THIS session only; the next new session resumes ON automatically (or after the 2h backstop); no mid-session re-enable.",
|
|
1040
|
+
}),
|
|
1041
|
+
},
|
|
1042
|
+
],
|
|
1043
|
+
};
|
|
1016
1044
|
}
|
|
1017
1045
|
// enabled === undefined -> query only; no marker mutation.
|
|
1046
|
+
const active = orchestrationMarker.isActive(cwd, key);
|
|
1018
1047
|
return {
|
|
1019
1048
|
content: [
|
|
1020
1049
|
{
|
|
1021
1050
|
type: "text",
|
|
1022
1051
|
text: JSON.stringify({
|
|
1023
|
-
orchestration_mode:
|
|
1024
|
-
marker_path: orchestrationMarker.markerPath(cwd),
|
|
1052
|
+
orchestration_mode: active ? "ON" : "disabled-this-session",
|
|
1025
1053
|
}),
|
|
1026
1054
|
},
|
|
1027
1055
|
],
|
|
@@ -1184,11 +1212,14 @@ if (isMain) {
|
|
|
1184
1212
|
process.exit(1);
|
|
1185
1213
|
}
|
|
1186
1214
|
// ORCHESTRATION MODE PERSISTS across restarts/sessions: the server does NOT
|
|
1187
|
-
// clear the marker on startup. DEFAULT
|
|
1188
|
-
//
|
|
1189
|
-
//
|
|
1190
|
-
//
|
|
1191
|
-
// (
|
|
1215
|
+
// clear the marker on startup. DEFAULT ON now means ABSENCE of a disable
|
|
1216
|
+
// record — a project stays ON with no marker write needed; OFF is only a
|
|
1217
|
+
// per-session disable record that holds while it is active, cleared with
|
|
1218
|
+
// explicit user permission. On a new session a carried-over legacy ON marker
|
|
1219
|
+
// (if any) triggers a one-time prompt asking whether to remain enabled; under
|
|
1220
|
+
// default-ON this rarely fires.
|
|
1221
|
+
// (the tool's enabled:false writes a disable record via writeDisable /
|
|
1222
|
+
// writeDisableCwd; it does not call disable().)
|
|
1192
1223
|
startLivenessHeartbeat();
|
|
1193
1224
|
const transport = new StdioServerTransport();
|
|
1194
1225
|
await server.connect(transport);
|
package/dist/init.js
CHANGED
|
@@ -29,7 +29,7 @@ export const INIT_BLOCK = [
|
|
|
29
29
|
"",
|
|
30
30
|
'NO-HOOK / UNKNOWN STATE: if no harness-hook injection bearing a <subagent-mcp state="..."> tag is present this session (e.g. Gemini, desktop apps, or any host that fires no hook), the state is UNKNOWN — represented by the ABSENCE of any tag, never by a tag value. Emit this UNKNOWN-STATE WARNING to the user: "subagent-mcp: no hook injection detected — orchestration state unknown; defaulting to ON". Briefly explain WHY: no hook injection detected — cannot verify orchestration state; defaulting to ON to prevent uncontrolled inline execution. Then DEFAULT TO ORCHESTRATION ON (fail-safe). One-time opt-out: if you are not currently running an orchestration workflow, you may explicitly opt out of ON for this session by saying so now; this opt-out does not persist and is not recorded. The sub-agent first-line exemption is the ONLY automatic suppressor of this default.',
|
|
31
31
|
"",
|
|
32
|
-
"DISABLE: never on your own initiative; you MAY propose OFF on task-fit mismatch via the structured-question tool, and only explicit user approval may
|
|
32
|
+
"DISABLE: never on your own initiative; you MAY propose OFF on task-fit mismatch via the structured-question tool, and only explicit user approval may set enabled:false — per-session only; the next new session resumes ON; no mid-session re-enable.",
|
|
33
33
|
"<!-- subagent-mcp:managed:end -->",
|
|
34
34
|
].join("\n");
|
|
35
35
|
function detectEol(s) {
|
|
@@ -234,7 +234,9 @@ export function runHook(payload, env, adapter) {
|
|
|
234
234
|
}
|
|
235
235
|
const cwd = payload.cwd || process.cwd();
|
|
236
236
|
const current = sessionKey(payload);
|
|
237
|
-
if (
|
|
237
|
+
if (current)
|
|
238
|
+
marker.writeCurrentSession(cwd, current);
|
|
239
|
+
if (!marker.isActive(cwd, current)) {
|
|
238
240
|
// OFF: no claim machinery — just the per-prompt reminder cadence.
|
|
239
241
|
const r = reminder.advance(cwd, current);
|
|
240
242
|
return cadenceEmit(env, adapter, adapter.reminderOffFile, adapter.shortOffFile, r.count, r.persisted);
|
|
@@ -3,6 +3,7 @@ import { existsSync, mkdirSync, readFileSync, unlinkSync, writeFileSync, } from
|
|
|
3
3
|
import { tmpdir } from "node:os";
|
|
4
4
|
import { join, resolve } from "node:path";
|
|
5
5
|
const markerDir = join(tmpdir(), "subagent-mcp");
|
|
6
|
+
export const ORCH_DISABLE_TTL_MS = 2 * 60 * 60 * 1000; // 2h GC backstop ONLY (independent of model-mode WINDOW_MS)
|
|
6
7
|
/**
|
|
7
8
|
* Shared per-project state dir for ALL hook state files (marker + reminder
|
|
8
9
|
* counter). Exported so sibling state modules key off the SAME location — a
|
|
@@ -33,15 +34,27 @@ export function normalizeCwd(cwd) {
|
|
|
33
34
|
}
|
|
34
35
|
return p;
|
|
35
36
|
}
|
|
36
|
-
|
|
37
|
+
function hashKey(key) {
|
|
37
38
|
return createHash("sha256")
|
|
38
|
-
.update(
|
|
39
|
+
.update(key, "utf8")
|
|
39
40
|
.digest("hex")
|
|
40
41
|
.slice(0, 16);
|
|
41
42
|
}
|
|
43
|
+
export function cwdHash(cwd) {
|
|
44
|
+
return hashKey(normalizeCwd(cwd));
|
|
45
|
+
}
|
|
42
46
|
export function markerPath(cwd) {
|
|
43
47
|
return join(markerDir, "orch-" + cwdHash(cwd) + ".flag");
|
|
44
48
|
}
|
|
49
|
+
export function disablePath(sessionKey) {
|
|
50
|
+
return join(stateDir, `orch-disable-${hashKey(sessionKey)}.json`);
|
|
51
|
+
}
|
|
52
|
+
function cwdDisablePath(cwd) {
|
|
53
|
+
return join(stateDir, `orch-disable-${cwdHash(cwd)}.json`);
|
|
54
|
+
}
|
|
55
|
+
export function sessionPointerPath(cwd) {
|
|
56
|
+
return join(stateDir, `orch-session-${cwdHash(cwd)}.json`);
|
|
57
|
+
}
|
|
45
58
|
/**
|
|
46
59
|
* Enable orchestration for cwd. ALWAYS overwrites — re-enabling re-baselines by
|
|
47
60
|
* clearing owner_session/baseline_turn back to null so the next hook turn
|
|
@@ -62,44 +75,105 @@ export function enable(cwd) {
|
|
|
62
75
|
carryover_ack: false,
|
|
63
76
|
};
|
|
64
77
|
writeFileSync(markerPath(cwd), JSON.stringify(state), { encoding: "utf8", mode: 0o600 });
|
|
78
|
+
try {
|
|
79
|
+
unlinkSync(cwdDisablePath(cwd));
|
|
80
|
+
}
|
|
81
|
+
catch (e) {
|
|
82
|
+
if (e?.code !== "ENOENT") {
|
|
83
|
+
// Fail-safe: enable still succeeds if stale disable cleanup fails.
|
|
84
|
+
}
|
|
85
|
+
}
|
|
65
86
|
}
|
|
66
87
|
catch {
|
|
67
88
|
// Fail-safe: never throw to the caller.
|
|
68
89
|
}
|
|
69
90
|
}
|
|
70
91
|
/**
|
|
71
|
-
* Disable orchestration for cwd
|
|
72
|
-
*
|
|
73
|
-
* No existsSync() guard: that only opens a TOCTOU window where a concurrent
|
|
74
|
-
* clearForCwd/disable for the same cwd removes the file between the check and
|
|
75
|
-
* the unlink. We just unlink and swallow ENOENT (already-gone is success).
|
|
76
|
-
*
|
|
77
|
-
* KNOWN LIMITATION: the marker is keyed by cwd, NOT by session. Two CLI
|
|
78
|
-
* sessions in the same project share one marker, so their enable/disable
|
|
79
|
-
* interleave and the last writer wins. Per-session isolation would require
|
|
80
|
-
* keying the marker by cwd+session_id; not done here because LOCKED DECISION 1
|
|
81
|
-
* keys the marker by working directory alone. (The hook tracks the owning
|
|
82
|
-
* session via owner_session so a carried-over marker is re-claimed, but the
|
|
83
|
-
* marker file itself is still shared per cwd.)
|
|
92
|
+
* Disable orchestration for cwd using cwd-keyed shared fallback state. The
|
|
93
|
+
* hook's session-keyed path uses writeDisable(sessionKey) instead.
|
|
84
94
|
*/
|
|
85
95
|
export function disable(cwd) {
|
|
86
96
|
try {
|
|
87
|
-
|
|
97
|
+
mkdirSync(markerDir, { recursive: true, mode: 0o700 });
|
|
98
|
+
writeFileSync(cwdDisablePath(cwd), JSON.stringify({ disabled_at: Date.now() }), {
|
|
99
|
+
encoding: "utf8",
|
|
100
|
+
mode: 0o600,
|
|
101
|
+
});
|
|
88
102
|
}
|
|
89
|
-
catch
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
103
|
+
catch {
|
|
104
|
+
// Fail-safe: never throw to the caller.
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
export function writeDisable(sessionKey) {
|
|
108
|
+
try {
|
|
109
|
+
mkdirSync(stateDir, { recursive: true, mode: 0o700 });
|
|
110
|
+
writeFileSync(disablePath(sessionKey), JSON.stringify({ disabled_at: Date.now() }), {
|
|
111
|
+
encoding: "utf8",
|
|
112
|
+
mode: 0o600,
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
catch {
|
|
116
|
+
// Fail-safe: never throw to the caller.
|
|
94
117
|
}
|
|
95
118
|
}
|
|
96
|
-
export function
|
|
119
|
+
export function writeDisableCwd(cwd) {
|
|
97
120
|
try {
|
|
98
|
-
|
|
121
|
+
mkdirSync(stateDir, { recursive: true, mode: 0o700 });
|
|
122
|
+
writeFileSync(cwdDisablePath(cwd), JSON.stringify({ disabled_at: Date.now() }), {
|
|
123
|
+
encoding: "utf8",
|
|
124
|
+
mode: 0o600,
|
|
125
|
+
});
|
|
99
126
|
}
|
|
100
127
|
catch {
|
|
128
|
+
// Fail-safe: never throw to the caller.
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
export function writeCurrentSession(cwd, sessionKey) {
|
|
132
|
+
try {
|
|
133
|
+
mkdirSync(stateDir, { recursive: true, mode: 0o700 });
|
|
134
|
+
writeFileSync(sessionPointerPath(cwd), JSON.stringify({ session_key: sessionKey }), {
|
|
135
|
+
encoding: "utf8",
|
|
136
|
+
mode: 0o600,
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
catch {
|
|
140
|
+
// Fail-safe: never throw to the caller.
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
export function readCurrentSession(cwd) {
|
|
144
|
+
try {
|
|
145
|
+
const raw = readFileSync(sessionPointerPath(cwd), "utf8");
|
|
146
|
+
const parsed = JSON.parse(raw);
|
|
147
|
+
return typeof parsed.session_key === "string" ? parsed.session_key : undefined;
|
|
148
|
+
}
|
|
149
|
+
catch {
|
|
150
|
+
return undefined;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
function isDisableActive(path, now) {
|
|
154
|
+
if (!existsSync(path)) {
|
|
101
155
|
return false;
|
|
102
156
|
}
|
|
157
|
+
const raw = readFileSync(path, "utf8");
|
|
158
|
+
const parsed = JSON.parse(raw);
|
|
159
|
+
if (typeof parsed.disabled_at !== "number") {
|
|
160
|
+
return false;
|
|
161
|
+
}
|
|
162
|
+
if (now - parsed.disabled_at <= ORCH_DISABLE_TTL_MS) {
|
|
163
|
+
return true;
|
|
164
|
+
}
|
|
165
|
+
// Lazy GC side-effect: the disable has expired, so remove it.
|
|
166
|
+
unlinkSync(path);
|
|
167
|
+
return false;
|
|
168
|
+
}
|
|
169
|
+
export function isActive(cwd, sessionKey) {
|
|
170
|
+
try {
|
|
171
|
+
const path = sessionKey === undefined ? cwdDisablePath(cwd) : disablePath(sessionKey);
|
|
172
|
+
return !isDisableActive(path, Date.now());
|
|
173
|
+
}
|
|
174
|
+
catch {
|
|
175
|
+
return true;
|
|
176
|
+
}
|
|
103
177
|
}
|
|
104
178
|
export function readMarker(cwd) {
|
|
105
179
|
try {
|
|
@@ -136,9 +210,8 @@ export function writeMarker(cwd, obj) {
|
|
|
136
210
|
}
|
|
137
211
|
}
|
|
138
212
|
/**
|
|
139
|
-
*
|
|
140
|
-
* marker explicitly (e.g. the tool's enabled:false path).
|
|
141
|
-
* longer calls this on startup — orchestration mode now PERSISTS across sessions.
|
|
213
|
+
* Cwd-keyed disable alias, identical to disable. RETAINED for callers that
|
|
214
|
+
* clear legacy marker state explicitly (e.g. the tool's enabled:false path).
|
|
142
215
|
*/
|
|
143
216
|
export function clearForCwd(cwd) {
|
|
144
217
|
disable(cwd);
|
package/dist/routing.js
CHANGED
|
@@ -120,10 +120,10 @@ export function normalizeEffort(provider, model, effort) {
|
|
|
120
120
|
* explicit (provider+model+effort all present): one candidate from the user's
|
|
121
121
|
* triple; the table is NOT read (works with a null table).
|
|
122
122
|
*
|
|
123
|
-
* auto/provider/provider_model: read
|
|
124
|
-
* array directly
|
|
125
|
-
*
|
|
126
|
-
*
|
|
123
|
+
* auto/provider/provider_model: read <branch>.<task_category> as the pairings
|
|
124
|
+
* array directly, sort by rank asc, map each model to a launch id, normalize
|
|
125
|
+
* effort, and drop non-launchable / unknown-effort pairings. An empty result
|
|
126
|
+
* sets noCandidates:true.
|
|
127
127
|
*/
|
|
128
128
|
export function buildCandidates(table, taskCategory, overrides, branch = DEFAULT_BRANCH) {
|
|
129
129
|
const { provider, model, effort } = overrides;
|
|
@@ -188,12 +188,7 @@ function readPairings(table, taskCategory, branch = DEFAULT_BRANCH) {
|
|
|
188
188
|
const perf = table[branch];
|
|
189
189
|
if (!perf || typeof perf !== "object")
|
|
190
190
|
return [];
|
|
191
|
-
|
|
192
|
-
// Defensive: tolerate a {pairings:[...]} wrapper even though the contract
|
|
193
|
-
// says the value IS the array directly.
|
|
194
|
-
if (raw && !Array.isArray(raw) && typeof raw === "object" && "pairings" in raw) {
|
|
195
|
-
raw = raw.pairings;
|
|
196
|
-
}
|
|
191
|
+
const raw = perf[taskCategory];
|
|
197
192
|
if (!Array.isArray(raw))
|
|
198
193
|
return [];
|
|
199
194
|
const entries = raw.filter((e) => !!e && typeof e === "object" && typeof e.model === "string");
|
|
@@ -251,7 +246,11 @@ export function validatePresence(p) {
|
|
|
251
246
|
if (model && !provider) {
|
|
252
247
|
return `Error: provider is required when model is given. You passed model=${model} without provider. Either also pass provider, or omit both.\n${AUTO_HINT}`;
|
|
253
248
|
}
|
|
254
|
-
//
|
|
249
|
+
// fallback_default is valid only for fully explicit launches.
|
|
250
|
+
if (task_category === "fallback_default" && !(provider && model && effort)) {
|
|
251
|
+
return `Error: fallback_default is a split hint sentinel, not a launchable routing-table category.\n${SPLIT_HINT}\n${AUTO_HINT}`;
|
|
252
|
+
}
|
|
253
|
+
// provider+model must satisfy the existing match rule.
|
|
255
254
|
if (provider && model) {
|
|
256
255
|
if (provider === "claude" && !["haiku", "sonnet", "opus", "opus-4-8"].includes(model)) {
|
|
257
256
|
return `Error: Claude provider only supports haiku, sonnet, opus, or opus-4-8. Got: ${model}`;
|
package/package.json
CHANGED
|
@@ -1,7 +1,22 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@heretyc/subagent-mcp",
|
|
3
|
-
"version": "2.9.
|
|
3
|
+
"version": "2.9.2",
|
|
4
4
|
"description": "MCP server that launches and manages always-interactive Claude Code and Codex sub-agent sessions (no direct Anthropic/OpenAI API).",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"mcp",
|
|
7
|
+
"model-context-protocol",
|
|
8
|
+
"mcp-server",
|
|
9
|
+
"claude",
|
|
10
|
+
"claude-code",
|
|
11
|
+
"codex",
|
|
12
|
+
"orchestration",
|
|
13
|
+
"subagent",
|
|
14
|
+
"sub-agent",
|
|
15
|
+
"multi-agent",
|
|
16
|
+
"ai-agents",
|
|
17
|
+
"anthropic",
|
|
18
|
+
"openai"
|
|
19
|
+
],
|
|
5
20
|
"type": "module",
|
|
6
21
|
"main": "dist/index.js",
|
|
7
22
|
"bin": {
|
|
@@ -47,7 +62,7 @@
|
|
|
47
62
|
"node": ">=18"
|
|
48
63
|
},
|
|
49
64
|
"publishConfig": {
|
|
50
|
-
"registry": "https://
|
|
65
|
+
"registry": "https://registry.npmjs.org",
|
|
51
66
|
"access": "public"
|
|
52
67
|
}
|
|
53
68
|
}
|