runboard 0.1.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/AGENTS.md +54 -0
- package/LICENSE +21 -0
- package/README.md +59 -0
- package/dist/chunk-U4SVYBXI.js +904 -0
- package/dist/cli.js +102 -0
- package/dist/mcp.js +137 -0
- package/examples/.runboard/assessments/2026-01-15.md +17 -0
- package/examples/.runboard/assessments/2026-03-15.md +15 -0
- package/examples/.runboard/assessments/2026-05-15.md +15 -0
- package/examples/.runboard/config.yaml +2 -0
- package/examples/.runboard/rubric.yaml +95 -0
- package/package.json +50 -0
- package/rubric/rubric.yaml +95 -0
- package/skills/assess/SKILL.md +56 -0
- package/skills/board-update/SKILL.md +34 -0
- package/skills/pulse/SKILL.md +31 -0
- package/skills/roadmap/SKILL.md +33 -0
- package/templates/baseline.eta +10 -0
- package/templates/board-update.eta +22 -0
- package/templates/monthly.eta +8 -0
- package/templates/pulse.eta +21 -0
- package/templates/roadmap.eta +20 -0
package/dist/cli.js
ADDED
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
UserError,
|
|
4
|
+
loadRubric,
|
|
5
|
+
registerAssess,
|
|
6
|
+
registerBoard,
|
|
7
|
+
registerPulse,
|
|
8
|
+
registerReport,
|
|
9
|
+
registerRoadmap,
|
|
10
|
+
registerStatus,
|
|
11
|
+
runboardPaths,
|
|
12
|
+
shippedRubricPath
|
|
13
|
+
} from "./chunk-U4SVYBXI.js";
|
|
14
|
+
|
|
15
|
+
// src/cli.ts
|
|
16
|
+
import { Command } from "commander";
|
|
17
|
+
|
|
18
|
+
// src/commands/init.ts
|
|
19
|
+
import { copyFileSync, existsSync, mkdirSync, writeFileSync as writeFileSync2 } from "fs";
|
|
20
|
+
import { stringify as stringify2 } from "yaml";
|
|
21
|
+
|
|
22
|
+
// src/data/config.ts
|
|
23
|
+
import { readFileSync, writeFileSync } from "fs";
|
|
24
|
+
import { parse, stringify } from "yaml";
|
|
25
|
+
function defaultConfig(rubricVersion) {
|
|
26
|
+
return { org: "", rubricVersion };
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// src/commands/init.ts
|
|
30
|
+
function runInit(root = process.cwd()) {
|
|
31
|
+
const paths = runboardPaths(root);
|
|
32
|
+
const created = [];
|
|
33
|
+
if (!existsSync(paths.dir)) {
|
|
34
|
+
mkdirSync(paths.dir, { recursive: true });
|
|
35
|
+
created.push(".runboard/");
|
|
36
|
+
}
|
|
37
|
+
if (!existsSync(paths.assessmentsDir)) {
|
|
38
|
+
mkdirSync(paths.assessmentsDir, { recursive: true });
|
|
39
|
+
created.push(".runboard/assessments/");
|
|
40
|
+
}
|
|
41
|
+
if (!existsSync(paths.rubric)) {
|
|
42
|
+
copyFileSync(shippedRubricPath(), paths.rubric);
|
|
43
|
+
created.push(".runboard/rubric.yaml");
|
|
44
|
+
}
|
|
45
|
+
if (!existsSync(paths.config)) {
|
|
46
|
+
const rubric = loadRubric(paths.rubric);
|
|
47
|
+
writeFileSync2(paths.config, stringify2(defaultConfig(rubric.version)), "utf8");
|
|
48
|
+
created.push(".runboard/config.yaml");
|
|
49
|
+
}
|
|
50
|
+
return created;
|
|
51
|
+
}
|
|
52
|
+
function registerInit(program) {
|
|
53
|
+
program.command("init").description("Scaffold .runboard/ in the current repo (idempotent).").action(() => {
|
|
54
|
+
const created = runInit();
|
|
55
|
+
if (created.length === 0) {
|
|
56
|
+
process.stdout.write("Runboard is already set up here. Nothing to do.\n");
|
|
57
|
+
} else {
|
|
58
|
+
process.stdout.write(`Created:
|
|
59
|
+
${created.map((c) => ` ${c}`).join("\n")}
|
|
60
|
+
`);
|
|
61
|
+
}
|
|
62
|
+
process.stdout.write("\nNext: run `runboard assess` to record your first assessment.\n");
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// src/cli.ts
|
|
67
|
+
var VERSION = "0.1.0";
|
|
68
|
+
function buildProgram() {
|
|
69
|
+
const program = new Command();
|
|
70
|
+
program.name("runboard").description("Local-first technical-leadership maturity scorecard.").version(VERSION, "-v, --version");
|
|
71
|
+
registerInit(program);
|
|
72
|
+
registerAssess(program);
|
|
73
|
+
registerBoard(program);
|
|
74
|
+
registerPulse(program);
|
|
75
|
+
registerRoadmap(program);
|
|
76
|
+
registerReport(program);
|
|
77
|
+
registerStatus(program);
|
|
78
|
+
return program;
|
|
79
|
+
}
|
|
80
|
+
async function main(argv) {
|
|
81
|
+
const program = buildProgram();
|
|
82
|
+
try {
|
|
83
|
+
await program.parseAsync(argv);
|
|
84
|
+
} catch (err) {
|
|
85
|
+
if (err instanceof UserError) {
|
|
86
|
+
process.stderr.write(`${err.message}
|
|
87
|
+
`);
|
|
88
|
+
process.exitCode = 1;
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
throw err;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
main(process.argv).catch((err) => {
|
|
95
|
+
process.stderr.write(`${err instanceof Error ? err.message : String(err)}
|
|
96
|
+
`);
|
|
97
|
+
process.exit(1);
|
|
98
|
+
});
|
|
99
|
+
export {
|
|
100
|
+
buildProgram,
|
|
101
|
+
main
|
|
102
|
+
};
|
package/dist/mcp.js
ADDED
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
bindingConstraint,
|
|
4
|
+
formatAverage,
|
|
5
|
+
latestAssessment,
|
|
6
|
+
runAssess,
|
|
7
|
+
runBoard,
|
|
8
|
+
runPulse,
|
|
9
|
+
runReport,
|
|
10
|
+
runRoadmap,
|
|
11
|
+
runStatus
|
|
12
|
+
} from "./chunk-U4SVYBXI.js";
|
|
13
|
+
|
|
14
|
+
// mcp/server.ts
|
|
15
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
16
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
17
|
+
import { z } from "zod";
|
|
18
|
+
|
|
19
|
+
// mcp/handlers.ts
|
|
20
|
+
function handleAssess(args) {
|
|
21
|
+
const sets = Object.entries(args.scores).map(
|
|
22
|
+
([key, s]) => `${key}=${s.level}:${s.trajectory}:${s.evidence ?? ""}`
|
|
23
|
+
);
|
|
24
|
+
const { date, path } = runAssess({
|
|
25
|
+
root: args.root,
|
|
26
|
+
sets,
|
|
27
|
+
type: args.type,
|
|
28
|
+
force: args.force,
|
|
29
|
+
date: args.date
|
|
30
|
+
});
|
|
31
|
+
return { date, path, written: true };
|
|
32
|
+
}
|
|
33
|
+
function handleBoard(ctx) {
|
|
34
|
+
const { summary, htmlPath } = runBoard({ root: ctx.root, html: ctx.html });
|
|
35
|
+
return {
|
|
36
|
+
cells: summary.cells,
|
|
37
|
+
average: formatAverage(summary.average),
|
|
38
|
+
trajectoryCounts: summary.trajectoryCounts,
|
|
39
|
+
...htmlPath ? { htmlPath } : {}
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
function handlePulse(ctx) {
|
|
43
|
+
const { path, triggers } = runPulse({ root: ctx.root });
|
|
44
|
+
return { path, triggers };
|
|
45
|
+
}
|
|
46
|
+
function handleRoadmap(ctx) {
|
|
47
|
+
const { path } = runRoadmap({ root: ctx.root });
|
|
48
|
+
const latest = latestAssessment(ctx.root);
|
|
49
|
+
if (!latest) throw new Error("unreachable");
|
|
50
|
+
return { path, bindingConstraint: bindingConstraint(latest) };
|
|
51
|
+
}
|
|
52
|
+
function handleReport(ctx) {
|
|
53
|
+
const { path } = runReport({ root: ctx.root, type: ctx.type });
|
|
54
|
+
return { path };
|
|
55
|
+
}
|
|
56
|
+
function handleStatus(ctx) {
|
|
57
|
+
const s = runStatus(ctx.root);
|
|
58
|
+
return {
|
|
59
|
+
latestDate: s.latestDate ?? null,
|
|
60
|
+
average: s.average ?? null,
|
|
61
|
+
trajectoryCounts: s.trajectoryCounts ?? {},
|
|
62
|
+
activeTriggers: s.activeTriggers
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// mcp/server.ts
|
|
67
|
+
var scoreShape = z.object({
|
|
68
|
+
level: z.number().int().min(1).max(5),
|
|
69
|
+
trajectory: z.enum(["up", "flat", "down", "volatile"]),
|
|
70
|
+
evidence: z.string().default("")
|
|
71
|
+
});
|
|
72
|
+
function json(value) {
|
|
73
|
+
return { content: [{ type: "text", text: JSON.stringify(value, null, 2) }] };
|
|
74
|
+
}
|
|
75
|
+
function buildServer() {
|
|
76
|
+
const server = new McpServer({ name: "runboard", version: "0.1.0" });
|
|
77
|
+
server.registerTool(
|
|
78
|
+
"runboard_assess",
|
|
79
|
+
{
|
|
80
|
+
description: "Record a 9-dimension assessment (the model supplies scores).",
|
|
81
|
+
inputSchema: {
|
|
82
|
+
scores: z.record(z.string(), scoreShape),
|
|
83
|
+
type: z.enum(["baseline", "pulse", "quarterly", "event"]).optional(),
|
|
84
|
+
force: z.boolean().optional()
|
|
85
|
+
}
|
|
86
|
+
},
|
|
87
|
+
async (args) => json(handleAssess(args))
|
|
88
|
+
);
|
|
89
|
+
server.registerTool(
|
|
90
|
+
"runboard_board",
|
|
91
|
+
{
|
|
92
|
+
description: "Render the board summary; set html to also write board.html.",
|
|
93
|
+
inputSchema: { html: z.boolean().optional() }
|
|
94
|
+
},
|
|
95
|
+
async (args) => json(handleBoard({ html: args.html }))
|
|
96
|
+
);
|
|
97
|
+
server.registerTool(
|
|
98
|
+
"runboard_pulse",
|
|
99
|
+
{
|
|
100
|
+
description: "Compare the two latest assessments and flag stuck dimensions.",
|
|
101
|
+
inputSchema: {}
|
|
102
|
+
},
|
|
103
|
+
async () => json(handlePulse({}))
|
|
104
|
+
);
|
|
105
|
+
server.registerTool(
|
|
106
|
+
"runboard_roadmap",
|
|
107
|
+
{ description: "Generate a Now/Next/Later plan from the binding constraint.", inputSchema: {} },
|
|
108
|
+
async () => json(handleRoadmap({}))
|
|
109
|
+
);
|
|
110
|
+
server.registerTool(
|
|
111
|
+
"runboard_report",
|
|
112
|
+
{
|
|
113
|
+
description: "Render a report (board-update | baseline | monthly).",
|
|
114
|
+
inputSchema: { type: z.enum(["board-update", "baseline", "monthly"]) }
|
|
115
|
+
},
|
|
116
|
+
async (args) => json(handleReport({ type: args.type }))
|
|
117
|
+
);
|
|
118
|
+
server.registerTool(
|
|
119
|
+
"runboard_status",
|
|
120
|
+
{ description: "One-screen current state.", inputSchema: {} },
|
|
121
|
+
async () => json(handleStatus({}))
|
|
122
|
+
);
|
|
123
|
+
return server;
|
|
124
|
+
}
|
|
125
|
+
async function main() {
|
|
126
|
+
const server = buildServer();
|
|
127
|
+
const transport = new StdioServerTransport();
|
|
128
|
+
await server.connect(transport);
|
|
129
|
+
}
|
|
130
|
+
main().catch((err) => {
|
|
131
|
+
process.stderr.write(`${err instanceof Error ? err.message : String(err)}
|
|
132
|
+
`);
|
|
133
|
+
process.exit(1);
|
|
134
|
+
});
|
|
135
|
+
export {
|
|
136
|
+
buildServer
|
|
137
|
+
};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
---
|
|
2
|
+
date: 2026-01-15
|
|
3
|
+
type: baseline
|
|
4
|
+
scores:
|
|
5
|
+
build.team: { level: 2, trajectory: flat, evidence: "All devs contracted; no retained capability" }
|
|
6
|
+
build.tools: { level: 2, trajectory: up, evidence: "CI being introduced" }
|
|
7
|
+
build.techniques: { level: 2, trajectory: flat, evidence: "Cadence inconsistent" }
|
|
8
|
+
run.team: { level: 2, trajectory: flat, evidence: "Informal on-call; knowledge concentrated" }
|
|
9
|
+
run.tools: { level: 1, trajectory: flat, evidence: "Almost no monitoring" }
|
|
10
|
+
run.techniques: { level: 2, trajectory: flat, evidence: "Loose incident response" }
|
|
11
|
+
plan.team: { level: 2, trajectory: up, evidence: "CEO comms strengthening" }
|
|
12
|
+
plan.tools: { level: 1, trajectory: flat, evidence: "No roadmap tool or analytics" }
|
|
13
|
+
plan.techniques: { level: 2, trajectory: up, evidence: "Strategy being established" }
|
|
14
|
+
notes: "First baseline."
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
First baseline assessment for Northwind Engineering.
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
---
|
|
2
|
+
date: 2026-03-15
|
|
3
|
+
type: pulse
|
|
4
|
+
scores:
|
|
5
|
+
build.team: { level: 2, trajectory: flat, evidence: "Still contractor-heavy" }
|
|
6
|
+
build.tools: { level: 3, trajectory: up, evidence: "CI in place; reproducible builds" }
|
|
7
|
+
build.techniques: { level: 2, trajectory: flat, evidence: "Cadence still inconsistent" }
|
|
8
|
+
run.team: { level: 2, trajectory: up, evidence: "On-call rotation forming" }
|
|
9
|
+
run.tools: { level: 2, trajectory: up, evidence: "Monitoring being extended" }
|
|
10
|
+
run.techniques: { level: 3, trajectory: up, evidence: "Defined incident process adopted" }
|
|
11
|
+
plan.team: { level: 3, trajectory: up, evidence: "Leadership aligned with business" }
|
|
12
|
+
plan.tools: { level: 1, trajectory: flat, evidence: "Still no roadmap tooling" }
|
|
13
|
+
plan.techniques: { level: 2, trajectory: up, evidence: "Prioritisation method emerging" }
|
|
14
|
+
notes: "Tools and incident practice improving; planning tooling stuck."
|
|
15
|
+
---
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
---
|
|
2
|
+
date: 2026-05-15
|
|
3
|
+
type: pulse
|
|
4
|
+
scores:
|
|
5
|
+
build.team: { level: 3, trajectory: up, evidence: "Two permanent engineers hired" }
|
|
6
|
+
build.tools: { level: 4, trajectory: up, evidence: "Lead time and failure rate tracked" }
|
|
7
|
+
build.techniques: { level: 3, trajectory: up, evidence: "Consistent delivery cadence" }
|
|
8
|
+
run.team: { level: 3, trajectory: up, evidence: "Clear ownership and rotation" }
|
|
9
|
+
run.tools: { level: 3, trajectory: up, evidence: "Critical paths monitored" }
|
|
10
|
+
run.techniques: { level: 3, trajectory: flat, evidence: "Blameless reviews routine" }
|
|
11
|
+
plan.team: { level: 3, trajectory: flat, evidence: "Trusted by the board" }
|
|
12
|
+
plan.tools: { level: 1, trajectory: flat, evidence: "Still no roadmap tooling or analytics" }
|
|
13
|
+
plan.techniques: { level: 3, trajectory: up, evidence: "Strategy and prioritisation defined" }
|
|
14
|
+
notes: "Strong progress across Build and Run; plan.tools remains the binding constraint."
|
|
15
|
+
---
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
# Runboard rubric — the 9-dimension technical-leadership maturity model.
|
|
2
|
+
# Areas: build | run | plan. Lenses: team | tools | techniques.
|
|
3
|
+
# Levels: 1 Ad-hoc · 2 Repeatable · 3 Defined (target) · 4 Measured · 5 Optimising.
|
|
4
|
+
version: "1.0.0"
|
|
5
|
+
dimensions:
|
|
6
|
+
- key: build.team
|
|
7
|
+
area: build
|
|
8
|
+
lens: team
|
|
9
|
+
title: Build · Team
|
|
10
|
+
anchors:
|
|
11
|
+
1: "All delivery depends on contractors or heroics; no retained engineering capability."
|
|
12
|
+
2: "A core team exists but knowledge is concentrated in a few people; onboarding is informal."
|
|
13
|
+
3: "Roles and ownership are defined; the team can deliver without single points of failure."
|
|
14
|
+
4: "Team health and delivery capacity are measured and actively managed."
|
|
15
|
+
5: "The team continuously improves its own capability; hiring and growth are deliberate and data-informed."
|
|
16
|
+
- key: build.tools
|
|
17
|
+
area: build
|
|
18
|
+
lens: tools
|
|
19
|
+
title: Build · Tools
|
|
20
|
+
anchors:
|
|
21
|
+
1: "No shared build/CI; environments are set up by hand and differ per developer."
|
|
22
|
+
2: "Basic version control and some scripts exist, but builds are inconsistent."
|
|
23
|
+
3: "CI is in place; builds and environments are reproducible."
|
|
24
|
+
4: "Build/delivery metrics (lead time, failure rate) are tracked."
|
|
25
|
+
5: "Tooling is continuously optimised; investments are driven by measured developer-experience data."
|
|
26
|
+
- key: build.techniques
|
|
27
|
+
area: build
|
|
28
|
+
lens: techniques
|
|
29
|
+
title: Build · Techniques
|
|
30
|
+
anchors:
|
|
31
|
+
1: "No agreed engineering practices; quality is accidental."
|
|
32
|
+
2: "Some practices exist (reviews, tests) but are applied inconsistently."
|
|
33
|
+
3: "A defined delivery cadence and engineering standards are followed consistently."
|
|
34
|
+
4: "Practice effectiveness (coverage, defect escape) is measured."
|
|
35
|
+
5: "Practices evolve continuously based on outcome data; experimentation is routine."
|
|
36
|
+
- key: run.team
|
|
37
|
+
area: run
|
|
38
|
+
lens: team
|
|
39
|
+
title: Run · Team
|
|
40
|
+
anchors:
|
|
41
|
+
1: "No clear ownership of production; incidents are handled ad-hoc by whoever is around."
|
|
42
|
+
2: "Informal on-call exists; operational knowledge is concentrated."
|
|
43
|
+
3: "Clear operational ownership and a defined on-call rotation are in place."
|
|
44
|
+
4: "Operational load and responsiveness are measured and balanced."
|
|
45
|
+
5: "The team continuously reduces operational toil; reliability is a shared, optimised discipline."
|
|
46
|
+
- key: run.tools
|
|
47
|
+
area: run
|
|
48
|
+
lens: tools
|
|
49
|
+
title: Run · Tools
|
|
50
|
+
anchors:
|
|
51
|
+
1: "No monitoring; problems are discovered from users."
|
|
52
|
+
2: "Some monitoring exists but coverage is partial and alerting is noisy."
|
|
53
|
+
3: "Monitoring and alerting cover the critical paths."
|
|
54
|
+
4: "Service health and SLOs are measured against targets."
|
|
55
|
+
5: "Observability is continuously tuned; tooling pre-empts issues before users feel them."
|
|
56
|
+
- key: run.techniques
|
|
57
|
+
area: run
|
|
58
|
+
lens: techniques
|
|
59
|
+
title: Run · Techniques
|
|
60
|
+
anchors:
|
|
61
|
+
1: "No incident process; responses are improvised."
|
|
62
|
+
2: "A loose incident response exists but post-incident learning is rare."
|
|
63
|
+
3: "A defined incident process with blameless reviews is followed."
|
|
64
|
+
4: "Incident metrics (MTTR, recurrence) are measured."
|
|
65
|
+
5: "Operational practices continuously improve from incident and reliability data."
|
|
66
|
+
- key: plan.team
|
|
67
|
+
area: plan
|
|
68
|
+
lens: team
|
|
69
|
+
title: Plan · Team
|
|
70
|
+
anchors:
|
|
71
|
+
1: "No alignment between engineering and the business; comms are reactive."
|
|
72
|
+
2: "Some leadership comms exist but stakeholder alignment is inconsistent."
|
|
73
|
+
3: "Engineering leadership communicates clearly and is aligned with business goals."
|
|
74
|
+
4: "Alignment and stakeholder confidence are measured (e.g., via structured feedback)."
|
|
75
|
+
5: "Leadership continuously strengthens trust and influence; the function shapes strategy."
|
|
76
|
+
- key: plan.tools
|
|
77
|
+
area: plan
|
|
78
|
+
lens: tools
|
|
79
|
+
title: Plan · Tools
|
|
80
|
+
anchors:
|
|
81
|
+
1: "No roadmap or planning tooling; priorities live in someone's head."
|
|
82
|
+
2: "A basic backlog or roadmap exists but is not kept current."
|
|
83
|
+
3: "A maintained roadmap and planning tooling support prioritisation."
|
|
84
|
+
4: "Delivery against plan and outcome analytics are tracked."
|
|
85
|
+
5: "Planning tooling continuously informs strategy with measured outcome data."
|
|
86
|
+
- key: plan.techniques
|
|
87
|
+
area: plan
|
|
88
|
+
lens: techniques
|
|
89
|
+
title: Plan · Techniques
|
|
90
|
+
anchors:
|
|
91
|
+
1: "No strategy or prioritisation method; work is driven by whoever shouts loudest."
|
|
92
|
+
2: "Strategy is being established but prioritisation is inconsistent."
|
|
93
|
+
3: "A defined strategy and prioritisation method guide investment."
|
|
94
|
+
4: "Strategic bets and their outcomes are measured."
|
|
95
|
+
5: "Strategy continuously adapts from measured business and delivery outcomes."
|
package/package.json
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "runboard",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Local-first CLI for the Runboard technical-leadership maturity framework. Deterministic scoring core, portable AI adapters, no phone-home.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"engines": {
|
|
8
|
+
"node": ">=20"
|
|
9
|
+
},
|
|
10
|
+
"bin": {
|
|
11
|
+
"runboard": "dist/cli.js",
|
|
12
|
+
"runboard-mcp": "dist/mcp.js"
|
|
13
|
+
},
|
|
14
|
+
"files": [
|
|
15
|
+
"dist",
|
|
16
|
+
"rubric",
|
|
17
|
+
"templates",
|
|
18
|
+
"skills",
|
|
19
|
+
"examples",
|
|
20
|
+
"AGENTS.md",
|
|
21
|
+
"README.md",
|
|
22
|
+
"LICENSE"
|
|
23
|
+
],
|
|
24
|
+
"scripts": {
|
|
25
|
+
"build": "tsup",
|
|
26
|
+
"typecheck": "tsc --noEmit",
|
|
27
|
+
"test": "vitest run",
|
|
28
|
+
"test:watch": "vitest",
|
|
29
|
+
"lint": "biome check .",
|
|
30
|
+
"format": "biome format --write .",
|
|
31
|
+
"prepublishOnly": "npm run lint && npm run typecheck && npm run test && npm run build"
|
|
32
|
+
},
|
|
33
|
+
"dependencies": {
|
|
34
|
+
"@clack/prompts": "^0.7.0",
|
|
35
|
+
"@modelcontextprotocol/sdk": "^1.0.4",
|
|
36
|
+
"commander": "^12.1.0",
|
|
37
|
+
"eta": "^3.5.0",
|
|
38
|
+
"picocolors": "^1.1.1",
|
|
39
|
+
"yaml": "^2.6.1",
|
|
40
|
+
"zod": "^4.0.0"
|
|
41
|
+
},
|
|
42
|
+
"devDependencies": {
|
|
43
|
+
"@biomejs/biome": "^1.9.4",
|
|
44
|
+
"@types/node": "^20.17.0",
|
|
45
|
+
"@vitest/coverage-v8": "^2.1.8",
|
|
46
|
+
"tsup": "^8.3.5",
|
|
47
|
+
"typescript": "^5.7.2",
|
|
48
|
+
"vitest": "^2.1.8"
|
|
49
|
+
}
|
|
50
|
+
}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
# Runboard rubric — the 9-dimension technical-leadership maturity model.
|
|
2
|
+
# Areas: build | run | plan. Lenses: team | tools | techniques.
|
|
3
|
+
# Levels: 1 Ad-hoc · 2 Repeatable · 3 Defined (target) · 4 Measured · 5 Optimising.
|
|
4
|
+
version: "1.0.0"
|
|
5
|
+
dimensions:
|
|
6
|
+
- key: build.team
|
|
7
|
+
area: build
|
|
8
|
+
lens: team
|
|
9
|
+
title: Build · Team
|
|
10
|
+
anchors:
|
|
11
|
+
1: "All delivery depends on contractors or heroics; no retained engineering capability."
|
|
12
|
+
2: "A core team exists but knowledge is concentrated in a few people; onboarding is informal."
|
|
13
|
+
3: "Roles and ownership are defined; the team can deliver without single points of failure."
|
|
14
|
+
4: "Team health and delivery capacity are measured and actively managed."
|
|
15
|
+
5: "The team continuously improves its own capability; hiring and growth are deliberate and data-informed."
|
|
16
|
+
- key: build.tools
|
|
17
|
+
area: build
|
|
18
|
+
lens: tools
|
|
19
|
+
title: Build · Tools
|
|
20
|
+
anchors:
|
|
21
|
+
1: "No shared build/CI; environments are set up by hand and differ per developer."
|
|
22
|
+
2: "Basic version control and some scripts exist, but builds are inconsistent."
|
|
23
|
+
3: "CI is in place; builds and environments are reproducible."
|
|
24
|
+
4: "Build/delivery metrics (lead time, failure rate) are tracked."
|
|
25
|
+
5: "Tooling is continuously optimised; investments are driven by measured developer-experience data."
|
|
26
|
+
- key: build.techniques
|
|
27
|
+
area: build
|
|
28
|
+
lens: techniques
|
|
29
|
+
title: Build · Techniques
|
|
30
|
+
anchors:
|
|
31
|
+
1: "No agreed engineering practices; quality is accidental."
|
|
32
|
+
2: "Some practices exist (reviews, tests) but are applied inconsistently."
|
|
33
|
+
3: "A defined delivery cadence and engineering standards are followed consistently."
|
|
34
|
+
4: "Practice effectiveness (coverage, defect escape) is measured."
|
|
35
|
+
5: "Practices evolve continuously based on outcome data; experimentation is routine."
|
|
36
|
+
- key: run.team
|
|
37
|
+
area: run
|
|
38
|
+
lens: team
|
|
39
|
+
title: Run · Team
|
|
40
|
+
anchors:
|
|
41
|
+
1: "No clear ownership of production; incidents are handled ad-hoc by whoever is around."
|
|
42
|
+
2: "Informal on-call exists; operational knowledge is concentrated."
|
|
43
|
+
3: "Clear operational ownership and a defined on-call rotation are in place."
|
|
44
|
+
4: "Operational load and responsiveness are measured and balanced."
|
|
45
|
+
5: "The team continuously reduces operational toil; reliability is a shared, optimised discipline."
|
|
46
|
+
- key: run.tools
|
|
47
|
+
area: run
|
|
48
|
+
lens: tools
|
|
49
|
+
title: Run · Tools
|
|
50
|
+
anchors:
|
|
51
|
+
1: "No monitoring; problems are discovered from users."
|
|
52
|
+
2: "Some monitoring exists but coverage is partial and alerting is noisy."
|
|
53
|
+
3: "Monitoring and alerting cover the critical paths."
|
|
54
|
+
4: "Service health and SLOs are measured against targets."
|
|
55
|
+
5: "Observability is continuously tuned; tooling pre-empts issues before users feel them."
|
|
56
|
+
- key: run.techniques
|
|
57
|
+
area: run
|
|
58
|
+
lens: techniques
|
|
59
|
+
title: Run · Techniques
|
|
60
|
+
anchors:
|
|
61
|
+
1: "No incident process; responses are improvised."
|
|
62
|
+
2: "A loose incident response exists but post-incident learning is rare."
|
|
63
|
+
3: "A defined incident process with blameless reviews is followed."
|
|
64
|
+
4: "Incident metrics (MTTR, recurrence) are measured."
|
|
65
|
+
5: "Operational practices continuously improve from incident and reliability data."
|
|
66
|
+
- key: plan.team
|
|
67
|
+
area: plan
|
|
68
|
+
lens: team
|
|
69
|
+
title: Plan · Team
|
|
70
|
+
anchors:
|
|
71
|
+
1: "No alignment between engineering and the business; comms are reactive."
|
|
72
|
+
2: "Some leadership comms exist but stakeholder alignment is inconsistent."
|
|
73
|
+
3: "Engineering leadership communicates clearly and is aligned with business goals."
|
|
74
|
+
4: "Alignment and stakeholder confidence are measured (e.g., via structured feedback)."
|
|
75
|
+
5: "Leadership continuously strengthens trust and influence; the function shapes strategy."
|
|
76
|
+
- key: plan.tools
|
|
77
|
+
area: plan
|
|
78
|
+
lens: tools
|
|
79
|
+
title: Plan · Tools
|
|
80
|
+
anchors:
|
|
81
|
+
1: "No roadmap or planning tooling; priorities live in someone's head."
|
|
82
|
+
2: "A basic backlog or roadmap exists but is not kept current."
|
|
83
|
+
3: "A maintained roadmap and planning tooling support prioritisation."
|
|
84
|
+
4: "Delivery against plan and outcome analytics are tracked."
|
|
85
|
+
5: "Planning tooling continuously informs strategy with measured outcome data."
|
|
86
|
+
- key: plan.techniques
|
|
87
|
+
area: plan
|
|
88
|
+
lens: techniques
|
|
89
|
+
title: Plan · Techniques
|
|
90
|
+
anchors:
|
|
91
|
+
1: "No strategy or prioritisation method; work is driven by whoever shouts loudest."
|
|
92
|
+
2: "Strategy is being established but prioritisation is inconsistent."
|
|
93
|
+
3: "A defined strategy and prioritisation method guide investment."
|
|
94
|
+
4: "Strategic bets and their outcomes are measured."
|
|
95
|
+
5: "Strategy continuously adapts from measured business and delivery outcomes."
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: runboard-assess
|
|
3
|
+
description: Run a Runboard 9-dimension maturity self-assessment with a technical leader, then persist it via the runboard CLI. Use when someone wants to assess or score their engineering maturity.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Runboard: Assess
|
|
7
|
+
|
|
8
|
+
You conduct the assessment conversation. **The CLI computes and stores everything — you
|
|
9
|
+
never calculate scores, averages, or constraints yourself.**
|
|
10
|
+
|
|
11
|
+
## Steps
|
|
12
|
+
|
|
13
|
+
1. Ensure the workspace exists. If `.runboard/` is absent, run:
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
runboard init
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
2. Read the anchors from `.runboard/rubric.yaml`. For each of the nine dimensions
|
|
20
|
+
(`build.team`, `build.tools`, `build.techniques`, `run.team`, `run.tools`,
|
|
21
|
+
`run.techniques`, `plan.team`, `plan.tools`, `plan.techniques`):
|
|
22
|
+
- Show the 1–5 behavioural anchors.
|
|
23
|
+
- Ask what best matches today. Suggest a level, but let the leader decide.
|
|
24
|
+
- Capture a trajectory: `up`, `flat`, `down`, or `volatile`.
|
|
25
|
+
- Capture one line of evidence.
|
|
26
|
+
|
|
27
|
+
3. Persist the assessment in a single non-interactive call. Pass every dimension:
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
runboard assess \
|
|
31
|
+
--set build.team=2:flat:"All devs contracted; no retained capability" \
|
|
32
|
+
--set build.tools=3:up:"CI introduced last quarter" \
|
|
33
|
+
--set build.techniques=2:flat:"Cadence inconsistent" \
|
|
34
|
+
--set run.team=2:flat:"Informal on-call; knowledge concentrated" \
|
|
35
|
+
--set run.tools=2:up:"Monitoring being extended" \
|
|
36
|
+
--set run.techniques=3:flat:"Defined incident process" \
|
|
37
|
+
--set plan.team=2:up:"CEO comms strengthening" \
|
|
38
|
+
--set plan.tools=1:flat:"No roadmap tool or analytics" \
|
|
39
|
+
--set plan.techniques=2:up:"Strategy being established"
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
4. Show the result:
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
runboard board
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
Read back the average and the named binding constraint from the CLI output. Do not
|
|
49
|
+
restate numbers you computed yourself.
|
|
50
|
+
|
|
51
|
+
## Rules
|
|
52
|
+
|
|
53
|
+
- All nine dimensions are required in one `assess` call.
|
|
54
|
+
- Levels are 1–5; trajectory is one of up/flat/down/volatile.
|
|
55
|
+
- If the CLI reports a validation error, fix the offending dimension and re-run.
|
|
56
|
+
- Never overwrite an existing same-day assessment without confirming `--force` with the user.
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: runboard-board-update
|
|
3
|
+
description: Generate a board-ready, business-language technology update from the latest Runboard assessment. Use when someone needs a board pack, leadership update, or exec summary of engineering maturity.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Runboard: Board Update
|
|
7
|
+
|
|
8
|
+
The CLI renders the report from the latest data and a template. You make sure it reads
|
|
9
|
+
well for a non-technical board.
|
|
10
|
+
|
|
11
|
+
## Steps
|
|
12
|
+
|
|
13
|
+
1. Generate the board-update report:
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
runboard report --type board-update
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
2. Read the generated file under `.runboard/reports/board-update-<date>.md`.
|
|
20
|
+
|
|
21
|
+
3. Present it (max two pages). It already translates the framework's jargon into business
|
|
22
|
+
outcomes. Optionally also produce the shareable board:
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
runboard board --html
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
and point the leader at `.runboard/board.html`.
|
|
29
|
+
|
|
30
|
+
## Rules
|
|
31
|
+
|
|
32
|
+
- Keep it to business language and outcomes. Do not paste raw dimension keys into a board
|
|
33
|
+
pack — use the titles and the constraint framing the CLI provides.
|
|
34
|
+
- All figures come from the CLI. Do not compute or estimate maturity yourself.
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: runboard-pulse
|
|
3
|
+
description: Generate a Runboard pulse comparing the two latest maturity assessments and surface stuck dimensions. Use when someone asks what changed, what moved, or whether progress is real.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Runboard: Pulse
|
|
7
|
+
|
|
8
|
+
The CLI computes the deltas and the auto-triggers. You interpret them in plain language.
|
|
9
|
+
|
|
10
|
+
## Steps
|
|
11
|
+
|
|
12
|
+
1. Generate the pulse:
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
runboard pulse
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
This needs at least two assessments. If the CLI says so, run `runboard assess` to add
|
|
19
|
+
one (or explain that a second sitting is needed later).
|
|
20
|
+
|
|
21
|
+
2. Read the generated memo at `.runboard/reports/pulse-<date>.md`.
|
|
22
|
+
|
|
23
|
+
3. Summarise for the leader, using only the CLI's numbers:
|
|
24
|
+
- What improved, what regressed.
|
|
25
|
+
- Any **auto-triggers** — dimensions flat or regressing across three consecutive
|
|
26
|
+
assessments. Treat these as the things to act on.
|
|
27
|
+
|
|
28
|
+
## Rules
|
|
29
|
+
|
|
30
|
+
- Never compute deltas or decide what is "stuck" yourself — read it from the CLI output.
|
|
31
|
+
- Keep the read-back short and business-focused.
|