bridgie 0.0.0-stage → 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 (157) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +135 -2
  3. package/VERSION +1 -0
  4. package/adapters/README.md +25 -0
  5. package/adapters/antigravity/gotchas.md +9 -0
  6. package/adapters/antigravity/run.mjs +49 -0
  7. package/adapters/claude-code/gotchas.md +5 -0
  8. package/adapters/claude-code/run.mjs +26 -0
  9. package/adapters/codex/gotchas.md +6 -0
  10. package/adapters/codex/run.mjs +18 -0
  11. package/adapters/copilot/gotchas.md +5 -0
  12. package/adapters/copilot/run.mjs +32 -0
  13. package/adapters/fake/fixtures/buyer.2.json +1 -0
  14. package/adapters/fake/fixtures/buyer.3.json +1 -0
  15. package/adapters/fake/fixtures/buyer.4.json +1 -0
  16. package/adapters/fake/fixtures/buyer.5.json +1 -0
  17. package/adapters/fake/fixtures/buyer.json +1 -0
  18. package/adapters/fake/fixtures/chair.json +8 -0
  19. package/adapters/fake/fixtures/decomposer.json +5 -0
  20. package/adapters/fake/fixtures/evidence.2.json +6 -0
  21. package/adapters/fake/fixtures/evidence.json +5 -0
  22. package/adapters/fake/fixtures/framer.json +9 -0
  23. package/adapters/fake/fixtures/grill.json +9 -0
  24. package/adapters/fake/fixtures/hardener.json +8 -0
  25. package/adapters/fake/fixtures/implementer.json +8 -0
  26. package/adapters/fake/fixtures/lens-moat.json +5 -0
  27. package/adapters/fake/fixtures/lens-offer.json +5 -0
  28. package/adapters/fake/fixtures/lens-product.json +5 -0
  29. package/adapters/fake/fixtures/packager.json +5 -0
  30. package/adapters/fake/fixtures/profiler.json +9 -0
  31. package/adapters/fake/fixtures/researcher.json +6 -0
  32. package/adapters/fake/fixtures/retro.json +14 -0
  33. package/adapters/fake/fixtures/reviewer-fail.json +11 -0
  34. package/adapters/fake/fixtures/reviewer.json +13 -0
  35. package/adapters/fake/fixtures/scout.json +8 -0
  36. package/adapters/fake/fixtures/shaper.json +15 -0
  37. package/adapters/fake/gotchas.md +2 -0
  38. package/adapters/fake/run.mjs +65 -0
  39. package/adapters/lib/common.mjs +89 -0
  40. package/adapters/lib/extract-json.mjs +25 -0
  41. package/bin/bridgie +4 -0
  42. package/bin/bridgie.mjs +28 -0
  43. package/bin/install.sh +5 -0
  44. package/lanes/engineering/attacks.md +11 -0
  45. package/lanes/engineering/checklists/data.md +5 -0
  46. package/lanes/engineering/checklists/docs.md +4 -0
  47. package/lanes/engineering/checklists/failure-modes.md +5 -0
  48. package/lanes/engineering/checklists/observability.md +4 -0
  49. package/lanes/engineering/checklists/operability.md +5 -0
  50. package/lanes/engineering/checklists/performance.md +4 -0
  51. package/lanes/engineering/checklists/security.md +5 -0
  52. package/lanes/engineering/gotchas.md +4 -0
  53. package/lanes/engineering/risk-paths.yaml +13 -0
  54. package/lanes/engineering/verifiers.yaml +13 -0
  55. package/lanes/marketing/attacks.md +4 -0
  56. package/lanes/marketing/gotchas.md +2 -0
  57. package/lanes/platform/attacks.md +4 -0
  58. package/lanes/platform/gotchas.md +2 -0
  59. package/lanes/product/attacks.md +4 -0
  60. package/lanes/product/gotchas.md +2 -0
  61. package/lanes/sales/attacks.md +4 -0
  62. package/lanes/sales/gotchas.md +2 -0
  63. package/lanes/security/attacks.md +4 -0
  64. package/lanes/security/gotchas.md +2 -0
  65. package/package.json +26 -4
  66. package/policy/default.yaml +50 -0
  67. package/runner/cli/core.mjs +103 -0
  68. package/runner/cli/git.mjs +114 -0
  69. package/runner/cli/seat.mjs +165 -0
  70. package/runner/cmd/accept.mjs +56 -0
  71. package/runner/cmd/ack.mjs +17 -0
  72. package/runner/cmd/bet.mjs +25 -0
  73. package/runner/cmd/build.mjs +77 -0
  74. package/runner/cmd/decide.mjs +14 -0
  75. package/runner/cmd/doctor.mjs +9 -0
  76. package/runner/cmd/evidence.mjs +30 -0
  77. package/runner/cmd/frame.mjs +23 -0
  78. package/runner/cmd/grill.mjs +28 -0
  79. package/runner/cmd/help.mjs +22 -0
  80. package/runner/cmd/init.mjs +24 -0
  81. package/runner/cmd/learn.mjs +26 -0
  82. package/runner/cmd/lenses.mjs +35 -0
  83. package/runner/cmd/new.mjs +23 -0
  84. package/runner/cmd/next.mjs +39 -0
  85. package/runner/cmd/numbers.mjs +25 -0
  86. package/runner/cmd/open.mjs +22 -0
  87. package/runner/cmd/panel.mjs +49 -0
  88. package/runner/cmd/plan.mjs +17 -0
  89. package/runner/cmd/research.mjs +35 -0
  90. package/runner/cmd/run.mjs +55 -0
  91. package/runner/cmd/scout.mjs +30 -0
  92. package/runner/cmd/seat-run.mjs +10 -0
  93. package/runner/cmd/setup.mjs +97 -0
  94. package/runner/cmd/shape.mjs +40 -0
  95. package/runner/cmd/sign.mjs +20 -0
  96. package/runner/cmd/status.mjs +13 -0
  97. package/runner/cmd/verify.mjs +121 -0
  98. package/runner/context.mjs +159 -0
  99. package/runner/decide.mjs +264 -0
  100. package/runner/doctor.mjs +92 -0
  101. package/runner/flow.mjs +528 -0
  102. package/runner/guard.mjs +110 -0
  103. package/runner/numbers.mjs +109 -0
  104. package/runner/panel.mjs +182 -0
  105. package/runner/schema.mjs +58 -0
  106. package/runner/skills.mjs +43 -0
  107. package/runner/state.mjs +378 -0
  108. package/runner/surface.mjs +343 -0
  109. package/runner/yaml.mjs +198 -0
  110. package/schemas/acceptance.json +122 -0
  111. package/schemas/bet.json +21 -0
  112. package/schemas/buyer-answer.json +15 -0
  113. package/schemas/claim.json +11 -0
  114. package/schemas/cost.json +19 -0
  115. package/schemas/customer.json +14 -0
  116. package/schemas/decisions.json +129 -0
  117. package/schemas/evidence.json +11 -0
  118. package/schemas/numbers.json +17 -0
  119. package/schemas/policy.json +150 -0
  120. package/schemas/seat-output.json +80 -0
  121. package/schemas/seat.json +84 -0
  122. package/schemas/tasks.json +28 -0
  123. package/seats/accept/packager/SKILL.md +30 -0
  124. package/seats/build/decomposer/SKILL.md +29 -0
  125. package/seats/build/hardener/SKILL.md +28 -0
  126. package/seats/build/implementer/SKILL.md +31 -0
  127. package/seats/build/shaper/SKILL.md +35 -0
  128. package/seats/build/shaper/references/perspectives/clean-code.md +6 -0
  129. package/seats/build/shaper/references/perspectives/data-intensive.md +6 -0
  130. package/seats/build/shaper/references/perspectives/platform.md +6 -0
  131. package/seats/build/shaper/references/perspectives/security.md +6 -0
  132. package/seats/build/shaper/references/perspectives/staff.md +6 -0
  133. package/seats/decide/buyer/SKILL.md +24 -0
  134. package/seats/decide/chair/SKILL.md +23 -0
  135. package/seats/decide/evidence/SKILL.md +28 -0
  136. package/seats/decide/framer/SKILL.md +32 -0
  137. package/seats/decide/grill/SKILL.md +31 -0
  138. package/seats/decide/lens-moat/SKILL.md +40 -0
  139. package/seats/decide/lens-offer/SKILL.md +40 -0
  140. package/seats/decide/lens-product/SKILL.md +40 -0
  141. package/seats/decide/profiler/SKILL.md +24 -0
  142. package/seats/decide/researcher/SKILL.md +32 -0
  143. package/seats/decide/scout/SKILL.md +41 -0
  144. package/seats/learn/retro/SKILL.md +28 -0
  145. package/seats/verify/invariants/SKILL.md +27 -0
  146. package/seats/verify/mechanical/SKILL.md +27 -0
  147. package/seats/verify/reviewer/SKILL.md +33 -0
  148. package/skills/bridgie/SKILL.md +82 -0
  149. package/templates/AGENTS.md +19 -0
  150. package/templates/bet.md +43 -0
  151. package/templates/bridgie-gitignore +7 -0
  152. package/templates/design.md +15 -0
  153. package/templates/project-policy.yaml +11 -0
  154. package/templates/requirements.md +14 -0
  155. package/ui/templates/base.html +26 -0
  156. package/ui/templates/bet.html +14 -0
  157. package/ui/templates/inbox.html +8 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Anoop Vijayan
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,3 +1,136 @@
1
- # Temporary Holding Version
1
+ # Bridgie
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ A file-based operating system for running a company's work through AI agents:
4
+ **decide → build → verify → accept → learn**. One tool, pointed at any folder,
5
+ including one with no code in it yet.
6
+
7
+ Humans own intent (the bet) and acceptance. Agents produce. The harness
8
+ verifies. Only the runner writes state; every human choice happens on a
9
+ rendered page and is written back to files you can diff.
10
+
11
+ ## Install
12
+
13
+ Needs **git** and **Node 20+**. Works the same in PowerShell, cmd, Git Bash, macOS and Linux terminals.
14
+
15
+ ```
16
+ npx bridgie@latest setup
17
+ ```
18
+
19
+ One command, for you and your agents:
20
+
21
+ 1. puts `bridgie` on your PATH (`npm install -g bridgie`; npm writes the right launcher for your shell);
22
+ 2. installs the `/bridgie` agent skill for every agent it finds on the machine (Claude Code, Codex,
23
+ GitHub Copilot, Antigravity, Gemini CLI, Cursor and others) through the open
24
+ [`skills`](https://skills.sh) installer; pass `--agent claude-code --agent codex` to pick;
25
+ 3. writes `~/.bridgie/policy.yaml`: which model CLI each seat uses, from the ones it finds.
26
+
27
+ Open a **new** terminal afterwards. To update the tool and the skill together, run the same command again;
28
+ `bridgie doctor` warns when an installed skill is out of date. The skill alone, without the CLI:
29
+ `npx skills add anoopvijayan-dev/bridgie` (the skill then runs Bridgie through `npx bridgie`).
30
+
31
+ **Claude chat and Claude cloud sessions** read skills from your claude.ai account, not your disk: upload
32
+ `skills/bridgie/SKILL.md` there once (and again after it changes).
33
+
34
+ **Working on Bridgie itself:** clone this repo and run `node bin/bridgie.mjs setup` in it; `setup` then links
35
+ your clone instead of installing from npm.
36
+
37
+ ## Start
38
+
39
+ ```bash
40
+ bridgie new my-idea --lane product # folder + git + Bridgie state, in one step
41
+ cd my-idea
42
+ bridgie # tells you exactly what to do next, at every stage
43
+ ```
44
+
45
+ `bridgie doctor` checks tools and model adapters. `bridgie help` lists every command.
46
+
47
+ ## Finding and testing an idea (the decide loop)
48
+
49
+ ```bash
50
+ mkdir ~/ideas && cd ~/ideas && git init
51
+ bridgie init --lane product
52
+ bridgie scout --from ~/Downloads/broker-emails # ranks the problems people describe, by independent sources
53
+ bridgie bet new packs --from broker-emails/O1 --risk money
54
+ bridgie frame packs # drafts who / problem / why now / today / outcome; assumptions → questions
55
+ bridgie research packs # competitors, prices, complaints, every fact linked (needs web access)
56
+ bridgie grill packs --lenses # adversarial grill + a three-lens board (offer, moat, product) and a chair
57
+ bridgie panel packs # drafts customer.yaml and pitch.md; you correct them; run again for 20 simulated buyers
58
+ bridgie numbers packs --template && $EDITOR .bridgie/bets/packs/numbers.yaml && bridgie numbers packs
59
+ bridgie evidence packs # interview guides; drop notes in .bridgie/bets/packs/evidence/ and run again
60
+ bridgie open packs # answer, accept the confidence proposal, sign
61
+ ```
62
+
63
+ Every verdict is computed by the runner, never written by a model: the board's vote and average, the
64
+ panel's buy rate and Van Westendorp price range, the unit-economics checks. Simulated buyers are an
65
+ upper bound and never change a bet's confidence; only `bridgie evidence` (real interviews, data, tests)
66
+ proposes a tier, and you accept it. A money bet cannot be signed without positive unit economics.
67
+
68
+ ## The loop
69
+
70
+ ```bash
71
+ cd ~/some-project # a git repo; for a brand-new company, an empty folder works until Build
72
+ bridgie init --lane engineering
73
+ bridgie bet new net-collect --title "Net collection for failed payments" --risk money
74
+ $EDITOR .bridgie/bets/net-collect/bet.md # who, problem in their words, why now, outcome
75
+ bridgie grill net-collect # questions that need real-world evidence
76
+ bridgie open net-collect # answer, then sign / kill / need more evidence
77
+ bridgie run net-collect # shape → plan → build → verify → package; stops at each decision
78
+ bridgie open net-collect # approve the design, ack risk paths, unblock tasks, accept
79
+ bridgie learn net-collect # proposals for tests, gotchas and policy
80
+ ```
81
+
82
+ What each step guarantees:
83
+
84
+ | Step | What happens | Guards |
85
+ |---|---|---|
86
+ | `shape` | branch `bridgie/<slug>`, `requirements.md` (EARS) and `design.md` | signed bet, clean tree |
87
+ | `plan` | `tasks.json`, every requirement mapped | approved design, no cycles; a requirement tagged `risk: money` raises the bet's risk; re-planning supersedes any acceptance package |
88
+ | `build` | one task per run in `.bridgie/worktrees/<slug>/<task>` | human ack for risky bets; `.bridgie/` edits discarded; only declared inputs reach the model |
89
+ | `verify` | the runner runs every required test tier, then a read-only reviewer reads the results in a detached worktree | changed risk paths raise the bet's risk (logged, never lowered) and need a fresh ack; a required tier with no command is not proven; every evidence row counts and the reviewer's verdict can only tighten the result; different vendor from the producer; 3 attempts then blocked |
90
+ | `accept` | one-page acceptance package, bound to the branch commit and a digest of spec, tasks and evidence | every task passed, re-checked at the moment of approval; a stale package is refused and rebuilt by `bridgie accept`; approvers per the current risk (2 for money), each a different person |
91
+
92
+ Verification commands live in `.bridgie/policy.yaml` (`verify.commands.<tier>`; see the comment `bridgie init`
93
+ writes). Without them Bridgie uses the lane's commands for the stacks it detects; a tier the risk requires
94
+ but nobody configured is never skipped silently.
95
+
96
+ While an agent runs, Bridgie state is read-only (a project-wide seat lock): your decisions are refused with a
97
+ message rather than rolled back, and anything the agent adds, changes or deletes under `.bridgie/` is restored.
98
+
99
+ `bridgie open` prints a personal link with an access token; decisions are recorded under the identity of that
100
+ link. `bridgie open --invite alice` prints a second link for a second approver. With `--host` beyond
101
+ localhost the traffic is plain HTTP, so share each link only with its person.
102
+
103
+ Bridgie never pushes and never merges into your base branch. Merge `bridgie/<slug>` yourself after acceptance.
104
+ In an agent harness, say `/bridgie` (the installed skill drives the CLI and leaves decisions to you).
105
+
106
+ ## Layout
107
+
108
+ | Path | What |
109
+ |---|---|
110
+ | `bin/bridgie` | the command |
111
+ | `bin/bridgie.mjs`, `runner/cmd/` | the CLI: one Node module per command, no bash anywhere |
112
+ | `runner/` | dependency-free Node modules (state, context, surface, guard, doctor) |
113
+ | `seats/<loop>/<seat>/SKILL.md` | what each agent seat is for, its inputs, what it may write (decide: scout, framer, researcher, three lenses, chair, profiler, buyer, grill, evidence) |
114
+ | `runner/panel.mjs`, `runner/numbers.mjs` | the computed parts of the decide loop: persona cards, tallies, price range; unit economics |
115
+ | `lanes/<lane>/` | risk paths, attack lists, checklists, verifiers per domain |
116
+ | `adapters/` | claude-code, copilot, codex, antigravity, fake: how a seat is launched on a model runtime |
117
+ | `skills/bridgie/` | the skill agent harnesses use to drive bridgie |
118
+ | `schemas/`, `templates/`, `policy/` | the contracts |
119
+ | `ui/templates/` | decision surface pages |
120
+
121
+ ## Status
122
+
123
+ v0.4.0 (M3 decide loop): scout, frame, research, lenses, panel, numbers, evidence; swarm seats and web
124
+ capability in the runner; confidence decisions. Borrowed with thanks from
125
+ [founder-skill](https://github.com/Jakeschincariol/founder-skill) (MIT): the three-lens board, the
126
+ runner-dealt buyer panel, Van Westendorp pricing and computed unit economics. v0.3.0 (M2 hardening): enforcement gaps from an external review closed (acceptance binding, evidence
127
+ reconciliation, effective risk and mandatory tiers, state guard and seat lock, authenticated decision
128
+ server, reviewer works from runner-run test results). v0.2.0 (M1): the whole loop runs end to end on the
129
+ fake adapter and is covered by tests for spec requirements R1–R14 and properties P1–P3. Real adapters are verified against stub CLIs with the
130
+ flags of Claude Code 2.1, Codex 0.167 and Copilot CLI 1.0; Antigravity follows the v1 notes and its
131
+ write mode is unverified (see `adapters/antigravity/gotchas.md`). Next: a first real run of the decide loop on live
132
+ models, recovery for interrupted runs, seeded-bug evals for the reviewer, marketing and sales lanes.
133
+
134
+ ## Tests
135
+
136
+ `npm test` runs the unit tests; `tests/run.sh` runs everything (unit, `bats tests/` for the CLI, doctor). CI runs both on Linux, macOS and Windows with Node 20 and 22, and checks that `bridgie` launches from PowerShell and cmd after `setup`. Tests ignore `~/.bridgie`.
package/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.6.0
@@ -0,0 +1,25 @@
1
+ # Adapters
2
+ Each adapter is `adapters/<name>/run.mjs`, run with the same `node` as Bridgie (run.mjs is plain Node, so adapters behave the same on Windows, macOS and Linux). A legacy `run.sh` is still launched with bash if no run.mjs exists.
3
+
4
+ An adapter launches one seat invocation on one model runtime. Contract:
5
+
6
+ run.mjs --seat <seat dir> --prompt <prompt file> --out <output file> --cwd <dir> \
7
+ --mode readonly|write --model <name> [--effort <level>]
8
+ run.mjs --capabilities --seat <seat dir> # prints {"vendor": "...", "reads_repo": true|false, "reads_web": true|false}
9
+ run.mjs --probe # prints OK when the CLI is installed (no model call)
10
+
11
+ Rules:
12
+ - Read the prompt from the file; never pass it inline (Windows argument limits).
13
+ - The seat ends its reply with one fenced ```json block. The adapter saves the full reply
14
+ next to `--out` as `reply.txt` and extracts the last JSON block into `--out` with
15
+ `adapters/lib/extract-json.mjs`. If the model wrote `--out` itself, that file wins.
16
+ - `readonly` mode must not let the model write in `--cwd`. The runner also checks state files
17
+ and the reviewer worktree afterwards and fails the run on any change.
18
+ - `reads_web: false` makes the runner refuse seats whose manifest lists the `web` tool (research).
19
+ - `vendor` drives cross-family checks; `reads_repo: false` makes the runner refuse to use the
20
+ adapter as a reviewer.
21
+ - Exit 0 only when `--out` exists. Any other exit code with a reason on stderr.
22
+ - Exit 6 when the CLI itself failed (signed out, over its usage limit, crashed) and left no JSON; put the CLI's last words on stderr. Exit 4 means no reply at all, exit 5 a reply with no valid JSON block.
23
+ - Keep the traps you learn in `gotchas.md` next to the adapter.
24
+
25
+ Adapters: `fake` (tests), `claude-code` (anthropic), `codex` (openai), `antigravity` (google).
@@ -0,0 +1,9 @@
1
+ # antigravity adapter gotchas (carried from Bridgie v1, verified 2026-08-12)
2
+ - The binary is the CLI `agy` (`%LOCALAPPDATA%\agy\bin\agy.exe`, often not on PATH in a spawned shell), not the IDE. The old `gemini` CLI's OAuth tier is retired.
3
+ - `--print` takes the prompt as its VALUE: put `--print "<prompt>"` last, or the next flag becomes the prompt.
4
+ - `--project` is load-bearing. Without it agy uses `default-cli-project`, clears the permission grants and every tool is denied. The adapter finds the project whose folderUri covers the working dir in `~/.gemini/config/projects/*.json`; override with `BRIDGIE_AGY_PROJECT`.
5
+ - Headless auto-denies tools. Grant read tools in `~/.gemini/antigravity-cli/settings.json`: `permissions.allow: ["read_file(*)","list_directory(*)","glob(*)","grep(*)","search_file_content(*)"]`, and deny `write_file(*)`, `edit_file(*)`, `replace(*)`, `run_shell_command(*)`, `command(*)` for reviewer use. Never use `--dangerously-skip-permissions`.
6
+ - `--sandbox` hangs on Windows. Do not use it.
7
+ - Probe first: `agy --project <id> --mode plan --print "Reply with exactly: OK"`.
8
+ - A QA seat that cannot read the repo invents findings (v1, 2026-08-08). Task worktrees live inside the repo (`.bridgie/worktrees/`) so the project's grants cover them.
9
+ - UNVERIFIED: write mode. The adapter uses `--mode ${BRIDGIE_AGY_WRITE_MODE:-agent}` for implementer seats; confirm the mode name on first use and record it here.
@@ -0,0 +1,49 @@
1
+ // Antigravity CLI adapter (google). agy has no stdin mode: it is told to read the prompt file.
2
+ import { existsSync, readdirSync, readFileSync } from 'node:fs';
3
+ import { dirname, join, basename } from 'node:path';
4
+ import { homedir } from 'node:os';
5
+ import * as A from '../lib/common.mjs';
6
+
7
+ const o = A.parse(process.argv.slice(2));
8
+ function findAgy() {
9
+ if (process.env.BRIDGIE_AGY_BIN) return process.env.BRIDGIE_AGY_BIN;
10
+ const onPath = A.which('agy');
11
+ if (onPath) return onPath;
12
+ const la = process.env.LOCALAPPDATA;
13
+ if (la && existsSync(join(la, 'agy', 'bin', 'agy.exe'))) return join(la, 'agy', 'bin', 'agy.exe');
14
+ return null;
15
+ }
16
+ // findProject: Antigravity project id whose folderUri covers dir. Without it agy runs in
17
+ // "default-cli-project" and wipes the permission grants (see gotchas.md).
18
+ function findProject(dir) {
19
+ if (process.env.BRIDGIE_AGY_PROJECT) return process.env.BRIDGIE_AGY_PROJECT;
20
+ const want = dir.replace(/\\/g, '/').toLowerCase();
21
+ const d = join(homedir(), '.gemini', 'config', 'projects');
22
+ let best = null;
23
+ for (const f of existsSync(d) ? readdirSync(d) : []) {
24
+ try {
25
+ const j = JSON.parse(readFileSync(join(d, f), 'utf8'));
26
+ const uris = [j.folderUri, ...(j.folders || []).map(x => x.uri || x)].filter(Boolean);
27
+ for (const u of uris) {
28
+ const p = decodeURIComponent(String(u).replace(/^file:\/\//, '')).replace(/\\/g, '/').replace(/^\/([a-zA-Z]:)/, '$1').toLowerCase().replace(/\/$/, '');
29
+ if (want.startsWith(p) && (!best || p.length > best.len)) best = { id: j.id || basename(f, '.json'), len: p.length };
30
+ }
31
+ } catch { /* skip unreadable project files */ }
32
+ }
33
+ return best?.id || null;
34
+ }
35
+ const bin = findAgy();
36
+ if (o.probe) A.probe(bin, 'agy (PATH or %LOCALAPPDATA%/agy/bin)');
37
+ if (o.caps) A.caps({ vendor: 'google', reads_repo: true, reads_web: false });
38
+ A.requireRunArgs(o);
39
+ if (!bin) { process.stderr.write('agy not found\n'); process.exit(1); }
40
+ const project = findProject(o.cwd);
41
+ if (!project) { process.stderr.write(`no Antigravity project covers ${o.cwd}; open it in Antigravity once or set BRIDGIE_AGY_PROJECT\n`); process.exit(1); }
42
+ const mode = o.mode === 'write' ? (process.env.BRIDGIE_AGY_WRITE_MODE || 'agent') : 'plan';
43
+ const instruction = `Read ${o.prompt} in full. It contains your role, inputs and output contract. Do the work now in ${o.cwd}, then end your reply with the fenced json block it asks for.`;
44
+ const args = ['--project', project, '--mode', mode, '--effort', o.effort || 'high', '--print-timeout', process.env.BRIDGIE_AGY_TIMEOUT || '15m', '--output-format', 'text'];
45
+ if (o.model !== 'default') args.push('--model', o.model);
46
+ args.push('--print', instruction); // --print takes the prompt as its VALUE and must come last
47
+ const reply = A.replyPath(o);
48
+ const rc = A.run(bin, args, { cwd: o.cwd, stdout: reply, stderr: join(dirname(o.out), 'agy.log') });
49
+ A.finish(o, reply, rc);
@@ -0,0 +1,5 @@
1
+ # claude-code adapter gotchas
2
+ - Flags verified against Claude Code 2.1.319: `-p`, `--output-format text`, `--permission-mode dontAsk|acceptEdits`, `--allowedTools`, `--disallowedTools`, `--add-dir`, `--model`, `--effort low|medium|high|xhigh|max`.
3
+ - The prompt goes on stdin; never inline it (Windows command-line length limit).
4
+ - `dontAsk` refuses any tool not in `--allowedTools` without prompting, which is what keeps a reviewer read-only in print mode.
5
+ - Override the binary with `BRIDGIE_CLAUDE_BIN` (e.g. a Copilot-hosted wrapper).
@@ -0,0 +1,26 @@
1
+ // Claude Code adapter (anthropic). Prompt on stdin, reply on stdout, JSON extracted to --out.
2
+ import { dirname } from 'node:path';
3
+ import * as A from '../lib/common.mjs';
4
+
5
+ const o = A.parse(process.argv.slice(2));
6
+ const bin = A.which(process.env.BRIDGIE_CLAUDE_BIN || 'claude');
7
+ if (o.probe) A.probe(bin, 'claude CLI');
8
+ if (o.caps) A.caps({ vendor: 'anthropic', reads_repo: true, reads_web: true });
9
+ A.requireRunArgs(o);
10
+ if (!bin) { process.stderr.write('claude CLI not found on PATH\n'); process.exit(1); }
11
+ const args = ['-p', '--output-format', 'text', '--add-dir', dirname(o.out)];
12
+ if (o.model !== 'default') args.push('--model', o.model);
13
+ if (o.effort) args.push('--effort', o.effort);
14
+ if (o.mode === 'readonly') {
15
+ // Read and inspect only; everything not allowed is refused without prompting.
16
+ args.push('--permission-mode', 'dontAsk',
17
+ '--allowedTools', 'Read', 'Grep', 'Glob', 'LS', 'WebSearch', 'WebFetch', 'Bash(git diff:*)', 'Bash(git log:*)', 'Bash(git show:*)', 'Bash(git status:*)',
18
+ '--disallowedTools', 'Edit', 'Write', 'NotebookEdit');
19
+ } else {
20
+ args.push('--permission-mode', 'acceptEdits',
21
+ '--allowedTools', 'Read', 'Grep', 'Glob', 'LS', 'Edit', 'Write', 'Bash',
22
+ '--disallowedTools', 'Bash(git push:*)', 'Bash(git remote:*)', 'Bash(git checkout:*)', 'Bash(git switch:*)');
23
+ }
24
+ const reply = A.replyPath(o);
25
+ const rc = A.run(bin, args, { cwd: o.cwd, stdin: o.prompt, stdout: reply });
26
+ A.finish(o, reply, rc);
@@ -0,0 +1,6 @@
1
+ # codex adapter gotchas
2
+ - Flags verified against codex-cli 0.167.0: `exec -s read-only|workspace-write -C <dir> --skip-git-repo-check -o <last message file>`, `-m`, `-c key=value`.
3
+ - Pipe the prompt on stdin (v1: inlining a large diff broke on Windows).
4
+ - ChatGPT-auth Codex rejects `-m` for models it does not offer: leave the model as `default` unless you know.
5
+ - "requires a newer version of Codex" → `npm install -g @openai/codex@latest`.
6
+ - v1 incident: a packet that swept in the run directory hit Codex's 1,048,576-character input limit; packets exclude `.bridgie/runs/**`.
@@ -0,0 +1,18 @@
1
+ // Codex CLI adapter (openai). Prompt on stdin; last message written with -o; JSON extracted to --out.
2
+ import { dirname, join } from 'node:path';
3
+ import * as A from '../lib/common.mjs';
4
+
5
+ const o = A.parse(process.argv.slice(2));
6
+ const bin = A.which(process.env.BRIDGIE_CODEX_BIN || 'codex');
7
+ if (o.probe) A.probe(bin, 'codex CLI');
8
+ if (o.caps) A.caps({ vendor: 'openai', reads_repo: true, reads_web: true });
9
+ A.requireRunArgs(o);
10
+ if (!bin) { process.stderr.write('codex CLI not found on PATH\n'); process.exit(1); }
11
+ const reply = A.replyPath(o);
12
+ const args = ['exec', '--search', '-s', o.mode === 'write' ? 'workspace-write' : 'read-only', '-C', o.cwd, '--skip-git-repo-check', '-o', reply]; // --search: web search tool on
13
+ // ChatGPT-auth Codex rejects -m for models it does not offer: only pass it when one is configured.
14
+ if (o.model !== 'default') args.push('-m', o.model);
15
+ if (o.effort) args.push('-c', `model_reasoning_effort="${o.effort}"`);
16
+ const log = join(dirname(o.out), 'codex.log');
17
+ const rc = A.run(bin, args, { stdin: o.prompt, stdout: log, stderr: log + '.err' });
18
+ A.finish(o, reply, rc);
@@ -0,0 +1,5 @@
1
+ # copilot adapter gotchas
2
+ - Flags verified against GitHub Copilot CLI 1.0.107: `-p` (non-interactive), `-s` (response only), `--no-ask-user`, `--model`, `--reasoning-effort none|minimal|low|medium|high|xhigh|max`, `--allow-tool` / `--deny-tool` (deny always wins), `--add-dir`.
3
+ - `-p` takes the prompt text, so the adapter passes a short instruction to read the prompt file (Windows command-line limit).
4
+ - Vendor is derived from `--model` (claude/opus/sonnet → anthropic, gpt → openai, gemini → google). With `default` the vendor is `copilot-default`, which never matches another adapter, so set an explicit model when cross-family matters.
5
+ - Model names are Copilot's (check `copilot --help` / `/model`), e.g. `claude-opus-5.5`; they are not Anthropic API ids.
@@ -0,0 +1,32 @@
1
+ // GitHub Copilot CLI adapter. Vendor follows the model (Claude → anthropic, GPT → openai, Gemini → google).
2
+ // The prompt is too large for a command line on Windows, so -p carries an instruction to read the file.
3
+ import { dirname, join } from 'node:path';
4
+ import * as A from '../lib/common.mjs';
5
+
6
+ const o = A.parse(process.argv.slice(2));
7
+ const bin = A.which(process.env.BRIDGIE_COPILOT_BIN || 'copilot');
8
+ const vendorOf = m => {
9
+ m = String(m || '').toLowerCase();
10
+ if (/claude|opus|sonnet|haiku|fable/.test(m)) return 'anthropic';
11
+ if (/gpt|^o\d|codex/.test(m)) return 'openai';
12
+ if (/gemini/.test(m)) return 'google';
13
+ return `copilot-${m || 'default'}`;
14
+ };
15
+ if (o.probe) A.probe(bin, 'copilot CLI');
16
+ if (o.caps) A.caps({ vendor: vendorOf(o.model), reads_repo: true, reads_web: process.env.BRIDGIE_COPILOT_WEB === '1' });
17
+ A.requireRunArgs(o);
18
+ if (!bin) { process.stderr.write('copilot CLI not found on PATH\n'); process.exit(1); }
19
+ const instruction = `Read ${o.prompt} in full. It contains your role, inputs and output contract. Do the work now in ${o.cwd}, then end your reply with the fenced json block it asks for.`;
20
+ const args = ['-s', '--no-ask-user', '--add-dir', dirname(o.prompt)];
21
+ if (o.model !== 'default') args.push('--model', o.model);
22
+ if (o.effort) args.push('--reasoning-effort', o.effort);
23
+ if (o.mode === 'readonly') {
24
+ // Non-interactive mode denies anything not allowed; deny rules win over allow rules.
25
+ args.push('--allow-tool', 'shell(git diff:*)', '--allow-tool', 'shell(git log:*)', '--allow-tool', 'shell(git show:*)', '--allow-tool', 'shell(git status:*)', '--deny-tool', 'write');
26
+ } else {
27
+ args.push('--allow-tool', 'write', '--allow-tool', 'shell', '--deny-tool', 'shell(git push)', '--deny-tool', 'shell(git remote)', '--deny-tool', 'shell(git checkout)', '--deny-tool', 'shell(git switch)');
28
+ }
29
+ args.push('-p', instruction);
30
+ const reply = A.replyPath(o);
31
+ const rc = A.run(bin, args, { cwd: o.cwd, stdout: reply, stderr: join(dirname(o.out), 'copilot.log') });
32
+ A.finish(o, reply, rc);
@@ -0,0 +1 @@
1
+ { "card": "CARD", "buys": false, "purchases_first_month": 0, "reason_code": "price", "reason": "£39 a deal adds up when margins are thin", "objection": "my junior is cheaper", "would_flip": "a monthly cap", "prices": { "too_cheap": 5, "bargain": 15, "getting_expensive": 30, "too_expensive": 60 } }
@@ -0,0 +1 @@
1
+ { "card": "CARD", "buys": false, "purchases_first_month": 0, "reason_code": "trust", "reason": "never heard of you and lenders are fussy", "objection": "lenders will not accept it", "would_flip": "a monthly cap", "prices": { "too_cheap": 10, "bargain": 20, "getting_expensive": 50, "too_expensive": 100 } }
@@ -0,0 +1 @@
1
+ { "card": "CARD", "buys": true, "purchases_first_month": 1, "reason_code": "need", "reason": "worth a try on the next stuck deal", "objection": "setup time", "would_flip": "n/a", "prices": { "too_cheap": 8, "bargain": 20, "getting_expensive": 60, "too_expensive": 100 } }
@@ -0,0 +1 @@
1
+ { "card": "CARD", "buys": false, "purchases_first_month": 0, "reason_code": "price", "reason": "no", "objection": "price", "would_flip": "free tier", "prices": { "too_cheap": 20, "bargain": 10, "getting_expensive": 30, "too_expensive": 60 } }
@@ -0,0 +1 @@
1
+ { "card": "CARD", "buys": true, "purchases_first_month": 2, "reason_code": "need", "reason": "that is my Tuesday back", "objection": "will the lender take it", "would_flip": "n/a", "prices": { "too_cheap": 5, "bargain": 25, "getting_expensive": 60, "too_expensive": 120 } }
@@ -0,0 +1,8 @@
1
+ {
2
+ "seat": "chair",
3
+ "summary_md": "Vote: one fund, one fund if, one pass. Shared risk: lenders refuse a standard pack. Disagreement: the moat lens sees no defensibility; the product lens sees a whole product. Strongest version: broker-side pack builder sold per deal. First: ask three brokers what Tuesday costs them.",
4
+ "artifact_md": "## Shared risks\n- Lenders refuse a standard pack (offer, moat)\n\n## Conditions\n- [ ] Three brokers confirm the Tuesday cost (evidence)\n- [ ] Two lenders accept a standard pack (evidence)\n\n## Where the board disagrees\n- Moat: nothing stops a lender copying it. Product: the broker relationship is the product.\n\n## The strongest version\nA pack builder brokers pay for per deal, starting with the two lenders brokers use most.",
5
+ "questions": [
6
+ { "context": "How many applications a month does a typical target broker handle?", "options": ["under 5", "5–20", "over 20", "don't know"], "allow_free_text": true }
7
+ ]
8
+ }
@@ -0,0 +1,5 @@
1
+ {
2
+ "seat": "decomposer",
3
+ "summary_md": "Two tasks; every requirement mapped.",
4
+ "artifact_md": "```json\n{\n \"tasks\": [\n {\n \"id\": \"T1\",\n \"title\": \"Create collection endpoint\",\n \"requirements\": [\n \"R1\"\n ],\n \"depends_on\": []\n },\n {\n \"id\": \"T2\",\n \"title\": \"Idempotent collection handling\",\n \"requirements\": [\n \"R2\",\n \"P1\"\n ],\n \"depends_on\": [\n \"T1\"\n ]\n }\n ]\n}\n```"
5
+ }
@@ -0,0 +1,6 @@
1
+ {
2
+ "seat": "evidence",
3
+ "summary_md": "Three brokers interviewed; all three spend half a day per application; none measured it.",
4
+ "artifact_md": "## What the material shows\n- 3 of 3 brokers say a pack takes 4–6 hours (notes-broker-1.md, notes-broker-2.md, notes-broker-3.md)\n\n## What it does not show\n- No timesheet; the hours are recalled, not measured.\n\n## Sources\n- 3 interview notes, 3 independent firms",
5
+ "proposals": [ { "kind": "confidence", "text": "anecdote: three independent brokers, recalled not measured" } ]
6
+ }
@@ -0,0 +1,5 @@
1
+ {
2
+ "seat": "evidence",
3
+ "summary_md": "Two tasks. Both interviews; five brokers each; stop when three agree.",
4
+ "artifact_md": "### E1\nMethod: interview. Sample: 5 brokers from NACFB list. Stop: after 5 or when 3 give the same answer.\nQuestions:\n- When did you last prepare a statement pack, and how long did it take?\n- What did you do when a lender rejected the pack?\n\n### E-panel\nMethod: priced landing page. Sample: 100 visitors. Stop: 2 weeks.\n"
5
+ }
@@ -0,0 +1,9 @@
1
+ {
2
+ "seat": "framer",
3
+ "summary_md": "Assumed: brokers pay per deal; the junior's time is the cost; lenders will accept a standard pack.",
4
+ "artifact_md": "## Who\nA UK commercial finance broker with two to five staff, preparing a lending application at month-end.\n\n## Problem in their words\n\"I spend most of Tuesday on statements for one client.\" (assumption: typical, from one broker)\n\n## Why now\nOpen banking data is now available for most SME accounts (changed 2025).\n\n## What they do today\nSpreadsheets and a junior who keys the numbers in.\n\n## Expected outcome\nStatement analysis per application from ~6 hours to under 1 hour, read from broker timesheets by 2027-03. Baseline unknown.",
5
+ "questions": [
6
+ { "context": "Who pays: the broker per deal, or the lender?", "options": ["broker per deal", "broker subscription", "lender", "don't know"], "allow_free_text": true },
7
+ { "context": "Is 6 hours per application measured or a guess?", "options": ["measured", "guess", "don't know"], "allow_free_text": true }
8
+ ]
9
+ }
@@ -0,0 +1,9 @@
1
+ {
2
+ "seat": "grill",
3
+ "summary_md": "Strongest assumption: merchants notice failed collections. Weakest evidence: no interview quotes. Pre-mortem: finance already retries by hand; the metric cannot be read by the date.",
4
+ "questions": [
5
+ { "context": "Does anyone retry failed card payments manually today, and who?", "options": ["yes, finance does", "yes, support does", "no", "don't know"], "allow_free_text": true },
6
+ { "context": "Is the churn baseline (4.1%) measured or estimated?", "options": ["measured", "estimated", "don't know"], "allow_free_text": true }
7
+ ],
8
+ "proposals": [ { "kind": "confidence", "text": "anecdote: two tickets and one conversation; no measured data yet" } ]
9
+ }
@@ -0,0 +1,8 @@
1
+ {
2
+ "task": "T1",
3
+ "claims": [
4
+ { "text": "failure-modes: idempotency covered by the request-id unique index", "proof_cmd": "grep -n unique feature.txt", "proof_output": "1:unique request_id" }
5
+ ],
6
+ "files_changed": [],
7
+ "notes": "observability: no metric yet (gap)"
8
+ }
@@ -0,0 +1,8 @@
1
+ {
2
+ "task": "T1",
3
+ "claims": [
4
+ { "text": "Requirement satisfied; see the new file", "proof_cmd": "cat feature.txt", "proof_output": "implemented" }
5
+ ],
6
+ "files_changed": ["feature.txt"],
7
+ "notes": ""
8
+ }
@@ -0,0 +1,5 @@
1
+ {
2
+ "seat": "lens-moat",
3
+ "summary_md": "PASS — biggest risk from the moat lens.",
4
+ "artifact_md": "Score: 5 | Vote: PASS\n## What is strong\nThe person is specific.\n## What would kill it\n- Lenders refuse a standard pack (moat lens)\n- Brokers will not pay per deal\n## Questions for the owner\n- How many deals a month does a typical broker do?\n## Conditions\n- [ ] Three brokers confirm the Tuesday cost"
5
+ }
@@ -0,0 +1,5 @@
1
+ {
2
+ "seat": "lens-offer",
3
+ "summary_md": "FUND IF — biggest risk from the offer lens.",
4
+ "artifact_md": "Score: 7 | Vote: FUND IF\n## What is strong\nThe person is specific.\n## What would kill it\n- Lenders refuse a standard pack (offer lens)\n- Brokers will not pay per deal\n## Questions for the owner\n- How many deals a month does a typical broker do?\n## Conditions\n- [ ] Three brokers confirm the Tuesday cost"
5
+ }
@@ -0,0 +1,5 @@
1
+ {
2
+ "seat": "lens-product",
3
+ "summary_md": "FUND — biggest risk from the product lens.",
4
+ "artifact_md": "Score: 8 | Vote: FUND\n## What is strong\nThe person is specific.\n## What would kill it\n- Lenders refuse a standard pack (product lens)\n- Brokers will not pay per deal\n## Questions for the owner\n- How many deals a month does a typical broker do?\n## Conditions\n- [ ] Three brokers confirm the Tuesday cost"
5
+ }
@@ -0,0 +1,5 @@
1
+ {
2
+ "seat": "packager",
3
+ "summary_md": "All three criteria pass; one minor finding; no load test.",
4
+ "artifact_md": "# Acceptance \u2014 Net collection\n\n## The bet and its criteria\nMerchants' failed collections retried once, idempotently. R1, R2, P1.\n\n## What changed and blast radius\nTwo files; one new endpoint; no shared contracts changed.\n\n## Evidence matrix\n| Criterion | Tier | Result |\n|---|---|---|\n| R1 | adversarial | pass |\n| R2 | adversarial | pass |\n| P1 | adversarial | pass |\n\n## Findings\nOne minor wording finding, not fixed.\n\n## Rollback and alerts\nFlag net_collect off.\n\n## Residual uncertainty\n- No load test was run.\n- Property P1 checked by review, not by a property test.\n\n## Decision\nApprove, approve with conditions, or reject on the decision page.\n"
5
+ }
@@ -0,0 +1,9 @@
1
+ {
2
+ "seat": "profiler",
3
+ "summary_md": "Guesses: segment shares, the income ranges. Check: whether solo brokers exist in volume.",
4
+ "files": {
5
+ "customer.yaml": "business: Statement pack builder for brokers\ntarget: UK commercial finance broker, 2–5 staff, at month-end\nsegments:\n - { name: solo broker, share: 0.5, income: [40000, 60000] }\n - { name: small firm, share: 0.5, income: [60000, 120000] }\nbehaviours:\n - { name: deadline buyer, share: 0.6, how: buys when a deal is stuck }\n - { name: tool sceptic, share: 0.4, how: has been burned by software before }\nobjections:\n - lenders will not accept it\n - my junior is cheaper\nhabits:\n - works Saturdays in Q4\n",
6
+ "pitch.md": "A pack builder that reads a year of bank statements and produces the lender's own template.\n£39 per application, pay as you go.\nUpload PDFs or connect open banking; the pack is ready in ten minutes.\nFirst three applications free.\n"
7
+ },
8
+ "proposals": [ { "kind": "confidence", "text": "data: the panel will tell us" } ]
9
+ }
@@ -0,0 +1,6 @@
1
+ {
2
+ "seat": "researcher",
3
+ "summary_md": "Crowded at the lender end, empty at the broker end. Prices £49–£299/month. Loudest complaint: categorisation errors. Gap: broker-side packs. Sources seen 2026-11.",
4
+ "artifact_md": "## Direct competitors\n| Name | What | Price | Link |\n|---|---|---|---|\n| StatementCo | PDF statement parsing for lenders | £299/month (seen 2026-11-07) | https://example.com/statementco |\n| Cashflow Ltd | Open-banking cash-flow reports | £49/month | https://example.com/cashflow |\n\n## Indirect and substitutes\n- Excel templates shared on broker forums https://example.com/forum/templates\n\n## Prices\n- Brokers pay nothing today; the junior's time is the cost (no public figure).\n\n## What their customers complain about\n- \"it miscategorises transfers as income\" https://example.com/reviews/statementco\n\n## Not found\n- No broker-side product with public pricing.\n\n## Sources\n- https://example.com/statementco\n- https://example.com/cashflow\n- https://example.com/forum/templates\n- https://example.com/reviews/statementco",
5
+ "questions": [ { "context": "Which geography counts: UK only, or UK and Ireland?", "options": ["UK only", "UK and Ireland", "don't know"], "allow_free_text": true } ]
6
+ }
@@ -0,0 +1,14 @@
1
+ {
2
+ "seat": "retro",
3
+ "summary_md": "Two tasks, one retry. The first reviewer round found a missing status.",
4
+ "proposals": [
5
+ {
6
+ "kind": "test",
7
+ "text": "Add a test that a new collection starts in status pending."
8
+ },
9
+ {
10
+ "kind": "gotcha",
11
+ "text": "Collections must set status on create; reviewers caught it once."
12
+ }
13
+ ]
14
+ }
@@ -0,0 +1,11 @@
1
+ {
2
+ "task": "T1",
3
+ "criteria": [
4
+ { "id": "R1", "tier": "adversarial", "check": "status not set to pending", "result": "fail", "artifact": null }
5
+ ],
6
+ "findings": [
7
+ { "severity": "major", "file": "feature-1.txt", "line": 1, "criterion": "R1", "claim": "collection created without a status", "repro": "POST /collections then GET it", "disposition": null }
8
+ ],
9
+ "verdict": "fail",
10
+ "verifier": { "seat": "reviewer", "adapter": "fake", "model": "default" }
11
+ }
@@ -0,0 +1,13 @@
1
+ {
2
+ "task": "T1",
3
+ "criteria": [
4
+ { "id": "R1", "tier": "adversarial", "check": "read the change; walked the event path", "result": "pass", "artifact": null },
5
+ { "id": "R2", "tier": "adversarial", "check": "duplicate request replayed against the handler", "result": "pass", "artifact": null },
6
+ { "id": "P1", "tier": "adversarial", "check": "unique index on request_id", "result": "pass", "artifact": null }
7
+ ],
8
+ "findings": [
9
+ { "severity": "minor", "file": "feature-1.txt", "line": 1, "criterion": null, "claim": "wording could be clearer", "repro": "read the file", "disposition": null }
10
+ ],
11
+ "verdict": "pass",
12
+ "verifier": { "seat": "reviewer", "adapter": "fake", "model": "default" }
13
+ }
@@ -0,0 +1,8 @@
1
+ {
2
+ "seat": "scout",
3
+ "summary_md": "Sample: 3 support exports and 2 broker emails, Sept–Oct 2026. Over-represents brokers who already complain. Small.",
4
+ "artifact_md": "## O1 · Reading a year of bank statements by hand takes a day per application\nSources: 4 (tickets__t1.txt, tickets__t2.txt, emails__broker-a.txt, emails__broker-b.txt)\nSeverity: high — a day of a broker's time per deal, deals lost to faster lenders\nQuote: \"I spend most of Tuesday on statements for one client\" (emails__broker-a.txt)\nToday: spreadsheets and a junior who keys the numbers in\nSymptom or cause: symptom; the cause is that lenders each want a different pack\n\n## O2 · Lenders ask for the same documents in different formats\nSources: 2 (emails__broker-b.txt, tickets__t3.txt)\nSeverity: medium — rework, not lost deals\nQuote: \"every lender has its own template\" (tickets__t3.txt)\nToday: not said\nSymptom or cause: cause of O1",
5
+ "questions": [
6
+ { "context": "Are the two broker emails from the same firm?", "options": ["same firm", "different firms", "don't know"], "allow_free_text": true }
7
+ ]
8
+ }
@@ -0,0 +1,15 @@
1
+ {
2
+ "seat": "shaper",
3
+ "summary_md": "Event-driven retry with an idempotency key; one new table; flag off by default.",
4
+ "files": {
5
+ "requirements.md": "# Requirements \u2014 Net collection\n\n## R1 \u00b7 event \u00b7 risk: none\nWHEN a collection is created THE SYSTEM SHALL record it with status pending.\n\n## R2 \u00b7 event \u00b7 risk: none\nWHEN the same collection request arrives twice THE SYSTEM SHALL apply side effects exactly once.\n\n## P1 \u00b7 property\nFor any sequence of collection requests, the number of ledger entries SHALL equal the number of distinct request ids.\nValidates: R2\n",
6
+ "design.md": "# Design \u2014 Net collection\n\n## Context\nFailed card payments are retried by hand.\n## Options considered\nA: scheduled job. B: event-driven retry. B chosen.\n## Decision\nEvent-driven retry with an idempotency key per request id.\n## Consequences\nNeeds a dedup table.\n## Data changes\nNew table collection(request_id unique).\n## Interfaces and contracts\nPOST /collections.\n## Failure modes\nDuplicate delivery; partial failure between insert and publish.\n## Migration\nAdditive.\n## Rollout and flag\nFlag net_collect, default off.\n## Observability\nCounter collections_created.\n## Security notes\nMerchant-scoped.\n## Consumer trace\nNone changed.\n"
7
+ },
8
+ "questions": [],
9
+ "proposals": [
10
+ {
11
+ "kind": "task",
12
+ "text": "T1 create collection; T2 idempotency"
13
+ }
14
+ ]
15
+ }
@@ -0,0 +1,2 @@
1
+ # fake adapter gotchas
2
+ - It ignores the prompt; tests that need prompt-dependent behaviour must assert on prompt.md directly.