runward 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (91) hide show
  1. package/LICENSE +21 -0
  2. package/NOTICE.md +13 -0
  3. package/README.md +128 -0
  4. package/dist/cli.js +76 -0
  5. package/dist/commands/check.js +50 -0
  6. package/dist/commands/doctor.js +75 -0
  7. package/dist/commands/init.js +90 -0
  8. package/dist/commands/status.js +49 -0
  9. package/dist/commands/update.js +48 -0
  10. package/dist/lib/constants.js +2 -0
  11. package/dist/lib/mission.js +96 -0
  12. package/dist/lib/paths.js +28 -0
  13. package/dist/lib/styles.js +60 -0
  14. package/dist/lib/tools.js +59 -0
  15. package/dist/lib/write.js +30 -0
  16. package/package.json +29 -0
  17. package/templates/mission/adr/ADR-0000-template.md +38 -0
  18. package/templates/mission/architecture.md +60 -0
  19. package/templates/mission/decision-matrix.md +37 -0
  20. package/templates/mission/evaluation-rubric.md +60 -0
  21. package/templates/mission/floor.md +47 -0
  22. package/templates/mission/framing.md +58 -0
  23. package/templates/mission/mission-contract.md +58 -0
  24. package/templates/mission/observability-schema.md +53 -0
  25. package/templates/mission/port-contract.md +63 -0
  26. package/templates/mission/reference-stack.md +70 -0
  27. package/templates/mission/runbook.md +70 -0
  28. package/templates/mission/shared-bricks.md +74 -0
  29. package/templates/mission/threat-model.md +53 -0
  30. package/templates/rules/async-job-guardrails.md +95 -0
  31. package/templates/rules/async-post-turn-pipeline.md +96 -0
  32. package/templates/rules/async-scheduled-maintenance.md +95 -0
  33. package/templates/rules/cache-three-tier-architecture.md +44 -0
  34. package/templates/rules/checklist-day-zero-project.md +97 -0
  35. package/templates/rules/checklist-pre-production-observability.md +99 -0
  36. package/templates/rules/checklist-pre-production-performance.md +109 -0
  37. package/templates/rules/checklist-pre-production-resilience.md +99 -0
  38. package/templates/rules/checklist-pre-production-security.md +86 -0
  39. package/templates/rules/config-secrets-boundary.md +57 -0
  40. package/templates/rules/config-typing-zod.md +78 -0
  41. package/templates/rules/contracts-governance.md +64 -0
  42. package/templates/rules/data-memory-consolidation.md +81 -0
  43. package/templates/rules/data-memory-invalidation.md +90 -0
  44. package/templates/rules/data-memory-scoring.md +154 -0
  45. package/templates/rules/data-migrations-forward-only.md +55 -0
  46. package/templates/rules/data-orphan-cleanup.md +142 -0
  47. package/templates/rules/data-ttl-types.md +100 -0
  48. package/templates/rules/eval-loop.md +52 -0
  49. package/templates/rules/frontier-deterministic-boundary.md +91 -0
  50. package/templates/rules/hexa-adapter-pattern.md +85 -0
  51. package/templates/rules/hexa-architecture.md +84 -0
  52. package/templates/rules/hexa-move-deterministic-out.md +93 -0
  53. package/templates/rules/hexa-recommended-stack.md +33 -0
  54. package/templates/rules/hexa-typescript-native.md +80 -0
  55. package/templates/rules/observability-alert-configuration.md +160 -0
  56. package/templates/rules/observability-llm-metrics.md +150 -0
  57. package/templates/rules/observability-startup-provider-log.md +128 -0
  58. package/templates/rules/observability-structured-json-logs.md +138 -0
  59. package/templates/rules/patterns-memory-router-tiered.md +139 -0
  60. package/templates/rules/patterns-prompt-compiler.md +126 -0
  61. package/templates/rules/patterns-request-id-propagation.md +137 -0
  62. package/templates/rules/process-adr-and-journal.md +50 -0
  63. package/templates/rules/provider-llm-auto-detection.md +54 -0
  64. package/templates/rules/provider-no-crash-missing-env.md +67 -0
  65. package/templates/rules/quality-codebase-metrics.md +115 -0
  66. package/templates/rules/quality-zod-input-validation.md +131 -0
  67. package/templates/rules/resilience-fail-open.md +65 -0
  68. package/templates/rules/resilience-multi-provider-fallback.md +100 -0
  69. package/templates/rules/resilience-retry-backoff.md +115 -0
  70. package/templates/rules/resilience-retryable-errors.md +107 -0
  71. package/templates/rules/routing-confidence-upgrade.md +89 -0
  72. package/templates/rules/routing-model-cost-ratios.md +68 -0
  73. package/templates/rules/routing-smart-complexity.md +131 -0
  74. package/templates/rules/scaling-db-connection-pooling.md +121 -0
  75. package/templates/rules/scaling-distributed-rate-limiting.md +141 -0
  76. package/templates/rules/scaling-state-externalization.md +84 -0
  77. package/templates/rules/security-prompt-injection.md +63 -0
  78. package/templates/rules/state-event-sourcing.md +66 -0
  79. package/templates/rules/tools-registry-pattern.md +153 -0
  80. package/templates/rules/tools-scope-atomicity.md +103 -0
  81. package/templates/targets/AGENTS.md +32 -0
  82. package/templates/workflows/architect.md +50 -0
  83. package/templates/workflows/brownfield.md +52 -0
  84. package/templates/workflows/decision-loop.md +52 -0
  85. package/templates/workflows/floor.md +60 -0
  86. package/templates/workflows/frame.md +69 -0
  87. package/templates/workflows/govern.md +55 -0
  88. package/templates/workflows/handover.md +55 -0
  89. package/templates/workflows/iterate.md +52 -0
  90. package/templates/workflows/method.md +53 -0
  91. package/templates/workflows/review.md +59 -0
@@ -0,0 +1,96 @@
1
+ import { existsSync, readFileSync, readdirSync } from "node:fs";
2
+ import { join } from "node:path";
3
+ import { TEMPLATES } from "./paths.js";
4
+ export const PHASES = [
5
+ {
6
+ id: "frame", label: "1 · Frame",
7
+ artifacts: [
8
+ { label: "Framing note", relPath: "framing.md", templateKey: "framing.md" },
9
+ { label: "Steering contract", relPath: "mission-contract.md", templateKey: "mission-contract.md" },
10
+ ],
11
+ },
12
+ {
13
+ id: "architect", label: "2 · Architect",
14
+ artifacts: [
15
+ { label: "Architecture note", relPath: "architecture.md", templateKey: "architecture.md" },
16
+ { label: "Decision matrix", relPath: "decision-matrix.md", templateKey: "decision-matrix.md" },
17
+ { label: "Decision journal (≥1 ADR)", relPath: "adr" },
18
+ { label: "Port contracts (≥1 filled)", relPath: "contracts" },
19
+ ],
20
+ },
21
+ {
22
+ id: "floor", label: "3 · Floor",
23
+ artifacts: [{ label: "Floor note (measured proof)", relPath: "floor.md", templateKey: "floor.md" }],
24
+ },
25
+ {
26
+ id: "govern", label: "5 · Govern (day zero)",
27
+ artifacts: [
28
+ { label: "Threat model", relPath: "governance/threat-model.md", templateKey: "threat-model.md" },
29
+ { label: "Evaluation rubric", relPath: "governance/evaluation-rubric.md", templateKey: "evaluation-rubric.md" },
30
+ { label: "Observability schema", relPath: "governance/observability-schema.md", templateKey: "observability-schema.md" },
31
+ ],
32
+ },
33
+ {
34
+ id: "handover", label: "6 · Hand over",
35
+ artifacts: [{ label: "Recovery runbook", relPath: "runbook.md", templateKey: "runbook.md" }],
36
+ },
37
+ ];
38
+ export function findMissionRoot(cwd) {
39
+ let dir = cwd;
40
+ for (let i = 0; i < 12; i++) {
41
+ // A mission root contains runward/ with at least the framing note —
42
+ // a directory merely named "runward" (e.g. this repository) does not count.
43
+ if (existsSync(join(dir, "runward", "framing.md")))
44
+ return dir;
45
+ const parent = join(dir, "..");
46
+ if (parent === dir)
47
+ break;
48
+ dir = parent;
49
+ }
50
+ return null;
51
+ }
52
+ // A placeholder is bracketed prose with whitespace ([the real process as observed…]),
53
+ // which distinguishes it from cross-references like [ADR-0001] or [framing.md].
54
+ // A closing bracket followed by "(" is a markdown link ([floor note](floor.md)) — never a placeholder.
55
+ const PLACEHOLDER = /\[[^\]\n]*\s[^\]\n]{1,80}\](?!\()/g;
56
+ export function artifactState(missionDir, a) {
57
+ const path = join(missionDir, a.relPath);
58
+ if (!existsSync(path))
59
+ return "missing";
60
+ // Special case: ADR directory — count real ADRs beyond the template.
61
+ if (a.relPath === "adr") {
62
+ const adrs = readdirSync(path).filter((f) => /^ADR-\d+/.test(f) && !f.includes("0000"));
63
+ return adrs.length > 0 ? "filled" : "untouched";
64
+ }
65
+ // Special case: contracts directory — filled as soon as one .md is not the raw port-contract template.
66
+ if (a.relPath === "contracts") {
67
+ const template = readFileSync(join(TEMPLATES, "mission", "port-contract.md"), "utf8").trim();
68
+ const contracts = readdirSync(path).filter((f) => f.endsWith(".md"));
69
+ if (contracts.length === 0)
70
+ return "untouched";
71
+ const hasFilled = contracts.some((f) => readFileSync(join(path, f), "utf8").trim() !== template);
72
+ return hasFilled ? "filled" : "untouched";
73
+ }
74
+ const content = readFileSync(path, "utf8");
75
+ if (a.templateKey) {
76
+ const template = readFileSync(join(TEMPLATES, "mission", a.templateKey), "utf8");
77
+ if (content.trim() === template.trim())
78
+ return "untouched";
79
+ }
80
+ const placeholders = (content.match(PLACEHOLDER) || []).length;
81
+ if (placeholders >= 3)
82
+ return "in-progress";
83
+ return "filled";
84
+ }
85
+ export function analyze(missionDir) {
86
+ const phases = PHASES.map((spec) => {
87
+ const artifacts = spec.artifacts.map((artifact) => ({ artifact, state: artifactState(missionDir, artifact) }));
88
+ return { spec, artifacts, complete: artifacts.every((a) => a.state === "filled") };
89
+ });
90
+ const adrDir = join(missionDir, "adr");
91
+ const adrCount = existsSync(adrDir)
92
+ ? readdirSync(adrDir).filter((f) => /^ADR-\d+/.test(f) && !f.includes("0000")).length
93
+ : 0;
94
+ const firstIncomplete = phases.find((p) => !p.complete);
95
+ return { phases, adrCount, currentPhase: firstIncomplete ? firstIncomplete.spec.label : "all gates passed" };
96
+ }
@@ -0,0 +1,28 @@
1
+ import { readFileSync } from "node:fs";
2
+ import { dirname, join } from "node:path";
3
+ import { fileURLToPath } from "node:url";
4
+ const HERE = dirname(fileURLToPath(import.meta.url));
5
+ /** Package root (works from dist/lib/ at runtime). */
6
+ export const PKG_ROOT = join(HERE, "..", "..");
7
+ export const TEMPLATES = join(PKG_ROOT, "templates");
8
+ export const VERSION = JSON.parse(readFileSync(join(PKG_ROOT, "package.json"), "utf8")).version;
9
+ /** Mission layout: template file -> destination inside runward/ */
10
+ export const MISSION_LAYOUT = {
11
+ "framing.md": "framing.md",
12
+ "architecture.md": "architecture.md",
13
+ "decision-matrix.md": "decision-matrix.md",
14
+ "mission-contract.md": "mission-contract.md",
15
+ "reference-stack.md": "reference-stack.md",
16
+ "shared-bricks.md": "shared-bricks.md",
17
+ "floor.md": "floor.md",
18
+ "adr/ADR-0000-template.md": "adr/ADR-0000-template.md",
19
+ "threat-model.md": "governance/threat-model.md",
20
+ "evaluation-rubric.md": "governance/evaluation-rubric.md",
21
+ "observability-schema.md": "governance/observability-schema.md",
22
+ "port-contract.md": "contracts/port-contract.md",
23
+ "runbook.md": "runbook.md",
24
+ };
25
+ export const WORKFLOWS = [
26
+ "method", "frame", "architect", "floor", "iterate",
27
+ "govern", "handover", "brownfield", "review", "decision-loop",
28
+ ];
@@ -0,0 +1,60 @@
1
+ import chalk from "chalk";
2
+ // Respect the NO_COLOR standard (https://no-color.org/)
3
+ if (process.env.NO_COLOR)
4
+ chalk.level = 0;
5
+ // Runward palette — electric indigo, tuned for dark terminals.
6
+ export const colors = {
7
+ primary: "#7B74FF", // electric indigo, readable on dark bg
8
+ primaryLight: "#A8A3FF", // highlights, current step
9
+ primaryDark: "#5B54F0", // borders, secondary accents
10
+ secondary: "#B0B8C4",
11
+ gray: "#8B95A5",
12
+ darkGray: "#5A6577",
13
+ };
14
+ export const c = {
15
+ primary: chalk.hex(colors.primary),
16
+ primaryLight: chalk.hex(colors.primaryLight),
17
+ primaryDark: chalk.hex(colors.primaryDark),
18
+ secondary: chalk.hex(colors.secondary),
19
+ gray: chalk.hex(colors.gray),
20
+ darkGray: chalk.hex(colors.darkGray),
21
+ bold: chalk.bold,
22
+ dim: chalk.dim,
23
+ white: chalk.white,
24
+ primaryBold: chalk.hex(colors.primary).bold,
25
+ success: chalk.green,
26
+ error: chalk.red,
27
+ warning: chalk.yellow,
28
+ info: chalk.cyan,
29
+ muted: chalk.hex(colors.gray),
30
+ };
31
+ export const status = {
32
+ success: (msg) => c.success("✓ ") + c.white(msg),
33
+ error: (msg) => c.error("✗ ") + c.white(msg),
34
+ warning: (msg) => c.warning("! ") + c.white(msg),
35
+ info: (msg) => c.info("• ") + c.white(msg),
36
+ skip: (msg) => c.darkGray("○ ") + c.gray(msg),
37
+ };
38
+ export function createHeader(title, subtitle) {
39
+ const width = Math.min(process.stdout.columns || 80, 72);
40
+ const inner = width - 4;
41
+ const pad = (s) => s + " ".repeat(Math.max(0, inner - stripAnsi(s).length));
42
+ const lines = [
43
+ c.primaryDark("┌" + "─".repeat(width - 2) + "┐"),
44
+ c.primaryDark("│ ") + pad(c.primaryBold(title)) + c.primaryDark(" │"),
45
+ ];
46
+ if (subtitle)
47
+ lines.push(c.primaryDark("│ ") + pad(c.gray(subtitle)) + c.primaryDark(" │"));
48
+ lines.push(c.primaryDark("└" + "─".repeat(width - 2) + "┘"));
49
+ return "\n" + lines.join("\n") + "\n";
50
+ }
51
+ export function section(title) {
52
+ return "\n" + c.primaryBold(title) + "\n" + c.darkGray("─".repeat(Math.min(title.length + 8, 60)));
53
+ }
54
+ export function isNonInteractive() {
55
+ return process.env.RUNWARD_YES === "1" || !process.stdout.isTTY;
56
+ }
57
+ function stripAnsi(s) {
58
+ // eslint-disable-next-line no-control-regex
59
+ return s.replace(/\[[0-9;]*m/g, "");
60
+ }
@@ -0,0 +1,59 @@
1
+ import { join } from "node:path";
2
+ import { WORKFLOWS } from "./paths.js";
3
+ const pointer = (wf) => [
4
+ "---",
5
+ `description: Runward — run the ${wf} workflow against the current mission state`,
6
+ "---",
7
+ "",
8
+ `Read \`runward/workflows/${wf}.md\` and execute it against the current mission state in \`runward/\`.`,
9
+ "Respect the charter in `AGENTS.md`. Do not mark the phase done unless its Definition of Done is demonstrably met.",
10
+ "",
11
+ ].join("\n");
12
+ const rulesBody = [
13
+ "This project follows the Runward method (after the spec: ship and run).",
14
+ "The agent charter is `AGENTS.md` — its boundaries are non-negotiable.",
15
+ "The method lives in `runward/workflows/` (start with `method.md`); the mission state lives in `runward/`.",
16
+ "Every structural decision goes through `runward/workflows/decision-loop.md` and is locked as an ADR in `runward/adr/`,",
17
+ "with a dated re-evaluation trigger. Complexity is added only on an objective trigger — no trigger, no change.",
18
+ "",
19
+ ].join("\n");
20
+ export const TOOL_PROFILES = [
21
+ {
22
+ id: "claude",
23
+ label: "Claude Code (.claude/commands/rw-*)",
24
+ files: (root) => WORKFLOWS.map((wf) => ({ path: join(root, ".claude", "commands", `rw-${wf}.md`), content: pointer(wf) })),
25
+ },
26
+ {
27
+ id: "cursor",
28
+ label: "Cursor (.cursor/rules/runward.mdc)",
29
+ files: (root) => [{
30
+ path: join(root, ".cursor", "rules", "runward.mdc"),
31
+ content: ["---", "description: Runward delivery method", "alwaysApply: true", "---", "", rulesBody].join("\n"),
32
+ }],
33
+ },
34
+ {
35
+ id: "copilot",
36
+ label: "GitHub Copilot (.github/copilot-instructions.md)",
37
+ files: (root) => [{
38
+ path: join(root, ".github", "copilot-instructions.md"),
39
+ content: "# Runward\n\n" + rulesBody,
40
+ }],
41
+ },
42
+ {
43
+ id: "gemini",
44
+ label: "Gemini CLI (GEMINI.md)",
45
+ files: (root) => [{
46
+ path: join(root, "GEMINI.md"),
47
+ content: "# Runward\n\n" + rulesBody,
48
+ }],
49
+ },
50
+ {
51
+ id: "windsurf",
52
+ label: "Windsurf (.windsurf/rules/runward.md)",
53
+ files: (root) => [{
54
+ path: join(root, ".windsurf", "rules", "runward.md"),
55
+ content: "# Runward\n\n" + rulesBody,
56
+ }],
57
+ },
58
+ ];
59
+ export const TOOL_IDS = TOOL_PROFILES.map((t) => t.id);
@@ -0,0 +1,30 @@
1
+ import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
2
+ import { dirname, relative } from "node:path";
3
+ import { c } from "./styles.js";
4
+ export function makeWriter(opts) {
5
+ const stats = { written: 0, skipped: 0 };
6
+ function write(path, content) {
7
+ const rel = relative(opts.root, path) || path;
8
+ if (existsSync(path) && !opts.force) {
9
+ stats.skipped++;
10
+ console.log(` ${c.darkGray("skip ")} ${c.gray(rel)} ${c.darkGray("(exists — --force to overwrite)")}`);
11
+ return;
12
+ }
13
+ if (opts.dryRun) {
14
+ stats.written++;
15
+ console.log(` ${c.info("would write")} ${rel}`);
16
+ return;
17
+ }
18
+ mkdirSync(dirname(path), { recursive: true });
19
+ writeFileSync(path, content);
20
+ stats.written++;
21
+ console.log(` ${c.success("write")} ${c.white(rel)}`);
22
+ }
23
+ function copy(src, dest, transform) {
24
+ let content = readFileSync(src, "utf8");
25
+ if (transform)
26
+ content = transform(content);
27
+ write(dest, content);
28
+ }
29
+ return { write, copy, stats };
30
+ }
package/package.json ADDED
@@ -0,0 +1,29 @@
1
+ {
2
+ "name": "runward",
3
+ "version": "0.6.0",
4
+ "description": "After the spec: ship and run. A delivery framework for agentic systems — floor first, evolution on evidence, governance from day zero, handover with proof.",
5
+ "keywords": ["agentic", "ai-agents", "spec-driven", "delivery", "governance", "llm", "architecture"],
6
+ "author": "Thibault Souris",
7
+ "license": "MIT",
8
+ "repository": { "type": "git", "url": "git+https://github.com/stranxik/runward.git" },
9
+ "homepage": "https://runward.dev",
10
+ "bugs": { "url": "https://github.com/stranxik/runward/issues" },
11
+ "type": "module",
12
+ "bin": { "runward": "dist/cli.js" },
13
+ "files": ["dist", "templates", "README.md", "NOTICE.md"],
14
+ "engines": { "node": ">=20" },
15
+ "scripts": {
16
+ "build": "tsc",
17
+ "test": "npm run build && node test/smoke.js",
18
+ "prepublishOnly": "npm run build && node test/smoke.js"
19
+ },
20
+ "dependencies": {
21
+ "@inquirer/prompts": "^7.0.0",
22
+ "chalk": "^5.6.0",
23
+ "commander": "^14.0.0"
24
+ },
25
+ "devDependencies": {
26
+ "typescript": "^5.5.0",
27
+ "@types/node": "^22.0.0"
28
+ }
29
+ }
@@ -0,0 +1,38 @@
1
+ # ADR-[number]: [short decision title]
2
+
3
+ > **Usage.** An ADR records one structuring decision at the moment it is taken, with its context and consequences, so a future reader understands why the system is what it is. Ground rules: every decision has a lean default and an explicit evolution trigger; no decision is irreversible, because all are taken behind a boundary. The **reevaluation trigger is mandatory and dated** — an ADR without a reopening signal hardens into dogma. One ADR per decision: short, dated, numbered. Never edit an accepted ADR; write a new one that supersedes it. Replace every `[placeholder]`; delete this notice on delivery.
4
+
5
+ **Date**: [YYYY-MM-DD]
6
+ **Status**: [proposed | accepted | superseded by ADR-[n] | deprecated]
7
+ **Deciders**: [names or roles]
8
+ **Method**: [e.g. decision-loop: reality-check, sourced state of the art, challenge, durable position]
9
+
10
+ ## Context
11
+
12
+ [The force that demands a decision now. The problem as observed, not as imagined. The hard constraints in play (sovereignty, regulated sector, legacy integration, confidentiality, human approval). What makes this choice structuring rather than local. State at which boundary the decision is taken: domain port, adapter, process boundary, contract.]
13
+
14
+ ## Decision
15
+
16
+ [What is decided, phrased as a default being applied. One sentence of commitment, then only the strictly necessary detail. If the decision follows a default from the decision matrix, name it and say why it applies here.]
17
+
18
+ ## Alternatives discarded
19
+
20
+ - **[Alternative A]**: [why discarded — the technical reason, not the habit.]
21
+ - **[Alternative B]**: [why discarded.]
22
+ - **[Alternative C]**: [why discarded, or tempered rather than eliminated.]
23
+
24
+ ## Consequences
25
+
26
+ - **Positive**: [what this decision enables or simplifies.]
27
+ - **Negative, accepted**: [the cost taken on knowingly — e.g. the explicit translation of a legacy adapter, or eventual consistency when crossing a process boundary.]
28
+ - **On other boundaries**: [impact on contracts, observability, security, evaluation.]
29
+
30
+ ## Reevaluation trigger (mandatory, dated)
31
+
32
+ [The objective, observable signal that will command reopening this decision — a measurable condition, never an intuition. Examples: latency or throughput proven insufficient; move to multi-instance; a genuinely parallelizable subtask appears; a new compliance constraint; behavioral divergence measured beyond a threshold. Until this signal appears, apply the decision without reopening it.]
33
+
34
+ **Trigger set on**: [YYYY-MM-DD] · **Watched via**: [metric, dashboard, or review cadence]
35
+
36
+ ## References
37
+
38
+ - [Public source, related ADR, port or contract concerned.]
@@ -0,0 +1,60 @@
1
+ # Architecture Note: [system name]
2
+
3
+ > **Usage.** Produce this note at the end of the `architect` workflow. It states boundaries before technology: the ports, the integration protocol, the default topology with its triggers, and what deliberately stays open. Keep it to a few pages — it is a map, not a detailed design dossier. Every structuring decision referenced here must already be locked in an ADR; the note cites, it does not decide. Replace every `[placeholder]`; delete this notice on delivery.
4
+
5
+ **Date**: [YYYY-MM-DD] · **Version**: [vX.Y] · **Framing note**: [link] · **ADR journal**: [link]
6
+
7
+ ## 1. Context
8
+
9
+ [One paragraph: the problem and success criterion from framing, and the floor this architecture must carry. No restating of the full framing note — link it.]
10
+
11
+ ## 2. Boundaries
12
+
13
+ [The two boundaries that make the stack secondary.]
14
+
15
+ - **Domain ports.** [How the domain expresses its needs as contracts, and why the model port is a port like any other: the reasoning engine is bound by its contract, not its brand — a replaceable adapter behind a stable port.]
16
+ - **Integration protocol.** [The standardized tool protocol through which out-of-process capabilities are exposed and consumed. A service is an adapter that moved into its own process; the domain does not change.]
17
+
18
+ ## 3. Ports
19
+
20
+ [One line per port; the full contract of each lives in its own port-contract spec.]
21
+
22
+ | Port | Direction | Intent | Contract version | Spec |
23
+ |---|---|---|---|---|
24
+ | [ModelPort] | [secondary] | [provide a model completion] | [v0.1] | [link] |
25
+ | [PersistencePort] | [secondary] | [persist the interaction log] | [v0.1] | [link] |
26
+ | [ActionPort] | [secondary] | [execute an action — approval required: yes/no] | [v0.1] | [link] |
27
+ | [EntryPort] | [primary] | [receive work: interface / API / tool protocol] | [v0.1] | [link] |
28
+
29
+ ## 4. Default topology and triggers
30
+
31
+ [The starting silhouette and the signal that would change each default. Defaults apply now; triggers are crossed only in `iterate`.]
32
+
33
+ | Default | Rationale | Evolution trigger |
34
+ |---|---|---|
35
+ | Modular hexagonal monolith | [one deployable, pure domain plus adapters] | [load, isolation, release-cycle, or availability signal] |
36
+ | Single orchestrator | [composes, carries no business logic] | [genuinely parallelizable subtasks] |
37
+ | Tool registry + middleware chain | [single transversal surface, thin channel] | [—] |
38
+ | One core language, thin model SDK | [no heavy chain framework] | [mature library or proven performance need → sidecar] |
39
+
40
+ ## 5. What stays open
41
+
42
+ [Explicitly undecided: language(s), framework, model provider, hosting. Each is an adapter decision, taken later behind the contracts above, justified by a local technical reason.]
43
+
44
+ ## 6. Legacy integration (if any)
45
+
46
+ [Where the anticorruption layer sits, which dialect it translates, and the named cost of that translation. The boundary is never free on legacy.]
47
+
48
+ ## 7. Target, named
49
+
50
+ [The architecture this system tends toward, per the framing note — named for direction, not built.]
51
+
52
+ ## 8. Decisions
53
+
54
+ [Pointers only. Every structuring choice is locked in an ADR before appearing here.]
55
+
56
+ | Decision | ADR |
57
+ |---|---|
58
+ | [starting topology] | [ADR-0001] |
59
+ | [core language] | [ADR-0002] |
60
+ | [legacy integration strategy] | [ADR-0003] |
@@ -0,0 +1,37 @@
1
+ # Decision Matrix
2
+
3
+ How to use this file: every structural decision below carries **one sober default and one explicit trigger**. You start on the default. You only move when the trigger fires — measured, observed, named. **No trigger, no change. Every switch is an ADR** (`runward/adr/`), with the evidence that fired the trigger and a date to re-evaluate. Fill the matrix during the Architect phase; reopen it at every Iterate gate.
4
+
5
+ | Decision | Sober default | Switch when |
6
+ |---|---|---|
7
+ | Core language | One typed language for the whole core, chosen for team fluency and ecosystem depth | A capability genuinely requires another runtime, and the need is measured and isolated |
8
+ | Specialized capability | Implement it in the core language | A mature library exists only in another ecosystem (OCR, NLP, scientific computing) — wrap it as a sidecar behind a contract |
9
+ | Hot-path component | Same runtime as the rest of the core | Profiling shows this component dominates latency or cost, and a faster runtime demonstrably fixes it |
10
+ | Service split | Modular monolith, single process, boundaries enforced by ports | A module needs its own scaling profile, release cycle, or failure isolation — observed, not predicted |
11
+ | Legacy integration | A thin adapter wrapping direct calls to the legacy system | Legacy concepts start leaking into your domain — install a full anticorruption layer that translates and validates at the boundary |
12
+ | Number of agents | One agent, one loop | The task decomposes into parallelizable subtasks of real complexity, or context isolation is required — several agents under a single orchestrator |
13
+ | Model abstraction | Every model call goes through a single port, one default model | Measured cost or quality spread justifies tiered routing behind the same port; bypassing the port for a direct SDK call requires an ADR of its own |
14
+ | State | Stateless reducer: state in, decision out, nothing hidden inside the process | Audit, replay, or debugging needs history — immutable journal of events plus derived views |
15
+ | Crossing the process boundary | In-process function calls behind ports | A consumer moves to another process — promote the port contract to a versioned network API; nothing else changes |
16
+ | Contract evolution | Versioned contracts, additive changes only, consumers read tolerantly (unknown fields ignored) | A breaking change is unavoidable — expand-then-contract: serve both shapes, migrate every consumer, then retire the old one |
17
+ | Memory & forgetting | Score each memory for value and decay; invalidate rather than delete, so nothing silently disappears | Memory grows past useful recall — consolidate into summaries that keep pointers back to their sources |
18
+ | Evaluation | Deterministic tests for deterministic code, plus a guarded continuous evaluation loop for model behavior | The loop is stable and trusted — allow bounded auto-tuning: parameters only, inside hard limits, owned by a human |
19
+ | Budget & discovery (multi-agent) | One central counter caps total spend across all agents | Contention on the counter slows the fleet — hand out lease blocks of budget that agents consume locally and return, paired with shared capability sheets: block allocation plus a shared capability registry, both handed out the moment budget leaves the central process |
20
+ | Model unavailable | Retry with backoff against the primary provider | The outage persists — fall back to a second provider behind the same port; the domain never notices the swap |
21
+ | Model change | Current model pinned; no silent upgrades | A candidate beats the incumbent in shadow deployment on your own rubric — staged rollout with rollback ready |
22
+ | Waiting on human approval | Suspend the run, persist its state, rehydrate when the decision lands — never hold a process open | Approvals become a chronic bottleneck — never start blocking; batch low-urgency requests into a queue and revisit the autonomy boundary instead |
23
+ | Non-critical vs sensitive | Non-critical dependencies fail open: the feature degrades, the system continues | The action touches money, private data leaving the system, or anything irreversible — fail closed: no guard response, no action |
24
+ | Delegation autonomy | Bounded autonomy: the agent acts within templates, budgets, and pre-approved action lists | Evidence of consistent reliability on a class of actions — widen the bounds for that class, one ADR at a time |
25
+ | Untrusted input | Least privilege everywhere, human approval on consequential actions, and never all three of: private data, untrusted content, external egress (2-of-3 rule) | A workflow claims to need all three — re-architect to break the triad: isolate, sanitize, or gate the exfiltration channel |
26
+ | Agent identity | Each agent runs as its own principal, with its own permissions and audit trail | The agent must act on behalf of a user — explicit, bounded, revocable delegation; never shared credentials |
27
+ | Execution secrets | The agent holds only a proxy token; real keys are injected at the network boundary, outside the model's reach | A target system cannot sit behind the proxy — isolate that call in a dedicated adapter the agent cannot introspect |
28
+ | Shared brick | Consumed through a port; discovered through an index — and the index stays an index, not a brain | A brick gains multiple consumers — version its contract and run it as a product, still behind the port |
29
+
30
+ ## Express decision tree
31
+
32
+ Four questions, in order. If none fires, stay on the sober default.
33
+
34
+ 1. **Does the task need a specialized library from another ecosystem?** → Sidecar behind a contract.
35
+ 2. **Does a component have its own load profile, release cycle, or isolation requirement?** → Split that service.
36
+ 3. **Is the work parallelizable, with real complexity in each branch?** → Multiple agents under one orchestrator.
37
+ 4. **Does the load require more than one instance?** → Externalize state first, then replicate.
@@ -0,0 +1,60 @@
1
+ # Evaluation Rubric: [agent or capability under evaluation]
2
+
3
+ > **Usage.** A deterministic system is tested; an agentic system is tested **and** evaluated. This rubric serves the evaluation half: measuring the quality of non-deterministic behavior where a test can no longer answer true or false. Scoring follows an explicit rubric; every scenario carries expected and forbidden terms, which makes **abstention** (refusing to invent) weigh as much as recall. Evaluation is not a final gate but a continuous loop, sampled off the hot path from the trace stream. Scoring is hybrid: deterministic wherever a guarantee exists, a judge model only for the irreducibly behavioral. Two mandatory guards: a **hold-out the optimizer never sees**, and an **anchored judge** (pinned version, or an anchor set replayed at every judge change) — without them the quality series silently becomes incomparable. Replace every `[placeholder]`; delete this notice on delivery.
4
+
5
+ **Version**: [vX.Y] · **Anchored judge**: [pinned version or anchor set] · **Rerun triggers**: [any change touching memory, prompts, or routing]
6
+
7
+ ## 1. Capabilities evaluated
8
+
9
+ [Select and adapt the relevant capabilities. For long-memory benches, the six core ones below.]
10
+
11
+ | Capability | What it verifies |
12
+ |---|---|
13
+ | Direct recall | [retrieve a fact given many turns earlier] |
14
+ | Multi-constraint recall | [combine several scattered pieces of information into one answer] |
15
+ | Knowledge update | [return the most recent value after a correction] |
16
+ | Temporal reasoning | [state what was true at a given date; distinguish when a fact was learned from when it was valid] |
17
+ | Abstention | [refuse to invent when the information was never given] |
18
+ | Long session | [remember across enough turns to trigger summarization] |
19
+
20
+ ## 2. Scoring scale
21
+
22
+ [Explicit and reproducible.]
23
+
24
+ | Answer quality | Score |
25
+ |---|---|
26
+ | Complete — restates all key elements | [max] |
27
+ | Partial — misses one | [intermediate] |
28
+ | Vague but not wrong | [half] |
29
+ | Wrong, or hallucinated where abstention was required | [zero] |
30
+
31
+ ## 3. Scenarios
32
+
33
+ [One block per scenario: the multi-turn conversation, the final question, and the expected / forbidden terms.]
34
+
35
+ ### Scenario [ID] — capability: [target capability]
36
+
37
+ - **Multi-turn conversation**: [describe the turns in order.]
38
+ - **Final question**: [the question asked at the end.]
39
+ - **Expected terms**: [elements a good answer must contain.]
40
+ - **Forbidden terms**: [elements whose presence signals hallucination or leakage. For an abstention scenario, the right answer is a motivated refusal; any invented fact is forbidden.]
41
+
42
+ ## 4. Hold-out (non-gameable)
43
+
44
+ [The strong guard that stops self-tuning from drifting toward whatever flatters the judge.]
45
+
46
+ - **Composition**: [a subset of scenarios with verifiable ground truth, invisible to the optimizer.]
47
+ - **Use**: [replayed to trigger rollback if its score drops, independently of the training score.]
48
+ - **Limit**: [for purely subjective behavior without ground truth, the safety net reverts to human sampling; the self-tuning envelope stays narrow.]
49
+
50
+ ## 5. Judge anchoring
51
+
52
+ [The judge is itself a model, and it will be updated.]
53
+
54
+ - **Anchoring method**: [pinned version, or an anchor set replayed at every judge change to recalibrate the measure.]
55
+ - **Judge scope**: [only irreducibly behavioral quality. The hard floor — safety, security, authorization, audit — stays deterministic, never delegated to the judge.]
56
+ - **Action boundary**: [the loop produces signals and recommendations; acting on them goes through bounded, audited, pre-approved tuning or human validation — never autonomous self-rewriting.]
57
+
58
+ ## References
59
+
60
+ - [Observability schema (the trace stream feeding this loop), related evaluation runbook, ADRs.]
@@ -0,0 +1,47 @@
1
+ # Floor Note: [system name]
2
+
3
+ > **Usage.** Produce this note at the end of the `floor` workflow, once the floor runs on real traffic. It records what was shipped, what was measured against the success criterion, the gaps, and the next tier. A floor is not delivered, it is proven — this note is the proof record. Replace every `[placeholder]`; delete this notice on delivery.
4
+
5
+ **Date**: [YYYY-MM-DD] · **Version**: [vX.Y] · **Architecture note**: [link] · **Success criterion**: [restate it verbatim from the framing note]
6
+
7
+ ## 1. Scope shipped
8
+
9
+ [Exactly what the floor contains — and confirmation that the six floor components are present.]
10
+
11
+ | Component | Status | Notes |
12
+ |---|---|---|
13
+ | Entry point ([interface / API / tool protocol]) | [shipped] | [matched to actual use, not a demo] |
14
+ | Single orchestrator | [shipped] | [composes only, no business logic] |
15
+ | Model port (real adapter, provider-agnostic) | [shipped] | [active with a key, deterministic fallback without] |
16
+ | Persistence (immutable interaction log) | [shipped] | [attached to entity: [entity]] |
17
+ | Deterministic guardrails | [shipped] | [classification, validation, mutation access control] |
18
+ | Baseline observability + cost ceiling | [shipped] | [request ID propagated; per-run ceiling: [value]] |
19
+
20
+ ## 2. Proof against the success criterion
21
+
22
+ [The measurement, on real traffic or a representative sample — never on cases picked to impress.]
23
+
24
+ - **Traffic used**: [source, volume, period, representativeness.]
25
+ - **Measured result**: [the number or observable fact, against the criterion.]
26
+ - **Verdict**: [criterion met / partially met / not met — and what that means for the gate.]
27
+ - **Observability check**: [confirmation that a full trajectory reconstructs from a single request ID.]
28
+
29
+ ## 3. Gaps and deviations
30
+
31
+ [Anything shipped differently from the architecture note, and anything the measurement revealed. Deviations were agreed with the sponsor, never silent.]
32
+
33
+ | Gap / deviation | Impact | Agreed with sponsor |
34
+ |---|---|---|
35
+ | [gap] | [impact] | [date / reference] |
36
+
37
+ ## 4. Deferrals confirmed
38
+
39
+ [The floor's named deferrals, restated with their triggers — the watchlist for `iterate`.]
40
+
41
+ | Deferred capability | Trigger being watched | Signal observed so far |
42
+ |---|---|---|
43
+ | [long-term memory] | [measured cross-session need] | [none / early signs] |
44
+
45
+ ## 5. Next tier
46
+
47
+ [What the evidence recommends: which trigger is closest to firing, which evolution it would command, and what proof would gate it. Or: hold the floor as is.]
@@ -0,0 +1,58 @@
1
+ # Framing Note: [system or mission name]
2
+
3
+ > **Usage.** Produce this note at the end of the `frame` workflow, before any code. One page is enough. It records the problem, the observable success criterion, the floor/target split with named deferrals, and the hard constraints. It closes with the Definition of Ready check for the engagement. Replace every `[placeholder]`; delete this notice on delivery.
4
+
5
+ **Date**: [YYYY-MM-DD] · **Sponsor**: [name or role] · **Entry mode**: [greenfield | brownfield M1–M4] · **Stopping tier**: [framing | floor | full chain]
6
+
7
+ ## 1. Problem
8
+
9
+ [The real process as observed, not as idealized. Where the friction, manual rework, and waiting actually are. Who lives with it, how often.]
10
+
11
+ ## 2. Value
12
+
13
+ [Where value is created if this works: time saved, errors avoided, quality raised, new service. Who benefits and at what frequency.]
14
+
15
+ ## 3. Observable success criterion
16
+
17
+ [The measurable fact, observable on real traffic, that will say "it works". Not an impression. This criterion is what the floor will be proven against — without it, no gate can be crossed.]
18
+
19
+ ## 4. Floor
20
+
21
+ [The smallest system that proves value on real traffic. Typically: one orchestrator, a model port, persistence, a few deterministic guardrails, baseline observability. List exactly what is in.]
22
+
23
+ ## 5. Target (named, not built)
24
+
25
+ [The full architecture this system heads toward: elaborate memory, multi-agent, externalized state, distribution, continuous evaluation — whichever apply. Named to give direction only.]
26
+
27
+ ## 6. Named deferrals
28
+
29
+ [Everything excluded from the floor, each with the objective trigger that will reactivate it.]
30
+
31
+ | Deferred capability | Lean default in place | Trigger to revisit |
32
+ |---|---|---|
33
+ | [e.g. long-term memory] | [explicit per-turn context] | [measured need for cross-session continuity] |
34
+ | [e.g. multi-agent] | [single orchestrator] | [genuinely parallelizable subtasks] |
35
+ | [e.g. externalized state] | [in-memory, single instance] | [replication or shared state needed] |
36
+
37
+ ## 7. Hard constraints
38
+
39
+ [Sovereignty, regulated sector, legacy integration, confidentiality, mandatory human approval on specific actions. These bound the solution space.]
40
+
41
+ ## 8. Presumed boundaries
42
+
43
+ [The domain ports and integration protocol foreseen at this stage. Language and topology explicitly left open — they are adapter decisions for the `architect` phase.]
44
+
45
+ ## 9. Definition of Ready check
46
+
47
+ [For each condition: met, or named as a risk owned by the sponsor. A missing condition does not block the start; it becomes the first object of discovery.]
48
+
49
+ | Condition | Status | If missing: named risk |
50
+ |---|---|---|
51
+ | Real problem, identified sponsor | [met / risk] | [—] |
52
+ | Observable success criterion | [met / risk] | [—] |
53
+ | Floor-first principle accepted | [met / risk] | [—] |
54
+ | Access to the real process and people | [met / risk] | [—] |
55
+ | Usable data or a path to it | [met / risk] | [—] |
56
+ | Access to technical infrastructure | [met / risk] | [—] |
57
+ | Hard constraints known | [met / risk] | [—] |
58
+ | Human available to decide and approve | [met / risk] | [—] |