runward 0.19.0 → 0.21.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/README.md +26 -12
- package/dist/commands/init.js +9 -2
- package/dist/lib/compliance.js +1 -1
- package/dist/lib/evidence.js +14 -8
- package/dist/lib/tools.js +1 -1
- package/examples/request-triage/code/README.md +1 -1
- package/package.json +3 -3
- package/regimes/eu-ai-act@2024-1689.json +1 -0
- package/regimes/iso-42001@2023.json +1 -0
- package/regimes/nist-ai-rmf@1.0.json +1 -0
package/README.md
CHANGED
|
@@ -1,28 +1,42 @@
|
|
|
1
1
|
# Runward
|
|
2
2
|
|
|
3
|
-

|
|
4
4
|
|
|
5
|
-
[ [](https://runward.dev/docs) [](https://github.com/marketplace/actions/runward-gate) [](LICENSE) [](https://github.com/stranxik/designing-and-running-agentic-systems) [](https://ko-fi.com/stranxik)
|
|
6
6
|
|
|
7
|
-
**
|
|
7
|
+
**AI writes the code. Runward verifies the engineering decisions behind it.**
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
Your coding agent (Claude Code, Cursor, Codex…) is great at producing code. The harder question is who checks the decisions that make a system survive *after* the code ships — the architecture, where things run, how it's secured, how it's handed over.
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
Runward is an open-source delivery methodology for AI-assisted software engineering — a discipline made executable, not a library you import. It doesn't replace your agent; it gives it a way to work through a full engineering mission, from framing to handover, and then **verifies, deterministically**, that the load-bearing decisions were actually made and written down. Same input, same verdict; no prompt can talk it into passing.
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
The core idea: don't ask an LLM whether the engineering process was followed. Verify it with plain code.
|
|
14
|
+
|
|
15
|
+
**Try it in one command** — `npx runward init --example` scaffolds a filled reference mission and ends by running the strict gate itself: the whole chain goes green in front of you. The reference floor even ships an intentional failure (a value the model invented) that the deterministic guard refuses — `npm run demo` in `code/` shows the catch. When you want it on your own project, `npx runward init` starts a blank mission. MIT, zero key, zero network by default.
|
|
14
16
|
|
|
15
17
|
> Spec Kit, OpenSpec and BMAD take you to tested, sometimes merged code. Runward pilots the whole mission — and picks up their output if you use them. What none of them *structures* is the run: governed memory, resilience, execution security, continuous evaluation, transmission.
|
|
16
18
|
|
|
19
|
+
## Documentation
|
|
20
|
+
|
|
21
|
+
The full documentation is at **[runward.dev/docs](https://runward.dev/docs)** — written for humans and coding agents alike, with a Markdown twin (`.md`) and a copy-to-clipboard button on every page.
|
|
22
|
+
|
|
23
|
+
- **[Quickstart](https://runward.dev/docs/getting-started/quickstart/)** — from an empty directory to a green `runward check`.
|
|
24
|
+
- **[Concepts: the deterministic gate](https://runward.dev/docs/concepts/the-gate/)** — what the gate verifies, and why it is deterministic and zero-LLM.
|
|
25
|
+
- **[The six phases](https://runward.dev/docs/concepts/six-phases/)** — the gated delivery spine, phase by phase.
|
|
26
|
+
- **[From an AI agent](https://runward.dev/docs/operating/from-an-agent/)** — how an agent installs and drives runward end to end.
|
|
27
|
+
- **[Compliance evidence](https://runward.dev/docs/compliance/evidence/)** — framed for ISO 42001, NIST AI RMF and the EU AI Act, exported as OSCAL.
|
|
28
|
+
- **[How it compares](https://runward.dev/docs/compare/)** — Spec Kit, BMAD, Kiro, OpenSpec, Spec Kitty: sourced, from their own docs.
|
|
29
|
+
- **[Case study: dropyour](https://runward.dev/docs/case-study/)** — a real product shipped with runward, the trail gate by gate.
|
|
30
|
+
|
|
17
31
|
## Why
|
|
18
32
|
|
|
19
|
-
|
|
33
|
+
Runward exists to carry an agentic system across the stretch where nearly everything dies today: between the demo and production. Not because the model is weak, but because nobody can evaluate a non-deterministic behavior, govern it, or say in advance when it fails. These are architecture problems, not model problems. The industry's own signal is unambiguous: model vendors now deploy engineers directly into client organizations, because the bottleneck has moved from the model to its integration into the real world.
|
|
20
34
|
|
|
21
|
-
Spec-driven frameworks answered the first half of that problem: write the right thing.
|
|
35
|
+
Spec-driven frameworks answered the first half of that problem: write the right thing. Runward structures the second half: ship it, run it, hand it over.
|
|
22
36
|
|
|
23
37
|
Agentic systems break four assumptions of classical distributed engineering. The core component is **non-deterministic**: same input, different output, by design. **Input is indistinguishable from instruction**: anything the model reads can try to command it, so prompt injection is structural, not a bug to patch. **Forgetting becomes an engineering problem**: memory that only grows drowns the signal, so decay, invalidation and consolidation have to be designed, not hoped for. And the **blast radius is unprecedented**: an agent with tools acts on the world, so a bad output is no longer just a bad answer.
|
|
24
38
|
|
|
25
|
-
Runward is the **FDE method** made executable. Its guiding principle: the architecture frames the model, never the other way around — the model and the infrastructure are adapter decisions
|
|
39
|
+
Runward is the **FDE (Forward Deployed Engineer) method** made executable — the way those embedded engineers deliver, written down and gated. Its guiding principle: the architecture frames the model, never the other way around — the model and the infrastructure are adapter decisions behind stable contracts. From there, a delivery spine: six gated phases (a gate: a checkpoint you cross on evidence, never on assertion), each with a Definition of Ready and a Definition of Done, a decision matrix, and 64 craft rules — the detail is in the sections below.
|
|
26
40
|
|
|
27
41
|
## Who it's for — and when
|
|
28
42
|
|
|
@@ -51,7 +65,7 @@ npx runward --yes init # non-interactive, defaults (CI-friendly)
|
|
|
51
65
|
npx runward init --tools claude,cursor,copilot,gemini,windsurf
|
|
52
66
|
```
|
|
53
67
|
|
|
54
|
-
**Fastest way to see what runward does:** `npx runward init --example` scaffolds the `request-triage` reference mission already filled
|
|
68
|
+
**Fastest way to see what runward does:** `npx runward init --example` scaffolds the `request-triage` reference mission already filled and ends by running `check --strict` itself — every gate green, in one command. Then `cd code && npm install && npm run demo` runs five requests end to end; one of them (req-005) carries an account reference the model invented, and you watch the deterministic guard refuse to route on it, fail-closed. `runward compliance iso-42001` emits an audit-ready OSCAL pack from the traced decisions. When you're ready, `npx runward init` (no `--example`) starts your own mission from blank templates.
|
|
55
69
|
|
|
56
70
|
**Install the gate where you already work — honestly tiered by how hard it blocks:**
|
|
57
71
|
|
|
@@ -138,14 +152,14 @@ Four things, and a code-level competitive check (July 2026) confirmed no other s
|
|
|
138
152
|
- **The gate you own — deterministic and zero-LLM.** `runward check --strict` is a non-probabilistic, operator-owned exit-code gate: it cannot be jailbroken by injection (no model in the gate path) and reruns byte-for-byte. Every competitor's *code* check is judged by the model; this one does not depend on an LLM to pass. (Two 2026 signals back the stance: FedRAMP RFC-0024 forbids GenAI-produced factual evidence, and the Delve affair showed why AI-produced audit evidence is not trusted.)
|
|
139
153
|
- **The gate verifies the evidence, not just the row.** A pointer must resolve to real, non-empty content; a symbol or test name must actually be there; a rule can declare the shape its evidence must contain (`signature:` — the founding cited-not-applied incident is now caught deterministically); a stale pointer fails the gate; a sealed gate (`--freeze`) makes later erosion loud. Still bytes, never judgment — and never a model.
|
|
140
154
|
- **runward gates itself.** This repository carries its own `runward/` mission, and CI requires `runward check --strict` green on runward's own code — including under network isolation. The discipline is demonstrated, not claimed.
|
|
141
|
-
- **Audit-ready evidence, in a published format.** Craft rules carry an OWASP ASI (Top 10 for Agentic Applications) mapping — a universal, region-agnostic security posture — so the conformance manifest reads as supporting evidence and exports as a machine-readable OSCAL pack. The decision → ADR → manifest → OSCAL chain is a **versioned, citable mini-spec** ([`docs/spec/runward-oscal-mapping.md`](docs/spec/runward-oscal-mapping.md)) anyone can reproduce or critique — the reference implementation of gate-level agentic-delivery evidence, not a black box. Security-only by default; it maps to your regime when you need one — ISO/IEC 42001 (global), NIST AI RMF (US), or the EU AI Act art.
|
|
155
|
+
- **Audit-ready evidence, in a published format.** Craft rules carry an OWASP ASI (Top 10 for Agentic Applications) mapping — a universal, region-agnostic security posture — so the conformance manifest reads as supporting evidence and exports as a machine-readable OSCAL pack. The decision → ADR → manifest → OSCAL chain is a **versioned, citable mini-spec** ([`docs/spec/runward-oscal-mapping.md`](docs/spec/runward-oscal-mapping.md)) anyone can reproduce or critique — the reference implementation of gate-level agentic-delivery evidence, not a black box. Security-only by default; it maps to your regime when you need one — ISO/IEC 42001 (global), NIST AI RMF (US), or the EU AI Act technical documentation (art. 11 / Annex IV) (EU) — see [`docs/compliance/`](docs/compliance/). An input to that work — never a conformity assessment, never a claim to certify. For a regulated procurement / TPRM review — what applies, what is moot because runward is **local with no data flow**, the supply-chain evidence (OIDC provenance + an attested CycloneDX **SBOM** on every release), the OpenSSF OSPS Baseline alignment, the licence framing and the honest limits — see [`docs/compliance/regulated-adoption.md`](docs/compliance/regulated-adoption.md) ([ADR-0031](docs/adr/ADR-0031-sovereign-engineering-evidence-for-regulated-environments.md)).
|
|
142
156
|
- **Never a runtime.** Runward writes nothing into `.git/`, installs nothing, and runs nothing of yours — it frames, gates and hands off. Your runtime and model are swappable adapters behind a port; the thing you depend on is never Runward.
|
|
143
157
|
- **Floor, not MVP deck.** The floor is the smallest *running* system that proves value on real traffic. A presentation is not a floor.
|
|
144
158
|
- **Evolution on evidence.** Multi-agent, long-term memory, microservices, a bigger model: each has a sober default and an explicit trigger. No trigger, no complexity. Every switch is an ADR.
|
|
145
159
|
- **Security by architecture, not detection.** Prompt injection is constrained structurally (lethal trifecta, 2-of-3 rule), not filtered heuristically.
|
|
146
160
|
- **Craft rules, not vibes.** 64 engineering craft rules ship with the mission (memory scoring, tiered retrieval, event sourcing, request-id propagation, multi-provider fallback, cost routing, post-turn pipelines, prompt-injection defenses…) — your agent applies them, `runward check` will not invent them. Code examples follow the reference-stack default (a single language in the core — TypeScript by default, an adapter decision like any other: see the decision matrix). The patterns are the contract; the language is the adapter.
|
|
147
161
|
- **One accountable operator, not a simulated team.** One human owns every gate while the agent executes the workflows — see [the operator role](docs/operator-role.md).
|
|
148
|
-
- **Hand-over gated on proof, not a folder.** The mission ends when the receiving team redoes a real task without you — and that succession is a gated deliverable (`handover.md`, four handover rules), verified like every other phase.
|
|
162
|
+
- **Hand-over gated on proof, not a folder.** The mission ends when the receiving team redoes a real task without you — and that succession is a gated deliverable (`handover.md`, four handover rules), verified like every other phase. Only one other scaffold (Spec Kitty) carries the mission past tested code — and its acceptance verdict is an AI review; runward's succession check is plain code, and its evidence exports as standardized OSCAL, not bespoke YAML.
|
|
149
163
|
|
|
150
164
|
## The reference floor
|
|
151
165
|
|
package/dist/commands/init.js
CHANGED
|
@@ -4,6 +4,7 @@ import { checkbox, input, select } from "@inquirer/prompts";
|
|
|
4
4
|
import { TEMPLATES, EXAMPLE_MISSION, EXAMPLE_CODE, MISSION_LAYOUT, VERSION } from "../lib/paths.js";
|
|
5
5
|
import { TOOL_PROFILES, TOOL_IDS, baselineSkills } from "../lib/tools.js";
|
|
6
6
|
import { makeWriter } from "../lib/write.js";
|
|
7
|
+
import { checkCommand } from "./check.js";
|
|
7
8
|
import { c, createHeader, isNonInteractive, section, status } from "../lib/styles.js";
|
|
8
9
|
/** Recursively copy a shipped directory tree (used to lay down the filled reference mission). */
|
|
9
10
|
const COPY_SKIP = new Set(["node_modules", "package-lock.json", ".DS_Store"]);
|
|
@@ -130,12 +131,18 @@ export async function initCommand(opts) {
|
|
|
130
131
|
console.log(status.success(`${w.stats.written} file(s) ${dryRun ? "planned" : "written"}, ${w.stats.skipped} skipped`));
|
|
131
132
|
if (example) {
|
|
132
133
|
console.log(`
|
|
133
|
-
${c.primaryBold("Filled reference mission — the
|
|
134
|
-
1.
|
|
134
|
+
${c.primaryBold("Filled reference mission — the gate audit runs on it right below.")}
|
|
135
|
+
1. See the deterministic guard refuse a fabricated value: ${c.primary("cd code && npm install && npm run demo")} ${c.gray("(req-005 carries an account reference the model invented — refused, fail-closed).")}
|
|
135
136
|
2. Run ${c.primary("runward compliance iso-42001")} — an audit-ready evidence pack (OSCAL) derived from the traced decisions.
|
|
136
137
|
3. Read ${c.white("runward/framing.md")}, the ADRs in ${c.white("runward/adr/")}, and ${c.white("runward/governance/threat-model.md")} to see how a real mission is traced end to end.
|
|
137
138
|
|
|
138
139
|
${c.gray("Start your own mission with")} ${c.primary("runward init")} ${c.gray("(without --example) to get blank templates.")}`);
|
|
140
|
+
// One command, whole chain: the scaffold ends by auditing itself, so the first
|
|
141
|
+
// contact with runward is the strict gate going green — not a promise to run it later.
|
|
142
|
+
if (!dryRun) {
|
|
143
|
+
console.log();
|
|
144
|
+
await checkCommand({ path: dir, strict: true });
|
|
145
|
+
}
|
|
139
146
|
}
|
|
140
147
|
else {
|
|
141
148
|
console.log(`
|
package/dist/lib/compliance.js
CHANGED
|
@@ -314,7 +314,7 @@ function detUuid(seed) {
|
|
|
314
314
|
const s = b.join("");
|
|
315
315
|
return `${s.slice(0, 8)}-${s.slice(8, 12)}-${s.slice(12, 16)}-${s.slice(16, 20)}-${s.slice(20, 32)}`;
|
|
316
316
|
}
|
|
317
|
-
const OSCAL_VERSION = "1.
|
|
317
|
+
const OSCAL_VERSION = "1.2.2";
|
|
318
318
|
const ASI_CATALOG = "https://genai.owasp.org/resource/owasp-top-10-for-agentic-applications-for-2026/";
|
|
319
319
|
/**
|
|
320
320
|
* Render the OWASP ASI control coverage as an OSCAL component-definition (JSON) — regime-neutral, the
|
package/dist/lib/evidence.js
CHANGED
|
@@ -55,11 +55,15 @@ function clean(token) {
|
|
|
55
55
|
}
|
|
56
56
|
/**
|
|
57
57
|
* A rule signature is operator-authored data the gate compiles into a RegExp and runs against file
|
|
58
|
-
* content — so a catastrophic-backtracking pattern
|
|
59
|
-
*
|
|
60
|
-
*
|
|
61
|
-
*
|
|
62
|
-
*
|
|
58
|
+
* content — so a catastrophic-backtracking pattern could hang the gate on adversarial input (a
|
|
59
|
+
* self-inflicted DoS in CI). Reject the two known-dangerous shapes up front, deterministically:
|
|
60
|
+
* 1. a quantifier applied to a group that itself contains a quantifier — `(a+)+`, `([a-z]+)*`;
|
|
61
|
+
* 2. a quantifier applied to a group holding an alternation — `(a|a)+`, `(ab|a)+`, `(\d|\d)*` —
|
|
62
|
+
* whose branches can overlap and blow up (the class the shape-1 screen misses).
|
|
63
|
+
* This is a conservative screen (it may reject a rare safe pattern like `(a|b)+` — the operator
|
|
64
|
+
* rewrites it), never a promise to catch every pathological regex; a linear-time engine (RE2) would
|
|
65
|
+
* be the complete fix, at the cost of a native dependency this zero-dep core avoids. Signatures are
|
|
66
|
+
* simple token alternations in practice. See ADR-0020.
|
|
63
67
|
*/
|
|
64
68
|
export function unsafeSignature(source) {
|
|
65
69
|
// Normalize character classes ([...], including [^()]) to a single token first: a quantifier INSIDE
|
|
@@ -67,9 +71,11 @@ export function unsafeSignature(source) {
|
|
|
67
71
|
// own `[^()]` stops at the `(` that lives literally inside the class. After normalization the class
|
|
68
72
|
// becomes `C`, so `([^()]+)+` reads as `(C+)+` and is caught.
|
|
69
73
|
const norm = source.replace(/\[(?:\\.|[^\]\\])*\]/g, "C");
|
|
70
|
-
// group whose body holds a quantifier, immediately followed by another quantifier: (…+…)+ (…*…)* etc.
|
|
74
|
+
// 1. group whose body holds a quantifier, immediately followed by another quantifier: (…+…)+ (…*…)* etc.
|
|
71
75
|
const NESTED = /\((?![?])[^()]*[+*}][^()]*\)[+*{]/;
|
|
72
|
-
|
|
76
|
+
// 2. group holding an alternation, immediately followed by a quantifier: (…|…)+ (…|…)* etc.
|
|
77
|
+
const ALT = /\((?![?])[^()]*\|[^()]*\)[+*{]/;
|
|
78
|
+
return NESTED.test(norm) || NESTED.test(source) || ALT.test(norm) || ALT.test(source);
|
|
73
79
|
}
|
|
74
80
|
/** The same three resolution bases as the drift pass (ADR-0004). */
|
|
75
81
|
export function resolutionBases(missionDir, deliverable) {
|
|
@@ -163,7 +169,7 @@ export function evidenceReport(missionDir, deliverable, signatures) {
|
|
|
163
169
|
const sig = signatures[row.rule];
|
|
164
170
|
if (sig) {
|
|
165
171
|
if (unsafeSignature(sig)) {
|
|
166
|
-
out.push({ rule: row.rule, problem: `unsafe signature regex (nested quantifiers risk catastrophic backtracking): /${sig}/ — simplify it in runward/rules/${row.rule}.md` });
|
|
172
|
+
out.push({ rule: row.rule, problem: `unsafe signature regex (nested or overlapping-alternation quantifiers risk catastrophic backtracking): /${sig}/ — simplify it in runward/rules/${row.rule}.md` });
|
|
167
173
|
continue;
|
|
168
174
|
}
|
|
169
175
|
let re;
|
package/dist/lib/tools.js
CHANGED
|
@@ -64,7 +64,7 @@ const skillMd = (s) => [
|
|
|
64
64
|
"",
|
|
65
65
|
skillBody(s),
|
|
66
66
|
].join("\n");
|
|
67
|
-
/** Emit the
|
|
67
|
+
/** Emit the five phase skills as SKILL.md folders under `<root>/<...dir>/runward-<phase>/SKILL.md`. */
|
|
68
68
|
const skillsAt = (root, ...dir) => PHASE_SKILLS.map((s) => ({ path: join(root, ...dir, `runward-${s.phase}`, "SKILL.md"), content: skillMd(s) }));
|
|
69
69
|
/**
|
|
70
70
|
* The vendor-neutral phase skills at `.agents/skills/` — the converged SKILL.md alias read by
|
|
@@ -41,7 +41,7 @@ Prerequisite: Node 20+.
|
|
|
41
41
|
```bash
|
|
42
42
|
npm install
|
|
43
43
|
npm test # 14 deterministic tests via node:test + tsx
|
|
44
|
-
npm run demo #
|
|
44
|
+
npm run demo # five requests end to end, including a compliance suspension and a fabricated account the guard refuses
|
|
45
45
|
```
|
|
46
46
|
|
|
47
47
|
## Layout
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "runward",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "After the spec: ship and run. A delivery framework for agentic systems
|
|
3
|
+
"version": "0.21.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
5
|
"keywords": [
|
|
6
6
|
"agentic",
|
|
7
7
|
"ai-agents",
|
|
@@ -44,7 +44,7 @@
|
|
|
44
44
|
"LICENSE"
|
|
45
45
|
],
|
|
46
46
|
"engines": {
|
|
47
|
-
"node": ">=
|
|
47
|
+
"node": ">=22.12.0"
|
|
48
48
|
},
|
|
49
49
|
"scripts": {
|
|
50
50
|
"build": "tsc",
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
"regime": "eu-ai-act",
|
|
4
4
|
"label": "EU AI Act (Annex IV)",
|
|
5
5
|
"version": "2024-1689",
|
|
6
|
+
"reviewBy": "2026-08-02",
|
|
6
7
|
"notes": "Mapped against Regulation (EU) 2024/1689 (OJ L, 12 July 2024), as amended by the Digital Omnibus on AI (Council final green light 29 June 2026), which postponed the Annex III high-risk obligations to 2 December 2027 (Annex I to 2 August 2028). The 2 August 2026 milestone remains real for other obligations (Article 50 transparency for systems placed on the market after that date, governance, GPAI enforcement) but is NOT the high-risk / Annex IV deadline. Annex IV wording moves — confirm against the Official Journal before filing.",
|
|
7
8
|
"highRisk": {
|
|
8
9
|
"bindFrom": "2 December 2027",
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
"regime": "iso-42001",
|
|
4
4
|
"label": "ISO/IEC 42001",
|
|
5
5
|
"version": "2023",
|
|
6
|
+
"reviewBy": "2027-01-01",
|
|
6
7
|
"notes": "Mapped 2026-07 against ISO/IEC 42001:2023 (first edition, 2023-12). ISO Annex A control counts/templates are behind the paywalled standard — confirm against the purchased text.",
|
|
7
8
|
"clauses": {
|
|
8
9
|
"riskAssessment": "6.1.2",
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
"regime": "nist-ai-rmf",
|
|
4
4
|
"label": "NIST AI RMF",
|
|
5
5
|
"version": "1.0",
|
|
6
|
+
"reviewBy": "2027-01-01",
|
|
6
7
|
"notes": "Mapped 2026-07 against NIST AI 100-1 (AI RMF 1.0, January 2023) and the companion Playbook.",
|
|
7
8
|
"crosswalk": {
|
|
8
9
|
"primary": "each agentic-security risk lands primarily under **MEASURE** (test & evaluate, esp. security & resilience) and **MANAGE** (risk treatment)",
|