@forwardimpact/pathway 0.24.0 → 0.25.1

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.
@@ -1,8 +1,8 @@
1
1
  /**
2
2
  * Agent Profile Formatter
3
3
  *
4
- * Formats agent profile data into .agent.md file content
5
- * following the GitHub Copilot Custom Agents specification.
4
+ * Formats agent profile data into .md file content
5
+ * following the Claude Code agent specification.
6
6
  *
7
7
  * Uses Mustache templates for flexible output formatting.
8
8
  * Templates are loaded from data/ directory with fallback to templates/ directory.
@@ -11,10 +11,7 @@
11
11
  import Mustache from "mustache";
12
12
 
13
13
  import { trimValue, trimRequired, trimFields } from "../shared.js";
14
- import {
15
- flattenToLine,
16
- preprocessArrayFrontmatter,
17
- } from "../template-preprocess.js";
14
+ import { flattenToLine } from "../template-preprocess.js";
18
15
 
19
16
  /**
20
17
  * @typedef {Object} WorkingStyleEntry
@@ -29,8 +26,8 @@ import {
29
26
  * @param {Object} params.frontmatter - YAML frontmatter data
30
27
  * @param {string} params.frontmatter.name - Agent name
31
28
  * @param {string} params.frontmatter.description - Agent description
32
- * @param {boolean} params.frontmatter.infer - Whether to auto-select
33
- * @param {Array} [params.frontmatter.handoffs] - Handoff definitions
29
+ * @param {string} params.frontmatter.model - Claude Code model (sonnet, opus, haiku)
30
+ * @param {string[]} params.frontmatter.skills - Skill dirnames for auto-loading
34
31
  * @param {Object} params.bodyData - Structured body data
35
32
  * @param {string} params.bodyData.title - Agent title
36
33
  * @param {string} params.bodyData.stageDescription - Stage description text
@@ -43,41 +40,51 @@ import {
43
40
  * @param {string} params.bodyData.roleContext - Role context text
44
41
  * @param {WorkingStyleEntry[]} params.bodyData.workingStyles - Working style entries
45
42
  * @param {string[]} params.bodyData.constraints - List of constraints
46
- * @param {Array<{id: string, name: string, description: string}>} [params.bodyData.agentIndex] - List of all available agents
47
- * @param {boolean} [params.bodyData.hasAgentIndex] - Whether agent index is available
43
+ * @param {Array<{targetStageName: string, summaryInstruction: string, entryCriteria: string[]}>} params.bodyData.stageTransitions - Stage transition definitions
48
44
  * @returns {Object} Data object ready for Mustache template
49
45
  */
50
46
  function prepareAgentProfileData({ frontmatter, bodyData }) {
51
- // Preprocess handoffs - flatten prompt field for front matter compatibility
52
- const preprocessedHandoffs = preprocessArrayFrontmatter(
53
- frontmatter.handoffs,
54
- ["prompt"],
47
+ const stageConstraints = (bodyData.stageConstraints || []).map((c) =>
48
+ trimRequired(c),
49
+ );
50
+ const disciplineConstraints = (bodyData.disciplineConstraints || []).map(
51
+ (c) => trimRequired(c),
52
+ );
53
+ const trackConstraints = (bodyData.trackConstraints || []).map((c) =>
54
+ trimRequired(c),
55
+ );
56
+ const returnFormat = (bodyData.returnFormat || []).map((r) =>
57
+ trimRequired(r),
55
58
  );
56
- // Then trim as before
57
- const handoffs = trimFields(preprocessedHandoffs, { prompt: "required" });
58
-
59
- const constraints = (bodyData.constraints || []).map((c) => trimRequired(c));
60
59
  const skillIndex = trimFields(bodyData.skillIndex, {
61
60
  name: "required",
62
61
  dirname: "required",
63
62
  useWhen: "required",
64
63
  });
65
- const agentIndex = trimFields(bodyData.agentIndex, {
66
- id: "required",
67
- name: "required",
68
- description: "required",
69
- });
70
64
  const workingStyles = trimFields(bodyData.workingStyles, {
71
65
  title: "required",
72
66
  content: "required",
73
67
  });
74
68
 
69
+ // Prepare stage transitions for body rendering
70
+ const stageTransitions = (bodyData.stageTransitions || []).map((t) => ({
71
+ targetStageName: t.targetStageName,
72
+ summaryInstruction: trimValue(t.summaryInstruction),
73
+ entryCriteria: (t.entryCriteria || []).map((c) => trimRequired(c)),
74
+ hasEntryCriteria: (t.entryCriteria || []).length > 0,
75
+ }));
76
+
77
+ const hasConstraints =
78
+ stageConstraints.length > 0 ||
79
+ disciplineConstraints.length > 0 ||
80
+ trackConstraints.length > 0;
81
+
75
82
  return {
76
- // Frontmatter - flatten description for single-line front matter
83
+ // Frontmatter
77
84
  name: frontmatter.name,
78
85
  description: flattenToLine(frontmatter.description),
79
- infer: frontmatter.infer,
80
- handoffs,
86
+ model: frontmatter.model,
87
+ skills: frontmatter.skills,
81
88
 
82
89
  // Body data - trim all string fields
83
90
  title: bodyData.title,
@@ -92,22 +99,28 @@ function prepareAgentProfileData({ frontmatter, bodyData }) {
92
99
  roleContext: trimValue(bodyData.roleContext),
93
100
  workingStyles,
94
101
  hasWorkingStyles: workingStyles.length > 0,
95
- constraints,
96
- hasConstraints: constraints.length > 0,
97
- agentIndex,
98
- hasAgentIndex: agentIndex.length > 0,
102
+ stageConstraints,
103
+ disciplineConstraints,
104
+ trackConstraints,
105
+ hasStageConstraints: stageConstraints.length > 0,
106
+ hasDisciplineOrTrackConstraints:
107
+ disciplineConstraints.length > 0 || trackConstraints.length > 0,
108
+ hasConstraints,
109
+ returnFormat,
110
+ hasReturnFormat: returnFormat.length > 0,
111
+ stageTransitions,
112
+ hasStageTransitions: stageTransitions.length > 0,
99
113
  };
100
114
  }
101
115
 
102
116
  /**
103
- * Format agent profile as .agent.md file content using Mustache template
117
+ * Format agent profile as .md file content using Mustache template
104
118
  * @param {Object} profile - Profile with frontmatter and bodyData
105
119
  * @param {Object} profile.frontmatter - YAML frontmatter data
106
120
  * @param {string} profile.frontmatter.name - Agent name
107
121
  * @param {string} profile.frontmatter.description - Agent description
108
- * @param {string[]} profile.frontmatter.tools - Available tools
109
- * @param {boolean} profile.frontmatter.infer - Whether to auto-select
110
- * @param {Array} [profile.frontmatter.handoffs] - Handoff definitions
122
+ * @param {string} profile.frontmatter.model - Claude Code model
123
+ * @param {string[]} profile.frontmatter.skills - Skill dirnames
111
124
  * @param {Object} profile.bodyData - Structured body data
112
125
  * @param {string} profile.bodyData.title - Agent title (e.g. "Software Engineering - Platform - Plan Agent")
113
126
  * @param {string} profile.bodyData.stageDescription - Stage description text
@@ -117,8 +130,9 @@ function prepareAgentProfileData({ frontmatter, bodyData }) {
117
130
  * @param {string} profile.bodyData.roleContext - Role context text
118
131
  * @param {WorkingStyleEntry[]} profile.bodyData.workingStyles - Working style entries
119
132
  * @param {string[]} profile.bodyData.constraints - List of constraints
133
+ * @param {Array} profile.bodyData.stageTransitions - Stage transitions for body section
120
134
  * @param {string} template - Mustache template string
121
- * @returns {string} Complete .agent.md file content
135
+ * @returns {string} Complete .md file content
122
136
  */
123
137
  export function formatAgentProfile({ frontmatter, bodyData }, template) {
124
138
  const data = prepareAgentProfileData({ frontmatter, bodyData });
@@ -2,7 +2,7 @@
2
2
  * Job formatting for DOM/web output
3
3
  */
4
4
 
5
- import { div, h1, h2, p, a, span, section } from "../../lib/render.js";
5
+ import { div, h1, h2, a, section } from "../../lib/render.js";
6
6
  import { createBackLink } from "../../components/nav.js";
7
7
  import {
8
8
  createDetailSection,
@@ -117,7 +117,9 @@ export function jobToDOM(view, options = {}) {
117
117
 
118
118
  createDetailSection({
119
119
  title: "Skill Matrix",
120
- content: createSkillMatrix(view.skillMatrix),
120
+ content: createSkillMatrix(view.skillMatrix, {
121
+ capabilityOrder: view.capabilityOrder,
122
+ }),
121
123
  }),
122
124
 
123
125
  // Toolkit (after skill matrix)
@@ -127,21 +129,6 @@ export function jobToDOM(view, options = {}) {
127
129
  content: createToolkitTable(view.toolkit),
128
130
  })
129
131
  : null,
130
-
131
- // Driver coverage
132
- view.driverCoverage.length > 0
133
- ? createDetailSection({
134
- title: "Driver Coverage",
135
- content: div(
136
- {},
137
- p(
138
- { className: "text-muted", style: "margin-bottom: 1rem" },
139
- "How well this job aligns with organizational outcome drivers.",
140
- ),
141
- createDriverCoverageDisplay(view.driverCoverage),
142
- ),
143
- })
144
- : null,
145
132
  )
146
133
  : null,
147
134
 
@@ -164,48 +151,6 @@ export function jobToDOM(view, options = {}) {
164
151
  );
165
152
  }
166
153
 
167
- /**
168
- * Create driver coverage display
169
- */
170
- function createDriverCoverageDisplay(coverage) {
171
- const items = coverage.map((c) => {
172
- const percentage = Math.round(c.coverage * 100);
173
-
174
- return div(
175
- { className: "driver-coverage-item" },
176
- div(
177
- { className: "driver-coverage-header" },
178
- a(
179
- {
180
- href: `#/driver/${c.id}`,
181
- className: "driver-coverage-name",
182
- },
183
- c.name,
184
- ),
185
- span({ className: "driver-coverage-score" }, `${percentage}%`),
186
- ),
187
- div(
188
- { className: "progress-bar" },
189
- div({
190
- className: "progress-bar-fill",
191
- style: `width: ${percentage}%; background: ${getScoreColor(c.coverage)}`,
192
- }),
193
- ),
194
- );
195
- });
196
-
197
- return div({ className: "driver-coverage" }, ...items);
198
- }
199
-
200
- /**
201
- * Get color based on score
202
- */
203
- function getScoreColor(score) {
204
- if (score >= 0.8) return "#10b981"; // Green
205
- if (score >= 0.5) return "#f59e0b"; // Yellow
206
- return "#ef4444"; // Red
207
- }
208
-
209
154
  /**
210
155
  * Create the job description section with copy button
211
156
  * @param {Object} params
@@ -243,6 +188,7 @@ export function createJobDescriptionSection({
243
188
  "Copy this markdown-formatted job description for use in job postings, documentation, or sharing.",
244
189
  toHtml: markdownToHtml,
245
190
  minHeight: 450,
191
+ open: true,
246
192
  }),
247
193
  );
248
194
  }
package/src/handout.html CHANGED
@@ -8,7 +8,7 @@
8
8
  <script type="importmap">
9
9
  {
10
10
  "imports": {
11
- "mustache": "https://esm.sh/mustache@4.2.0",
11
+ "mustache": "/vendor/mustache.mjs",
12
12
  "@forwardimpact/map": "/map/lib/index.js",
13
13
  "@forwardimpact/map/levels": "/map/lib/levels.js",
14
14
  "@forwardimpact/map/loader": "/map/lib/loader.js",
package/src/index.html CHANGED
@@ -15,12 +15,18 @@
15
15
  href="https://cdn.jsdelivr.net/npm/prismjs@1.29.0/themes/prism.min.css"
16
16
  />
17
17
  <link rel="stylesheet" href="css/bundles/app.css" />
18
- <script src="https://cdn.jsdelivr.net/npm/prismjs@1.29.0/prism.min.js"></script>
19
- <script src="https://cdn.jsdelivr.net/npm/prismjs@1.29.0/components/prism-markdown.min.js"></script>
18
+ <script
19
+ src="https://cdn.jsdelivr.net/npm/prismjs@1.29.0/prism.min.js"
20
+ defer
21
+ ></script>
22
+ <script
23
+ src="https://cdn.jsdelivr.net/npm/prismjs@1.29.0/components/prism-markdown.min.js"
24
+ defer
25
+ ></script>
20
26
  <script type="importmap">
21
27
  {
22
28
  "imports": {
23
- "mustache": "https://esm.sh/mustache@4.2.0",
29
+ "mustache": "/vendor/mustache.mjs",
24
30
  "@forwardimpact/map": "/map/lib/index.js",
25
31
  "@forwardimpact/map/levels": "/map/lib/levels.js",
26
32
  "@forwardimpact/map/loader": "/map/lib/loader.js",
package/src/lib/radar.js CHANGED
@@ -2,6 +2,20 @@
2
2
  * Radar chart visualization using SVG
3
3
  */
4
4
 
5
+ /**
6
+ * Escape HTML special characters to prevent XSS
7
+ * @param {string} text
8
+ * @returns {string}
9
+ */
10
+ function escapeHtml(text) {
11
+ return text
12
+ .replace(/&/g, "&amp;")
13
+ .replace(/</g, "&lt;")
14
+ .replace(/>/g, "&gt;")
15
+ .replace(/"/g, "&quot;")
16
+ .replace(/'/g, "&#039;");
17
+ }
18
+
5
19
  /**
6
20
  * @typedef {Object} RadarDataPoint
7
21
  * @property {string} label - Label for this axis
@@ -393,9 +407,9 @@ export class RadarChart {
393
407
  const y = event.clientY - rect.top;
394
408
 
395
409
  this.tooltip.innerHTML = `
396
- <strong>${data.label}</strong><br>
410
+ <strong>${escapeHtml(data.label)}</strong><br>
397
411
  Value: ${data.value}/${data.maxValue}
398
- ${data.description ? `<br><small>${data.description}</small>` : ""}
412
+ ${data.description ? `<br><small>${escapeHtml(data.description)}</small>` : ""}
399
413
  `;
400
414
 
401
415
  this.tooltip.style.left = `${x + 10}px`;
@@ -815,9 +829,9 @@ export class ComparisonRadarChart {
815
829
  const typeLabel = type === "current" ? "Current" : "Target";
816
830
 
817
831
  this.tooltip.innerHTML = `
818
- <strong>${data.label}</strong><br>
832
+ <strong>${escapeHtml(data.label)}</strong><br>
819
833
  ${typeLabel}: ${data.value}/${data.maxValue}
820
- ${data.description ? `<br><small>${data.description}</small>` : ""}
834
+ ${data.description ? `<br><small>${escapeHtml(data.description)}</small>` : ""}
821
835
  `;
822
836
 
823
837
  this.tooltip.style.left = `${x + 10}px`;
@@ -844,7 +858,7 @@ export class ComparisonRadarChart {
844
858
  : "<span style='color: #94a3b8'>No change</span>";
845
859
 
846
860
  this.tooltip.innerHTML = `
847
- <strong>${currentData.label}</strong><br>
861
+ <strong>${escapeHtml(currentData.label)}</strong><br>
848
862
  Current: ${currentData.value}/${currentData.maxValue}<br>
849
863
  Target: ${targetData.value}/${targetData.maxValue}<br>
850
864
  ${diffText}
@@ -287,27 +287,15 @@ export async function loadAllData(dataDir = "./data") {
287
287
  * @returns {Promise<Object>}
288
288
  */
289
289
  export async function loadAgentDataBrowser(dataDir = "./data") {
290
- const [
291
- disciplines,
292
- tracks,
293
- behaviours,
294
- vscodeSettings,
295
- devcontainer,
296
- copilotSetupSteps,
297
- ] = await Promise.all([
298
- loadDisciplinesFromDir(`${dataDir}/disciplines`),
299
- loadTracksFromDir(`${dataDir}/tracks`),
300
- loadBehavioursFromDir(`${dataDir}/behaviours`),
301
- tryLoadYamlFile(`${dataDir}/repository/vscode-settings.yaml`).then(
302
- (r) => r ?? tryLoadYamlFile(`${dataDir}/vscode-settings.yaml`),
303
- ),
304
- tryLoadYamlFile(`${dataDir}/repository/devcontainer.yaml`).then(
305
- (r) => r ?? tryLoadYamlFile(`${dataDir}/devcontainer.yaml`),
306
- ),
307
- tryLoadYamlFile(`${dataDir}/repository/copilot-setup-steps.yaml`).then(
308
- (r) => r ?? tryLoadYamlFile(`${dataDir}/copilot-setup-steps.yaml`),
309
- ),
310
- ]);
290
+ const [disciplines, tracks, behaviours, claudeCodeSettings] =
291
+ await Promise.all([
292
+ loadDisciplinesFromDir(`${dataDir}/disciplines`),
293
+ loadTracksFromDir(`${dataDir}/tracks`),
294
+ loadBehavioursFromDir(`${dataDir}/behaviours`),
295
+ tryLoadYamlFile(`${dataDir}/repository/claude-code-settings.yaml`).then(
296
+ (r) => r ?? tryLoadYamlFile(`${dataDir}/claude-code-settings.yaml`),
297
+ ),
298
+ ]);
311
299
 
312
300
  return {
313
301
  disciplines: disciplines
@@ -319,8 +307,6 @@ export async function loadAgentDataBrowser(dataDir = "./data") {
319
307
  behaviours: behaviours
320
308
  .filter((b) => b.agent)
321
309
  .map((b) => ({ id: b.id, ...b.agent })),
322
- vscodeSettings: vscodeSettings || {},
323
- devcontainer: devcontainer || {},
324
- copilotSetupSteps: copilotSetupSteps || null,
310
+ claudeCodeSettings: claudeCodeSettings || {},
325
311
  };
326
312
  }
@@ -28,7 +28,6 @@ import {
28
28
  deriveAgentSkills,
29
29
  deriveReferenceLevel,
30
30
  deriveToolkit,
31
- buildAgentIndex,
32
31
  } from "@forwardimpact/libskill";
33
32
  import {
34
33
  createSelectWithValue,
@@ -259,15 +258,6 @@ export async function renderAgentBuilder() {
259
258
  // Get reference level for derivation
260
259
  const level = deriveReferenceLevel(data.levels);
261
260
 
262
- // Build agent index for all valid combinations
263
- const agentIndex = buildAgentIndex({
264
- disciplines: data.disciplines,
265
- tracks: data.tracks,
266
- stages,
267
- agentDisciplines: agentData.disciplines,
268
- agentTracks: agentData.tracks,
269
- });
270
-
271
261
  // Build context for generation
272
262
  const context = {
273
263
  humanDiscipline,
@@ -279,10 +269,8 @@ export async function renderAgentBuilder() {
279
269
  skills: data.skills,
280
270
  behaviours: data.behaviours,
281
271
  agentBehaviours: agentData.behaviours,
282
- vscodeSettings: agentData.vscodeSettings,
283
- devcontainer: agentData.devcontainer,
272
+ claudeCodeSettings: agentData.claudeCodeSettings,
284
273
  templates,
285
- agentIndex,
286
274
  };
287
275
 
288
276
  // Generate preview based on stage selection
@@ -316,7 +304,7 @@ export async function renderAgentBuilder() {
316
304
  p(
317
305
  { className: "page-description" },
318
306
  "Generate coding agent teams from discipline × track × stage combinations. " +
319
- "Export complete agent profiles and skill files for GitHub Copilot.",
307
+ "Export complete agent profiles and skill files for Claude Code.",
320
308
  ),
321
309
  ),
322
310
 
@@ -456,10 +444,8 @@ function createAllStagesPreview(context) {
456
444
  skills,
457
445
  behaviours,
458
446
  agentBehaviours,
459
- vscodeSettings,
460
- devcontainer,
447
+ claudeCodeSettings,
461
448
  templates,
462
- agentIndex,
463
449
  } = context;
464
450
 
465
451
  // Generate all stage agents
@@ -474,7 +460,6 @@ function createAllStagesPreview(context) {
474
460
  agentBehaviours,
475
461
  agentDiscipline,
476
462
  agentTrack,
477
- stages,
478
463
  });
479
464
 
480
465
  const profile = generateStageAgentProfile({
@@ -488,7 +473,6 @@ function createAllStagesPreview(context) {
488
473
  agentDiscipline,
489
474
  agentTrack,
490
475
  stages,
491
- agentIndex,
492
476
  });
493
477
 
494
478
  return { stage, derived, profile };
@@ -521,8 +505,7 @@ function createAllStagesPreview(context) {
521
505
  createDownloadAllButton(
522
506
  stageAgents,
523
507
  skillFiles,
524
- vscodeSettings,
525
- devcontainer,
508
+ claudeCodeSettings,
526
509
  context,
527
510
  ),
528
511
 
@@ -532,7 +515,7 @@ function createAllStagesPreview(context) {
532
515
  h2({}, `Agents (${stageAgents.length})`),
533
516
  p(
534
517
  { className: "text-muted" },
535
- "Stage-specific agents with appropriate tools, constraints, and handoffs.",
518
+ "Stage-specific agents with skills, constraints, and stage transitions.",
536
519
  ),
537
520
  div(
538
521
  { className: "agent-cards-grid" },
@@ -598,11 +581,9 @@ function createSingleStagePreview(context, stage) {
598
581
  skills,
599
582
  behaviours,
600
583
  agentBehaviours,
601
- vscodeSettings,
602
- devcontainer,
584
+ claudeCodeSettings,
603
585
  stages,
604
586
  templates,
605
- agentIndex,
606
587
  } = context;
607
588
 
608
589
  const profile = generateStageAgentProfile({
@@ -616,7 +597,6 @@ function createSingleStagePreview(context, stage) {
616
597
  agentDiscipline,
617
598
  agentTrack,
618
599
  stages,
619
- agentIndex,
620
600
  });
621
601
 
622
602
  // Get skills for this stage (using full derived skills)
@@ -645,8 +625,7 @@ function createSingleStagePreview(context, stage) {
645
625
  createDownloadSingleButton(
646
626
  profile,
647
627
  skillFiles,
648
- vscodeSettings,
649
- devcontainer,
628
+ claudeCodeSettings,
650
629
  templates,
651
630
  ),
652
631
 
@@ -756,16 +735,14 @@ function buildSkillFileCard(skill, templates) {
756
735
  * Create download all button for all stages
757
736
  * @param {Array} stageAgents - Array of {stage, derived, profile}
758
737
  * @param {Array} skillFiles - Array of skill file objects
759
- * @param {Object} vscodeSettings - VS Code settings
760
- * @param {Object} devcontainer - Devcontainer config
738
+ * @param {Object} claudeCodeSettings - Claude Code settings
761
739
  * @param {Object} context - Context with discipline/track info and templates
762
740
  * @returns {HTMLElement}
763
741
  */
764
742
  function createDownloadAllButton(
765
743
  stageAgents,
766
744
  skillFiles,
767
- vscodeSettings,
768
- devcontainer,
745
+ claudeCodeSettings,
769
746
  context,
770
747
  ) {
771
748
  const { humanDiscipline, humanTrack, templates } = context;
@@ -783,10 +760,10 @@ function createDownloadAllButton(
783
760
  const JSZip = await importJSZip();
784
761
  const zip = new JSZip();
785
762
 
786
- // Add all stage agent profiles
763
+ // Add all stage agent profiles to .claude/agents/
787
764
  for (const { profile } of stageAgents) {
788
765
  const content = formatAgentProfile(profile, templates.agent);
789
- zip.file(`.github/agents/${profile.filename}`, content);
766
+ zip.file(`.claude/agents/${profile.filename}`, content);
790
767
  }
791
768
 
792
769
  // Add skills (SKILL.md + optional install script + optional reference)
@@ -812,27 +789,11 @@ function createDownloadAllButton(
812
789
  }
813
790
  }
814
791
 
815
- // Add VS Code settings
816
- if (Object.keys(vscodeSettings).length > 0) {
817
- zip.file(
818
- ".vscode/settings.json",
819
- JSON.stringify(vscodeSettings, null, 2) + "\n",
820
- );
821
- }
822
-
823
- // Add devcontainer.json with VS Code settings embedded
824
- if (devcontainer && Object.keys(devcontainer).length > 0) {
825
- const devcontainerJson = {
826
- ...devcontainer,
827
- customizations: {
828
- vscode: {
829
- settings: vscodeSettings,
830
- },
831
- },
832
- };
792
+ // Add Claude Code settings
793
+ if (Object.keys(claudeCodeSettings).length > 0) {
833
794
  zip.file(
834
- ".devcontainer/devcontainer.json",
835
- JSON.stringify(devcontainerJson, null, 2) + "\n",
795
+ ".claude/settings.json",
796
+ JSON.stringify(claudeCodeSettings, null, 2) + "\n",
836
797
  );
837
798
  }
838
799
 
@@ -861,16 +822,14 @@ function createDownloadAllButton(
861
822
  * Create download button for single stage
862
823
  * @param {Object} profile - Agent profile
863
824
  * @param {Array} skillFiles - Skill files
864
- * @param {Object} vscodeSettings - VS Code settings
865
- * @param {Object} devcontainer - Devcontainer config
825
+ * @param {Object} claudeCodeSettings - Claude Code settings
866
826
  * @param {{agent: string, skill: string}} templates - Mustache templates
867
827
  * @returns {HTMLElement}
868
828
  */
869
829
  function createDownloadSingleButton(
870
830
  profile,
871
831
  skillFiles,
872
- vscodeSettings,
873
- devcontainer,
832
+ claudeCodeSettings,
874
833
  templates,
875
834
  ) {
876
835
  const btn = document.createElement("button");
@@ -885,9 +844,9 @@ function createDownloadSingleButton(
885
844
  const JSZip = await importJSZip();
886
845
  const zip = new JSZip();
887
846
 
888
- // Add profile
847
+ // Add profile to .claude/agents/
889
848
  const content = formatAgentProfile(profile, templates.agent);
890
- zip.file(`.github/agents/${profile.filename}`, content);
849
+ zip.file(`.claude/agents/${profile.filename}`, content);
891
850
 
892
851
  // Add skills (SKILL.md + optional install script + optional reference)
893
852
  for (const skill of skillFiles) {
@@ -912,27 +871,11 @@ function createDownloadSingleButton(
912
871
  }
913
872
  }
914
873
 
915
- // Add VS Code settings
916
- if (Object.keys(vscodeSettings).length > 0) {
917
- zip.file(
918
- ".vscode/settings.json",
919
- JSON.stringify(vscodeSettings, null, 2) + "\n",
920
- );
921
- }
922
-
923
- // Add devcontainer.json with VS Code settings embedded
924
- if (devcontainer && Object.keys(devcontainer).length > 0) {
925
- const devcontainerJson = {
926
- ...devcontainer,
927
- customizations: {
928
- vscode: {
929
- settings: vscodeSettings,
930
- },
931
- },
932
- };
874
+ // Add Claude Code settings
875
+ if (Object.keys(claudeCodeSettings).length > 0) {
933
876
  zip.file(
934
- ".devcontainer/devcontainer.json",
935
- JSON.stringify(devcontainerJson, null, 2) + "\n",
877
+ ".claude/settings.json",
878
+ JSON.stringify(claudeCodeSettings, null, 2) + "\n",
936
879
  );
937
880
  }
938
881
 
@@ -982,7 +925,7 @@ function createHelpSection() {
982
925
  p(
983
926
  {},
984
927
  "Agents are generated for each stage: Plan (research), Code (implement), and Review (verify). " +
985
- "Each stage has specific tools, constraints, and handoffs.",
928
+ "Each stage has specific skills, constraints, and stage transitions.",
986
929
  ),
987
930
  ),
988
931
  div(
@@ -990,8 +933,8 @@ function createHelpSection() {
990
933
  div({ className: "detail-item-label" }, "Agent Profiles"),
991
934
  p(
992
935
  {},
993
- "The .agent.md files contain the agent's identity, capabilities, and constraints. " +
994
- "Place them in .github/agents/ to register with GitHub Copilot.",
936
+ "The .md files contain the agent's identity, skills, and constraints. " +
937
+ "Place them in .claude/agents/ for Claude Code to discover.",
995
938
  ),
996
939
  ),
997
940
  div(
@@ -299,7 +299,7 @@ export function renderLanding() {
299
299
  p(
300
300
  {},
301
301
  "Generate coding agent team configurations from discipline × track combinations " +
302
- "for GitHub Copilot custom agents.",
302
+ "for Claude Code agents.",
303
303
  ),
304
304
  div(
305
305
  { className: "page-actions", style: "justify-content: center" },