verity-framework 0.2.0 → 0.2.1

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
@@ -2,93 +2,92 @@
2
2
 
3
3
  **Prompt to production, proven.**
4
4
 
5
- Verity is a CI/CD-native, GitHub-native, production-lifecycle AI software delivery framework a clean-room successor to [spec-driven-devops](https://www.npmjs.com/package/spec-driven-devops) 1.4 for projects that go *beyond MVP* into real, operated production.
5
+ Most AI coding tools stop when the code is written — leaving you to find out later whether it runs, deploys, or actually works. **Verity keeps going.** It carries a project from an idea all the way to software that is tested, deployed, and **proven working in front of a real user** — and then keeps it running.
6
6
 
7
- Most AI coding tools stop when the code is written. Verity keeps going until the software is tested, deployed, and **proven working in front of a user**. It runs a project as a sequence of specialized AI roles (architect, builder, reviewer, release operator, verifier…) that hand work off through clear contracts, with GitHub as the source of truth.
7
+ It does that by running your project as a sequence of specialized AI roles — a vision assistant, an architect, a builder, a reviewer, a release operator, a verifier, and more — that hand work to each other through clear contracts, with **GitHub as the single source of truth**. It's CI/CD-native and GitHub-native by design, built for projects going *beyond a prototype* into real, operated production. (Verity is a clean-room successor to [spec-driven-devops](https://www.npmjs.com/package/spec-driven-devops) 1.4.)
8
8
 
9
- > **Status:** published [`verity-framework@0.2.0`](https://www.npmjs.com/package/verity-framework) on npm. 13 role commands, the full Relay/Ledger/Gate/Shipyard/Verify engine, adapters for Claude Code + OpenCode, and the deployment-methods catalog (see below).
9
+ > 📦 On npm as [`verity-framework`](https://www.npmjs.com/package/verity-framework) · works with **Claude Code** and **OpenCode**.
10
10
 
11
- ## Install
11
+ ## What makes it different
12
12
 
13
- ```bash
14
- npm i -g verity-framework
15
- verity install --claude # or: --opencode
16
- ```
13
+ - **"Done" means proven, not written.** Every change is reviewed, deployed, and driven like a real user before it counts as finished.
14
+ - **The AI decides; a deterministic tool records.** The `verity` CLI is the "notebook" that never forgets — it holds the rules and the official state, so a forgetful model (or a brand-new chat) can always pick up exactly where things left off.
15
+ - **State is read from GitHub, never a file that drifts.** A merged PR *is* "built"; a tag *is* "released." Nothing to hand-maintain, nothing to lie about.
16
+ - **Specialist roles with real handoffs** beat one mega-prompt trying to do everything.
17
+
18
+ ## How it works
19
+
20
+ A Verity project moves through three arcs:
21
+
22
+ 1. **Bootstrap** *(once)* — name the project, create the repo, design the architecture, choose where it deploys, and prove the whole build→ship pipeline on a tiny end-to-end "walking skeleton."
23
+ 2. **Stream** *(the loop)* — every feature flows through the same short cycle: **plan → build → review → merge**, riding that proven pipeline.
24
+ 3. **Operate** *(continuous)* — cut releases, deploy, **verify on the live app**, and keep it healthy.
25
+
26
+ Five subsystems carry that out:
27
+
28
+ | Subsystem | Job |
29
+ |---|---|
30
+ | **Relay** | Orchestrates the roles, the stream loop, and the dependency engine |
31
+ | **Shipyard** | The CI/CD spine — releases, deploys, the deployment-methods catalog, and runtime truth (`STATUS.md`) |
32
+ | **Ledger** | Derives state from GitHub, so nothing goes stale |
33
+ | **Gate** | Review, security, and the quality gates |
34
+ | **Verify** | Live "observably-works" verification |
35
+
36
+ ## Install
17
37
 
18
- **Prerequisites:** a GitHub account · Node ≥16 · `git` and the GitHub CLI (`gh`) installed **and signed in** (`gh auth login` — installing `gh` is not the same as being authenticated). Preflight:
38
+ **Prerequisites:** a GitHub account · Node ≥16 · `git` and the GitHub CLI (`gh`) installed **and signed in** (run `gh auth login` once — installing `gh` is not the same as being authenticated).
19
39
 
20
40
  ```bash
41
+ # preflight — all three should answer without error:
21
42
  node -v && git --version && gh auth status
43
+
44
+ # install, then connect it to your assistant:
45
+ npm i -g verity-framework
46
+ verity install --claude # or: --opencode
22
47
  ```
23
48
 
24
- Then, in your AI assistant, start a project with `/verity:vision`.
49
+ Then, in your AI assistant, start a project with `/verity:vision`. The [interactive guides](#guides) walk through it step by step.
25
50
 
26
51
  ## Deployment methods
27
52
 
28
- **What it is.** A catalog of the places *you* can deploy to (an AWS box, a server on your LAN, a managed host…), plus a per-app record of where each project actually runs. Verity reads it when the **Architect** designs an app, so deployment becomes a *deliberate choice you make* not an accident.
29
-
30
- **Why it exists.** Without it, an AI agent picks a host by whatever happens to be lying around — e.g. suggesting Render.com simply because a Render tool is installed in its environment. That's not a decision; it's a coincidence. The catalog makes the Architect ask *"here's what you can deploy to — which one for this app?"*, and record the answer as an [ADR](docs/commands.md). It also keeps host and credential details **out of git** while still letting a team share them safely.
53
+ Verity makes **where your app deploys a deliberate choice**, not an accident. Left alone, an AI agent picks a host by whatever happens to be wired into its environment suggesting Render.com, say, just because a Render tool is installed. The deployment-methods catalog fixes that: the **Architect** reads your saved targets and works with you to choose one (recording it as an ADR), and if none are configured yet it asks how you want to deploy and offers suggestions.
31
54
 
32
- **Two files, two scopes:**
55
+ It's **two files, two scopes** — and crucially, no secrets ever touch git:
33
56
 
34
57
  | | Global catalog | Per-app access |
35
58
  |---|---|---|
36
59
  | **Path** | `~/.verity/deployment-methods.md` | `.verity/deploy-access.md` |
37
60
  | **Scope** | You, across *every* project | One app |
38
61
  | **Holds** | The deploy targets you *can* use | How to reach *this* app's host |
39
- | **Created** | At `verity install` (seeded once, never overwritten) | Written by the Architect, per app |
40
- | **In git?** | No lives in your home dir | **No — gitignored.** A committed, secret-free pointer (`.verity/deploy-access.README.md`) tells teammates who lack it to ask the project admin |
41
-
42
- > 🔒 **Both files reference credential *locations*, never secrets.** Point at a key file (`~/.ssh/prod.pem`), an SSO profile, or a secret-store entry — never paste an actual key, password, or token. The real per-app file is shared out-of-band (not through the repo), so nothing sensitive ever lands in git history. (Same rule as `STATUS.md`.)
43
-
44
- **How to use it.** The global catalog is seeded at install with two worked examples (AWS EC2 over SSH, and a local-network server) — edit it to describe *your* real targets:
62
+ | **Created** | At `verity install` seeded once, never overwritten | Written by the Architect, per app |
63
+ | **In git?** | No (lives in your home dir) | **No — gitignored.** A committed, secret-free pointer tells teammates who lack it to ask the project admin |
45
64
 
46
- ```bash
47
- verity deployment list # what targets you have (the Architect reads this)
48
- verity deployment show aws-ec2 # one method's details
49
- verity deployment path # where the catalog file lives
50
- verity deployment edit # open it in $EDITOR to add/adjust targets
51
- ```
65
+ > 🔒 Both files reference credential **locations** — a key file like `~/.ssh/prod.pem`, an SSO profile, a secret-store entry — never an actual key, password, or token. The per-app file is shared out-of-band, so nothing sensitive lands in git history. (Same rule as `STATUS.md`.)
52
66
 
53
- When the Architect designs an app it runs `verity deployment list`, helps you **pick a target** (recording it as an ADR), and if nothing real is configured yet — **asks how you want to deploy and offers suggestions**. It then sets up the per-app access file:
67
+ The global catalog ships with two worked examples (AWS EC2 over SSH, and a local-network server). Edit it to describe your real targets:
54
68
 
55
69
  ```bash
56
- verity deployment init-access # gitignore the real file + commit the "ask the admin" pointer
57
- verity deployment access # is the access file present on this machine? if not, who to ask
70
+ verity deployment list # your targets (this is what the Architect reads)
71
+ verity deployment show aws-ec2 # one target's details
72
+ verity deployment edit # open the catalog in $EDITOR
73
+ verity deployment path # where the catalog lives
58
74
  ```
59
75
 
60
- and writes `.verity/deploy-access.md` with how to reach this app's host. The **Release/Deploy Operator** (`/verity:ship`) consumes that target when it builds the deploy step.
61
-
62
- ## Guides (interactive, beginner-friendly)
63
-
64
- Self-contained HTML — clone/download the repo and open them in any browser (no server or internet needed):
65
-
66
- - [`docs/verity-overview.html`](docs/verity-overview.html) — **Overview**: what Verity is, the mental model, how it works (no jargon assumed)
67
- - [`docs/verity-usage.html`](docs/verity-usage.html) — **Usage**: install + command-by-command recipes + pro tips (Claude Code / OpenCode toggle)
68
- - [`docs/verity-flows.html`](docs/verity-flows.html) — **Flows**: start-from-scratch vs add-to-an-existing-project, side by side
69
- - [`docs/verity-flows.drawio`](docs/verity-flows.drawio) — the flow diagram as an editable draw.io / diagrams.net file
70
- - [`docs/commands.md`](docs/commands.md) — **Command reference**: all 13 `/verity:*` role commands and what each one does
71
- - [`docs/explainer-kit.md`](docs/explainer-kit.md) — **Explainer kit**: a briefing for an AI to describe Verity to humans (podcast/deck/talk) — story, diagrams, soundbites, fact sheet
76
+ When the Architect picks a target it sets up the per-app access file — `verity deployment init-access` gitignores the real file and commits the "ask the admin" pointer — then writes `.verity/deploy-access.md` with how to reach this app's host. From there, `/verity:ship` deploys to that target. (`verity deployment access` tells a teammate whether they have the file, and who to ask if not.)
72
77
 
73
- ## Subsystems
74
- - **Relay** — role orchestration + the stream loop + dependency engine
75
- - **Shipyard** — CI/CD spine + Release/Deploy Operator + deployment-methods catalog + runtime truth (`STATUS.md`)
76
- - **Ledger** — GitHub-derived state engine (no stale files)
77
- - **Gate** — review + security + the quality gates
78
- - **Verify** — live "observably-works" verification
78
+ ## Guides
79
79
 
80
- ## Design docs
81
- - [`docs/framework-spec.md`](docs/framework-spec.md) — the build-ready architecture spec
82
- - [`docs/roles-spec.md`](docs/roles-spec.md) — working log + full rationale (all roles)
83
- - [`docs/interview-findings.md`](docs/interview-findings.md) — forensic interview of the real build that drove the design
84
- - [`docs/brand.md`](docs/brand.md) — naming / positioning
85
- - [`docs/walking-skeleton-plan.md`](docs/walking-skeleton-plan.md) — the first implementation slice
80
+ Interactive, beginner-friendly, and fully self-contained — clone or download the repo and open them in any browser (no server or internet needed):
86
81
 
87
- ## Package
88
- `verity-framework` (npm) · CLI binary: `verity` · Node ≥16 · host deps: `git`, `gh`
82
+ - [**Overview**](docs/verity-overview.html) — what Verity is and the mental model, no jargon assumed
83
+ - [**Usage**](docs/verity-usage.html) install + command-by-command recipes + pro tips (Claude Code / OpenCode toggle)
84
+ - [**Flows**](docs/verity-flows.html) — start-from-scratch vs. add-to-an-existing-project, side by side ([editable `.drawio`](docs/verity-flows.drawio))
85
+ - [**Command reference**](docs/commands.md) — all 13 `/verity:*` roles and what each one does
86
+ - [**Explainer kit**](docs/explainer-kit.md) — a briefing for an AI to describe Verity to humans (podcast / deck / talk)
89
87
 
90
- ## Contributing
91
- See [`CONTRIBUTING.md`](CONTRIBUTING.md) — local setup, the test/lint checks, project layout, and conventions.
88
+ ## Reference
92
89
 
93
- ## License
94
- MIT
90
+ - **Package:** `verity-framework` · CLI binary `verity` · Node ≥16 · host deps `git`, `gh`
91
+ - **Design docs:** [framework spec](docs/framework-spec.md) · [roles spec](docs/roles-spec.md) · [the interview that drove the design](docs/interview-findings.md) · [brand / positioning](docs/brand.md) · [walking-skeleton plan](docs/walking-skeleton-plan.md)
92
+ - **Contributing:** [`CONTRIBUTING.md`](CONTRIBUTING.md) — local setup, the test/lint checks, project layout, and conventions
93
+ - **License:** MIT
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "verity-framework",
3
- "version": "0.2.0",
3
+ "version": "0.2.1",
4
4
  "description": "Verity — a CI/CD-native, GitHub-native, production-lifecycle AI software delivery framework.",
5
5
  "keywords": ["verity", "ai", "ci-cd", "github", "devops", "agent", "framework"],
6
6
  "author": "Sean Mahoney",
@@ -75,18 +75,34 @@ function changelogFrom(commits, version) {
75
75
  return lines.join('\n').trim();
76
76
  }
77
77
 
78
+ // Prepend a changelog section, returning a rollback that restores the file to its
79
+ // exact prior state (content, or non-existence) — so a later failure can undo it.
78
80
  function prependChangelog(cwd, section) {
79
81
  const p = path.join(cwd, 'CHANGELOG.md');
82
+ const existedBefore = fs.existsSync(p);
83
+ const before = existedBefore ? fs.readFileSync(p, 'utf8') : null;
80
84
  const header = '# Changelog';
81
- const existing = fs.existsSync(p) ? fs.readFileSync(p, 'utf8').replace(header, '').trim() : '';
85
+ const existing = before ? before.replace(header, '').trim() : '';
82
86
  const body = `${header}\n\n${section}\n\n${existing}`.trim();
83
87
  fs.writeFileSync(p, `${body}\n`);
88
+ return () => {
89
+ if (existedBefore) {
90
+ fs.writeFileSync(p, before);
91
+ } else {
92
+ fs.rmSync(p, { force: true });
93
+ }
94
+ };
84
95
  }
85
96
 
86
97
  function run(cmd, args) {
87
98
  execFileSync(cmd, args, { stdio: 'inherit' });
88
99
  }
89
100
 
101
+ // A release has three side effects (tag, changelog edit, push) that must be
102
+ // all-or-nothing: a half-done release leaves either a dirty CHANGELOG.md with no
103
+ // tag, or a local tag that never pushed. We order them cheap-and-reversible-first
104
+ // (tag → changelog → push) and roll back the earlier steps if a later one throws.
105
+ // The git runner is injectable (opts.run) so partial failure is unit-testable.
90
106
  function cut(cwd, opts = {}) {
91
107
  const tags = opts.tags || gitTags(cwd);
92
108
  const previous = ledger.latestTag(tags);
@@ -94,14 +110,34 @@ function cut(cwd, opts = {}) {
94
110
  const tag = `v${version}`;
95
111
  const commits = opts.commits || commitsSince(cwd, previous);
96
112
  const changelog = changelogFrom(commits, version);
97
- if (!opts.dryRun) {
98
- prependChangelog(cwd, changelog);
99
- run('git', ['-C', cwd, 'tag', tag]);
100
- if (opts.push !== false) {
101
- run('git', ['-C', cwd, 'push', 'origin', tag]);
113
+ const result = { version, tag, previous, changelog, commitCount: commits.length };
114
+ if (opts.dryRun) {
115
+ return { ...result, applied: false };
116
+ }
117
+
118
+ const exec = opts.run || run;
119
+ exec('git', ['-C', cwd, 'tag', tag]); // step 1 — if this throws, nothing changed yet
120
+
121
+ let restoreChangelog;
122
+ try {
123
+ restoreChangelog = prependChangelog(cwd, changelog); // step 2
124
+ } catch (err) {
125
+ exec('git', ['-C', cwd, 'tag', '-d', tag]); // roll back step 1
126
+ throw err;
127
+ }
128
+
129
+ if (opts.push !== false) {
130
+ try {
131
+ exec('git', ['-C', cwd, 'push', 'origin', tag]); // step 3
132
+ } catch (err) {
133
+ restoreChangelog(); // roll back step 2
134
+ exec('git', ['-C', cwd, 'tag', '-d', tag]); // roll back step 1
135
+ throw new Error(
136
+ `release push failed — rolled back tag ${tag} and CHANGELOG.md, working tree is clean. Original error: ${err.message}`,
137
+ );
102
138
  }
103
139
  }
104
- return { version, tag, previous, changelog, commitCount: commits.length, applied: !opts.dryRun };
140
+ return { ...result, applied: true };
105
141
  }
106
142
 
107
143
  function current(cwd) {
@@ -78,9 +78,36 @@ function buildScript(baseUrl, flow) {
78
78
  return lines.join('\n');
79
79
  }
80
80
 
81
- function defaultProbe(cwd) {
81
+ function resolvableFrom(pkg, cwd) {
82
+ try {
83
+ require.resolve(pkg, { paths: [cwd, process.cwd()] });
84
+ return true;
85
+ } catch {
86
+ return false;
87
+ }
88
+ }
89
+
90
+ function onPath(bin, pathDirs) {
91
+ const exts = process.platform === 'win32' ? ['.cmd', '.exe', '.bat', ''] : [''];
92
+ return pathDirs.some((d) => exts.some((e) => fs.existsSync(path.join(d, bin + e))));
93
+ }
94
+
95
+ // Capability probe — is a headless browser usable here? Checks three honest sources
96
+ // so we don't false-skip when the tool is installed in a non-local layout:
97
+ // 1. the project's local node_modules/.bin
98
+ // 2. resolvable as a package from cwd (hoisted / monorepo / npm-linked global)
99
+ // 3. a CLI on PATH (a globally-installed playwright)
100
+ // Pure (no execution). If none match it returns unavailable, and runSmoke degrades
101
+ // to a non-pass — never a false green. Callers can bypass detection entirely by
102
+ // injecting opts.probe / opts.driver into runSmoke (e.g. a project-specific runner).
103
+ function defaultProbe(cwd, env = process.env) {
104
+ const pathDirs = (env.PATH || '').split(path.delimiter).filter(Boolean);
82
105
  for (const bin of ['playwright', 'puppeteer']) {
83
- if (fs.existsSync(path.join(cwd, 'node_modules', '.bin', bin))) {
106
+ if (
107
+ fs.existsSync(path.join(cwd, 'node_modules', '.bin', bin)) ||
108
+ resolvableFrom(bin, cwd) ||
109
+ onPath(bin, pathDirs)
110
+ ) {
84
111
  return { available: true, tool: bin };
85
112
  }
86
113
  }