@forwardimpact/pathway 0.3.0 → 0.5.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.
Files changed (90) hide show
  1. package/app/commands/agent.js +1 -1
  2. package/app/commands/behaviour.js +1 -1
  3. package/app/commands/command-factory.js +2 -2
  4. package/app/commands/discipline.js +1 -1
  5. package/app/commands/driver.js +1 -1
  6. package/app/commands/grade.js +1 -1
  7. package/app/commands/index.js +4 -3
  8. package/app/commands/serve.js +2 -2
  9. package/app/commands/site.js +22 -2
  10. package/app/commands/skill.js +57 -3
  11. package/app/commands/stage.js +1 -1
  12. package/app/commands/tool.js +112 -0
  13. package/app/commands/track.js +1 -1
  14. package/app/components/card.js +11 -1
  15. package/app/components/checklist.js +6 -4
  16. package/app/components/code-display.js +153 -0
  17. package/app/components/markdown-textarea.js +153 -0
  18. package/app/css/bundles/app.css +14 -0
  19. package/app/css/components/badges.css +15 -8
  20. package/app/css/components/forms.css +55 -0
  21. package/app/css/components/layout.css +12 -0
  22. package/app/css/components/surfaces.css +71 -3
  23. package/app/css/components/typography.css +1 -2
  24. package/app/css/pages/agent-builder.css +11 -102
  25. package/app/css/pages/detail.css +60 -0
  26. package/app/css/pages/job-builder.css +0 -42
  27. package/app/css/tokens.css +3 -0
  28. package/app/formatters/agent/dom.js +26 -71
  29. package/app/formatters/agent/profile.js +67 -10
  30. package/app/formatters/agent/skill.js +48 -6
  31. package/app/formatters/grade/dom.js +6 -6
  32. package/app/formatters/job/description.js +21 -16
  33. package/app/formatters/job/dom.js +9 -70
  34. package/app/formatters/json-ld.js +1 -1
  35. package/app/formatters/shared.js +58 -0
  36. package/app/formatters/skill/dom.js +70 -3
  37. package/app/formatters/skill/markdown.js +18 -0
  38. package/app/formatters/skill/shared.js +14 -4
  39. package/app/formatters/stage/microdata.js +2 -2
  40. package/app/formatters/stage/shared.js +3 -3
  41. package/app/formatters/tool/shared.js +78 -0
  42. package/app/handout-main.js +19 -18
  43. package/app/index.html +16 -3
  44. package/app/lib/card-mappers.js +91 -17
  45. package/app/lib/render.js +4 -0
  46. package/app/lib/yaml-loader.js +12 -1
  47. package/app/main.js +4 -0
  48. package/app/model/agent.js +47 -23
  49. package/app/model/checklist.js +2 -2
  50. package/app/model/derivation.js +5 -5
  51. package/app/model/levels.js +4 -2
  52. package/app/model/loader.js +12 -1
  53. package/app/model/validation.js +77 -11
  54. package/app/pages/agent-builder.js +121 -77
  55. package/app/pages/landing.js +35 -15
  56. package/app/pages/self-assessment.js +7 -5
  57. package/app/pages/skill.js +5 -17
  58. package/app/pages/stage.js +12 -8
  59. package/app/pages/tool.js +50 -0
  60. package/app/slide-main.js +1 -1
  61. package/app/slides/chapter.js +8 -8
  62. package/app/slides/index.js +26 -26
  63. package/app/slides/overview.js +8 -8
  64. package/app/slides/skill.js +1 -0
  65. package/bin/pathway.js +31 -16
  66. package/examples/capabilities/business.yaml +18 -18
  67. package/examples/capabilities/delivery.yaml +54 -37
  68. package/examples/capabilities/people.yaml +1 -1
  69. package/examples/capabilities/reliability.yaml +130 -115
  70. package/examples/capabilities/scale.yaml +39 -37
  71. package/examples/disciplines/engineering_management.yaml +1 -1
  72. package/examples/framework.yaml +21 -9
  73. package/examples/grades.yaml +5 -7
  74. package/examples/self-assessments.yaml +1 -1
  75. package/examples/stages.yaml +18 -10
  76. package/package.json +2 -1
  77. package/templates/agent.template.md +47 -17
  78. package/templates/job.template.md +8 -8
  79. package/templates/skill.template.md +33 -11
  80. package/examples/agents/.claude/skills/architecture-design/SKILL.md +0 -130
  81. package/examples/agents/.claude/skills/cloud-platforms/SKILL.md +0 -131
  82. package/examples/agents/.claude/skills/code-quality-review/SKILL.md +0 -108
  83. package/examples/agents/.claude/skills/devops-cicd/SKILL.md +0 -142
  84. package/examples/agents/.claude/skills/full-stack-development/SKILL.md +0 -134
  85. package/examples/agents/.claude/skills/sre-practices/SKILL.md +0 -163
  86. package/examples/agents/.claude/skills/technical-debt-management/SKILL.md +0 -164
  87. package/examples/agents/.github/agents/se-platform-code.agent.md +0 -132
  88. package/examples/agents/.github/agents/se-platform-plan.agent.md +0 -131
  89. package/examples/agents/.github/agents/se-platform-review.agent.md +0 -136
  90. package/examples/agents/.vscode/settings.json +0 -8
@@ -7,6 +7,7 @@ import { getState } from "../lib/state.js";
7
7
  import { createStatCard } from "../components/card.js";
8
8
  import { groupSkillsByCapability, getConceptEmoji } from "../model/levels.js";
9
9
  import { getStageEmoji } from "../formatters/stage/shared.js";
10
+ import { aggregateTools } from "../formatters/tool/shared.js";
10
11
 
11
12
  /**
12
13
  * Create lifecycle flow visualization for landing page
@@ -43,6 +44,7 @@ export function renderLanding() {
43
44
  // Calculate stats using centralized capability ordering
44
45
  const skillsByCapability = groupSkillsByCapability(data.skills);
45
46
  const capabilityCount = Object.keys(skillsByCapability).length;
47
+ const tools = aggregateTools(data.skills);
46
48
 
47
49
  const page = div(
48
50
  { className: "landing-page" },
@@ -51,7 +53,7 @@ export function renderLanding() {
51
53
  { className: "landing-hero" },
52
54
  div(
53
55
  { className: "hero-title-wrapper" },
54
- h1({}, `${framework.emoji} ${framework.title}`),
56
+ h1({}, `${framework.emojiIcon} ${framework.title}`),
55
57
  span({ className: "brand-tag brand-tag-hero" }, framework.tag),
56
58
  ),
57
59
  p({}, framework.description.trim()),
@@ -83,7 +85,7 @@ export function renderLanding() {
83
85
 
84
86
  // Stats grid
85
87
  div(
86
- { className: "grid grid-6" },
88
+ { className: "grid grid-4" },
87
89
  createStatCard({
88
90
  value: data.disciplines.length,
89
91
  label: "Disciplines",
@@ -99,28 +101,41 @@ export function renderLanding() {
99
101
  label: "Tracks",
100
102
  href: "/track",
101
103
  }),
104
+ createStatCard({
105
+ value: data.behaviours.length,
106
+ label: "Behaviours",
107
+ href: "/behaviour",
108
+ }),
102
109
  createStatCard({
103
110
  value: data.skills.length,
104
111
  label: "Skills",
105
112
  href: "/skill",
106
113
  }),
107
114
  createStatCard({
108
- value: data.behaviours.length,
109
- label: "Behaviours",
110
- href: "/behaviour",
115
+ value: data.drivers.length,
116
+ label: "Drivers",
117
+ href: "/driver",
111
118
  }),
112
119
  createStatCard({
113
120
  value: stages.length,
114
121
  label: "Stages",
115
122
  href: "/stage",
116
123
  }),
124
+ createStatCard({
125
+ value: tools.length,
126
+ label: "Tools",
127
+ href: "/tool",
128
+ }),
117
129
  ),
118
130
 
119
131
  // Lifecycle flow visualization
120
132
  stages.length > 0
121
133
  ? div(
122
134
  { className: "section section-detail" },
123
- h2({ className: "section-title" }, "🔄 Engineering Lifecycle"),
135
+ h2(
136
+ { className: "section-title" },
137
+ `${getConceptEmoji(framework, "stage")} Engineering Lifecycle`,
138
+ ),
124
139
  p(
125
140
  { className: "text-muted", style: "margin-bottom: 1rem" },
126
141
  "The three stages of engineering work, from planning through review.",
@@ -134,7 +149,7 @@ export function renderLanding() {
134
149
  { className: "section section-detail" },
135
150
  h2({ className: "section-title" }, "Explore the Framework"),
136
151
  div(
137
- { className: "grid grid-3" },
152
+ { className: "grid grid-4" },
138
153
  createQuickLinkCard(
139
154
  `${getConceptEmoji(framework, "discipline")} ${framework.entityDefinitions.discipline.title}`,
140
155
  `${data.disciplines.length} ${framework.entityDefinitions.discipline.title.toLowerCase()} — ${framework.entityDefinitions.discipline.description.trim().split("\n")[0]}`,
@@ -150,26 +165,31 @@ export function renderLanding() {
150
165
  `${data.tracks.length} ${framework.entityDefinitions.track.title.toLowerCase()} — ${framework.entityDefinitions.track.description.trim().split("\n")[0]}`,
151
166
  "/track",
152
167
  ),
153
- createQuickLinkCard(
154
- `${getConceptEmoji(framework, "skill")} ${framework.entityDefinitions.skill.title}`,
155
- `${data.skills.length} ${framework.entityDefinitions.skill.title.toLowerCase()} across ${capabilityCount} capabilities — ${framework.entityDefinitions.skill.description.trim().split("\n")[0]}`,
156
- "/skill",
157
- ),
158
168
  createQuickLinkCard(
159
169
  `${getConceptEmoji(framework, "behaviour")} ${framework.entityDefinitions.behaviour.title}`,
160
170
  `${data.behaviours.length} ${framework.entityDefinitions.behaviour.title.toLowerCase()} — ${framework.entityDefinitions.behaviour.description.trim().split("\n")[0]}`,
161
171
  "/behaviour",
162
172
  ),
163
173
  createQuickLinkCard(
164
- "🔄 Stages",
165
- `${stages.length} stages The engineering lifecycle from planning through review.`,
166
- "/stage",
174
+ `${getConceptEmoji(framework, "skill")} ${framework.entityDefinitions.skill.title}`,
175
+ `${data.skills.length} ${framework.entityDefinitions.skill.title.toLowerCase()} across ${capabilityCount} capabilities ${framework.entityDefinitions.skill.description.trim().split("\n")[0]}`,
176
+ "/skill",
167
177
  ),
168
178
  createQuickLinkCard(
169
179
  `${getConceptEmoji(framework, "driver")} ${framework.entityDefinitions.driver.title}`,
170
180
  `${data.drivers.length} ${framework.entityDefinitions.driver.title.toLowerCase()} — ${framework.entityDefinitions.driver.description.trim().split("\n")[0]}`,
171
181
  "/driver",
172
182
  ),
183
+ createQuickLinkCard(
184
+ `${getConceptEmoji(framework, "stage")} ${framework.entityDefinitions.stage.title}`,
185
+ `${stages.length} ${framework.entityDefinitions.stage.title.toLowerCase()} — ${framework.entityDefinitions.stage.description.trim().split("\n")[0]}`,
186
+ "/stage",
187
+ ),
188
+ createQuickLinkCard(
189
+ `${getConceptEmoji(framework, "tool")} ${framework.entityDefinitions.tool.title}`,
190
+ `${tools.length} ${framework.entityDefinitions.tool.title.toLowerCase()} — ${framework.entityDefinitions.tool.description.trim().split("\n")[0]}`,
191
+ "/tool",
192
+ ),
173
193
  ),
174
194
  ),
175
195
 
@@ -82,7 +82,7 @@ function getWizardSteps(data) {
82
82
  if (skills && skills.length > 0) {
83
83
  steps.push({
84
84
  id: `skills-${capability}`,
85
- name: formatCapability(capability),
85
+ name: formatCapability(capability, data.capabilities),
86
86
  icon: getCapabilityEmoji(data.capabilities, capability),
87
87
  type: "skills",
88
88
  capability: capability,
@@ -113,11 +113,13 @@ function getWizardSteps(data) {
113
113
 
114
114
  /**
115
115
  * Format capability name for display
116
- * @param {string} capability
116
+ * @param {string} capabilityId
117
+ * @param {Array} capabilities
117
118
  * @returns {string}
118
119
  */
119
- function formatCapability(capability) {
120
- return capability.charAt(0).toUpperCase() + capability.slice(1);
120
+ function formatCapability(capabilityId, capabilities) {
121
+ const capability = capabilities.find((c) => c.id === capabilityId);
122
+ return capability?.name || capabilityId;
121
123
  }
122
124
 
123
125
  /**
@@ -412,7 +414,7 @@ function renderSkillsStep(step, data) {
412
414
  h2(
413
415
  {},
414
416
  span({ className: "step-header-icon" }, step.icon),
415
- ` ${formatCapability(capability)} Skills`,
417
+ ` ${formatCapability(capability, data.capabilities)} Skills`,
416
418
  ),
417
419
  span(
418
420
  { className: "step-progress" },
@@ -89,25 +89,13 @@ export function renderSkillDetail(params) {
89
89
 
90
90
  /**
91
91
  * Format capability for display
92
- * @param {string} capability
92
+ * @param {string} capabilityId
93
93
  * @param {Array} capabilities
94
94
  * @returns {string}
95
95
  */
96
- function formatCapability(capability, capabilities) {
97
- const capabilityLabels = {
98
- delivery: "Delivery",
99
- scale: "Scale",
100
- reliability: "Reliability",
101
- data: "Data",
102
- ai: "AI",
103
- process: "Process",
104
- business: "Business",
105
- people: "People",
106
- documentation: "Documentation",
107
- };
108
- const label =
109
- capabilityLabels[capability] ||
110
- capability.replace(/_/g, " ").replace(/\b\w/g, (c) => c.toUpperCase());
111
- const emoji = getCapabilityEmoji(capabilities, capability);
96
+ function formatCapability(capabilityId, capabilities) {
97
+ const capability = capabilities.find((c) => c.id === capabilityId);
98
+ const label = capability?.name || capabilityId;
99
+ const emoji = getCapabilityEmoji(capabilities, capabilityId);
112
100
  return `${emoji} ${label}`;
113
101
  }
@@ -7,15 +7,16 @@ import { getState } from "../lib/state.js";
7
7
  import { createCardList } from "../components/list.js";
8
8
  import { renderNotFound } from "../components/error-page.js";
9
9
  import { prepareStagesList, stageToDOM } from "../formatters/stage/index.js";
10
+ import { getConceptEmoji } from "../model/levels.js";
10
11
 
11
12
  /**
12
13
  * Map stage to card configuration
13
- * @param {Object} stage - Prepared stage item (includes emoji)
14
+ * @param {Object} stage - Prepared stage item (includes emojiIcon)
14
15
  * @returns {Object} Card configuration
15
16
  */
16
17
  function stageToCardConfig(stage) {
17
18
  return {
18
- title: `${stage.emoji || "🔄"} ${stage.name}`,
19
+ title: `${stage.emojiIcon} ${stage.name}`,
19
20
  description: stage.truncatedDescription,
20
21
  href: `/stage/${stage.id}`,
21
22
  };
@@ -23,19 +24,18 @@ function stageToCardConfig(stage) {
23
24
 
24
25
  /**
25
26
  * Create lifecycle flow visualization
26
- * @param {Array} stages - Array of stage items (each includes emoji)
27
+ * @param {Array} stages - Array of stage items (each includes emojiIcon)
27
28
  * @returns {HTMLElement}
28
29
  */
29
30
  function createLifecycleFlow(stages) {
30
31
  const flowItems = stages.map((stage, index) => {
31
- const emoji = stage.emoji || "🔄";
32
32
  const isLast = index === stages.length - 1;
33
33
 
34
34
  return div(
35
35
  { className: "lifecycle-flow-item" },
36
36
  a(
37
37
  { href: `#/stage/${stage.id}`, className: "lifecycle-stage" },
38
- span({ className: "lifecycle-emoji" }, emoji),
38
+ span({ className: "lifecycle-emoji" }, stage.emojiIcon),
39
39
  span({ className: "lifecycle-name" }, stage.name),
40
40
  ),
41
41
  !isLast ? span({ className: "lifecycle-arrow" }, "→") : null,
@@ -50,7 +50,9 @@ function createLifecycleFlow(stages) {
50
50
  */
51
51
  export function renderStagesList() {
52
52
  const { data } = getState();
53
+ const { framework } = data;
53
54
  const stages = data.stages || [];
55
+ const stageEmoji = getConceptEmoji(framework, "stage");
54
56
 
55
57
  // Transform data for list view
56
58
  const { items } = prepareStagesList(stages);
@@ -60,11 +62,13 @@ export function renderStagesList() {
60
62
  // Header
61
63
  div(
62
64
  { className: "page-header" },
63
- h1({ className: "page-title" }, "🔄 Stages"),
65
+ h1(
66
+ { className: "page-title" },
67
+ `${stageEmoji} ${framework.entityDefinitions.stage.title}`,
68
+ ),
64
69
  p(
65
70
  { className: "page-description" },
66
- "The engineering lifecycle stages. Each stage has specific tools, " +
67
- "constraints, and handoffs to guide work from planning through review.",
71
+ framework.entityDefinitions.stage.description.trim().split("\n")[0],
68
72
  ),
69
73
  ),
70
74
 
@@ -0,0 +1,50 @@
1
+ /**
2
+ * Tools page
3
+ *
4
+ * Displays aggregated tools from all skills with links to skill context.
5
+ */
6
+
7
+ import { render, div, h1, p } from "../lib/render.js";
8
+ import { getState } from "../lib/state.js";
9
+ import { prepareToolsList } from "../formatters/tool/shared.js";
10
+ import { createBadge } from "../components/card.js";
11
+ import { createCardList } from "../components/list.js";
12
+ import { toolToCardConfig } from "../lib/card-mappers.js";
13
+ import { getConceptEmoji } from "../model/levels.js";
14
+
15
+ /**
16
+ * Render tools list page
17
+ */
18
+ export function renderToolsList() {
19
+ const { data } = getState();
20
+ const { framework } = data;
21
+ const toolEmoji = getConceptEmoji(framework, "tool");
22
+
23
+ const { tools, totalCount } = prepareToolsList(data.skills);
24
+
25
+ const page = div(
26
+ { className: "tools-page" },
27
+ // Header
28
+ div(
29
+ { className: "page-header" },
30
+ h1(
31
+ { className: "page-title" },
32
+ `${toolEmoji} ${framework.entityDefinitions.tool.title}`,
33
+ ),
34
+ p(
35
+ { className: "page-description" },
36
+ framework.entityDefinitions.tool.description.trim().split("\n")[0],
37
+ ),
38
+ createBadge(`${totalCount} tools`, "default"),
39
+ ),
40
+
41
+ // Tools list using standard card grid
42
+ createCardList(
43
+ tools,
44
+ (tool) => toolToCardConfig(tool, data.capabilities),
45
+ "No tools defined yet.",
46
+ ),
47
+ );
48
+
49
+ render(page);
50
+ }
package/app/slide-main.js CHANGED
@@ -346,7 +346,7 @@ function populateBrandHeader(framework) {
346
346
  header.appendChild(
347
347
  a(
348
348
  { className: "brand-title", href: "#/" },
349
- `${framework.emoji} ${framework.title}`,
349
+ `${framework.emojiIcon} ${framework.title}`,
350
350
  ),
351
351
  );
352
352
  header.appendChild(span({ className: "brand-tag" }, framework.tag));
@@ -20,37 +20,37 @@ export function renderChapterSlide({ render, data, params }) {
20
20
  const chapterConfig = {
21
21
  driver: {
22
22
  title: framework.entityDefinitions.driver.title,
23
- emoji: framework.entityDefinitions.driver.emoji,
23
+ emojiIcon: framework.entityDefinitions.driver.emojiIcon,
24
24
  description: framework.entityDefinitions.driver.description,
25
25
  },
26
26
  skill: {
27
27
  title: framework.entityDefinitions.skill.title,
28
- emoji: framework.entityDefinitions.skill.emoji,
28
+ emojiIcon: framework.entityDefinitions.skill.emojiIcon,
29
29
  description: framework.entityDefinitions.skill.description,
30
30
  },
31
31
  behaviour: {
32
32
  title: framework.entityDefinitions.behaviour.title,
33
- emoji: framework.entityDefinitions.behaviour.emoji,
33
+ emojiIcon: framework.entityDefinitions.behaviour.emojiIcon,
34
34
  description: framework.entityDefinitions.behaviour.description,
35
35
  },
36
36
  discipline: {
37
37
  title: framework.entityDefinitions.discipline.title,
38
- emoji: framework.entityDefinitions.discipline.emoji,
38
+ emojiIcon: framework.entityDefinitions.discipline.emojiIcon,
39
39
  description: framework.entityDefinitions.discipline.description,
40
40
  },
41
41
  grade: {
42
42
  title: framework.entityDefinitions.grade.title,
43
- emoji: framework.entityDefinitions.grade.emoji,
43
+ emojiIcon: framework.entityDefinitions.grade.emojiIcon,
44
44
  description: framework.entityDefinitions.grade.description,
45
45
  },
46
46
  track: {
47
47
  title: framework.entityDefinitions.track.title,
48
- emoji: framework.entityDefinitions.track.emoji,
48
+ emojiIcon: framework.entityDefinitions.track.emojiIcon,
49
49
  description: framework.entityDefinitions.track.description,
50
50
  },
51
51
  job: {
52
52
  title: framework.entityDefinitions.job.title,
53
- emoji: framework.entityDefinitions.job.emoji,
53
+ emojiIcon: framework.entityDefinitions.job.emojiIcon,
54
54
  description: framework.entityDefinitions.job.description,
55
55
  },
56
56
  };
@@ -72,7 +72,7 @@ export function renderChapterSlide({ render, data, params }) {
72
72
  { className: "slide chapter-cover" },
73
73
  h1(
74
74
  { className: "chapter-title" },
75
- config.emoji ? `${config.emoji} ` : "",
75
+ config.emojiIcon ? `${config.emojiIcon} ` : "",
76
76
  span({ className: "gradient-text" }, config.title),
77
77
  ),
78
78
  p({ className: "chapter-description" }, config.description.trim()),
@@ -22,7 +22,7 @@ export function renderSlideIndex({ render, data }) {
22
22
  { className: "page-header" },
23
23
  heading1(
24
24
  { className: "page-title" },
25
- `${framework.emoji} ${framework.title}`,
25
+ `${framework.emojiIcon} ${framework.title}`,
26
26
  ),
27
27
  p(
28
28
  { className: "page-description" },
@@ -55,25 +55,6 @@ export function renderSlideIndex({ render, data }) {
55
55
  ),
56
56
  ),
57
57
 
58
- // Tracks
59
- div(
60
- { className: "slide-section" },
61
- a(
62
- { href: "#/overview/track" },
63
- heading2(
64
- { className: "slide-section-title" },
65
- `${getConceptEmoji(data.framework, "track")} `,
66
- span({ className: "gradient-text" }, "Tracks"),
67
- ),
68
- ),
69
- ul(
70
- { className: "related-list" },
71
- ...data.tracks.map((track) =>
72
- li({}, a({ href: `#/track/${track.id}` }, track.name)),
73
- ),
74
- ),
75
- ),
76
-
77
58
  // Grades
78
59
  div(
79
60
  { className: "slide-section" },
@@ -99,21 +80,21 @@ export function renderSlideIndex({ render, data }) {
99
80
  ),
100
81
  ),
101
82
 
102
- // Skills
83
+ // Tracks
103
84
  div(
104
85
  { className: "slide-section" },
105
86
  a(
106
- { href: "#/overview/skill" },
87
+ { href: "#/overview/track" },
107
88
  heading2(
108
89
  { className: "slide-section-title" },
109
- `${getConceptEmoji(data.framework, "skill")} `,
110
- span({ className: "gradient-text" }, "Skills"),
90
+ `${getConceptEmoji(data.framework, "track")} `,
91
+ span({ className: "gradient-text" }, "Tracks"),
111
92
  ),
112
93
  ),
113
94
  ul(
114
95
  { className: "related-list" },
115
- ...data.skills.map((skill) =>
116
- li({}, a({ href: `#/skill/${skill.id}` }, skill.name)),
96
+ ...data.tracks.map((track) =>
97
+ li({}, a({ href: `#/track/${track.id}` }, track.name)),
117
98
  ),
118
99
  ),
119
100
  ),
@@ -137,6 +118,25 @@ export function renderSlideIndex({ render, data }) {
137
118
  ),
138
119
  ),
139
120
 
121
+ // Skills
122
+ div(
123
+ { className: "slide-section" },
124
+ a(
125
+ { href: "#/overview/skill" },
126
+ heading2(
127
+ { className: "slide-section-title" },
128
+ `${getConceptEmoji(data.framework, "skill")} `,
129
+ span({ className: "gradient-text" }, "Skills"),
130
+ ),
131
+ ),
132
+ ul(
133
+ { className: "related-list" },
134
+ ...data.skills.map((skill) =>
135
+ li({}, a({ href: `#/skill/${skill.id}` }, skill.name)),
136
+ ),
137
+ ),
138
+ ),
139
+
140
140
  // Drivers
141
141
  div(
142
142
  { className: "slide-section" },
@@ -63,14 +63,14 @@ export function renderOverviewSlide({ render, data, params }) {
63
63
  const chapterConfig = {
64
64
  driver: {
65
65
  title: framework.entityDefinitions.driver.title,
66
- emoji: framework.entityDefinitions.driver.emoji,
66
+ emojiIcon: framework.entityDefinitions.driver.emojiIcon,
67
67
  description: framework.entityDefinitions.driver.description,
68
68
  entities: prepareDriversList(data.drivers).items,
69
69
  mapper: driverToCardConfig,
70
70
  },
71
71
  skill: {
72
72
  title: framework.entityDefinitions.skill.title,
73
- emoji: framework.entityDefinitions.skill.emoji,
73
+ emojiIcon: framework.entityDefinitions.skill.emojiIcon,
74
74
  description: framework.entityDefinitions.skill.description,
75
75
  entities: Object.values(
76
76
  prepareSkillsList(data.skills, data.capabilities).groups,
@@ -79,14 +79,14 @@ export function renderOverviewSlide({ render, data, params }) {
79
79
  },
80
80
  behaviour: {
81
81
  title: framework.entityDefinitions.behaviour.title,
82
- emoji: framework.entityDefinitions.behaviour.emoji,
82
+ emojiIcon: framework.entityDefinitions.behaviour.emojiIcon,
83
83
  description: framework.entityDefinitions.behaviour.description,
84
84
  entities: prepareBehavioursList(data.behaviours).items,
85
85
  mapper: behaviourToCardConfig,
86
86
  },
87
87
  discipline: {
88
88
  title: framework.entityDefinitions.discipline.title,
89
- emoji: framework.entityDefinitions.discipline.emoji,
89
+ emojiIcon: framework.entityDefinitions.discipline.emojiIcon,
90
90
  description: framework.entityDefinitions.discipline.description,
91
91
  groups: prepareDisciplinesList(data.disciplines).groups,
92
92
  mapper: disciplineToCardConfig,
@@ -94,21 +94,21 @@ export function renderOverviewSlide({ render, data, params }) {
94
94
  },
95
95
  grade: {
96
96
  title: framework.entityDefinitions.grade.title,
97
- emoji: framework.entityDefinitions.grade.emoji,
97
+ emojiIcon: framework.entityDefinitions.grade.emojiIcon,
98
98
  description: framework.entityDefinitions.grade.description,
99
99
  entities: prepareGradesList(data.grades).items,
100
100
  mapper: gradeToCardConfig,
101
101
  },
102
102
  track: {
103
103
  title: framework.entityDefinitions.track.title,
104
- emoji: framework.entityDefinitions.track.emoji,
104
+ emojiIcon: framework.entityDefinitions.track.emojiIcon,
105
105
  description: framework.entityDefinitions.track.description,
106
106
  entities: prepareTracksList(data.tracks).items,
107
107
  mapper: trackToCardConfig,
108
108
  },
109
109
  job: {
110
110
  title: framework.entityDefinitions.job.title,
111
- emoji: framework.entityDefinitions.job.emoji,
111
+ emojiIcon: framework.entityDefinitions.job.emojiIcon,
112
112
  description: framework.entityDefinitions.job.description,
113
113
  entities: generateAllJobs({
114
114
  disciplines: data.disciplines,
@@ -150,7 +150,7 @@ export function renderOverviewSlide({ render, data, params }) {
150
150
  { className: "overview-header" },
151
151
  h1(
152
152
  { className: "overview-title" },
153
- config.emoji ? `${config.emoji} ` : "",
153
+ config.emojiIcon ? `${config.emojiIcon} ` : "",
154
154
  span({ className: "gradient-text" }, config.title),
155
155
  ),
156
156
  p({ className: "overview-description" }, config.description.trim()),
@@ -35,6 +35,7 @@ export function renderSkillSlide({ render, data, params }) {
35
35
  drivers: data.drivers,
36
36
  capabilities: data.capabilities,
37
37
  showBackLink: false,
38
+ showToolsAndPatterns: false,
38
39
  }),
39
40
  );
40
41
  }
package/bin/pathway.js CHANGED
@@ -9,15 +9,17 @@
9
9
  * npx pathway <command> [options]
10
10
  *
11
11
  * Commands:
12
- * skill [<id>] Show skills (summary, --list, or detail)
13
- * behaviour [<id>] Show behaviours
14
12
  * discipline [<id>] Show disciplines
15
13
  * grade [<id>] Show grades
16
14
  * track [<id>] Show tracks
15
+ * behaviour [<id>] Show behaviours
16
+ * skill [<id>] Show skills (summary, --list, or detail)
17
17
  * driver [<id>] Show drivers
18
- * job [<discipline> <track> <grade>] Generate job definition
19
- * interview <discipline> <track> <grade> [--type=TYPE] Generate interview
20
- * progress <discipline> <track> <grade> [--compare=GRADE] Career progression
18
+ * stage [<id>] Show stages
19
+ * tool [<name>] Show tools
20
+ * job [<discipline> <grade>] [--track=TRACK] Generate job definition
21
+ * interview <discipline> <grade> [--track=TRACK] [--type=TYPE] Generate interview
22
+ * progress <discipline> <grade> [--track=TRACK] [--compare=GRADE] Career progression
21
23
  * questions [options] Browse interview questions
22
24
  * agent [<discipline> <track>] [--output=PATH] Generate AI agent
23
25
  *
@@ -37,13 +39,14 @@ import { formatError } from "../app/lib/cli-output.js";
37
39
  import { runSchemaValidation } from "../app/model/schema-validation.js";
38
40
 
39
41
  // Import command handlers
40
- import { runSkillCommand } from "../app/commands/skill.js";
41
- import { runBehaviourCommand } from "../app/commands/behaviour.js";
42
42
  import { runDisciplineCommand } from "../app/commands/discipline.js";
43
43
  import { runGradeCommand } from "../app/commands/grade.js";
44
44
  import { runTrackCommand } from "../app/commands/track.js";
45
+ import { runBehaviourCommand } from "../app/commands/behaviour.js";
46
+ import { runSkillCommand } from "../app/commands/skill.js";
45
47
  import { runDriverCommand } from "../app/commands/driver.js";
46
48
  import { runStageCommand } from "../app/commands/stage.js";
49
+ import { runToolCommand } from "../app/commands/tool.js";
47
50
  import { runJobCommand } from "../app/commands/job.js";
48
51
  import { runInterviewCommand } from "../app/commands/interview.js";
49
52
  import { runProgressCommand } from "../app/commands/progress.js";
@@ -58,13 +61,14 @@ const __dirname = dirname(__filename);
58
61
  const rootDir = join(__dirname, "..");
59
62
 
60
63
  const COMMANDS = {
61
- skill: runSkillCommand,
62
- behaviour: runBehaviourCommand,
63
64
  discipline: runDisciplineCommand,
64
65
  grade: runGradeCommand,
65
66
  track: runTrackCommand,
67
+ behaviour: runBehaviourCommand,
68
+ skill: runSkillCommand,
66
69
  driver: runDriverCommand,
67
70
  stage: runStageCommand,
71
+ tool: runToolCommand,
68
72
  job: runJobCommand,
69
73
  interview: runInterviewCommand,
70
74
  progress: runProgressCommand,
@@ -86,19 +90,21 @@ Getting Started:
86
90
  site [--output=PATH] Generate static site to ./site/
87
91
 
88
92
  Entity Commands (summary by default, --list for IDs, <id> for detail):
89
- skill [<id>] Browse skills
90
- behaviour [<id>] Browse behaviours
91
93
  discipline [<id>] Browse disciplines
92
94
  grade [<id>] Browse grades
93
95
  track [<id>] Browse tracks
96
+ behaviour [<id>] Browse behaviours
97
+ skill [<id>] Browse skills
98
+ --agent Output as agent SKILL.md format
94
99
  driver [<id>] Browse drivers
95
100
  stage [<id>] Browse lifecycle stages
101
+ tool [<name>] Browse recommended tools
96
102
 
97
103
  Composite Commands:
98
- job [<discipline> <track> <grade>] Generate job definition
99
- interview <discipline> <track> <grade> [--type=TYPE]
104
+ job [<discipline> <grade>] [--track=TRACK] Generate job definition
105
+ interview <discipline> <grade> [--track=TRACK] [--type=TYPE]
100
106
  Generate interview questions
101
- progress <discipline> <track> <grade> [--compare=GRADE]
107
+ progress <discipline> <grade> [--track=TRACK] [--compare=GRADE]
102
108
  Show career progression
103
109
  questions [filters] Browse interview questions
104
110
  agent <discipline> [--track=<track>] Generate AI coding agent
@@ -130,11 +136,17 @@ Examples:
130
136
  npx pathway skill # Summary of all skills
131
137
  npx pathway skill --list # Skill IDs for piping
132
138
  npx pathway skill ai_evaluation # Detail view
139
+ npx pathway skill architecture_design --agent # Agent SKILL.md output
140
+
141
+ npx pathway tool # Summary of all tools
142
+ npx pathway tool --list # Tool names for piping
143
+ npx pathway tool DuckDB # Tool detail with skill usages
133
144
 
134
145
  npx pathway job # Summary of valid combinations
135
146
  npx pathway job --list # All combinations for piping
136
- npx pathway job software_engineering platform L4
137
- npx pathway job se platform L3 --checklist=code_to_review
147
+ npx pathway job software_engineering L4
148
+ npx pathway job software_engineering L4 --track=platform
149
+ npx pathway job se L3 --track=platform --checklist=code
138
150
 
139
151
  npx pathway questions --level=practitioner
140
152
  npx pathway questions --stats
@@ -176,6 +188,7 @@ function parseArgs(args) {
176
188
  output: null,
177
189
  stage: null,
178
190
  "all-stages": false,
191
+ agent: false,
179
192
  // Serve command options
180
193
  port: null,
181
194
  // Init command options
@@ -227,6 +240,8 @@ function parseArgs(args) {
227
240
  result.stage = arg.slice(8);
228
241
  } else if (arg === "--all-stages") {
229
242
  result["all-stages"] = true;
243
+ } else if (arg === "--agent") {
244
+ result.agent = true;
230
245
  } else if (arg.startsWith("--checklist=")) {
231
246
  result.checklist = arg.slice(12);
232
247
  } else if (arg.startsWith("--port=")) {