gateproof 0.1.1 → 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 +266 -55
- package/dist/cli/gateproof.d.ts +3 -0
- package/dist/cli/gateproof.d.ts.map +1 -0
- package/dist/cli/gateproof.js +472 -0
- package/dist/cli/gateproof.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +9 -5
- package/dist/index.js.map +1 -1
- package/dist/prd/define-prd.d.ts +7 -0
- package/dist/prd/define-prd.d.ts.map +1 -0
- package/dist/prd/define-prd.js +8 -0
- package/dist/prd/define-prd.js.map +1 -0
- package/dist/prd/index.d.ts +5 -0
- package/dist/prd/index.d.ts.map +1 -0
- package/dist/prd/index.js +4 -0
- package/dist/prd/index.js.map +1 -0
- package/dist/prd/runner.d.ts +22 -0
- package/dist/prd/runner.d.ts.map +1 -0
- package/dist/prd/runner.js +221 -0
- package/dist/prd/runner.js.map +1 -0
- package/dist/prd/scope-check.d.ts +28 -0
- package/dist/prd/scope-check.d.ts.map +1 -0
- package/dist/prd/scope-check.js +135 -0
- package/dist/prd/scope-check.js.map +1 -0
- package/dist/prd/types.d.ts +21 -0
- package/dist/prd/types.d.ts.map +1 -0
- package/dist/prd/types.js +2 -0
- package/dist/prd/types.js.map +1 -0
- package/dist/report.d.ts +67 -0
- package/dist/report.d.ts.map +1 -0
- package/dist/report.js +51 -0
- package/dist/report.js.map +1 -0
- package/package.json +10 -2
package/README.md
CHANGED
|
@@ -1,47 +1,150 @@
|
|
|
1
1
|
# gateproof
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Build software in reverse. PRD defines what should exist. Gates verify reality. Agent iterations refine until gates pass.
|
|
4
4
|
|
|
5
5
|
## What gateproof does
|
|
6
6
|
|
|
7
|
-
gateproof **
|
|
7
|
+
gateproof enables **agent iterations** with minimal context overhead.
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
**The workflow:**
|
|
10
|
+
1. PRD defines stories (what should exist)
|
|
11
|
+
2. Gates verify reality (does it work?)
|
|
12
|
+
3. Agent gets PRD + gate failure (minimal context)
|
|
13
|
+
4. Agent fixes, gates re-run
|
|
14
|
+
5. Iterate until all gates pass
|
|
10
15
|
|
|
11
|
-
|
|
16
|
+
**Why this works:**
|
|
17
|
+
- PRD is single source of truth (clear intent, minimal context)
|
|
18
|
+
- Gates provide concrete feedback (not vague requirements)
|
|
19
|
+
- Agent gets context only when needed (efficient)
|
|
20
|
+
- Iteration ensures correctness (converges to working code)
|
|
21
|
+
|
|
22
|
+
gateproof **executes gates**. It does not define intent, plans, or workflows. A gate is a test specification: observe logs, run actions, assert results. gateproof runs it and returns evidence.
|
|
12
23
|
|
|
13
24
|
**Authority chain:**
|
|
14
|
-
- **PRD (`prd.ts`
|
|
25
|
+
- **PRD (`prd.ts`)** — authority on intent, order, and dependencies (if you use the PRD runner)
|
|
15
26
|
- **Gate implementations** — authority on how reality is observed
|
|
16
27
|
- **gateproof runtime** — authority on enforcement only
|
|
17
28
|
|
|
18
|
-
gateproof never decides *what* to build. It
|
|
29
|
+
gateproof never decides *what* to build. It returns results; your CI/CD decides whether you are allowed to proceed.
|
|
30
|
+
|
|
31
|
+
## Agent skill: prdts-maker
|
|
32
|
+
|
|
33
|
+
This repo is agent-first. Use the `prdts-maker` skill to turn story bullets into a working `prd.ts`.
|
|
34
|
+
|
|
35
|
+
**How to use it:**
|
|
36
|
+
- Provide story bullets + dependencies in plain language.
|
|
37
|
+
- Ask the agent to run the `prdts-maker` skill and output a complete `prd.ts`.
|
|
38
|
+
- Save and run: `bun run prd.ts`.
|
|
39
|
+
|
|
40
|
+
**Example prompt:**
|
|
41
|
+
```text
|
|
42
|
+
@prdts-maker Create prd.ts for:
|
|
43
|
+
- User can sign up
|
|
44
|
+
- Email verification works (depends on signup)
|
|
45
|
+
- User can log in (depends on verification)
|
|
46
|
+
Include gate files under ./gates/.
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
## CLI: npx gateproof prdts
|
|
50
|
+
|
|
51
|
+
Generate a `prd.ts` from story bullets without opening the repo.
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
echo "User can sign up\nEmail verification works (depends on signup)" | npx gateproof prdts --stdout
|
|
55
|
+
npx gateproof prdts --in stories.txt --out prd.ts
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
This calls Opencode directly. Set `OPENCODE_ZEN_API_KEY` (or pass `--api-key`).
|
|
59
|
+
|
|
60
|
+
Paste mode (interactive stdin):
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
npx gateproof prdts
|
|
64
|
+
# paste stories, then Ctrl-D
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
To target a different Opencode base URL or model:
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
npx gateproof prdts --endpoint https://opencode.ai/zen/v1 --model big-pickle --in stories.txt --out prd.ts
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
## Agent Iterations: The Loop
|
|
74
|
+
|
|
75
|
+
The core innovation: agents work from PRD only, gates verify, iterate until correct.
|
|
76
|
+
|
|
77
|
+
**The iteration loop:**
|
|
78
|
+
1. Run PRD → executes gates in dependency order
|
|
79
|
+
2. Gate fails → agent gets: codebase context (e.g., `AGENTS.md`) + failure output
|
|
80
|
+
3. Agent fixes → makes changes to codebase
|
|
81
|
+
4. Loop repeats → re-run PRD, check if gates pass
|
|
82
|
+
5. All gates pass → done
|
|
83
|
+
|
|
84
|
+
**Why minimal context:**
|
|
85
|
+
- Agent starts with PRD only (no full codebase upfront)
|
|
86
|
+
- Agent gets context only when gates fail (just-in-time)
|
|
87
|
+
- PRD stays as authority (what to build)
|
|
88
|
+
- Gates provide concrete feedback (what's wrong)
|
|
89
|
+
|
|
90
|
+
**Example loop script:**
|
|
91
|
+
```bash
|
|
92
|
+
# patterns/prd/agent-iteration-loop.sh
|
|
93
|
+
while true; do
|
|
94
|
+
bun run prd.ts || {
|
|
95
|
+
# Gate failed - agent gets PRD + failure output
|
|
96
|
+
agent --context prd.ts --failure "$(cat gate-output.txt)"
|
|
97
|
+
# Agent fixes, loop continues
|
|
98
|
+
}
|
|
99
|
+
break # All gates passed
|
|
100
|
+
done
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
**The guardrails:**
|
|
104
|
+
- Max failures (default: 5) → auto-pause if stuck
|
|
105
|
+
- Git diff check → agent must make changes
|
|
106
|
+
- Pause file → manual control
|
|
107
|
+
|
|
108
|
+
This solves the context management problem: agents don't need full codebase context upfront. They get minimal context (PRD), concrete feedback (gate failures), and iterate until correct.
|
|
19
109
|
|
|
20
110
|
## Stories as gates
|
|
21
111
|
|
|
22
112
|
A PRD (Product Requirements Document) defines stories. Stories are gates. Each story references a gate file. The gate file verifies the story against reality.
|
|
23
113
|
|
|
24
|
-
Reality
|
|
114
|
+
Reality is the source of truth; gates make it enforceable in CI.
|
|
25
115
|
|
|
26
116
|
### prd.ts example
|
|
27
117
|
|
|
28
118
|
```typescript
|
|
29
119
|
// prd.ts
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
120
|
+
import { definePrd } from "gateproof/prd";
|
|
121
|
+
|
|
122
|
+
export const prd = definePrd({
|
|
123
|
+
stories: [
|
|
124
|
+
{
|
|
125
|
+
id: "user-signup",
|
|
126
|
+
title: "User can sign up",
|
|
127
|
+
gateFile: "./gates/user-signup.gate.ts",
|
|
128
|
+
},
|
|
129
|
+
{
|
|
130
|
+
id: "email-verification",
|
|
131
|
+
title: "User receives verification email",
|
|
132
|
+
gateFile: "./gates/email-verification.gate.ts",
|
|
133
|
+
dependsOn: ["user-signup"],
|
|
134
|
+
},
|
|
135
|
+
] as const, // keep story IDs as literal types
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
// Make it executable
|
|
139
|
+
if (import.meta.main) {
|
|
140
|
+
const { runPrd } = await import("gateproof/prd");
|
|
141
|
+
const result = await runPrd(prd);
|
|
142
|
+
if (!result.success) {
|
|
143
|
+
if (result.failedStory) console.error(`Failed at: ${result.failedStory.id}`);
|
|
144
|
+
process.exit(1);
|
|
43
145
|
}
|
|
44
|
-
|
|
146
|
+
process.exit(0);
|
|
147
|
+
}
|
|
45
148
|
```
|
|
46
149
|
|
|
47
150
|
Each story references a gate file. The gate file uses gateproof's API:
|
|
@@ -51,55 +154,111 @@ Each story references a gate file. The gate file uses gateproof's API:
|
|
|
51
154
|
import { Gate, Act, Assert } from "gateproof";
|
|
52
155
|
import { CloudflareProvider } from "gateproof/cloudflare";
|
|
53
156
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
157
|
+
export async function run() {
|
|
158
|
+
const provider = CloudflareProvider({
|
|
159
|
+
accountId: process.env.CLOUDFLARE_ACCOUNT_ID!,
|
|
160
|
+
apiToken: process.env.CLOUDFLARE_API_TOKEN!,
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
const result = await Gate.run({
|
|
164
|
+
name: "user-signup",
|
|
165
|
+
observe: provider.observe({ backend: "analytics", dataset: "worker_logs" }),
|
|
166
|
+
act: [Act.browser({ url: "https://app.example.com/signup" })],
|
|
167
|
+
assert: [
|
|
168
|
+
Assert.noErrors(),
|
|
169
|
+
Assert.hasAction("user_created"),
|
|
170
|
+
],
|
|
171
|
+
});
|
|
172
|
+
|
|
173
|
+
return { status: result.status };
|
|
174
|
+
}
|
|
175
|
+
```
|
|
58
176
|
|
|
59
|
-
|
|
60
|
-
name: "user-signup",
|
|
61
|
-
observe: provider.observe({ backend: "analytics", dataset: "worker_logs" }),
|
|
62
|
-
act: [Act.browser({ url: "https://app.example.com/signup" })],
|
|
63
|
-
assert: [
|
|
64
|
-
Assert.noErrors(),
|
|
65
|
-
Assert.hasAction("user_created")
|
|
66
|
-
]
|
|
67
|
-
});
|
|
177
|
+
**gateproof does not own your PRD’s intent or state.** If you choose to use `gateproof/prd`, your PRD must match a small capsule shape (`stories[]` with `id/title/gateFile/dependsOn?`). Otherwise, orchestrate gates however you want — gateproof only cares about executing gate files.
|
|
68
178
|
|
|
69
|
-
|
|
179
|
+
Stories execute in dependency order. The runner stops on first failure. Progress is not declared. It is proven.
|
|
180
|
+
|
|
181
|
+
## How it works
|
|
182
|
+
|
|
183
|
+
The PRD defines stories. Stories reference gate files. Gate files use gateproof's API. Gates can be enforced in CI before merge/deploy.
|
|
184
|
+
|
|
185
|
+
**The sequence:** PRD story → gate file → gate execution → story marked "done" only when gate passes.
|
|
186
|
+
|
|
187
|
+
**For agent iterations:** PRD → gate fails → agent fixes → gate re-runs → loop until pass.
|
|
188
|
+
|
|
189
|
+
Run your PRD:
|
|
190
|
+
|
|
191
|
+
```bash
|
|
192
|
+
bun run prd.ts
|
|
70
193
|
```
|
|
71
194
|
|
|
72
|
-
|
|
195
|
+
Run agent iteration loop:
|
|
196
|
+
|
|
197
|
+
```bash
|
|
198
|
+
bash patterns/prd/agent-iteration-loop.sh
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
## Hardening `prd.ts` (recommended)
|
|
202
|
+
|
|
203
|
+
Treat `prd.ts` like code: typecheck + validate before push + enforce in CI.
|
|
204
|
+
|
|
205
|
+
- **Validate PRD**:
|
|
206
|
+
|
|
207
|
+
```bash
|
|
208
|
+
bun run prd:validate
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
- **Pre-push (default for everyone on your team)**: add to your `prepush` script (Husky calls it).
|
|
73
212
|
|
|
74
213
|
```json
|
|
75
214
|
{
|
|
76
|
-
"
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
"title": "User can sign up",
|
|
80
|
-
"gateFile": "./gates/user-signup.gate.ts",
|
|
81
|
-
"status": "pending"
|
|
82
|
-
}
|
|
83
|
-
]
|
|
215
|
+
"scripts": {
|
|
216
|
+
"prepush": "bun run typecheck && bun run prd:validate && bun test"
|
|
217
|
+
}
|
|
84
218
|
}
|
|
85
219
|
```
|
|
86
220
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
Stories carry state. The PRD tracks which stories are pending, in progress, or done. gateproof does not manage this state. It only enforces: proceed only when gates pass.
|
|
221
|
+
- **CI**: run the validator before running PRD/tests.
|
|
90
222
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
223
|
+
```yaml
|
|
224
|
+
- name: Validate PRD
|
|
225
|
+
run: bun run prd:validate
|
|
226
|
+
```
|
|
94
227
|
|
|
95
|
-
|
|
228
|
+
- **Monorepo**: validate any PRD file by path.
|
|
96
229
|
|
|
97
|
-
|
|
230
|
+
```bash
|
|
231
|
+
bun run scripts/prd-validate.ts packages/api/prd.ts
|
|
232
|
+
```
|
|
98
233
|
|
|
99
234
|
## Design notes
|
|
100
235
|
|
|
101
236
|
- [Effect and Schema: Gateproof's Foundation](docs/effect-and-schema.md)
|
|
102
237
|
|
|
238
|
+
## Writing good gates (agent-first)
|
|
239
|
+
|
|
240
|
+
Gates can fail loudly. They can also pass on silence if you write weak assertions.
|
|
241
|
+
|
|
242
|
+
- **Always assert at least one positive signal**: `Assert.hasAction(...)` and/or `Assert.hasStage(...)`. If your backend can be silent, add an explicit “evidence must exist” custom assertion.
|
|
243
|
+
- **Don’t rely on absence-only checks**: `Assert.noErrors()` alone can pass if you collect no logs.
|
|
244
|
+
- **Treat observability as part of the system**: your confidence is bounded by what you can observe.
|
|
245
|
+
|
|
246
|
+
## Limits / Non-goals
|
|
247
|
+
|
|
248
|
+
- **Not a planner or orchestrator**: gateproof executes gates; your PRD (or CI) decides what to run and in what context.
|
|
249
|
+
- **Not a truth oracle**: if your backend drops logs, a gate can be wrong. Gateproof can’t fix missing telemetry.
|
|
250
|
+
- **Enforcement is external**: gateproof returns results; CI/CD decides whether to block merge/deploy.
|
|
251
|
+
|
|
252
|
+
## Common objections (and answers)
|
|
253
|
+
|
|
254
|
+
- **"Isn't this just E2E tests?"** Similar goal, different anchor. Gates are evidence-first (logs/telemetry + explicit assertions), not DOM-only. The contract is: observe → act → assert → evidence.
|
|
255
|
+
|
|
256
|
+
- **"What about flaky telemetry?"** Gates don't fix missing telemetry. They make the dependency explicit. If your backend drops logs, a gate can be wrong — but you'll know immediately, not in production.
|
|
257
|
+
|
|
258
|
+
- **"Isn't this overhead?"** It can be. The pitch isn't "gate everything." It's "gate the few transitions that are expensive to get wrong." Start with one critical path.
|
|
259
|
+
|
|
260
|
+
- **"Will this lock us in?"** Gates are just TypeScript files. If you stop using gateproof, you keep the scripts and the intent. No vendor lock-in.
|
|
261
|
+
|
|
103
262
|
## Quick Start
|
|
104
263
|
|
|
105
264
|
The API is minimal: three concepts (Gate, Act, Assert). Here's a gate:
|
|
@@ -110,14 +269,14 @@ import { CloudflareProvider } from "gateproof/cloudflare";
|
|
|
110
269
|
|
|
111
270
|
const provider = CloudflareProvider({
|
|
112
271
|
accountId: process.env.CLOUDFLARE_ACCOUNT_ID!,
|
|
113
|
-
apiToken: process.env.CLOUDFLARE_API_TOKEN
|
|
272
|
+
apiToken: process.env.CLOUDFLARE_API_TOKEN!,
|
|
114
273
|
});
|
|
115
274
|
|
|
116
275
|
const result = await Gate.run({
|
|
117
276
|
name: "api-health-check",
|
|
118
277
|
observe: provider.observe({ backend: "analytics", dataset: "worker_logs" }),
|
|
119
278
|
act: [Act.browser({ url: "https://my-worker.workers.dev" })],
|
|
120
|
-
assert: [Assert.noErrors(), Assert.hasAction("request_received")]
|
|
279
|
+
assert: [Assert.noErrors(), Assert.hasAction("request_received")],
|
|
121
280
|
});
|
|
122
281
|
|
|
123
282
|
if (result.status !== "success") process.exit(1);
|
|
@@ -163,6 +322,42 @@ Assert.custom("name", fn) // Custom: (logs) => boolean
|
|
|
163
322
|
}
|
|
164
323
|
```
|
|
165
324
|
|
|
325
|
+
## PRD Runner
|
|
326
|
+
|
|
327
|
+
gateproof provides a PRD runner that executes stories in dependency order:
|
|
328
|
+
|
|
329
|
+
```typescript
|
|
330
|
+
import { definePrd, runPrd } from "gateproof/prd";
|
|
331
|
+
|
|
332
|
+
const prd = definePrd({
|
|
333
|
+
stories: [
|
|
334
|
+
{
|
|
335
|
+
id: "story-1",
|
|
336
|
+
title: "First story",
|
|
337
|
+
gateFile: "./gates/story-1.gate.ts",
|
|
338
|
+
},
|
|
339
|
+
{
|
|
340
|
+
id: "story-2",
|
|
341
|
+
title: "Second story",
|
|
342
|
+
gateFile: "./gates/story-2.gate.ts",
|
|
343
|
+
dependsOn: ["story-1"],
|
|
344
|
+
},
|
|
345
|
+
] as const, // keep story IDs as literal types
|
|
346
|
+
});
|
|
347
|
+
|
|
348
|
+
const result = await runPrd(prd);
|
|
349
|
+
if (!result.success) {
|
|
350
|
+
console.error(`Failed at: ${result.failedStory?.id}`);
|
|
351
|
+
process.exit(1);
|
|
352
|
+
}
|
|
353
|
+
```
|
|
354
|
+
|
|
355
|
+
The runner:
|
|
356
|
+
- Validates dependencies (unknown IDs and cycles throw)
|
|
357
|
+
- Topologically sorts stories by `dependsOn`
|
|
358
|
+
- Executes gates in order
|
|
359
|
+
- **Stops on first failure**
|
|
360
|
+
|
|
166
361
|
## Plug Your Backend
|
|
167
362
|
|
|
168
363
|
gateproof works with any observability backend. Just implement the `Backend` interface:
|
|
@@ -202,18 +397,34 @@ See `patterns/` for complete examples:
|
|
|
202
397
|
- `patterns/cloudflare/` - Cloudflare-specific patterns
|
|
203
398
|
- `patterns/ci-cd/` - CI/CD integration
|
|
204
399
|
- `patterns/advanced/` - Advanced patterns
|
|
400
|
+
- `patterns/prd/` - PRD-as-code + agent iteration loop examples
|
|
401
|
+
- `patterns/agent-first/` - Spec interview → PRD stories (agent-first)
|
|
402
|
+
- `examples/hello-world-agent/` - Minimal agent with 5 tools + end-to-end gates
|
|
403
|
+
|
|
404
|
+
Run the hello-world agent example (requires `OPENCODE_ZEN_API_KEY` and network access to `opencode.ai`):
|
|
405
|
+
|
|
406
|
+
```bash
|
|
407
|
+
export OPENCODE_ZEN_API_KEY="your_key_here"
|
|
408
|
+
bun run examples/hello-world-agent/prd.ts
|
|
409
|
+
```
|
|
205
410
|
|
|
206
411
|
## CI/CD
|
|
207
412
|
|
|
208
413
|
gateproof enforces gates in CI/CD. See `patterns/ci-cd/github-actions.ts` for examples.
|
|
209
414
|
|
|
415
|
+
Run your PRD in CI:
|
|
416
|
+
|
|
417
|
+
```yaml
|
|
418
|
+
- name: Run PRD
|
|
419
|
+
run: bun run prd.ts
|
|
420
|
+
```
|
|
421
|
+
|
|
210
422
|
## Requirements
|
|
211
423
|
|
|
212
424
|
- Node.js 18+ or Bun
|
|
213
425
|
- `playwright` (optional, for Act.browser)
|
|
214
426
|
- Cloudflare credentials (for CloudflareProvider, or bring your own backend)
|
|
215
427
|
|
|
216
|
-
|
|
217
428
|
## License
|
|
218
429
|
|
|
219
430
|
MIT
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gateproof.d.ts","sourceRoot":"","sources":["../../src/cli/gateproof.ts"],"names":[],"mappings":""}
|