@forwardimpact/pathway 0.4.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.
- package/app/commands/behaviour.js +1 -1
- package/app/commands/command-factory.js +2 -2
- package/app/commands/discipline.js +1 -1
- package/app/commands/driver.js +1 -1
- package/app/commands/grade.js +1 -1
- package/app/commands/serve.js +2 -2
- package/app/commands/site.js +22 -2
- package/app/commands/skill.js +1 -1
- package/app/commands/stage.js +1 -1
- package/app/commands/track.js +1 -1
- package/app/components/card.js +11 -1
- package/app/components/code-display.js +153 -0
- package/app/components/markdown-textarea.js +68 -47
- package/app/css/bundles/app.css +14 -0
- package/app/css/components/badges.css +15 -8
- package/app/css/components/forms.css +23 -13
- package/app/css/components/surfaces.css +49 -3
- package/app/css/components/typography.css +1 -2
- package/app/css/pages/agent-builder.css +11 -102
- package/app/css/pages/detail.css +11 -1
- package/app/css/tokens.css +3 -0
- package/app/formatters/agent/dom.js +26 -71
- package/app/formatters/agent/profile.js +11 -6
- package/app/formatters/grade/dom.js +6 -6
- package/app/formatters/job/dom.js +3 -3
- package/app/formatters/json-ld.js +1 -1
- package/app/formatters/skill/dom.js +68 -56
- package/app/formatters/skill/shared.js +3 -1
- package/app/formatters/stage/microdata.js +2 -2
- package/app/formatters/stage/shared.js +3 -3
- package/app/formatters/tool/shared.js +6 -0
- package/app/handout-main.js +12 -11
- package/app/index.html +7 -1
- package/app/lib/card-mappers.js +27 -0
- package/app/model/agent.js +21 -5
- package/app/model/checklist.js +2 -2
- package/app/model/derivation.js +2 -2
- package/app/model/levels.js +2 -2
- package/app/model/validation.js +3 -3
- package/app/pages/agent-builder.js +119 -75
- package/app/pages/landing.js +1 -1
- package/app/pages/stage.js +4 -4
- package/app/slide-main.js +1 -1
- package/app/slides/chapter.js +8 -8
- package/app/slides/index.js +1 -1
- package/app/slides/overview.js +8 -8
- package/app/slides/skill.js +1 -0
- package/examples/capabilities/business.yaml +1 -1
- package/examples/capabilities/delivery.yaml +3 -1
- package/examples/capabilities/people.yaml +1 -1
- package/examples/capabilities/reliability.yaml +3 -1
- package/examples/capabilities/scale.yaml +1 -1
- package/examples/framework.yaml +11 -11
- package/examples/stages.yaml +18 -10
- package/package.json +2 -1
- package/templates/agent.template.md +47 -17
- package/templates/job.template.md +8 -8
- package/templates/skill.template.md +12 -9
- package/examples/agents/.claude/skills/architecture-design/SKILL.md +0 -130
- package/examples/agents/.claude/skills/cloud-platforms/SKILL.md +0 -131
- package/examples/agents/.claude/skills/code-quality-review/SKILL.md +0 -108
- package/examples/agents/.claude/skills/devops-cicd/SKILL.md +0 -142
- package/examples/agents/.claude/skills/full-stack-development/SKILL.md +0 -134
- package/examples/agents/.claude/skills/sre-practices/SKILL.md +0 -163
- package/examples/agents/.claude/skills/technical-debt-management/SKILL.md +0 -164
- package/examples/agents/.github/agents/se-platform-code.agent.md +0 -132
- package/examples/agents/.github/agents/se-platform-plan.agent.md +0 -131
- package/examples/agents/.github/agents/se-platform-review.agent.md +0 -136
- package/examples/agents/.vscode/settings.json +0 -8
|
@@ -16,6 +16,8 @@ import {
|
|
|
16
16
|
span,
|
|
17
17
|
label,
|
|
18
18
|
section,
|
|
19
|
+
select,
|
|
20
|
+
option,
|
|
19
21
|
} from "../lib/render.js";
|
|
20
22
|
import { getState } from "../lib/state.js";
|
|
21
23
|
import { loadAgentDataBrowser } from "../lib/yaml-loader.js";
|
|
@@ -34,6 +36,7 @@ import { createReactive } from "../lib/reactive.js";
|
|
|
34
36
|
import { getStageEmoji } from "../formatters/stage/shared.js";
|
|
35
37
|
import { formatAgentProfile } from "../formatters/agent/profile.js";
|
|
36
38
|
import { formatAgentSkill } from "../formatters/agent/skill.js";
|
|
39
|
+
import { createCodeDisplay } from "../components/code-display.js";
|
|
37
40
|
|
|
38
41
|
/** All stages option value */
|
|
39
42
|
const ALL_STAGES_VALUE = "all";
|
|
@@ -101,9 +104,71 @@ export async function renderAgentBuilder() {
|
|
|
101
104
|
const availableDisciplines = data.disciplines.filter((d) =>
|
|
102
105
|
agentDisciplineIds.has(d.id),
|
|
103
106
|
);
|
|
104
|
-
|
|
107
|
+
// All tracks with agent definitions (will be filtered per-discipline)
|
|
108
|
+
const allAgentTracks = data.tracks.filter((t) => agentTrackIds.has(t.id));
|
|
105
109
|
const stages = data.stages || [];
|
|
106
110
|
|
|
111
|
+
/**
|
|
112
|
+
* Get tracks valid for a discipline that also have agent definitions
|
|
113
|
+
* @param {string} disciplineId - Discipline ID
|
|
114
|
+
* @returns {Array} - Valid tracks for the discipline
|
|
115
|
+
*/
|
|
116
|
+
function getValidTracksForDiscipline(disciplineId) {
|
|
117
|
+
const discipline = data.disciplines.find((d) => d.id === disciplineId);
|
|
118
|
+
if (!discipline) return [];
|
|
119
|
+
|
|
120
|
+
const validTracks = discipline.validTracks ?? [];
|
|
121
|
+
// Filter to track IDs only (exclude null which means trackless)
|
|
122
|
+
const validTrackIds = validTracks.filter((t) => t !== null);
|
|
123
|
+
|
|
124
|
+
// Intersection: valid for discipline AND has agent definition
|
|
125
|
+
return allAgentTracks.filter((t) => validTrackIds.includes(t.id));
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// Track select element - created once, options updated when discipline changes
|
|
129
|
+
const trackSelectEl = select(
|
|
130
|
+
{ className: "form-select", id: "agent-track-select" },
|
|
131
|
+
option({ value: "", disabled: true, selected: true }, "Select a track..."),
|
|
132
|
+
);
|
|
133
|
+
trackSelectEl.disabled = true;
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Update track select options based on selected discipline
|
|
137
|
+
* @param {string} disciplineId - Discipline ID
|
|
138
|
+
*/
|
|
139
|
+
function updateTrackOptions(disciplineId) {
|
|
140
|
+
const validTracks = getValidTracksForDiscipline(disciplineId);
|
|
141
|
+
|
|
142
|
+
// Clear existing options
|
|
143
|
+
trackSelectEl.innerHTML = "";
|
|
144
|
+
|
|
145
|
+
if (validTracks.length === 0) {
|
|
146
|
+
trackSelectEl.appendChild(
|
|
147
|
+
option(
|
|
148
|
+
{ value: "", disabled: true, selected: true },
|
|
149
|
+
"No tracks available for this discipline",
|
|
150
|
+
),
|
|
151
|
+
);
|
|
152
|
+
trackSelectEl.disabled = true;
|
|
153
|
+
return;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
// Add placeholder
|
|
157
|
+
trackSelectEl.appendChild(
|
|
158
|
+
option(
|
|
159
|
+
{ value: "", disabled: true, selected: true },
|
|
160
|
+
"Select a track...",
|
|
161
|
+
),
|
|
162
|
+
);
|
|
163
|
+
|
|
164
|
+
// Add available track options
|
|
165
|
+
validTracks.forEach((t) => {
|
|
166
|
+
trackSelectEl.appendChild(option({ value: t.id }, t.name));
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
trackSelectEl.disabled = false;
|
|
170
|
+
}
|
|
171
|
+
|
|
107
172
|
// Build stage options with "All Stages" first
|
|
108
173
|
const stageOptions = [
|
|
109
174
|
{ id: ALL_STAGES_VALUE, name: "All Stages" },
|
|
@@ -134,7 +199,7 @@ export async function renderAgentBuilder() {
|
|
|
134
199
|
// Preview container - will be updated reactively
|
|
135
200
|
const previewContainer = div(
|
|
136
201
|
{ className: "agent-preview" },
|
|
137
|
-
createEmptyState(availableDisciplines.length,
|
|
202
|
+
createEmptyState(availableDisciplines.length, allAgentTracks.length),
|
|
138
203
|
);
|
|
139
204
|
|
|
140
205
|
/**
|
|
@@ -156,7 +221,7 @@ export async function renderAgentBuilder() {
|
|
|
156
221
|
|
|
157
222
|
if (!discipline) {
|
|
158
223
|
previewContainer.appendChild(
|
|
159
|
-
createEmptyState(availableDisciplines.length,
|
|
224
|
+
createEmptyState(availableDisciplines.length, allAgentTracks.length),
|
|
160
225
|
);
|
|
161
226
|
return;
|
|
162
227
|
}
|
|
@@ -251,7 +316,14 @@ export async function renderAgentBuilder() {
|
|
|
251
316
|
initialValue: selection.get().discipline,
|
|
252
317
|
placeholder: "Select a discipline...",
|
|
253
318
|
onChange: (value) => {
|
|
254
|
-
|
|
319
|
+
// Update track options when discipline changes
|
|
320
|
+
updateTrackOptions(value);
|
|
321
|
+
// Reset track selection when discipline changes
|
|
322
|
+
selection.update((prev) => ({
|
|
323
|
+
...prev,
|
|
324
|
+
discipline: value,
|
|
325
|
+
track: "",
|
|
326
|
+
}));
|
|
255
327
|
},
|
|
256
328
|
getDisplayName: (d) => d.specialization || d.name,
|
|
257
329
|
})
|
|
@@ -260,25 +332,32 @@ export async function renderAgentBuilder() {
|
|
|
260
332
|
"No disciplines have agent definitions.",
|
|
261
333
|
),
|
|
262
334
|
),
|
|
263
|
-
// Track selector
|
|
335
|
+
// Track selector (dynamically filtered by discipline)
|
|
264
336
|
div(
|
|
265
337
|
{ className: "form-group" },
|
|
266
338
|
label({ className: "form-label" }, "Track"),
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
339
|
+
(() => {
|
|
340
|
+
// Wire up track select change handler
|
|
341
|
+
trackSelectEl.addEventListener("change", (e) => {
|
|
342
|
+
selection.update((prev) => ({ ...prev, track: e.target.value }));
|
|
343
|
+
});
|
|
344
|
+
// Initialize track options if discipline is pre-selected
|
|
345
|
+
const initialDiscipline = selection.get().discipline;
|
|
346
|
+
if (initialDiscipline) {
|
|
347
|
+
updateTrackOptions(initialDiscipline);
|
|
348
|
+
// Set initial track value if provided and valid
|
|
349
|
+
const initialTrack = selection.get().track;
|
|
350
|
+
const validTracks =
|
|
351
|
+
getValidTracksForDiscipline(initialDiscipline);
|
|
352
|
+
if (
|
|
353
|
+
initialTrack &&
|
|
354
|
+
validTracks.some((t) => t.id === initialTrack)
|
|
355
|
+
) {
|
|
356
|
+
trackSelectEl.value = initialTrack;
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
return trackSelectEl;
|
|
360
|
+
})(),
|
|
282
361
|
),
|
|
283
362
|
// Stage selector (dropdown with All Stages option)
|
|
284
363
|
div(
|
|
@@ -590,10 +669,15 @@ function createAgentCard(stage, profile, stages, agentTemplate, _derived) {
|
|
|
590
669
|
span({ className: "agent-card-emoji" }, stageEmoji),
|
|
591
670
|
h3({}, `${stage.name} Agent`),
|
|
592
671
|
),
|
|
593
|
-
createCopyButton(content),
|
|
594
672
|
),
|
|
595
|
-
|
|
596
|
-
|
|
673
|
+
div(
|
|
674
|
+
{ className: "agent-card-preview" },
|
|
675
|
+
createCodeDisplay({
|
|
676
|
+
content,
|
|
677
|
+
filename: profile.filename,
|
|
678
|
+
maxHeight: 400,
|
|
679
|
+
}),
|
|
680
|
+
),
|
|
597
681
|
);
|
|
598
682
|
|
|
599
683
|
return card;
|
|
@@ -614,57 +698,18 @@ function createSkillCard(skill, skillTemplate) {
|
|
|
614
698
|
div(
|
|
615
699
|
{ className: "skill-card-header" },
|
|
616
700
|
span({ className: "skill-card-name" }, skill.frontmatter.name),
|
|
617
|
-
createCopyButton(content),
|
|
618
701
|
),
|
|
619
|
-
|
|
620
|
-
|
|
702
|
+
div(
|
|
703
|
+
{ className: "skill-card-preview" },
|
|
704
|
+
createCodeDisplay({
|
|
705
|
+
content,
|
|
706
|
+
filename,
|
|
707
|
+
maxHeight: 300,
|
|
708
|
+
}),
|
|
709
|
+
),
|
|
621
710
|
);
|
|
622
711
|
}
|
|
623
712
|
|
|
624
|
-
/**
|
|
625
|
-
* Create a code preview element
|
|
626
|
-
* @param {string} content - Code content
|
|
627
|
-
* @returns {HTMLElement}
|
|
628
|
-
*/
|
|
629
|
-
function createCodePreview(content) {
|
|
630
|
-
const pre = document.createElement("pre");
|
|
631
|
-
pre.className = "code-block code-preview";
|
|
632
|
-
|
|
633
|
-
const code = document.createElement("code");
|
|
634
|
-
code.textContent = content;
|
|
635
|
-
|
|
636
|
-
pre.appendChild(code);
|
|
637
|
-
return pre;
|
|
638
|
-
}
|
|
639
|
-
|
|
640
|
-
/**
|
|
641
|
-
* Create a copy button
|
|
642
|
-
* @param {string} content - Content to copy
|
|
643
|
-
* @returns {HTMLElement}
|
|
644
|
-
*/
|
|
645
|
-
function createCopyButton(content) {
|
|
646
|
-
const btn = document.createElement("button");
|
|
647
|
-
btn.className = "btn btn-sm copy-btn";
|
|
648
|
-
btn.textContent = "π Copy";
|
|
649
|
-
|
|
650
|
-
btn.addEventListener("click", async () => {
|
|
651
|
-
try {
|
|
652
|
-
await navigator.clipboard.writeText(content);
|
|
653
|
-
btn.textContent = "β Copied";
|
|
654
|
-
setTimeout(() => {
|
|
655
|
-
btn.textContent = "π Copy";
|
|
656
|
-
}, 2000);
|
|
657
|
-
} catch {
|
|
658
|
-
btn.textContent = "Failed";
|
|
659
|
-
setTimeout(() => {
|
|
660
|
-
btn.textContent = "π Copy";
|
|
661
|
-
}, 2000);
|
|
662
|
-
}
|
|
663
|
-
});
|
|
664
|
-
|
|
665
|
-
return btn;
|
|
666
|
-
}
|
|
667
|
-
|
|
668
713
|
/**
|
|
669
714
|
* Create download all button for all stages
|
|
670
715
|
* @param {Array} stageAgents - Array of {stage, derived, profile}
|
|
@@ -860,11 +905,10 @@ function createCliHint(disciplineId, trackId, stageId) {
|
|
|
860
905
|
{ className: "agent-section cli-hint" },
|
|
861
906
|
h2({}, "CLI Alternative"),
|
|
862
907
|
p({}, "Generate this agent from the command line:"),
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
),
|
|
908
|
+
createCodeDisplay({
|
|
909
|
+
content: command,
|
|
910
|
+
language: "bash",
|
|
911
|
+
}),
|
|
868
912
|
);
|
|
869
913
|
|
|
870
914
|
return container;
|
package/app/pages/landing.js
CHANGED
|
@@ -53,7 +53,7 @@ export function renderLanding() {
|
|
|
53
53
|
{ className: "landing-hero" },
|
|
54
54
|
div(
|
|
55
55
|
{ className: "hero-title-wrapper" },
|
|
56
|
-
h1({}, `${framework.
|
|
56
|
+
h1({}, `${framework.emojiIcon} ${framework.title}`),
|
|
57
57
|
span({ className: "brand-tag brand-tag-hero" }, framework.tag),
|
|
58
58
|
),
|
|
59
59
|
p({}, framework.description.trim()),
|
package/app/pages/stage.js
CHANGED
|
@@ -11,12 +11,12 @@ import { getConceptEmoji } from "../model/levels.js";
|
|
|
11
11
|
|
|
12
12
|
/**
|
|
13
13
|
* Map stage to card configuration
|
|
14
|
-
* @param {Object} stage - Prepared stage item (includes
|
|
14
|
+
* @param {Object} stage - Prepared stage item (includes emojiIcon)
|
|
15
15
|
* @returns {Object} Card configuration
|
|
16
16
|
*/
|
|
17
17
|
function stageToCardConfig(stage) {
|
|
18
18
|
return {
|
|
19
|
-
title: `${stage.
|
|
19
|
+
title: `${stage.emojiIcon} ${stage.name}`,
|
|
20
20
|
description: stage.truncatedDescription,
|
|
21
21
|
href: `/stage/${stage.id}`,
|
|
22
22
|
};
|
|
@@ -24,7 +24,7 @@ function stageToCardConfig(stage) {
|
|
|
24
24
|
|
|
25
25
|
/**
|
|
26
26
|
* Create lifecycle flow visualization
|
|
27
|
-
* @param {Array} stages - Array of stage items (each includes
|
|
27
|
+
* @param {Array} stages - Array of stage items (each includes emojiIcon)
|
|
28
28
|
* @returns {HTMLElement}
|
|
29
29
|
*/
|
|
30
30
|
function createLifecycleFlow(stages) {
|
|
@@ -35,7 +35,7 @@ function createLifecycleFlow(stages) {
|
|
|
35
35
|
{ className: "lifecycle-flow-item" },
|
|
36
36
|
a(
|
|
37
37
|
{ href: `#/stage/${stage.id}`, className: "lifecycle-stage" },
|
|
38
|
-
span({ className: "lifecycle-emoji" }, stage.
|
|
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,
|
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.
|
|
349
|
+
`${framework.emojiIcon} ${framework.title}`,
|
|
350
350
|
),
|
|
351
351
|
);
|
|
352
352
|
header.appendChild(span({ className: "brand-tag" }, framework.tag));
|
package/app/slides/chapter.js
CHANGED
|
@@ -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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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.
|
|
75
|
+
config.emojiIcon ? `${config.emojiIcon} ` : "",
|
|
76
76
|
span({ className: "gradient-text" }, config.title),
|
|
77
77
|
),
|
|
78
78
|
p({ className: "chapter-description" }, config.description.trim()),
|
package/app/slides/index.js
CHANGED
|
@@ -22,7 +22,7 @@ export function renderSlideIndex({ render, data }) {
|
|
|
22
22
|
{ className: "page-header" },
|
|
23
23
|
heading1(
|
|
24
24
|
{ className: "page-title" },
|
|
25
|
-
`${framework.
|
|
25
|
+
`${framework.emojiIcon} ${framework.title}`,
|
|
26
26
|
),
|
|
27
27
|
p(
|
|
28
28
|
{ className: "page-description" },
|
package/app/slides/overview.js
CHANGED
|
@@ -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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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.
|
|
153
|
+
config.emojiIcon ? `${config.emojiIcon} ` : "",
|
|
154
154
|
span({ className: "gradient-text" }, config.title),
|
|
155
155
|
),
|
|
156
156
|
p({ className: "overview-description" }, config.description.trim()),
|
package/app/slides/skill.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# yaml-language-server: $schema=https://schema.forwardimpact.team/json/capability.schema.json
|
|
2
2
|
|
|
3
3
|
name: Delivery
|
|
4
|
-
|
|
4
|
+
emojiIcon: π
|
|
5
5
|
displayOrder: 1
|
|
6
6
|
description: |
|
|
7
7
|
Building and shipping solutions that solve real problems.
|
|
@@ -271,6 +271,7 @@ skills:
|
|
|
271
271
|
toolReferences:
|
|
272
272
|
- name: Terraform
|
|
273
273
|
url: https://developer.hashicorp.com/terraform/docs
|
|
274
|
+
simpleIcon: terraform
|
|
274
275
|
description: Infrastructure as code tool
|
|
275
276
|
useWhen: Provisioning and managing cloud infrastructure
|
|
276
277
|
- name: CloudFormation
|
|
@@ -279,6 +280,7 @@ skills:
|
|
|
279
280
|
useWhen: Managing AWS infrastructure as code
|
|
280
281
|
- name: Docker
|
|
281
282
|
url: https://docs.docker.com/
|
|
283
|
+
simpleIcon: docker
|
|
282
284
|
description: Container platform
|
|
283
285
|
useWhen: Containerizing applications or managing container environments
|
|
284
286
|
implementationReference: |
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# yaml-language-server: $schema=https://schema.forwardimpact.team/json/capability.schema.json
|
|
2
2
|
|
|
3
3
|
name: Reliability
|
|
4
|
-
|
|
4
|
+
emojiIcon: π‘οΈ
|
|
5
5
|
displayOrder: 5
|
|
6
6
|
description: |
|
|
7
7
|
Ensuring systems are dependable, secure, and observable.
|
|
@@ -158,10 +158,12 @@ skills:
|
|
|
158
158
|
toolReferences:
|
|
159
159
|
- name: Terraform
|
|
160
160
|
url: https://developer.hashicorp.com/terraform/docs
|
|
161
|
+
simpleIcon: terraform
|
|
161
162
|
description: Infrastructure as code tool
|
|
162
163
|
useWhen: Provisioning and managing cloud infrastructure
|
|
163
164
|
- name: Docker
|
|
164
165
|
url: https://docs.docker.com/
|
|
166
|
+
simpleIcon: docker
|
|
165
167
|
description: Container platform
|
|
166
168
|
useWhen: Containerizing applications or managing container environments
|
|
167
169
|
implementationReference: |
|
package/examples/framework.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# yaml-language-server: $schema=https://schema.forwardimpact.team/json/framework.schema.json
|
|
2
2
|
|
|
3
3
|
title: Engineering Pathway
|
|
4
|
-
|
|
4
|
+
emojiIcon: "π§"
|
|
5
5
|
tag: "#AcmeCorp"
|
|
6
6
|
description: |
|
|
7
7
|
A unified framework for human and AI collaboration in engineering. Define roles, track skills and behaviours, build career paths, and generate AI coding agentsβall from the same coherent foundation. The pathway aligns human capabilities with AI assistance, enabling productive teams in the AI era.
|
|
@@ -10,60 +10,60 @@ description: |
|
|
|
10
10
|
entityDefinitions:
|
|
11
11
|
driver:
|
|
12
12
|
title: Drivers
|
|
13
|
-
|
|
13
|
+
emojiIcon: "π―"
|
|
14
14
|
description: |
|
|
15
15
|
Organizational outcomes that productive teams achieve. Drivers link skills and behaviours to business value, helping teams understand how their capabilities contribute to organizational success.
|
|
16
16
|
|
|
17
17
|
skill:
|
|
18
18
|
title: Skills
|
|
19
|
-
|
|
19
|
+
emojiIcon: "π‘"
|
|
20
20
|
description: |
|
|
21
21
|
Capabilities required to perform work effectively. Skills are organized by capability and measured across five levels from Awareness to Expert. They form the foundation of technical and professional competence.
|
|
22
22
|
|
|
23
23
|
behaviour:
|
|
24
24
|
title: Behaviours
|
|
25
|
-
|
|
25
|
+
emojiIcon: "π§ "
|
|
26
26
|
description: |
|
|
27
27
|
Mindsets and ways of working that underpin effective application of skills. Behaviours are measured across five maturity levels from Emerging to Exemplifying. They describe how engineers approach their work, collaborate with others, and drive outcomes.
|
|
28
28
|
|
|
29
29
|
discipline:
|
|
30
30
|
title: Disciplines
|
|
31
|
-
|
|
31
|
+
emojiIcon: "π§"
|
|
32
32
|
description: |
|
|
33
33
|
Engineering specializations that define T-shaped skill profiles. Each discipline specifies primary skills for deep expertise, secondary skills for supporting capabilities, and broad skills for general awareness. Disciplines answer the question: "What kind of engineer are you?"
|
|
34
34
|
|
|
35
35
|
grade:
|
|
36
36
|
title: Grades
|
|
37
|
-
|
|
37
|
+
emojiIcon: "π"
|
|
38
38
|
description: |
|
|
39
39
|
Career levels that define expectations for skill proficiency, behaviour maturity, and scope of impact. Grades provide a clear progression path from entry-level to distinguished leadership roles, with defined expectations at each stage.
|
|
40
40
|
|
|
41
41
|
track:
|
|
42
42
|
title: Tracks
|
|
43
|
-
|
|
43
|
+
emojiIcon: "π€οΈ"
|
|
44
44
|
description: |
|
|
45
45
|
Work contexts that modify skill and behaviour expectations based on the nature of the role. Tracks answer the question: "Where and how do you work?" They apply modifiers to adjust expectations for different working environments and responsibilities.
|
|
46
46
|
|
|
47
47
|
job:
|
|
48
48
|
title: Jobs
|
|
49
|
-
|
|
49
|
+
emojiIcon: "π"
|
|
50
50
|
description: |
|
|
51
51
|
Complete role specifications that combine discipline, track, and grade into actionable job definitions with skill matrices, behaviour profiles, and derived responsibilities. Jobs represent the practical application of the framework to define concrete engineering positions.
|
|
52
52
|
|
|
53
53
|
agent:
|
|
54
54
|
title: Agents
|
|
55
|
-
|
|
55
|
+
emojiIcon: "π€"
|
|
56
56
|
description: |
|
|
57
57
|
AI coding agent configurations generated from the same disciplines, tracks, and skills that define human roles. Agent profiles and skills follow the GitHub Copilot specification, ensuring AI assistants understand context, constraints, and working styles aligned with human engineering expectations.
|
|
58
58
|
|
|
59
59
|
stage:
|
|
60
60
|
title: Stages
|
|
61
|
-
|
|
61
|
+
emojiIcon: "π"
|
|
62
62
|
description: |
|
|
63
63
|
Defined phases of the engineering lifecycle that structure work from planning through delivery and review. Stages provide context for AI agents and define entry criteria, exit criteria, and appropriate handoffs between phases.
|
|
64
64
|
|
|
65
65
|
tool:
|
|
66
66
|
title: Tools
|
|
67
|
-
|
|
67
|
+
emojiIcon: "π§"
|
|
68
68
|
description: |
|
|
69
69
|
Recommended tools and utilities referenced by skills for effective engineering workflows. Tools are linked to specific skills with guidance on when and how to use them, surfacing best practices directly in skill definitions.
|