@heretyc/subagent-mcp 2.12.19 → 2.12.21
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 +3 -2
- package/dist/doctor.js +3 -3
- package/dist/index.js +2 -2
- package/dist/setup.js +76 -2
- package/package.json +3 -2
- package/skills/handoff-resume/SKILL.md +12 -0
package/README.md
CHANGED
|
@@ -27,7 +27,7 @@ of raw file context. The main invariants are:
|
|
|
27
27
|
|
|
28
28
|
### What You Need First
|
|
29
29
|
|
|
30
|
-
- Node.js
|
|
30
|
+
- Node.js 20 or newer (`node --version`)
|
|
31
31
|
- `claude` CLI, installed and signed in (`claude --version`)
|
|
32
32
|
- `codex` CLI, installed and signed in (`codex --version`; optional if you only
|
|
33
33
|
use Claude)
|
|
@@ -54,7 +54,8 @@ Installing the package only ships the program. It does not connect anything on
|
|
|
54
54
|
its own. `subagent-mcp setup` finds your Claude Code or Codex install and
|
|
55
55
|
registers both the server and the per-turn orchestration hooks. For Claude Code
|
|
56
56
|
it also registers or wraps `statusLine` so the hook can read Claude's
|
|
57
|
-
authoritative context percentage without replacing your custom statusline
|
|
57
|
+
authoritative context percentage without replacing your custom statusline, and
|
|
58
|
+
deploys the `handoff-resume` Agent Skill to your Claude user scope.
|
|
58
59
|
Preview first with `subagent-mcp setup --dry-run`.
|
|
59
60
|
|
|
60
61
|
### Restart, Then Turn On The Invariant
|
package/dist/doctor.js
CHANGED
|
@@ -11,9 +11,9 @@ import { verifyWiring } from "./setup.js";
|
|
|
11
11
|
export async function runDoctor() {
|
|
12
12
|
console.log("subagent-mcp doctor (checks wiring, including Claude statusLine; repairs missing MCP registrations via vendor CLIs)\n");
|
|
13
13
|
const major = Number(process.versions.node.split(".")[0]);
|
|
14
|
-
console.log(` ${major >=
|
|
15
|
-
(major >=
|
|
16
|
-
let failed = major <
|
|
14
|
+
console.log(` ${major >= 20 ? "PASS" : "FAIL"} node version — ${process.versions.node}` +
|
|
15
|
+
(major >= 20 ? "" : " (Node >= 20 required)"));
|
|
16
|
+
let failed = major < 20 ? 1 : 0;
|
|
17
17
|
for (const r of verifyWiring(undefined, true)) {
|
|
18
18
|
console.log(` ${r.ok ? "PASS" : "FAIL"} ${r.label} — ${r.detail}`);
|
|
19
19
|
if (!r.ok)
|
package/dist/index.js
CHANGED
|
@@ -572,7 +572,7 @@ const ORCHESTRATION_INSTRUCTIONS = "subagent-mcp - CANONICAL OPERATING MODEL (fu
|
|
|
572
572
|
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. launch_agent is code-capped at 2 spawn levels below the main orchestrator: depth 1 may launch depth 2 workers; depth 2 workers cannot spawn further.\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.";
|
|
573
573
|
const server = new McpServer({
|
|
574
574
|
name: "subagent-mcp",
|
|
575
|
-
version: "2.12.
|
|
575
|
+
version: "2.12.21",
|
|
576
576
|
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.",
|
|
577
577
|
}, {
|
|
578
578
|
instructions: process.env.SUBAGENT_MCP_SUBAGENT === "1"
|
|
@@ -1696,7 +1696,7 @@ server.tool("orchestration-mode", "Toggle or query per-project ORCHESTRATION MOD
|
|
|
1696
1696
|
],
|
|
1697
1697
|
};
|
|
1698
1698
|
}));
|
|
1699
|
-
// Tool
|
|
1699
|
+
// Tool 9: model-selection-mode
|
|
1700
1700
|
server.tool("model-selection-mode", "Set or query per-project MODEL SELECTION MODE, which gates launch_agent's `provider`/`model`/`effort` selectors. `mode`: \"smart\" or \"user-approved-overrides\"; omit to query. \"smart\" is the DEFAULT (used whenever unset): launch_agent REJECTS any call supplying provider/model/effort and the server auto-picks the best model for the task_category. \"user-approved-overrides\" opens a 30-MINUTE window where selectors are HONORED, enforced LAZILY (reverts to smart on the next launch_agent call after the 30 min elapse); re-enabling does NOT extend an active window. HONOR-BASED, parallel to orchestration-mode: 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; a plain yes/no if neither exists). This tool CANNOT verify that authorization — never enable on your own initiative. PERSISTENCE: state keyed by cwd; both the mode and the override-window timestamp survive server restarts (remaining window is restored, not reset).", {
|
|
1701
1701
|
mode: z.enum(["smart", "user-approved-overrides"]).optional(),
|
|
1702
1702
|
}, withMaintenance(async (params) => {
|
package/dist/setup.js
CHANGED
|
@@ -41,6 +41,12 @@ export function serverPaths(root = INSTALL_ROOT) {
|
|
|
41
41
|
codexHook: `${f}/dist/hooks/orchestration-codex.js`,
|
|
42
42
|
};
|
|
43
43
|
}
|
|
44
|
+
export function handoffResumeSkillPaths(root = INSTALL_ROOT, home = homedir()) {
|
|
45
|
+
return {
|
|
46
|
+
source: join(root, "skills", "handoff-resume", "SKILL.md"),
|
|
47
|
+
target: join(home, ".claude", "skills", "handoff-resume", "SKILL.md"),
|
|
48
|
+
};
|
|
49
|
+
}
|
|
44
50
|
function statuslineCommand(shimPath, innerCommand = "") {
|
|
45
51
|
const inner = innerCommand.trim();
|
|
46
52
|
return `node "${shimPath}"${inner ? ` ${quoteStatuslineInnerArg(inner)}` : ""}`;
|
|
@@ -480,6 +486,51 @@ function describe(status, what) {
|
|
|
480
486
|
else
|
|
481
487
|
console.log(` ${what}: pointed at a stale path — repaired.`);
|
|
482
488
|
}
|
|
489
|
+
export function deployHandoffResumeSkill(root = INSTALL_ROOT, home = homedir()) {
|
|
490
|
+
const { source, target } = handoffResumeSkillPaths(root, home);
|
|
491
|
+
if (!existsSync(source)) {
|
|
492
|
+
return {
|
|
493
|
+
changed: false,
|
|
494
|
+
status: "missing-source",
|
|
495
|
+
source,
|
|
496
|
+
target,
|
|
497
|
+
detail: `source missing at ${source}; reinstall @heretyc/subagent-mcp, then run subagent-mcp setup`,
|
|
498
|
+
};
|
|
499
|
+
}
|
|
500
|
+
const desired = readFileSync(source, "utf8");
|
|
501
|
+
if (existsSync(target) && readFileSync(target, "utf8") === desired) {
|
|
502
|
+
return { changed: false, status: "ok", source, target, detail: "deployed" };
|
|
503
|
+
}
|
|
504
|
+
const status = existsSync(target) ? "repaired" : "added";
|
|
505
|
+
if (!DRY_RUN) {
|
|
506
|
+
mkdirSync(dirname(target), { recursive: true });
|
|
507
|
+
writeFileSync(target, desired);
|
|
508
|
+
}
|
|
509
|
+
return { changed: true, status, source, target, detail: status === "added" ? "deployed" : "restored" };
|
|
510
|
+
}
|
|
511
|
+
export function verifyHandoffResumeSkill(root = INSTALL_ROOT, home = homedir()) {
|
|
512
|
+
const { source, target } = handoffResumeSkillPaths(root, home);
|
|
513
|
+
if (!existsSync(source)) {
|
|
514
|
+
return {
|
|
515
|
+
label: "claude: handoff-resume skill",
|
|
516
|
+
ok: false,
|
|
517
|
+
detail: "source missing from install - reinstall @heretyc/subagent-mcp",
|
|
518
|
+
};
|
|
519
|
+
}
|
|
520
|
+
if (!existsSync(target)) {
|
|
521
|
+
return {
|
|
522
|
+
label: "claude: handoff-resume skill",
|
|
523
|
+
ok: false,
|
|
524
|
+
detail: "missing - run subagent-mcp setup",
|
|
525
|
+
};
|
|
526
|
+
}
|
|
527
|
+
const ok = readFileSync(target, "utf8") === readFileSync(source, "utf8");
|
|
528
|
+
return {
|
|
529
|
+
label: "claude: handoff-resume skill",
|
|
530
|
+
ok,
|
|
531
|
+
detail: ok ? "deployed" : "stale - run subagent-mcp setup",
|
|
532
|
+
};
|
|
533
|
+
}
|
|
483
534
|
export function vendorWireSpecs(p = serverPaths(), home = homedir()) {
|
|
484
535
|
const claudeFile = join(home, ".claude.json");
|
|
485
536
|
const codexDir = join(home, ".codex");
|
|
@@ -585,12 +636,33 @@ function wireClaude() {
|
|
|
585
636
|
catch (e) {
|
|
586
637
|
fail("claude", `could not write the settings.json hook: ${e.message}`);
|
|
587
638
|
}
|
|
639
|
+
// 3) Claude Agent Skill for resuming saved handoffs.
|
|
640
|
+
try {
|
|
641
|
+
const r = deployHandoffResumeSkill(INSTALL_ROOT);
|
|
642
|
+
if (r.status === "missing-source") {
|
|
643
|
+
fail("claude", r.detail);
|
|
644
|
+
}
|
|
645
|
+
else {
|
|
646
|
+
if (r.status === "ok")
|
|
647
|
+
console.log(" handoff-resume skill: already correct.");
|
|
648
|
+
else if (r.status === "added")
|
|
649
|
+
console.log(" handoff-resume skill: added.");
|
|
650
|
+
else
|
|
651
|
+
console.log(" handoff-resume skill: restored from package copy.");
|
|
652
|
+
if (r.changed && DRY_RUN)
|
|
653
|
+
console.log(" (dry-run: not written)");
|
|
654
|
+
}
|
|
655
|
+
}
|
|
656
|
+
catch (e) {
|
|
657
|
+
fail("claude", `could not deploy the handoff-resume skill: ${e.message}`);
|
|
658
|
+
}
|
|
588
659
|
}
|
|
589
660
|
function wireCodex() {
|
|
590
661
|
console.log("\n--- Codex CLI ---");
|
|
591
662
|
const p = serverPaths();
|
|
592
663
|
const codexDir = join(homedir(), ".codex");
|
|
593
664
|
const specs = vendorWireSpecs(p);
|
|
665
|
+
// Codex has no Agent Skill mechanism; MCP instructions carry handoff guidance.
|
|
594
666
|
// 1) config.toml — MCP server block (created if the file is missing).
|
|
595
667
|
try {
|
|
596
668
|
const existed = existsSync(specs.codex.configFile);
|
|
@@ -696,6 +768,7 @@ export function verifyWiring(root = INSTALL_ROOT, repair = false) {
|
|
|
696
768
|
: "wired; waiting for Claude statusLine signal"
|
|
697
769
|
: `${sl.status === "repaired" ? "stale path" : "not wired"} - run: subagent-mcp setup`,
|
|
698
770
|
});
|
|
771
|
+
results.push(verifyHandoffResumeSkill(root, home));
|
|
699
772
|
}
|
|
700
773
|
else if (hasClaudeConfig) {
|
|
701
774
|
const cj = readJson(join(home, ".claude.json"), {});
|
|
@@ -722,6 +795,7 @@ export function verifyWiring(root = INSTALL_ROOT, repair = false) {
|
|
|
722
795
|
: "wired; waiting for Claude statusLine signal"
|
|
723
796
|
: `${sl.status === "repaired" ? "stale path" : "not wired"} - run: subagent-mcp setup`,
|
|
724
797
|
});
|
|
798
|
+
results.push(verifyHandoffResumeSkill(root, home));
|
|
725
799
|
}
|
|
726
800
|
const hasCodexCli = findOnPath("codex") !== null;
|
|
727
801
|
const hasCodex = hasCodexCli || existsSync(join(home, ".codex"));
|
|
@@ -770,8 +844,8 @@ export async function runSetup() {
|
|
|
770
844
|
console.log(`subagent-mcp setup${DRY_RUN ? " (dry-run)" : ""}`);
|
|
771
845
|
console.log(`Install root: ${INSTALL_ROOT}\n`);
|
|
772
846
|
const major = Number(process.versions.node.split(".")[0]);
|
|
773
|
-
if (major <
|
|
774
|
-
console.error(`ERROR: Node ${process.versions.node} is too old
|
|
847
|
+
if (major < 20) {
|
|
848
|
+
console.error(`ERROR: Node ${process.versions.node} is too old. Node >= 20 required.`);
|
|
775
849
|
process.exit(1);
|
|
776
850
|
}
|
|
777
851
|
const missing = verifyInstall();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@heretyc/subagent-mcp",
|
|
3
|
-
"version": "2.12.
|
|
3
|
+
"version": "2.12.21",
|
|
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",
|
|
@@ -25,6 +25,7 @@
|
|
|
25
25
|
"files": [
|
|
26
26
|
"dist",
|
|
27
27
|
"directives",
|
|
28
|
+
"skills/handoff-resume",
|
|
28
29
|
"scripts/postinstall.mjs",
|
|
29
30
|
"LICENSE",
|
|
30
31
|
"NOTICE",
|
|
@@ -61,7 +62,7 @@
|
|
|
61
62
|
"typescript": "^7.0.2"
|
|
62
63
|
},
|
|
63
64
|
"engines": {
|
|
64
|
-
"node": ">=
|
|
65
|
+
"node": ">=20"
|
|
65
66
|
},
|
|
66
67
|
"publishConfig": {
|
|
67
68
|
"registry": "https://registry.npmjs.org",
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: handoff-resume
|
|
3
|
+
version: 1.0.0
|
|
4
|
+
description: Resume prior work from a saved subagent-mcp handoff when the user says "handoff-resume", "resume handoff", or "resume work"; call handoff-read, confirm intent with exactly 5 structured questions before acting, and know the handoff-write/read/clear lifecycle.
|
|
5
|
+
author: Lexi Blackburn (https://github.com/Heretyc/)
|
|
6
|
+
created: 2026-07-11
|
|
7
|
+
updated: 2026-07-11
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# Handoff Resume
|
|
11
|
+
|
|
12
|
+
When triggered, call the `handoff-read` MCP tool for the current cwd, then confirm the user's intent with EXACTLY 5 structured questions before acting on the saved handoff. `handoff-write` saves a compact resume record once 50% context utilization unlocks it. `handoff-read` retrieves the saved record for this cwd and binds reminder re-append behavior to this reading session. `handoff-clear` deletes the saved record and overflow file, if any, for this cwd.
|