@cardor/agent-harness-kit 2.5.0 → 2.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.js CHANGED
@@ -36,6 +36,51 @@ var write = (cwd2, relPath, content, mode) => {
36
36
  writeFileSync(abs, content, { encoding: "utf8", mode });
37
37
  };
38
38
 
39
+ // src/core/materializer/delegation-guidance.ts
40
+ var PROVIDER_DELEGATION_GUIDANCE = {
41
+ "claude-code": {
42
+ invoke: ["@mention"],
43
+ sequential: "Use @<role-name> to delegate to a specific agent. Claude selects the subagent by role name.",
44
+ parallel: "Launch multiple @mentions in a single message for parallel work.",
45
+ contextTransfer: "Pass a self-contained objective, scope, known context, restrictions, and output contract with each @mention.",
46
+ waitForCompletion: "Wait for each @mention to complete before proceeding to the next step."
47
+ },
48
+ opencode: {
49
+ invoke: ["@mention"],
50
+ sequential: "Use @<role-name> to delegate to a specific agent. Child sessions need a self-contained objective.",
51
+ parallel: "Launch multiple @mentions in a single message for parallel work.",
52
+ contextTransfer: "Each child session needs: objective, scope, known context, restrictions, output contract.",
53
+ waitForCompletion: "Wait for each @mention to complete before proceeding."
54
+ },
55
+ "codex-cli": {
56
+ invoke: ["spawn", "delegate", "parallel", "wait", "summarize"],
57
+ sequential: "Use spawn \u2192 delegate \u2192 wait \u2192 summarize pattern. Explicit commands for each step.",
58
+ parallel: "Use parallel spawns for independent agents. Wait for all to complete.",
59
+ contextTransfer: "Provide full context in the spawn command \u2014 no shared state between children.",
60
+ waitForCompletion: "Use explicit wait after spawning parallel tasks.",
61
+ inspectProgress: "Check progress via status commands between waits."
62
+ },
63
+ "grok-cli": {
64
+ invoke: ["project subagent", "/tasks"],
65
+ sequential: "Refer to project-defined subagents by role name.",
66
+ parallel: "Launch multiple project subagents by role for parallel work.",
67
+ contextTransfer: "Provide bounded context when delegating to subagents.",
68
+ waitForCompletion: "Wait for subagent completion before proceeding.",
69
+ inspectProgress: "Use /tasks to check progress of running subagents."
70
+ }
71
+ };
72
+ function renderDelegationGuidance(provider, _audience = "lead") {
73
+ const guidance = PROVIDER_DELEGATION_GUIDANCE[provider];
74
+ if (!guidance) return "";
75
+ const lines = [];
76
+ for (const [key, value] of Object.entries(guidance)) {
77
+ if (key === "invoke") continue;
78
+ const label = key.replace(/([A-Z])/g, " $1").replace(/^./, (s) => s.toUpperCase());
79
+ lines.push(`- ${label}: ${value}`);
80
+ }
81
+ return lines.join("\n");
82
+ }
83
+
39
84
  // src/core/materializer/detect-package-manager.ts
40
85
  import { existsSync as existsSync3, readFileSync as readFileSync2 } from "fs";
41
86
  import { join as join4 } from "path";
@@ -207,15 +252,12 @@ var MCP_CLAUDE_PERMISSIONS_LEAD = [
207
252
  "mcp__agent-harness-kit__actions_write",
208
253
  "mcp__agent-harness-kit__actions_complete",
209
254
  "mcp__agent-harness-kit__actions_get",
210
- "mcp__agent-harness-kit__actions_record_file",
211
- "mcp__agent-harness-kit__actions_record_tool",
212
- "mcp__agent-harness-kit__tasks_get",
213
- "mcp__agent-harness-kit__tasks_claim",
214
- "mcp__agent-harness-kit__tasks_add",
215
- "mcp__agent-harness-kit__tasks_update",
216
- "mcp__agent-harness-kit__tasks_edit",
217
- "mcp__agent-harness-kit__tasks_archive",
218
- "mcp__agent-harness-kit__tasks_unarchive",
255
+ "mcp__agent-harness-kit__actions_get_by_id",
256
+ "mcp__agent-harness-kit__actions_handoff_get",
257
+ "mcp__agent-harness-kit__actions_handoff_write",
258
+ "mcp__agent-harness-kit__actions_list",
259
+ "mcp__agent-harness-kit__actions_sections_get",
260
+ "mcp__agent-harness-kit__actions_sections_list",
219
261
  "mcp__agent-harness-kit__tasks_acceptance_get",
220
262
  "mcp__agent-harness-kit__docs_search",
221
263
  "mcp__agent-harness-kit__ahk_doctor"
@@ -225,6 +267,12 @@ var MCP_CLAUDE_PERMISSIONS_EXPLORER = [
225
267
  "mcp__agent-harness-kit__actions_write",
226
268
  "mcp__agent-harness-kit__actions_complete",
227
269
  "mcp__agent-harness-kit__actions_get",
270
+ "mcp__agent-harness-kit__actions_get_by_id",
271
+ "mcp__agent-harness-kit__actions_handoff_get",
272
+ "mcp__agent-harness-kit__actions_handoff_write",
273
+ "mcp__agent-harness-kit__actions_list",
274
+ "mcp__agent-harness-kit__actions_sections_get",
275
+ "mcp__agent-harness-kit__actions_sections_list",
228
276
  "mcp__agent-harness-kit__actions_record_file",
229
277
  "mcp__agent-harness-kit__actions_record_tool",
230
278
  "mcp__agent-harness-kit__tasks_get",
@@ -238,6 +286,12 @@ var MCP_CLAUDE_PERMISSIONS_BUILDER = [
238
286
  "mcp__agent-harness-kit__actions_write",
239
287
  "mcp__agent-harness-kit__actions_complete",
240
288
  "mcp__agent-harness-kit__actions_get",
289
+ "mcp__agent-harness-kit__actions_get_by_id",
290
+ "mcp__agent-harness-kit__actions_handoff_get",
291
+ "mcp__agent-harness-kit__actions_handoff_write",
292
+ "mcp__agent-harness-kit__actions_list",
293
+ "mcp__agent-harness-kit__actions_sections_get",
294
+ "mcp__agent-harness-kit__actions_sections_list",
241
295
  "mcp__agent-harness-kit__actions_record_file",
242
296
  "mcp__agent-harness-kit__actions_record_tool",
243
297
  "mcp__agent-harness-kit__tasks_get",
@@ -256,6 +310,12 @@ var MCP_CLAUDE_PERMISSIONS_REVIEWER = [
256
310
  "mcp__agent-harness-kit__actions_write",
257
311
  "mcp__agent-harness-kit__actions_complete",
258
312
  "mcp__agent-harness-kit__actions_get",
313
+ "mcp__agent-harness-kit__actions_get_by_id",
314
+ "mcp__agent-harness-kit__actions_handoff_get",
315
+ "mcp__agent-harness-kit__actions_handoff_write",
316
+ "mcp__agent-harness-kit__actions_list",
317
+ "mcp__agent-harness-kit__actions_sections_get",
318
+ "mcp__agent-harness-kit__actions_sections_list",
259
319
  "mcp__agent-harness-kit__actions_record_file",
260
320
  "mcp__agent-harness-kit__actions_record_tool",
261
321
  "mcp__agent-harness-kit__tasks_get",
@@ -275,6 +335,12 @@ var MCP_CLAUDE_PERMISSIONS_CONSULTANT = [
275
335
  "mcp__agent-harness-kit__actions_write",
276
336
  "mcp__agent-harness-kit__actions_complete",
277
337
  "mcp__agent-harness-kit__actions_get",
338
+ "mcp__agent-harness-kit__actions_get_by_id",
339
+ "mcp__agent-harness-kit__actions_handoff_get",
340
+ "mcp__agent-harness-kit__actions_handoff_write",
341
+ "mcp__agent-harness-kit__actions_list",
342
+ "mcp__agent-harness-kit__actions_sections_get",
343
+ "mcp__agent-harness-kit__actions_sections_list",
278
344
  "mcp__agent-harness-kit__actions_record_file",
279
345
  "mcp__agent-harness-kit__actions_record_tool",
280
346
  "mcp__agent-harness-kit__tasks_get",
@@ -417,6 +483,37 @@ function mergeGrokConfigToml(filePath, port, cwd2, pm = "npm") {
417
483
  writeFileSync2(filePath, content, "utf8");
418
484
  }
419
485
 
486
+ // src/core/materializer/provider-research-capabilities.ts
487
+ var capabilities = {
488
+ "claude-code": { context7: true, mintlifyIndex: false, webSearch: true },
489
+ opencode: { context7: true, mintlifyIndex: true, webSearch: true },
490
+ "codex-cli": { context7: true, mintlifyIndex: false, webSearch: true },
491
+ "grok-cli": { context7: true, mintlifyIndex: false, webSearch: true }
492
+ };
493
+ function getResearchCapabilities(provider) {
494
+ return capabilities[provider];
495
+ }
496
+ function buildCapabilityHints(provider) {
497
+ const caps = getResearchCapabilities(provider);
498
+ const hints = [];
499
+ if (caps.context7) {
500
+ hints.push("- Context7 MCP tools available: resolve library ID before querying docs");
501
+ } else {
502
+ hints.push("- Context7 MCP tools NOT available \u2014 use official web documentation");
503
+ }
504
+ if (caps.mintlifyIndex) {
505
+ hints.push("- Mintlify Index available for publisher-maintained technical documentation");
506
+ } else {
507
+ hints.push("- Mintlify Index NOT available \u2014 fall back to official web documentation");
508
+ }
509
+ if (caps.webSearch) {
510
+ hints.push("- Web search available for current information outside documentation indexes");
511
+ } else {
512
+ hints.push("- Web search NOT available \u2014 report proof boundary, do not describe remembered behavior as current");
513
+ }
514
+ return hints.join("\n");
515
+ }
516
+
420
517
  // src/core/materializer/scaffold-utils.ts
421
518
  import { createHash } from "crypto";
422
519
  import { existsSync as existsSync5, mkdirSync as mkdirSync3, readFileSync as readFileSync5, writeFileSync as writeFileSync3 } from "fs";
@@ -489,12 +586,12 @@ echo "Edit this file with your project's health checks."
489
586
  echo "It must exit 0 for agents to start working."
490
587
  exit 1
491
588
  `;
492
- function agentsMd(config) {
589
+ function agentsMdBody(config, fileName, extraInitLines = "", orchestratingOverride) {
493
590
  const { name, description, docsPath } = config.project;
494
591
  const port = config.tools.mcp.port;
495
- return `# AGENTS.md \u2014 ${name}
592
+ let body = `# ${fileName} \u2014 ${name}
496
593
 
497
- > **Read this file first.** It is the navigation map for every AI agent working in this repository.
594
+ **Read this file first.** It is the navigation map for every AI agent working in this repository.
498
595
 
499
596
  ## Project
500
597
 
@@ -526,7 +623,12 @@ actions.write actionId section text \u2192 record a sect
526
623
  actions.record_tool actionId calls[] \u2192 batch-log tool calls to the Tools dashboard (array, min 1)
527
624
  actions.record_file actionId files[] \u2192 batch-log file touches to the Files dashboard (array, min 1)
528
625
  actions.complete actionId summary \u2192 close the action
529
- actions.get taskId \u2192 full action history for a task
626
+ actions.list taskId [agent] [status] [limit] [cursor] \u2192 compact newest-first action index with pagination
627
+ actions.get_by_id actionId \u2192 single action with section index (no content)
628
+ actions.sections_list actionId [types] [limit] [cursor] \u2192 compact section index with type filtering
629
+ actions.sections_get sectionId [length] [offset] \u2192 ranged section content reader
630
+ actions.handoff.get taskId [recipient] \u2192 newest completed canonical handoff
631
+ actions.handoff.write actionId recipient ... \u2192 recipient-directed bounded handoff
530
632
  tasks.add title [slug] [description] [acceptance] \u2192 create a new task from natural language
531
633
  tasks.get [status] \u2192 list tasks (pending | in_progress | done | blocked)
532
634
  tasks.claim id \u2192 atomically claim a pending task
@@ -542,15 +644,15 @@ docs.search query \u2192 search ${docs
542
644
  - Assess user intent: only run health.sh if changes are needed
543
645
  - tasks.get('in_progress') \u2192 resume if something is in progress
544
646
  - tasks.get('pending') \u2192 pick lowest id
545
-
647
+ ${extraInitLines ? "\n" : ""}${extraInitLines}
546
648
  2. WORK (lead \u2192 explorer \u2192 consultant \u2192 builder \u2192 reviewer)
547
- - Each agent calls actions.start(taskId, agentName) \u2192 numeric actionId
548
- - Accumulate tool calls / file touches as you work; flush periodically (every few calls or at a phase boundary) via actions.record_tool(actionId, calls: [...]) and actions.record_file(actionId, files: [...]) \u2014 both are batch-only, even a single entry goes through as a one-element array
549
- - Closes with actions.complete(actionId, summary)
649
+ - Each agent calls actions.start(taskId, agentName) \u2192 numeric actionId
650
+ - Accumulate tool calls / file touches as you work; flush periodically (every few calls or at a phase boundary) via actions.record_tool(actionId, calls: [...]) and actions.record_file(actionId, files: [...]) \u2014 both are batch-only, even a single entry goes through as a one-element array
651
+ - Closes with actions.complete(actionId, summary)
550
652
 
551
653
  3. CLOSE
552
- - tasks.update(taskId, 'done')
553
- - Run health.sh (if changes were made) \u2192 must be green before closing
654
+ - tasks.update(taskId, 'done')
655
+ - Run health.sh (if changes were made) \u2192 must be green before closing
554
656
  \`\`\`
555
657
 
556
658
  ## Agent roles
@@ -568,93 +670,39 @@ docs.search query \u2192 search ${docs
568
670
  \`\`\`
569
671
  Always: .harness/current.md (or MCP tasks.get)
570
672
  If implementing: ${docsPath}/
571
- If orchestrating: Agent definition files in your provider's agents directory
673
+ If orchestrating: ${orchestratingOverride ?? "Agent definition files in your provider's agents directory"}
572
674
  \`\`\`
573
675
  `;
676
+ if (extraInitLines) {
677
+ body = body.replace(
678
+ " - tasks.get('pending') \u2192 pick lowest id\n",
679
+ ` - tasks.get('pending') \u2192 pick lowest id
680
+ ${extraInitLines}
681
+ `
682
+ );
683
+ }
684
+ return body;
574
685
  }
575
- function claudeMd(config) {
576
- const { name, description, docsPath } = config.project;
577
- const port = config.tools.mcp.port;
578
- return `# CLAUDE.md \u2014 ${name}
579
-
580
- > **Read this file first.** It is the navigation map for every AI agent working in this repository.
581
-
582
- ## Project
583
-
584
- **${name}** \u2014 ${description}
686
+ function agentsMd(config, capabilityHints = "") {
687
+ const capabilityBlock = capabilityHints ? `## Available Research Tools
585
688
 
586
- ## Health check (run before making codebase changes)
689
+ ${capabilityHints}
587
690
 
588
- \`\`\`bash
589
- bash health.sh
590
- \`\`\`
591
-
592
- If it exits non-zero, stop and report the issue. Do not proceed with codebase changes until health is green.
593
-
594
- ## Harness data (source of truth)
595
-
596
- | File | Purpose |
597
- |------|---------|
598
- | \`.harness/harness.db\` | SQLite: all tasks, actions, file changes, tool calls |
599
- | \`.harness/current.md\` | Markdown fallback \u2014 read this if MCP server is unavailable |
600
- | \`.harness/feature_list.json\` | Human-editable task seed list |
601
-
602
- ## MCP tools (preferred)
603
-
604
- The harness exposes tools via MCP server on port ${port}. Use these instead of reading files directly.
605
-
606
- \`\`\`
607
- actions.start taskId agent \u2192 start an action, returns a numeric actionId
608
- actions.write actionId section text \u2192 record a section (result, blockers, ...)
609
- actions.record_tool actionId calls[] \u2192 batch-log tool calls to the Tools dashboard (array, min 1)
610
- actions.record_file actionId files[] \u2192 batch-log file touches to the Files dashboard (array, min 1)
611
- actions.complete actionId summary \u2192 close the action
612
- actions.get taskId \u2192 full action history for a task
613
- tasks.add title [slug] [description] [acceptance] \u2192 create a new task from natural language
614
- tasks.get [status] \u2192 list tasks (pending | in_progress | done | blocked)
615
- tasks.claim id \u2192 atomically claim a pending task
616
- tasks.update id status \u2192 change task status
617
- tasks.acceptance.update criterionId \u2192 mark an acceptance criterion as met
618
- docs.search query \u2192 search ${docsPath} for relevant content
619
- \`\`\`
620
-
621
- ## Workflow
622
-
623
- \`\`\`
624
- 1. INIT
625
- - Assess user intent: only run health.sh if changes are needed
626
- - tasks.get('in_progress') \u2192 resume if something is in progress
627
- - tasks.get('pending') \u2192 pick lowest id
628
- - No pending tasks? \u2192 ask user, infer fields, call tasks.add, then tasks.claim
629
-
630
- 2. WORK (lead \u2192 explorer \u2192 consultant \u2192 builder \u2192 reviewer)
631
- - Each agent calls actions.start(taskId, agentName) \u2192 numeric actionId
632
- - Accumulate tool calls / file touches as you work; flush periodically (every few calls or at a phase boundary) via actions.record_tool(actionId, calls: [...]) and actions.record_file(actionId, files: [...]) \u2014 both are batch-only, even a single entry goes through as a one-element array
633
- - Closes with actions.complete(actionId, summary)
634
-
635
- 3. CLOSE
636
- - tasks.update(taskId, 'done')
637
- - Run health.sh (if changes were made) \u2192 must be green before closing
638
- \`\`\`
639
-
640
- ## Agent roles
641
-
642
- | Agent | Responsibility |
643
- |-------|---------------|
644
- | lead | Decomposes the task into a plan, assigns sub-agents |
645
- | explorer | Reads and maps relevant code, never writes |
646
- | consultant | Technical advisor, runs after explorer, before builder. Never writes code. |
647
- | builder | Implements the plan, writes files |
648
- | reviewer | Verifies acceptance criteria, approves or blocks |
691
+ ` : "";
692
+ return `${capabilityBlock}${agentsMdBody(config, "AGENTS.md")}`;
693
+ }
694
+ function claudeMd(config, capabilityHints = "") {
695
+ const capabilityBlock = capabilityHints ? `## Available Research Tools
649
696
 
650
- ## What to read
697
+ ${capabilityHints}
651
698
 
652
- \`\`\`
653
- Always: .harness/current.md (or MCP tasks.get)
654
- If implementing: ${docsPath}/
655
- If orchestrating: Agent definition files in .claude/agents/
656
- \`\`\`
657
- `;
699
+ ` : "";
700
+ return `${capabilityBlock}${agentsMdBody(
701
+ config,
702
+ "CLAUDE.md",
703
+ " - No pending tasks? \u2192 ask user, infer fields, call tasks.add, then tasks.claim",
704
+ "Agent definition files in .claude/agents/"
705
+ )}`;
658
706
  }
659
707
  function configObjectBody(params) {
660
708
  const isGlobal = params.scope === "global";
@@ -772,20 +820,54 @@ ${configObjectBody(params)}}
772
820
  module.exports = config
773
821
  `;
774
822
  }
775
- function agentLead(vars) {
776
- return loadAgentTemplate("lead", vars);
823
+ function injectCapabilityHints(md, capabilityHints) {
824
+ if (!capabilityHints) return md;
825
+ const headingMatch = md.match(/^(#\s+.*?\n\n)/m);
826
+ if (!headingMatch) return md;
827
+ return `${headingMatch[1]}## Available Research Tools
828
+
829
+ ${capabilityHints}
830
+
831
+ ${md.slice(headingMatch[1].length)}`;
832
+ }
833
+ function injectDelegationGuidance(md, delegationGuidance) {
834
+ if (!delegationGuidance) return md;
835
+ const researchSection = md.match(/(## Available Research Tools\n\n[\s\S]*?)\n\n/m);
836
+ if (researchSection) {
837
+ const insertionPoint = researchSection[1].length + "## Available Research Tools\n\n".length;
838
+ const afterResearch = md.slice(insertionPoint);
839
+ return md.slice(0, insertionPoint) + `
840
+ ## Provider Delegation Guidance
841
+
842
+ ${delegationGuidance}
843
+
844
+ ${afterResearch}`;
845
+ }
846
+ const headingMatch = md.match(/^(#\s+.*?\n\n)/m);
847
+ if (!headingMatch) return md;
848
+ return `${headingMatch[1]}## Provider Delegation Guidance
849
+
850
+ ${delegationGuidance}
851
+
852
+ ${md.slice(headingMatch[1].length)}`;
853
+ }
854
+ function agentLead(opts, capabilityHints = "", delegationGuidance = "") {
855
+ let result = loadAgentTemplate("lead", opts);
856
+ result = injectCapabilityHints(result, capabilityHints);
857
+ result = injectDelegationGuidance(result, delegationGuidance);
858
+ return result;
777
859
  }
778
- function agentExplorer(vars) {
779
- return loadAgentTemplate("explorer", vars);
860
+ function agentExplorer(opts, capabilityHints = "") {
861
+ return injectCapabilityHints(loadAgentTemplate("explorer", opts), capabilityHints);
780
862
  }
781
- function agentBuilder(vars) {
782
- return loadAgentTemplate("builder", vars);
863
+ function agentBuilder(opts, capabilityHints = "") {
864
+ return injectCapabilityHints(loadAgentTemplate("builder", opts), capabilityHints);
783
865
  }
784
- function agentConsultant(vars) {
785
- return loadAgentTemplate("consultant", vars);
866
+ function agentConsultant(opts, capabilityHints = "") {
867
+ return injectCapabilityHints(loadAgentTemplate("consultant", opts), capabilityHints);
786
868
  }
787
- function agentReviewer(vars) {
788
- return loadAgentTemplate("reviewer", vars);
869
+ function agentReviewer(opts, capabilityHints = "") {
870
+ return injectCapabilityHints(loadAgentTemplate("reviewer", opts), capabilityHints);
789
871
  }
790
872
  function stripFrontmatter(md) {
791
873
  const parts = md.split(/^---\s*$/m);
@@ -828,13 +910,23 @@ ${safe(instructions)}
828
910
  """
829
911
  `;
830
912
  }
831
- function agentLeadToml(vars, opts) {
913
+ function agentLeadToml(vars, opts, delegationGuidance = "") {
832
914
  const { description, body } = stripFrontmatter(loadAgentTemplate("lead", vars));
833
- return toCodexToml("lead", "lead", description, body, opts);
915
+ const bodyWithDelegation = delegationGuidance ? `${body}
916
+
917
+ ## Provider Delegation Guidance
918
+
919
+ ${delegationGuidance}` : body;
920
+ return toCodexToml("lead", "lead", description, bodyWithDelegation, opts);
834
921
  }
835
- function agentLeadAsDefaultToml(vars, opts) {
922
+ function agentLeadAsDefaultToml(vars, opts, delegationGuidance = "") {
836
923
  const { description, body } = stripFrontmatter(loadAgentTemplate("lead", vars));
837
- return toCodexToml("default", "lead", description, body, opts);
924
+ const bodyWithDelegation = delegationGuidance ? `${body}
925
+
926
+ ## Provider Delegation Guidance
927
+
928
+ ${delegationGuidance}` : body;
929
+ return toCodexToml("default", "lead", description, bodyWithDelegation, opts);
838
930
  }
839
931
  function agentExplorerToml(vars, opts) {
840
932
  const { description, body } = stripFrontmatter(loadAgentTemplate("explorer", vars));
@@ -1056,33 +1148,38 @@ function appendGitignore(cwd2) {
1056
1148
  function slugify(title) {
1057
1149
  return title.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 64);
1058
1150
  }
1059
- function writeSkills(cwd2, skillsDir) {
1151
+ function writeSkills(cwd2, skillsDir, delegationGuidance) {
1060
1152
  const skillNames = ["ahk-ask", "ahk-consultant", "ahk-triage", "ahk-review", "ahk-test"];
1061
1153
  for (const skillName of skillNames) {
1062
1154
  const src = join6(__dirname2, "skills", skillName, "SKILL.md");
1063
1155
  const destDir = join6(cwd2, skillsDir, skillName);
1064
1156
  const dest = join6(destDir, "SKILL.md");
1065
1157
  mkdirSync3(destDir, { recursive: true });
1066
- writeFileSync3(dest, readFileSync5(src, "utf8"), "utf8");
1158
+ let content = readFileSync5(src, "utf8");
1159
+ if (delegationGuidance) {
1160
+ content = injectDelegationGuidance(content, delegationGuidance);
1161
+ }
1162
+ writeFileSync3(dest, content, "utf8");
1067
1163
  }
1068
1164
  }
1069
1165
 
1070
1166
  // src/core/materializer/claude-code.ts
1071
- function claudeAgentFiles(config, modelsByRole) {
1167
+ function claudeAgentFiles(config, modelsByRole, capabilityHints = "") {
1072
1168
  const projectName = config.project.name;
1073
1169
  return [
1074
- { relPath: ".claude/agents/lead.md", content: translateFrontmatterForClaudeCode(agentLead({ projectName }), "lead", { model: modelsByRole?.lead }) },
1075
- { relPath: ".claude/agents/explorer.md", content: translateFrontmatterForClaudeCode(agentExplorer({ projectName }), "explorer", { model: modelsByRole?.explorer }) },
1076
- { relPath: ".claude/agents/consultant.md", content: translateFrontmatterForClaudeCode(agentConsultant({ projectName }), "consultant", { model: modelsByRole?.consultant }) },
1077
- { relPath: ".claude/agents/builder.md", content: translateFrontmatterForClaudeCode(agentBuilder({ projectName }), "builder", { model: modelsByRole?.builder }) },
1078
- { relPath: ".claude/agents/reviewer.md", content: translateFrontmatterForClaudeCode(agentReviewer({ projectName }), "reviewer", { model: modelsByRole?.reviewer }) }
1170
+ { relPath: ".claude/agents/lead.md", content: translateFrontmatterForClaudeCode(agentLead({ projectName }, capabilityHints, renderDelegationGuidance("claude-code", "lead")), "lead", { model: modelsByRole?.lead }) },
1171
+ { relPath: ".claude/agents/explorer.md", content: translateFrontmatterForClaudeCode(agentExplorer({ projectName }, capabilityHints), "explorer", { model: modelsByRole?.explorer }) },
1172
+ { relPath: ".claude/agents/consultant.md", content: translateFrontmatterForClaudeCode(agentConsultant({ projectName }, capabilityHints), "consultant", { model: modelsByRole?.consultant }) },
1173
+ { relPath: ".claude/agents/builder.md", content: translateFrontmatterForClaudeCode(agentBuilder({ projectName }, capabilityHints), "builder", { model: modelsByRole?.builder }) },
1174
+ { relPath: ".claude/agents/reviewer.md", content: translateFrontmatterForClaudeCode(agentReviewer({ projectName }, capabilityHints), "reviewer", { model: modelsByRole?.reviewer }) }
1079
1175
  ];
1080
1176
  }
1081
1177
  var ClaudeCodeMaterializer = class {
1082
1178
  async scaffold(config, opts) {
1083
1179
  const { cwd: cwd2, claudeAgentModels } = opts;
1084
- write(cwd2, "AGENTS.md", stampGenerated(agentsMd(config)));
1085
- write(cwd2, "CLAUDE.md", stampGenerated(claudeMd(config)));
1180
+ const capabilityHints = buildCapabilityHints("claude-code");
1181
+ write(cwd2, "AGENTS.md", stampGenerated(agentsMd(config, capabilityHints)));
1182
+ write(cwd2, "CLAUDE.md", stampGenerated(claudeMd(config, capabilityHints)));
1086
1183
  if (!existsSync6(join7(cwd2, "health.sh"))) {
1087
1184
  write(cwd2, "health.sh", HEALTH_SH, 493);
1088
1185
  }
@@ -1099,30 +1196,31 @@ No tasks in progress.
1099
1196
  `
1100
1197
  );
1101
1198
  }
1102
- writeAgentFiles(cwd2, claudeAgentFiles(config, claudeAgentModels));
1199
+ writeAgentFiles(cwd2, claudeAgentFiles(config, claudeAgentModels, capabilityHints));
1103
1200
  mergeClaudeMcpJson(join7(cwd2, ".mcp.json"), config.tools.mcp.port, cwd2, detectPackageManager(cwd2));
1104
1201
  mergeClaudeSettingsJson(join7(cwd2, ".claude/settings.json"));
1105
1202
  mergeClaudeSettingsLocalJson(join7(cwd2, ".claude/settings.local.json"));
1106
1203
  appendGitignore(cwd2);
1107
- writeSkills(cwd2, ".claude/skills");
1204
+ writeSkills(cwd2, ".claude/skills", renderDelegationGuidance("claude-code", "coordination-skill"));
1108
1205
  }
1109
1206
  async build(config, cwd2, opts = {}) {
1207
+ const capabilityHints = buildCapabilityHints("claude-code");
1110
1208
  const derived = reconcileGeneratedFiles(
1111
1209
  cwd2,
1112
1210
  [
1113
- { relPath: "AGENTS.md", content: agentsMd(config) },
1114
- { relPath: "CLAUDE.md", content: claudeMd(config) }
1211
+ { relPath: "AGENTS.md", content: agentsMd(config, capabilityHints) },
1212
+ { relPath: "CLAUDE.md", content: claudeMd(config, capabilityHints) }
1115
1213
  ],
1116
1214
  { force: opts.force, backupRoot: join7(cwd2, config.storage.dir, "backups") }
1117
1215
  );
1118
- const agents = writeAgentFiles(cwd2, claudeAgentFiles(config, opts.claudeAgentModels), {
1216
+ const agents = writeAgentFiles(cwd2, claudeAgentFiles(config, opts.claudeAgentModels, capabilityHints), {
1119
1217
  force: opts.force,
1120
1218
  backupRoot: join7(cwd2, config.storage.dir, "backups")
1121
1219
  });
1122
1220
  mergeClaudeMcpJson(join7(cwd2, ".mcp.json"), config.tools.mcp.port, cwd2, detectPackageManager(cwd2));
1123
1221
  mergeClaudeSettingsJson(join7(cwd2, ".claude/settings.json"));
1124
1222
  mergeClaudeSettingsLocalJson(join7(cwd2, ".claude/settings.local.json"));
1125
- writeSkills(cwd2, ".claude/skills");
1223
+ writeSkills(cwd2, ".claude/skills", renderDelegationGuidance("claude-code", "coordination-skill"));
1126
1224
  return { agents, derived };
1127
1225
  }
1128
1226
  async migrate(config, _to, _cwd) {
@@ -1152,15 +1250,15 @@ No tasks in progress.
1152
1250
  // src/core/materializer/codex-cli.ts
1153
1251
  import { existsSync as existsSync7, mkdirSync as mkdirSync4, writeFileSync as writeFileSync4 } from "fs";
1154
1252
  import { join as join8, resolve as resolve3 } from "path";
1155
- function codexAgentFiles(config, modelsByRole) {
1253
+ function codexAgentFiles(config, modelsByRole, _capabilityHints = "") {
1156
1254
  const projectName = config.project.name;
1157
1255
  return [
1158
- { relPath: ".codex/agents/lead.toml", content: agentLeadToml({ projectName }, modelsByRole?.lead) },
1256
+ { relPath: ".codex/agents/lead.toml", content: agentLeadToml({ projectName }, modelsByRole?.lead, renderDelegationGuidance("codex-cli", "lead")) },
1159
1257
  { relPath: ".codex/agents/explorer.toml", content: agentExplorerToml({ projectName }, modelsByRole?.explorer) },
1160
1258
  { relPath: ".codex/agents/consultant.toml", content: agentConsultantToml({ projectName }, modelsByRole?.consultant) },
1161
1259
  { relPath: ".codex/agents/builder.toml", content: agentBuilderToml({ projectName }, modelsByRole?.builder) },
1162
1260
  { relPath: ".codex/agents/reviewer.toml", content: agentReviewerToml({ projectName }, modelsByRole?.reviewer) },
1163
- { relPath: ".codex/agents/default.toml", content: agentLeadAsDefaultToml({ projectName }, modelsByRole?.lead) }
1261
+ { relPath: ".codex/agents/default.toml", content: agentLeadAsDefaultToml({ projectName }, modelsByRole?.lead, renderDelegationGuidance("codex-cli", "lead")) }
1164
1262
  ];
1165
1263
  }
1166
1264
  var CodexCliMaterializer = class {
@@ -1190,7 +1288,7 @@ No tasks in progress.
1190
1288
  writeAgentFiles(cwd2, codexAgentFiles(config, codexAgentModels));
1191
1289
  mergeCodexConfigToml(join8(cwd2, ".codex/config.toml"), config.tools.mcp.port, cwd2, detectPackageManager(cwd2));
1192
1290
  appendGitignore(cwd2);
1193
- writeSkills(cwd2, ".agents/skills");
1291
+ writeSkills(cwd2, ".agents/skills", renderDelegationGuidance("codex-cli", "coordination-skill"));
1194
1292
  }
1195
1293
  async build(config, cwd2, opts = {}) {
1196
1294
  const derived = reconcileGeneratedFiles(
@@ -1203,7 +1301,7 @@ No tasks in progress.
1203
1301
  backupRoot: join8(cwd2, config.storage.dir, "backups")
1204
1302
  });
1205
1303
  mergeCodexConfigToml(join8(cwd2, ".codex/config.toml"), config.tools.mcp.port, cwd2, detectPackageManager(cwd2));
1206
- writeSkills(cwd2, ".agents/skills");
1304
+ writeSkills(cwd2, ".agents/skills", renderDelegationGuidance("codex-cli", "coordination-skill"));
1207
1305
  return { agents, derived };
1208
1306
  }
1209
1307
  async migrate(config, _to, _cwd) {
@@ -1220,7 +1318,7 @@ import { join as join9, resolve as resolve4 } from "path";
1220
1318
  function grokAgentFiles(config) {
1221
1319
  const projectName = config.project.name;
1222
1320
  return [
1223
- { relPath: ".grok/agents/lead.md", content: translateFrontmatterForGrok(agentLead({ projectName }), "lead") },
1321
+ { relPath: ".grok/agents/lead.md", content: translateFrontmatterForGrok(agentLead({ projectName }, "", renderDelegationGuidance("grok-cli", "lead")), "lead") },
1224
1322
  { relPath: ".grok/agents/explorer.md", content: translateFrontmatterForGrok(agentExplorer({ projectName }), "explorer") },
1225
1323
  { relPath: ".grok/agents/consultant.md", content: translateFrontmatterForGrok(agentConsultant({ projectName }), "consultant") },
1226
1324
  { relPath: ".grok/agents/builder.md", content: translateFrontmatterForGrok(agentBuilder({ projectName }), "builder") },
@@ -1254,7 +1352,7 @@ No tasks in progress.
1254
1352
  writeAgentFiles(cwd2, grokAgentFiles(config));
1255
1353
  mergeGrokConfigToml(join9(cwd2, ".grok/config.toml"), config.tools.mcp.port, cwd2, detectPackageManager(cwd2));
1256
1354
  appendGitignore(cwd2);
1257
- writeSkills(cwd2, ".grok/skills");
1355
+ writeSkills(cwd2, ".grok/skills", renderDelegationGuidance("grok-cli", "coordination-skill"));
1258
1356
  }
1259
1357
  async build(config, cwd2, opts = {}) {
1260
1358
  const derived = reconcileGeneratedFiles(
@@ -1267,7 +1365,7 @@ No tasks in progress.
1267
1365
  backupRoot: join9(cwd2, config.storage.dir, "backups")
1268
1366
  });
1269
1367
  mergeGrokConfigToml(join9(cwd2, ".grok/config.toml"), config.tools.mcp.port, cwd2, detectPackageManager(cwd2));
1270
- writeSkills(cwd2, ".grok/skills");
1368
+ writeSkills(cwd2, ".grok/skills", renderDelegationGuidance("grok-cli", "coordination-skill"));
1271
1369
  return { agents, derived };
1272
1370
  }
1273
1371
  async migrate(config, _to, _cwd) {
@@ -1281,25 +1379,26 @@ No tasks in progress.
1281
1379
  // src/core/materializer/opencode.ts
1282
1380
  import { existsSync as existsSync9, mkdirSync as mkdirSync6, writeFileSync as writeFileSync6 } from "fs";
1283
1381
  import { join as join10, resolve as resolve5 } from "path";
1284
- function opencodeAgentFiles(config) {
1382
+ function opencodeAgentFiles(config, capabilityHints = "") {
1285
1383
  const projectName = config.project.name;
1286
1384
  return [
1287
- { relPath: ".opencode/agents/lead.md", content: translateFrontmatterForOpenCode(agentLead({ projectName }), "lead") },
1288
- { relPath: ".opencode/agents/explorer.md", content: translateFrontmatterForOpenCode(agentExplorer({ projectName }), "explorer") },
1289
- { relPath: ".opencode/agents/consultant.md", content: translateFrontmatterForOpenCode(agentConsultant({ projectName }), "consultant") },
1290
- { relPath: ".opencode/agents/builder.md", content: translateFrontmatterForOpenCode(agentBuilder({ projectName }), "builder") },
1291
- { relPath: ".opencode/agents/reviewer.md", content: translateFrontmatterForOpenCode(agentReviewer({ projectName }), "reviewer") }
1385
+ { relPath: ".opencode/agents/lead.md", content: translateFrontmatterForOpenCode(agentLead({ projectName }, capabilityHints, renderDelegationGuidance("opencode", "lead")), "lead") },
1386
+ { relPath: ".opencode/agents/explorer.md", content: translateFrontmatterForOpenCode(agentExplorer({ projectName }, capabilityHints), "explorer") },
1387
+ { relPath: ".opencode/agents/consultant.md", content: translateFrontmatterForOpenCode(agentConsultant({ projectName }, capabilityHints), "consultant") },
1388
+ { relPath: ".opencode/agents/builder.md", content: translateFrontmatterForOpenCode(agentBuilder({ projectName }, capabilityHints), "builder") },
1389
+ { relPath: ".opencode/agents/reviewer.md", content: translateFrontmatterForOpenCode(agentReviewer({ projectName }, capabilityHints), "reviewer") }
1292
1390
  ];
1293
1391
  }
1294
1392
  var OpenCodeMaterializer = class {
1295
1393
  async scaffold(config, opts) {
1296
1394
  const { cwd: cwd2 } = opts;
1395
+ const capabilityHints = buildCapabilityHints("opencode");
1297
1396
  const write2 = (relPath, content, mode) => {
1298
1397
  const abs = join10(cwd2, relPath);
1299
1398
  mkdirSync6(resolve5(abs, ".."), { recursive: true });
1300
1399
  writeFileSync6(abs, content, { encoding: "utf8", mode });
1301
1400
  };
1302
- write2("AGENTS.md", stampGenerated(agentsMd(config)));
1401
+ write2("AGENTS.md", stampGenerated(agentsMd(config, capabilityHints)));
1303
1402
  if (!existsSync9(join10(cwd2, "health.sh"))) {
1304
1403
  write2("health.sh", HEALTH_SH, 493);
1305
1404
  }
@@ -1315,23 +1414,24 @@ No tasks in progress.
1315
1414
  `
1316
1415
  );
1317
1416
  }
1318
- writeAgentFiles(cwd2, opencodeAgentFiles(config));
1417
+ writeAgentFiles(cwd2, opencodeAgentFiles(config, capabilityHints));
1319
1418
  mergeOpencodeJson(join10(cwd2, "opencode.json"), config.tools.mcp.port, cwd2, detectPackageManager(cwd2));
1320
1419
  appendGitignore(cwd2);
1321
- writeSkills(cwd2, ".opencode/skills");
1420
+ writeSkills(cwd2, ".opencode/skills", renderDelegationGuidance("opencode", "coordination-skill"));
1322
1421
  }
1323
1422
  async build(config, cwd2, opts = {}) {
1423
+ const capabilityHints = buildCapabilityHints("opencode");
1324
1424
  const derived = reconcileGeneratedFiles(
1325
1425
  cwd2,
1326
- [{ relPath: "AGENTS.md", content: agentsMd(config) }],
1426
+ [{ relPath: "AGENTS.md", content: agentsMd(config, capabilityHints) }],
1327
1427
  { force: opts.force, backupRoot: join10(cwd2, config.storage.dir, "backups") }
1328
1428
  );
1329
- const agents = writeAgentFiles(cwd2, opencodeAgentFiles(config), {
1429
+ const agents = writeAgentFiles(cwd2, opencodeAgentFiles(config, capabilityHints), {
1330
1430
  force: opts.force,
1331
1431
  backupRoot: join10(cwd2, config.storage.dir, "backups")
1332
1432
  });
1333
1433
  mergeOpencodeJson(join10(cwd2, "opencode.json"), config.tools.mcp.port, cwd2, detectPackageManager(cwd2));
1334
- writeSkills(cwd2, ".opencode/skills");
1434
+ writeSkills(cwd2, ".opencode/skills", renderDelegationGuidance("opencode", "coordination-skill"));
1335
1435
  return { agents, derived };
1336
1436
  }
1337
1437
  async migrate(config, _to, _cwd) {