runward 0.19.0 → 0.20.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
CHANGED
|
@@ -1,19 +1,29 @@
|
|
|
1
1
|
# Runward
|
|
2
2
|
|
|
3
|
-

|
|
4
4
|
|
|
5
|
-
[](https://www.npmjs.com/package/runward) [](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
14
|
|
|
15
15
|
> 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
16
|
|
|
17
|
+
## Documentation
|
|
18
|
+
|
|
19
|
+
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.
|
|
20
|
+
|
|
21
|
+
- **[Quickstart](https://runward.dev/docs/getting-started/quickstart/)** — from an empty directory to a green `runward check`.
|
|
22
|
+
- **[Concepts: the deterministic gate](https://runward.dev/docs/concepts/the-gate/)** — what the gate verifies, and why it is deterministic and zero-LLM.
|
|
23
|
+
- **[The six phases](https://runward.dev/docs/concepts/six-phases/)** — the gated delivery spine, phase by phase.
|
|
24
|
+
- **[From an AI agent](https://runward.dev/docs/operating/from-an-agent/)** — how an agent installs and drives runward end to end.
|
|
25
|
+
- **[Compliance evidence](https://runward.dev/docs/compliance/evidence/)** — framed for ISO 42001, NIST AI RMF and the EU AI Act, exported as OSCAL.
|
|
26
|
+
|
|
17
27
|
## Why
|
|
18
28
|
|
|
19
29
|
Nearly everything that calls itself agentic today dies somewhere 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.
|
|
@@ -138,7 +148,7 @@ Four things, and a code-level competitive check (July 2026) confirmed no other s
|
|
|
138
148
|
- **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
149
|
- **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
150
|
- **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.
|
|
151
|
+
- **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
152
|
- **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
153
|
- **Floor, not MVP deck.** The floor is the smallest *running* system that proves value on real traffic. A presentation is not a floor.
|
|
144
154
|
- **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.
|
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
|
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.20.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)",
|