gateproof 0.2.1 → 0.2.4

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 (62) hide show
  1. package/README.md +132 -340
  2. package/dist/act.d.ts +45 -0
  3. package/dist/act.d.ts.map +1 -1
  4. package/dist/act.js +22 -0
  5. package/dist/act.js.map +1 -1
  6. package/dist/action-executors.d.ts +17 -0
  7. package/dist/action-executors.d.ts.map +1 -1
  8. package/dist/action-executors.js +60 -0
  9. package/dist/action-executors.js.map +1 -1
  10. package/dist/assert.d.ts +20 -0
  11. package/dist/assert.d.ts.map +1 -1
  12. package/dist/assert.js +32 -0
  13. package/dist/assert.js.map +1 -1
  14. package/dist/authority.d.ts +34 -0
  15. package/dist/authority.d.ts.map +1 -0
  16. package/dist/authority.js +141 -0
  17. package/dist/authority.js.map +1 -0
  18. package/dist/cli/gateproof.js +81 -5
  19. package/dist/cli/gateproof.js.map +1 -1
  20. package/dist/filepath-backend.d.ts +64 -0
  21. package/dist/filepath-backend.d.ts.map +1 -0
  22. package/dist/filepath-backend.js +126 -0
  23. package/dist/filepath-backend.js.map +1 -0
  24. package/dist/filepath-protocol.d.ts +214 -0
  25. package/dist/filepath-protocol.d.ts.map +1 -0
  26. package/dist/filepath-protocol.js +239 -0
  27. package/dist/filepath-protocol.js.map +1 -0
  28. package/dist/filepath-runtime.d.ts +100 -0
  29. package/dist/filepath-runtime.d.ts.map +1 -0
  30. package/dist/filepath-runtime.js +190 -0
  31. package/dist/filepath-runtime.js.map +1 -0
  32. package/dist/http-backend.d.ts +9 -0
  33. package/dist/http-backend.d.ts.map +1 -1
  34. package/dist/http-backend.js +50 -8
  35. package/dist/http-backend.js.map +1 -1
  36. package/dist/index.d.ts +11 -2
  37. package/dist/index.d.ts.map +1 -1
  38. package/dist/index.js +9 -1
  39. package/dist/index.js.map +1 -1
  40. package/dist/prd/index.d.ts +2 -0
  41. package/dist/prd/index.d.ts.map +1 -1
  42. package/dist/prd/index.js +4 -0
  43. package/dist/prd/index.js.map +1 -1
  44. package/dist/prd/loop.d.ts +160 -0
  45. package/dist/prd/loop.d.ts.map +1 -0
  46. package/dist/prd/loop.js +462 -0
  47. package/dist/prd/loop.js.map +1 -0
  48. package/dist/prd/runner.d.ts +2 -5
  49. package/dist/prd/runner.d.ts.map +1 -1
  50. package/dist/prd/runner.js +154 -122
  51. package/dist/prd/runner.js.map +1 -1
  52. package/dist/prd/scope-defaults.d.ts +75 -0
  53. package/dist/prd/scope-defaults.d.ts.map +1 -0
  54. package/dist/prd/scope-defaults.js +235 -0
  55. package/dist/prd/scope-defaults.js.map +1 -0
  56. package/dist/prd/types.d.ts +80 -0
  57. package/dist/prd/types.d.ts.map +1 -1
  58. package/dist/report.d.ts +70 -0
  59. package/dist/report.d.ts.map +1 -1
  60. package/dist/report.js +183 -0
  61. package/dist/report.js.map +1 -1
  62. package/package.json +11 -3
package/README.md CHANGED
@@ -1,269 +1,89 @@
1
1
  # gateproof
2
2
 
3
- Build software in reverse. PRD defines what should exist. Gates verify reality. Agent iterations refine until gates pass.
3
+ Software is built in reverse. You know what you want before you know how to get there. TDD proved the idea: write the test first, then make it pass. Gateproof takes the next step.
4
4
 
5
- ## What gateproof does
5
+ Write stories. Attach gates. Let agents iterate until reality matches intent.
6
6
 
7
- gateproof enables **agent iterations** with minimal context overhead.
7
+ A **gate** observes real evidence (logs, telemetry), acts (browser, shell, deploy), and asserts outcomes. A **story** is a gate with a name and a place in a plan. A **prd.ts** is a list of stories in dependency order. The agent's only job is to make the next failing gate pass.
8
8
 
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
9
+ ## The thesis
15
10
 
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)
11
+ Plans are solid. Implementation is liquid.
21
12
 
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.
13
+ Any codebase can be scoped down to stories and a `prd.ts`. Multiple agents can work the same plan, falling through the same checkpoints. Once a gate passes, previous work can't break -- the gate proves it. The skill shifts from writing code to defining the right guardrails.
23
14
 
24
- **Authority chain:**
25
- - **PRD (`prd.ts`)** — authority on intent, order, and dependencies (if you use the PRD runner)
26
- - **Gate implementations** — authority on how reality is observed
27
- - **gateproof runtime** — authority on enforcement only
15
+ Gates are checkpoints that keep agents safe. They don't decide intent. They verify reality.
28
16
 
29
- gateproof never decides *what* to build. It returns results; your CI/CD decides whether you are allowed to proceed.
17
+ ## Why this works
30
18
 
31
- ## Agent skill: prdts-maker
19
+ Formal verification research established that the relationship between a specification and its implementation — called **refinement** — is itself a testable property. You don't need a theorem prover to get value from this idea. You can test refinement cheaply by running the system and checking that its behavior satisfies the spec.
32
20
 
33
- This repo is agent-first. Use the `prdts-maker` skill to turn story bullets into a working `prd.ts`.
21
+ Gateproof distills this into three primitives:
34
22
 
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`.
23
+ 1. **Observe** collect real evidence (logs, telemetry) from a running system
24
+ 2. **Act** trigger real behavior (browser navigation, shell commands, deploys)
25
+ 3. **Assert** check that the evidence satisfies the specification
39
26
 
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
27
+ Each gate is a refinement check: does the running system's behavior refine what the story claims? The PRD orders these checks by dependency, so failures localize to the first broken obligation.
50
28
 
51
- Generate a `prd.ts` from story bullets without opening the repo.
29
+ This is a deliberate simplification. We trade random input generation and exhaustive coverage for something an engineer can write in minutes and an agent can iterate against in a loop. The gate is the contract. The loop is the proof search.
52
30
 
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
- ```
31
+ > Lineage: the *observe → act → assert* pattern draws on property-based testing ideas from [Chen, Rizkallah et al. — "Property-Based Testing: Climbing the Stairway to Verification" (SLE 2022)](https://doi.org/10.1145/3567512.3567520), which demonstrated that refinement properties can serve as a practical, incremental path toward verified systems.
57
32
 
58
- This calls Opencode directly. Set `OPENCODE_ZEN_API_KEY` (or pass `--api-key`).
59
-
60
- Paste mode (interactive stdin):
33
+ ## Install
61
34
 
62
35
  ```bash
63
- npx gateproof prdts
64
- # paste stories, then Ctrl-D
36
+ bun add gateproof
65
37
  ```
66
38
 
67
- To target a different Opencode base URL or model:
39
+ ## Minimal gate
68
40
 
69
- ```bash
70
- npx gateproof prdts --endpoint https://opencode.ai/zen/v1 --model big-pickle --in stories.txt --out prd.ts
71
- ```
41
+ ```ts
42
+ import { Gate, Act, Assert, createHttpObserveResource } from "gateproof";
72
43
 
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)
44
+ const result = await Gate.run({
45
+ name: "post-deploy",
46
+ observe: createHttpObserveResource({
47
+ url: "https://api.example.com/health",
48
+ }),
49
+ act: [Act.wait(500)],
50
+ assert: [Assert.noErrors()],
51
+ stop: { maxMs: 10_000 },
52
+ });
89
53
 
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
54
+ if (result.status !== "success") process.exit(1);
101
55
  ```
102
56
 
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.
109
-
110
- ## Stories as gates
111
-
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.
113
-
114
- Reality is the source of truth; gates make it enforceable in CI.
115
-
116
- ### prd.ts example
57
+ ## Stories + PRD
117
58
 
118
- ```typescript
119
- // prd.ts
120
- import { definePrd } from "gateproof/prd";
59
+ ```ts
60
+ import { definePrd, runPrd } from "gateproof/prd";
121
61
 
122
- export const prd = definePrd({
62
+ const prd = definePrd({
123
63
  stories: [
124
64
  {
125
65
  id: "user-signup",
126
- title: "User can sign up",
127
- gateFile: "./gates/user-signup.gate.ts",
66
+ title: "User can sign up with email",
67
+ gateFile: "./gates/signup.gate.ts",
128
68
  },
129
69
  {
130
70
  id: "email-verification",
131
71
  title: "User receives verification email",
132
- gateFile: "./gates/email-verification.gate.ts",
72
+ gateFile: "./gates/verify.gate.ts",
133
73
  dependsOn: ["user-signup"],
134
74
  },
135
- ] as const, // keep story IDs as literal types
75
+ ] as const,
136
76
  });
137
77
 
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);
145
- }
146
- process.exit(0);
147
- }
148
- ```
149
-
150
- Each story references a gate file. The gate file uses gateproof's API:
151
-
152
- ```typescript
153
- // gates/user-signup.gate.ts
154
- import { Gate, Act, Assert } from "gateproof";
155
- import { CloudflareProvider } from "gateproof/cloudflare";
156
-
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
- ```
176
-
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.
178
-
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
193
- ```
194
-
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).
212
-
213
- ```json
214
- {
215
- "scripts": {
216
- "prepush": "bun run typecheck && bun run prd:validate && bun test"
217
- }
218
- }
219
- ```
220
-
221
- - **CI**: run the validator before running PRD/tests.
222
-
223
- ```yaml
224
- - name: Validate PRD
225
- run: bun run prd:validate
226
- ```
227
-
228
- - **Monorepo**: validate any PRD file by path.
229
-
230
- ```bash
231
- bun run scripts/prd-validate.ts packages/api/prd.ts
78
+ const result = await runPrd(prd);
79
+ if (!result.success) process.exit(1);
232
80
  ```
233
81
 
234
- ## Design notes
235
-
236
- - [Effect and Schema: Gateproof's Foundation](docs/effect-and-schema.md)
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.
82
+ ## Assertions
245
83
 
246
- ## Limits / Non-goals
84
+ `Assert.noErrors()`, `Assert.hasAction(name)`, `Assert.hasStage(name)`, `Assert.custom(name, fn)`, `Assert.authority(policy)`.
247
85
 
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
-
262
- ## Quick Start
263
-
264
- The API is minimal: three concepts (Gate, Act, Assert). Here's a gate:
265
-
266
- ```typescript
86
+ ```ts
267
87
  import { Gate, Act, Assert } from "gateproof";
268
88
  import { CloudflareProvider } from "gateproof/cloudflare";
269
89
 
@@ -273,157 +93,129 @@ const provider = CloudflareProvider({
273
93
  });
274
94
 
275
95
  const result = await Gate.run({
276
- name: "api-health-check",
96
+ name: "checkout-flow",
277
97
  observe: provider.observe({ backend: "analytics", dataset: "worker_logs" }),
278
- act: [Act.browser({ url: "https://my-worker.workers.dev" })],
279
- assert: [Assert.noErrors(), Assert.hasAction("request_received")],
98
+ act: [Act.browser({ url: "https://app.example.com/checkout" })],
99
+ assert: [
100
+ Assert.noErrors(),
101
+ Assert.hasAction("checkout_started"),
102
+ Assert.custom("has-total", (logs) => logs.some(l => (l as { data?: { total?: number } }).data?.total > 0)),
103
+ ],
104
+ stop: { maxMs: 15_000 },
280
105
  });
281
-
282
106
  if (result.status !== "success") process.exit(1);
283
107
  ```
284
108
 
285
- This gate is a story verification. The PRD points at it.
109
+ ## Agent gates
286
110
 
287
- ## Core API
288
-
289
- ### Gate.run(spec)
290
- Run a gate. Returns a result with status, logs, and evidence.
291
- `spec.name` is optional metadata for labeling a gate.
292
-
293
- ### Actions
294
- ```typescript
295
- Act.exec("command") // Run shell command
296
- Act.browser({ url, headless? }) // Browser automation (needs playwright)
297
- Act.wait(ms) // Sleep
298
- Act.deploy({ worker }) // Deploy marker
299
- ```
111
+ Spawn an AI agent in an isolated container, observe its NDJSON event stream, and assert what it's allowed to do.
300
112
 
301
- ### Assertions
302
- ```typescript
303
- Assert.noErrors() // No error logs
304
- Assert.hasAction("name") // Action was logged
305
- Assert.hasStage("worker") // Stage was seen
306
- Assert.custom("name", fn) // Custom: (logs) => boolean
307
- ```
113
+ ```ts
114
+ import { Gate, Act, Assert } from "gateproof";
115
+ import { setFilepathRuntime, CloudflareSandboxRuntime } from "gateproof";
116
+ import { getSandbox } from "@cloudflare/sandbox";
117
+
118
+ // 1. Wire up your container runtime (once at startup)
119
+ setFilepathRuntime(new CloudflareSandboxRuntime({
120
+ getSandbox: (config) => getSandbox(env.Sandbox, `agent-${config.name}`),
121
+ }));
122
+
123
+ // 2. Run the gate
124
+ const container = await runtime.spawn({
125
+ name: "fix-auth",
126
+ agent: "claude-code",
127
+ model: "claude-sonnet-4-20250514",
128
+ task: "Fix the null pointer in src/auth.ts",
129
+ });
308
130
 
309
- ### Result
310
- ```typescript
311
- {
312
- status: "success" | "failed" | "timeout",
313
- durationMs: number,
314
- logs: Log[],
315
- evidence: {
316
- requestIds: string[],
317
- stagesSeen: string[],
318
- actionsSeen: string[],
319
- errorTags: string[]
320
- },
321
- error?: Error
322
- }
131
+ const observe = createFilepathObserveResource(container, "fix-auth");
132
+
133
+ await Gate.run({
134
+ name: "fix-auth-bug",
135
+ observe,
136
+ act: [Act.wait(300_000)],
137
+ assert: [
138
+ Assert.noErrors(),
139
+ Assert.hasAction("commit"),
140
+ Assert.hasAction("done"),
141
+ Assert.authority({
142
+ canCommit: true,
143
+ canSpawn: false,
144
+ forbiddenTools: ["delete_file"],
145
+ }),
146
+ ],
147
+ stop: { idleMs: 5000, maxMs: 300_000 },
148
+ });
323
149
  ```
324
150
 
325
- ## PRD Runner
151
+ `Assert.authority()` enforces governance policies against the agent's actual behavior — what it committed, spawned, and which tools it used.
326
152
 
327
- gateproof provides a PRD runner that executes stories in dependency order:
153
+ ## Writing good gates
328
154
 
329
- ```typescript
330
- import { definePrd, runPrd } from "gateproof/prd";
155
+ The hardest part of gateproof is not the library — it's writing gates that actually prove what you think they prove.
331
156
 
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
- });
157
+ **A weak gate passes on silence.** If your system emits no logs and your only assertion is `Assert.noErrors()`, the gate passes vacuously. Nothing was tested. Use `requirePositiveSignal: true` on stories, or assert specific evidence (`Assert.hasAction`, `Assert.hasStage`).
347
158
 
348
- const result = await runPrd(prd);
349
- if (!result.success) {
350
- console.error(`Failed at: ${result.failedStory?.id}`);
351
- process.exit(1);
352
- }
353
- ```
159
+ **A good gate is falsifiable.** Ask: "what broken implementation would still pass this gate?" If the answer is "many," the gate is too weak. Tighten it until a broken system fails.
354
160
 
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**
161
+ **Start narrow, then widen.** One specific assertion that catches a real failure is worth more than ten vague ones. You can always add assertions later — you can't take back a false pass.
360
162
 
361
- ## Plug Your Backend
163
+ ## The loop
362
164
 
363
- gateproof works with any observability backend. Just implement the `Backend` interface:
165
+ Gate fails. Agent reads the failure evidence. Agent fixes code. Gate re-runs. Loop until pass.
364
166
 
365
- ```typescript
366
- interface Backend {
367
- start(): Effect.Effect<LogStream, ObservabilityError>;
368
- stop(): Effect.Effect<void, ObservabilityError>;
369
- }
370
- ```
167
+ **Bring your own agent** — the loop takes any async function:
371
168
 
372
- See `patterns/` for examples including:
373
- - Cloudflare Analytics Engine
374
- - Cloudflare Workers Logs API
375
- - CLI Stream (local dev)
376
- - Custom backends
169
+ ```ts
170
+ import { runPrdLoop } from "gateproof/prd";
377
171
 
378
- ## Cloudflare Backends
172
+ await runPrdLoop("./prd.ts", {
173
+ agent: async (ctx) => {
174
+ // ctx.failureSummary — what failed and why
175
+ // ctx.recentDiff — recent git changes
176
+ // ctx.prdContent — full PRD for context
177
+ // ctx.failedStory — the Story object that failed
178
+ // ctx.signal — AbortSignal for cancellation
379
179
 
380
- ```typescript
381
- const provider = CloudflareProvider({ accountId, apiToken });
180
+ // Use any agent: Claude Code, Cursor, Codex, custom LLM wrapper
181
+ const result = await yourAgent.fix(ctx.failureSummary);
182
+ return { changes: result.files, commitMsg: "fix: resolve failing gate" };
183
+ },
184
+ maxIterations: 5,
185
+ });
186
+ ```
382
187
 
383
- // Analytics Engine
384
- provider.observe({ backend: "analytics", dataset: "worker_logs" })
188
+ Or use a pre-built agent:
385
189
 
386
- // Workers Logs API
387
- provider.observe({ backend: "workers-logs", workerName: "my-worker" })
190
+ ```ts
191
+ import { runPrdLoop, createOpenCodeAgent } from "gateproof/prd";
388
192
 
389
- // CLI Stream (local dev)
390
- provider.observe({ backend: "cli-stream", workerName: "my-worker" })
193
+ await runPrdLoop("./prd.ts", {
194
+ agent: createOpenCodeAgent({ apiKey: process.env.OPENCODE_ZEN_API_KEY }),
195
+ maxIterations: 7,
196
+ });
391
197
  ```
392
198
 
393
- ## Examples
394
-
395
- See `patterns/` for complete examples:
396
- - `patterns/basic/` - Basic usage patterns
397
- - `patterns/cloudflare/` - Cloudflare-specific patterns
398
- - `patterns/ci-cd/` - CI/CD integration
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`):
199
+ ## Generate a PRD from plain language
405
200
 
406
201
  ```bash
407
- export OPENCODE_ZEN_API_KEY="your_key_here"
408
- bun run examples/hello-world-agent/prd.ts
202
+ echo "Build a signup flow with email verification" | npx gateproof prdts --stdout
409
203
  ```
410
204
 
411
- ## CI/CD
205
+ ## End-to-end CLI pipeline
412
206
 
413
- gateproof enforces gates in CI/CD. See `patterns/ci-cd/github-actions.ts` for examples.
207
+ > Contributed by @grok
414
208
 
415
- Run your PRD in CI:
416
-
417
- ```yaml
418
- - name: Run PRD
419
- run: bun run prd.ts
209
+ ```bash
210
+ # Natural language → prd.ts → agent loop
211
+ echo "Build a signup flow with email verification" | npx gateproof prdts --out prd.ts
212
+ npx gateproof smoke ./prd.ts
213
+ bun run prd.ts
420
214
  ```
421
215
 
422
- ## Requirements
216
+ ## Docs
423
217
 
424
- - Node.js 18+ or Bun
425
- - `playwright` (optional, for Act.browser)
426
- - Cloudflare credentials (for CloudflareProvider, or bring your own backend)
218
+ Full documentation, tutorials, and API reference: [gateproof.dev/docs](https://gateproof.dev/docs)
427
219
 
428
220
  ## License
429
221
 
package/dist/act.d.ts CHANGED
@@ -1,3 +1,26 @@
1
+ /**
2
+ * Agent configuration for Filepath container execution.
3
+ *
4
+ * Specifies which agent runtime, model, and task to run inside
5
+ * an isolated container. The container communicates via NDJSON
6
+ * on stdout/stdin using the Filepath Agent Protocol (FAP).
7
+ */
8
+ export interface AgentActConfig {
9
+ /** Display name for the agent (used in logs and tree UI) */
10
+ name: string;
11
+ /** Agent runtime: "claude-code" | "codex" | "cursor" | or a custom Docker image */
12
+ agent: string;
13
+ /** Model to use (e.g. "claude-sonnet-4-20250514", "gpt-4o") */
14
+ model: string;
15
+ /** Task description — sent as FILEPATH_TASK env var */
16
+ task: string;
17
+ /** Git repository URL to clone into /workspace */
18
+ repo?: string;
19
+ /** Additional environment variables for the container */
20
+ env?: Record<string, string>;
21
+ /** Timeout for the entire agent run in ms (default: 300_000 = 5 min) */
22
+ timeoutMs?: number;
23
+ }
1
24
  export type Action = {
2
25
  _tag: "Deploy";
3
26
  worker: string;
@@ -14,6 +37,9 @@ export type Action = {
14
37
  command: string;
15
38
  cwd?: string;
16
39
  timeoutMs?: number;
40
+ } | {
41
+ _tag: "Agent";
42
+ config: AgentActConfig;
17
43
  };
18
44
  export declare namespace Act {
19
45
  function deploy(config: {
@@ -29,5 +55,24 @@ export declare namespace Act {
29
55
  cwd?: string;
30
56
  timeoutMs?: number;
31
57
  }): Action;
58
+ /**
59
+ * Run an AI agent in a Filepath container.
60
+ *
61
+ * The agent executes in an isolated container with a git repo at /workspace.
62
+ * It communicates via the Filepath Agent Protocol (FAP) — NDJSON events on
63
+ * stdout that get mapped to Gateproof Log entries for gate assertions.
64
+ *
65
+ * @example
66
+ * ```ts
67
+ * Act.agent({
68
+ * name: "fix-auth",
69
+ * agent: "claude-code",
70
+ * model: "claude-sonnet-4-20250514",
71
+ * task: "Fix the authentication bug in src/auth.ts",
72
+ * repo: "https://github.com/org/repo",
73
+ * })
74
+ * ```
75
+ */
76
+ function agent(config: AgentActConfig): Action;
32
77
  }
33
78
  //# sourceMappingURL=act.d.ts.map
package/dist/act.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"act.d.ts","sourceRoot":"","sources":["../src/act.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,MAAM,GACd;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GAClC;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,OAAO,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,GACrE;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,MAAM,CAAA;CAAE,GAC5B;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,GAAG,CAAC,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AAExE,yBAAiB,GAAG,CAAC;IACnB,SAAgB,MAAM,CAAC,MAAM,EAAE;QAAE,MAAM,EAAE,MAAM,CAAA;KAAE,GAAG,MAAM,CAEzD;IAED,SAAgB,OAAO,CAAC,MAAM,EAAE;QAC9B,GAAG,EAAE,MAAM,CAAC;QACZ,QAAQ,CAAC,EAAE,OAAO,CAAC;QACnB,MAAM,CAAC,EAAE,MAAM,CAAC;KACjB,GAAG,MAAM,CAOT;IAED,SAAgB,IAAI,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,CAEvC;IAED,SAAgB,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE;QAAE,GAAG,CAAC,EAAE,MAAM,CAAC;QAAC,SAAS,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,MAAM,CAEzF;CACF"}
1
+ {"version":3,"file":"act.d.ts","sourceRoot":"","sources":["../src/act.ts"],"names":[],"mappings":"AAEA;;;;;;GAMG;AACH,MAAM,WAAW,cAAc;IAC7B,4DAA4D;IAC5D,IAAI,EAAE,MAAM,CAAC;IACb,mFAAmF;IACnF,KAAK,EAAE,MAAM,CAAC;IACd,+DAA+D;IAC/D,KAAK,EAAE,MAAM,CAAC;IACd,uDAAuD;IACvD,IAAI,EAAE,MAAM,CAAC;IACb,kDAAkD;IAClD,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,yDAAyD;IACzD,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC7B,wEAAwE;IACxE,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,MAAM,MAAM,GACd;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GAClC;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,OAAO,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,GACrE;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,MAAM,CAAA;CAAE,GAC5B;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,GAAG,CAAC,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,GACnE;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,MAAM,EAAE,cAAc,CAAA;CAAE,CAAC;AAE9C,yBAAiB,GAAG,CAAC;IACnB,SAAgB,MAAM,CAAC,MAAM,EAAE;QAAE,MAAM,EAAE,MAAM,CAAA;KAAE,GAAG,MAAM,CAEzD;IAED,SAAgB,OAAO,CAAC,MAAM,EAAE;QAC9B,GAAG,EAAE,MAAM,CAAC;QACZ,QAAQ,CAAC,EAAE,OAAO,CAAC;QACnB,MAAM,CAAC,EAAE,MAAM,CAAC;KACjB,GAAG,MAAM,CAOT;IAED,SAAgB,IAAI,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,CAEvC;IAED,SAAgB,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE;QAAE,GAAG,CAAC,EAAE,MAAM,CAAC;QAAC,SAAS,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,MAAM,CAEzF;IAED;;;;;;;;;;;;;;;;;OAiBG;IACH,SAAgB,KAAK,CAAC,MAAM,EAAE,cAAc,GAAG,MAAM,CAEpD;CACF"}
package/dist/act.js CHANGED
@@ -21,5 +21,27 @@ export var Act;
21
21
  return { _tag: "Exec", command, cwd: opts?.cwd, timeoutMs: opts?.timeoutMs };
22
22
  }
23
23
  Act.exec = exec;
24
+ /**
25
+ * Run an AI agent in a Filepath container.
26
+ *
27
+ * The agent executes in an isolated container with a git repo at /workspace.
28
+ * It communicates via the Filepath Agent Protocol (FAP) — NDJSON events on
29
+ * stdout that get mapped to Gateproof Log entries for gate assertions.
30
+ *
31
+ * @example
32
+ * ```ts
33
+ * Act.agent({
34
+ * name: "fix-auth",
35
+ * agent: "claude-code",
36
+ * model: "claude-sonnet-4-20250514",
37
+ * task: "Fix the authentication bug in src/auth.ts",
38
+ * repo: "https://github.com/org/repo",
39
+ * })
40
+ * ```
41
+ */
42
+ function agent(config) {
43
+ return { _tag: "Agent", config };
44
+ }
45
+ Act.agent = agent;
24
46
  })(Act || (Act = {}));
25
47
  //# sourceMappingURL=act.js.map
package/dist/act.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"act.js","sourceRoot":"","sources":["../src/act.ts"],"names":[],"mappings":"AAQA,MAAM,KAAW,GAAG,CAyBnB;AAzBD,WAAiB,GAAG;IAClB,SAAgB,MAAM,CAAC,MAA0B;QAC/C,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC;IACnD,CAAC;IAFe,UAAM,SAErB,CAAA;IAED,SAAgB,OAAO,CAAC,MAIvB;QACC,OAAO;YACL,IAAI,EAAE,SAAS;YACf,GAAG,EAAE,MAAM,CAAC,GAAG;YACf,QAAQ,EAAE,MAAM,CAAC,QAAQ,IAAI,IAAI;YACjC,MAAM,EAAE,MAAM,CAAC,MAAM,IAAI,IAAI;SAC9B,CAAC;IACJ,CAAC;IAXe,WAAO,UAWtB,CAAA;IAED,SAAgB,IAAI,CAAC,EAAU;QAC7B,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC;IAC9B,CAAC;IAFe,QAAI,OAEnB,CAAA;IAED,SAAgB,IAAI,CAAC,OAAe,EAAE,IAA2C;QAC/E,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,GAAG,EAAE,SAAS,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC;IAC/E,CAAC;IAFe,QAAI,OAEnB,CAAA;AACH,CAAC,EAzBgB,GAAG,KAAH,GAAG,QAyBnB"}
1
+ {"version":3,"file":"act.js","sourceRoot":"","sources":["../src/act.ts"],"names":[],"mappings":"AAiCA,MAAM,KAAW,GAAG,CA+CnB;AA/CD,WAAiB,GAAG;IAClB,SAAgB,MAAM,CAAC,MAA0B;QAC/C,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC;IACnD,CAAC;IAFe,UAAM,SAErB,CAAA;IAED,SAAgB,OAAO,CAAC,MAIvB;QACC,OAAO;YACL,IAAI,EAAE,SAAS;YACf,GAAG,EAAE,MAAM,CAAC,GAAG;YACf,QAAQ,EAAE,MAAM,CAAC,QAAQ,IAAI,IAAI;YACjC,MAAM,EAAE,MAAM,CAAC,MAAM,IAAI,IAAI;SAC9B,CAAC;IACJ,CAAC;IAXe,WAAO,UAWtB,CAAA;IAED,SAAgB,IAAI,CAAC,EAAU;QAC7B,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC;IAC9B,CAAC;IAFe,QAAI,OAEnB,CAAA;IAED,SAAgB,IAAI,CAAC,OAAe,EAAE,IAA2C;QAC/E,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,GAAG,EAAE,SAAS,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC;IAC/E,CAAC;IAFe,QAAI,OAEnB,CAAA;IAED;;;;;;;;;;;;;;;;;OAiBG;IACH,SAAgB,KAAK,CAAC,MAAsB;QAC1C,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC;IACnC,CAAC;IAFe,SAAK,QAEpB,CAAA;AACH,CAAC,EA/CgB,GAAG,KAAH,GAAG,QA+CnB"}