@heretyc/subagent-mcp 2.12.5-beta.2 → 2.12.7

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 CHANGED
@@ -5,39 +5,56 @@
5
5
  [![node](https://img.shields.io/node/v/@heretyc/subagent-mcp)](https://www.npmjs.com/package/@heretyc/subagent-mcp)
6
6
  [![CI](https://github.com/Heretyc/subagent-mcp/actions/workflows/claude-routine.yml/badge.svg)](https://github.com/Heretyc/subagent-mcp/actions/workflows/claude-routine.yml)
7
7
 
8
- Turn any AI coding assistant into a **manager of other AI agents**. subagent-mcp
9
- lets your Claude Code or Codex session start, watch, message, and stop a whole
10
- team of AI sub-agents on macOS, Linux, and Windows. **No direct API calls. No
11
- API keys.** It drives the `claude` and `codex` command-line tools you already
12
- signed into.
13
-
14
- ## What it does
15
-
16
- Normally one AI assistant does all the work in one conversation. That
17
- conversation fills up, slows down, and eventually forgets its early context. As
18
- of a certain size it "compacts" summarizing and dropping detail.
19
-
20
- subagent-mcp changes the shape of the work. Your assistant becomes an
21
- **orchestrator**: it hands each task to a fresh sub-agent, watches the results,
22
- and moves on without ever doing the reading or writing itself.
23
-
24
- ## Why it works this way
25
-
26
- Four bets drive the whole design. The full reasoning lives in
27
- [docs/spec/arch-rationale.md](docs/spec/arch-rationale.md); the short version:
28
-
29
- - **The effective memory grows geometrically.** Because the orchestrator only
30
- ever holds *summaries* of what its sub-agents did — never the raw files — its
31
- own memory fills up far more slowly. That means **very long tasks with little
32
- or no compaction**.
33
- - **Mixed providers avoid blind spots.** Using Claude *and* Codex together means
34
- one vendor's weak spot or outage doesn't blind or block the whole job — and
35
- you're never locked in to a single vendor.
36
- - **Ruthless token efficiency.** Every hand-off is compressed and every read is
37
- kept small, so the system stays fast and cheap even on marathon tasks.
38
- - **Durable, authoritative reminders.** The operating rules are re-injected every
39
- turn through official host hooks, so the assistant doesn't drift off-task or
40
- start making things up over a long run.
8
+ ## Core premise
9
+
10
+ subagent-mcp is an MCP (stdio) server that turns any AI coding assistant
11
+ (Claude Code, Codex, Gemini CLI) into a **manager/orchestrator of a team of
12
+ AI sub-agents** running on macOS, Linux, and Windows. It drives the locally
13
+ authenticated `claude` and `codex` CLIs you already signed into — **no direct
14
+ HTTP API calls and no API keys, ever** (an explicit, permanent non-goal). It
15
+ serves developers running big, long-horizon coding jobs who want to escape a
16
+ single conversation's context limits and vendor lock-in.
17
+
18
+ Its central promise: the orchestrator **monitors but never reads or writes
19
+ files itself** — every step is delegated to a fresh sub-agent, so the
20
+ orchestrator's context fills only with ≤100-line summaries. This extends
21
+ effective context "geometrically" instead of linearly, enabling marathon tasks
22
+ with little or no compaction. Guarantees/invariants it promises: a single
23
+ machine-global, provider-agnostic concurrency cap (default 20, min 10; rejects
24
+ at cap, never queues); fail-safe **ON** on hosts lacking hooks (unknown
25
+ orchestration state defaults to ON); orchestration state is authoritative only
26
+ via harness-verified `<subagent-mcp state="...">` hook tags, never inferred from
27
+ prose (guards against directive drift/hallucination); sub-agents run **gated by
28
+ default** (permission ceiling `auto`); and automatic model/provider/effort
29
+ routing per task category so the user never picks a model.
30
+
31
+ ## Key problems it solves
32
+
33
+ - **Context exhaustion / compaction on long tasks** delegate-only
34
+ orchestration keeps the manager's context holding summaries, not raw files,
35
+ so long jobs run with minimal compaction.
36
+ - **Single-vendor blind spots and lock-in** mixed Claude + Codex (provider-
37
+ agnostic) operation means one vendor's weakness or outage doesn't blind or
38
+ block the whole job.
39
+ - **No API keys / no direct API calls** drives locally signed-in vendor CLIs
40
+ instead of the Anthropic/OpenAI HTTP APIs, avoiding key management and cost of
41
+ a gateway.
42
+ - **Directive drift & hallucination over long runs** — operating rules are
43
+ re-injected redundantly (MCP `instructions`, INIT_BLOCK, per-turn hooks,
44
+ managed AGENTS.md/CLAUDE.md/GEMINI.md blocks) and made authoritative via
45
+ harness-verified state tags.
46
+ - **Model-selection burden** — a benchmark-derived routing table auto-picks
47
+ provider/model/effort from a plain-English prompt + task category.
48
+ - **Uncontrolled/unsafe sub-agent actions** — a shared permission engine gates
49
+ sub-agent operations (SAFE→allow, DANGER→deny, NEUTRAL→park for a decision)
50
+ with `auto`/`manual`/`yolo` ceilings and one-time `respond_permission`.
51
+ - **Runaway fan-out / resource contention** — one machine-wide concurrency cap
52
+ and worktree isolation (branch-per-task) with a first-line sub-agent
53
+ carve-out to prevent fork-bomb recursion.
54
+ - **Orchestrator observability** — a fixed set of tools (launch/poll/kill/
55
+ send_message/list/wait/respond_permission + orchestration & model modes) plus
56
+ a status lifecycle (processing/stalled/finished/errored/stopped/
57
+ zombie_killed/permission_requested) so a quiet agent isn't mistaken for dead.
41
58
 
42
59
  ## Install
43
60
 
@@ -25,7 +25,7 @@ export function clampCap(raw) {
25
25
  return v;
26
26
  }
27
27
  export function stripJsoncComments(text) {
28
- return text.replace(/^\s*\/\/.*$/gm, "");
28
+ return text.replace(/^\uFEFF/, "").replace(/^\s*\/\/.*$/gm, "");
29
29
  }
30
30
  function parseJsonObject(text) {
31
31
  const parsed = JSON.parse(stripJsoncComments(text));
package/dist/index.js CHANGED
@@ -441,8 +441,7 @@ function handleCompletedStdoutLines(agent, lines, at) {
441
441
  agent.status = "finished";
442
442
  if (agent.exitedAt === null)
443
443
  agent.exitedAt = at;
444
- releaseSlot(agent.slotPath ?? null);
445
- agent.slotPath = null;
444
+ updateSlotMetadata(agent, at);
446
445
  }
447
446
  }
448
447
  }
@@ -516,7 +515,7 @@ const ORCHESTRATION_INSTRUCTIONS = "subagent-mcp - CANONICAL OPERATING MODEL (fu
516
515
  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.";
517
516
  const server = new McpServer({
518
517
  name: "subagent-mcp",
519
- version: "2.12.5-beta.2",
518
+ version: "2.12.7",
520
519
  description: "Launches always-interactive local Claude and Codex sub-agent sessions and is the orchestrator's sole launch channel. Claude runs via the Claude Agent SDK over the local Claude Code executable; Codex via `codex app-server` over stdio. The server never calls Anthropic or OpenAI HTTP APIs directly.",
521
520
  }, {
522
521
  instructions: process.env.SUBAGENT_MCP_SUBAGENT === "1"
@@ -55,6 +55,9 @@ function cwdDisablePath(cwd) {
55
55
  export function sessionPointerPath(cwd) {
56
56
  return join(stateDir, `orch-session-${cwdHash(cwd)}.json`);
57
57
  }
58
+ export function serverSessionPointerPath(cwd, serverKey = process.ppid) {
59
+ return join(stateDir, `orch-session-${cwdHash(cwd)}-${hashKey(String(serverKey))}.json`);
60
+ }
58
61
  /**
59
62
  * Enable orchestration for cwd. ALWAYS overwrites — re-enabling re-baselines by
60
63
  * clearing owner_session/baseline_turn back to null so the next hook turn
@@ -128,9 +131,15 @@ export function writeDisableCwd(cwd) {
128
131
  // Fail-safe: never throw to the caller.
129
132
  }
130
133
  }
131
- export function writeCurrentSession(cwd, sessionKey) {
134
+ export function writeCurrentSession(cwd, sessionKey, serverKey = process.ppid) {
132
135
  try {
133
136
  mkdirSync(stateDir, { recursive: true, mode: 0o700 });
137
+ writeFileSync(serverSessionPointerPath(cwd, serverKey), JSON.stringify({ session_key: sessionKey }), {
138
+ encoding: "utf8",
139
+ mode: 0o600,
140
+ });
141
+ // Back-compat only: older consumers may still read the cwd-keyed pointer.
142
+ // New disable/query paths must read the server-scoped pointer instead.
134
143
  writeFileSync(sessionPointerPath(cwd), JSON.stringify({ session_key: sessionKey }), {
135
144
  encoding: "utf8",
136
145
  mode: 0o600,
@@ -140,9 +149,9 @@ export function writeCurrentSession(cwd, sessionKey) {
140
149
  // Fail-safe: never throw to the caller.
141
150
  }
142
151
  }
143
- export function readCurrentSession(cwd) {
152
+ export function readCurrentSession(cwd, serverKey = process.ppid) {
144
153
  try {
145
- const raw = readFileSync(sessionPointerPath(cwd), "utf8");
154
+ const raw = readFileSync(serverSessionPointerPath(cwd, serverKey), "utf8");
146
155
  const parsed = JSON.parse(raw);
147
156
  return typeof parsed.session_key === "string" ? parsed.session_key : undefined;
148
157
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@heretyc/subagent-mcp",
3
- "version": "2.12.5-beta.2",
3
+ "version": "2.12.7",
4
4
  "description": "MCP server that launches and manages always-interactive Claude Code and Codex sub-agent sessions (no direct Anthropic/OpenAI API).",
5
5
  "keywords": [
6
6
  "mcp",
@@ -38,7 +38,7 @@
38
38
  "postinstall": "node scripts/postinstall.mjs",
39
39
  "prepare": "npm run build",
40
40
  "prepublishOnly": "npm test",
41
- "test": "npm run check:versions && node test/effort.test.mjs && node test/drivers.test.mjs && node test/platform.test.mjs && node test/wait.test.mjs && node test/status.test.mjs && node test/output.test.mjs && node test/stream.test.mjs && node test/routing.test.mjs && node test/deadlock.test.mjs && node test/handler-validation.test.mjs && node test/index-handler.test.mjs && node test/ruleset.test.mjs && node test/ruleset-exec.test.mjs && node test/ruleset-handler.test.mjs && node test/failover.test.mjs && node test/global-concurrency-cap.test.mjs && node test/update-check.test.mjs && node test/zombie.test.mjs && node test/zombie-reap-idle.test.mjs && node test/orchestration-marker.test.mjs && node test/orchestration-hook-core.test.mjs && node test/orchestration-adapters.test.mjs && node test/orchestration-pretool.test.mjs && node test/orchestration-directives.test.mjs && node test/no-five-call.test.mjs && node test/no-per-provider-cap.test.mjs && node test/rag-pointers.test.mjs && node test/check-worktree-subagent.test.mjs && node test/launch-agent-upsert.test.mjs && node test/claude-session-limit.test.mjs && node test/init-migration.test.mjs && node test/init-global.test.mjs && node test/mirror-fragments.test.mjs && node test/performance-tier-effort.test.mjs && node test/setup-repair.test.mjs && node test/setup-quoting.test.mjs && node test/setup-wire.test.mjs && node test/setup-cli-integration.test.mjs && node test/init.test.mjs && node test/model-selection-mode.test.mjs && node test/cli-args.test.mjs && node test/index-guard.test.mjs && node test/drivers-guard.test.mjs && node test/audit-next13-lb3.test.mjs && node test/zombie-guard.test.mjs && node test/concurrency-guard.test.mjs && node test/hook-core-guard.test.mjs && node scripts/validate_provider.mjs && node scripts/validate_seed_sites.mjs && node scripts/validate_routing_audit.mjs && node test/seed-sites.test.mjs && node test/mcp-compliance.test.mjs"
41
+ "test": "npm run check:versions && node test/effort.test.mjs && node test/drivers.test.mjs && node test/platform.test.mjs && node test/wait.test.mjs && node test/status.test.mjs && node test/output.test.mjs && node test/stream.test.mjs && node test/routing.test.mjs && node test/deadlock.test.mjs && node test/handler-validation.test.mjs && node test/index-handler.test.mjs && node test/ruleset.test.mjs && node test/ruleset-exec.test.mjs && node test/ruleset-handler.test.mjs && node test/failover.test.mjs && node test/global-concurrency-cap.test.mjs && node test/update-check.test.mjs && node test/zombie.test.mjs && node test/zombie-reap-idle.test.mjs && node test/orchestration-marker.test.mjs && node test/orchestration-hook-core.test.mjs && node test/orchestration-adapters.test.mjs && node test/orchestration-pretool.test.mjs && node test/orchestration-directives.test.mjs && node test/no-five-call.test.mjs && node test/no-per-provider-cap.test.mjs && node test/rag-pointers.test.mjs && node test/check-worktree-subagent.test.mjs && node test/launch-agent-upsert.test.mjs && node test/claude-session-limit.test.mjs && node test/init-migration.test.mjs && node test/init-global.test.mjs && node test/mirror-fragments.test.mjs && node test/performance-tier-effort.test.mjs && node test/setup-repair.test.mjs && node test/setup-quoting.test.mjs && node test/setup-wire.test.mjs && node test/setup-cli-integration.test.mjs && node test/init.test.mjs && node test/model-selection-mode.test.mjs && node test/cli-args.test.mjs && node test/index-guard.test.mjs && node test/drivers-guard.test.mjs && node test/audit-next13-lb3.test.mjs && node test/zombie-guard.test.mjs && node test/concurrency-guard.test.mjs && node test/hook-core-guard.test.mjs && node scripts/validate_provider.mjs && node scripts/validate_seed_sites.mjs && node scripts/validate_routing_audit.mjs && node test/seed-sites.test.mjs && node test/config-bom.test.mjs && node test/permission-system.test.mjs && node test/lifecycle-matrix.test.mjs && node test/output-hook-registration.test.mjs && node test/mcp-compliance.test.mjs"
42
42
  },
43
43
  "author": "Lexi Blackburn",
44
44
  "license": "Apache-2.0",