debutly 0.0.0-stage → 0.2.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 (93) hide show
  1. package/LICENSE +662 -0
  2. package/README.md +192 -2
  3. package/bin/debutly.mjs +8 -0
  4. package/drizzle/0000_init.sql +107 -0
  5. package/drizzle/0001_predictions.sql +14 -0
  6. package/drizzle/0002_dashboard.sql +15 -0
  7. package/drizzle/meta/0000_snapshot.json +722 -0
  8. package/drizzle/meta/0001_snapshot.json +821 -0
  9. package/drizzle/meta/0002_snapshot.json +942 -0
  10. package/drizzle/meta/_journal.json +27 -0
  11. package/package.json +83 -4
  12. package/src/agent/describe.ts +29 -0
  13. package/src/agent/effect.ts +94 -0
  14. package/src/agent/give-up.ts +42 -0
  15. package/src/agent/label.ts +19 -0
  16. package/src/agent/loop.ts +302 -0
  17. package/src/agent/parse-reply.ts +127 -0
  18. package/src/agent/prompt.ts +85 -0
  19. package/src/agent/run-agent.ts +68 -0
  20. package/src/artifacts/db.ts +55 -0
  21. package/src/artifacts/s3.ts +36 -0
  22. package/src/artifacts/store.ts +26 -0
  23. package/src/bin.ts +140 -0
  24. package/src/browser/ax.ts +77 -0
  25. package/src/browser/execute.ts +401 -0
  26. package/src/browser/observe.ts +62 -0
  27. package/src/browser/reflow.ts +73 -0
  28. package/src/browser/samples.ts +119 -0
  29. package/src/browser/scan-script.ts +108 -0
  30. package/src/browser/settle.ts +32 -0
  31. package/src/browser/signals.ts +73 -0
  32. package/src/cancel.ts +20 -0
  33. package/src/cli.ts +281 -0
  34. package/src/config.ts +62 -0
  35. package/src/cost/estimate.ts +32 -0
  36. package/src/cost/prices.ts +32 -0
  37. package/src/cost/tiers.ts +27 -0
  38. package/src/costs.ts +96 -0
  39. package/src/crew/run-unit.ts +62 -0
  40. package/src/detect/findings.ts +649 -0
  41. package/src/detect/wcag.ts +38 -0
  42. package/src/doctor.ts +145 -0
  43. package/src/hear-cli.ts +137 -0
  44. package/src/hear.ts +309 -0
  45. package/src/import.ts +108 -0
  46. package/src/inbox/mailpit.ts +46 -0
  47. package/src/inbox/types.ts +10 -0
  48. package/src/init.ts +184 -0
  49. package/src/llm/anthropic.ts +41 -0
  50. package/src/llm/credits.ts +35 -0
  51. package/src/llm/factory.ts +65 -0
  52. package/src/llm/meter.ts +39 -0
  53. package/src/llm/openai-compatible.ts +90 -0
  54. package/src/llm/openrouter.ts +9 -0
  55. package/src/llm/scripted.ts +18 -0
  56. package/src/llm/types.ts +36 -0
  57. package/src/perceive.ts +150 -0
  58. package/src/perception/aggregate.ts +111 -0
  59. package/src/perception/compare.ts +77 -0
  60. package/src/perception/evaluate.ts +83 -0
  61. package/src/perception/exhibits.ts +146 -0
  62. package/src/perception/market-context.ts +50 -0
  63. package/src/perception/run-perception.ts +178 -0
  64. package/src/persona/generate.ts +92 -0
  65. package/src/persona/inclusion.ts +53 -0
  66. package/src/persona/language.ts +59 -0
  67. package/src/persona/people.ts +32 -0
  68. package/src/predictions.ts +33 -0
  69. package/src/queue/dispatch.ts +18 -0
  70. package/src/queue/jobs.ts +28 -0
  71. package/src/queue/processor.ts +42 -0
  72. package/src/report/fix-first.ts +121 -0
  73. package/src/report/launch-readiness.ts +106 -0
  74. package/src/report/markdown.ts +202 -0
  75. package/src/run.ts +141 -0
  76. package/src/sandbox/outbox.ts +65 -0
  77. package/src/store/db.ts +40 -0
  78. package/src/store/import-run.ts +116 -0
  79. package/src/store/pg-run-store.ts +163 -0
  80. package/src/store/predictions.ts +70 -0
  81. package/src/store/run-store.ts +78 -0
  82. package/src/store/schema.ts +193 -0
  83. package/src/store/url.ts +15 -0
  84. package/src/types.ts +201 -0
  85. package/src/util/chromium.ts +20 -0
  86. package/src/util/json.ts +7 -0
  87. package/src/util/key-defaults.ts +34 -0
  88. package/src/util/legacy-env.ts +14 -0
  89. package/src/util/load-env.ts +28 -0
  90. package/src/util/pool.ts +12 -0
  91. package/src/util/run-origin.ts +27 -0
  92. package/src/worker.ts +53 -0
  93. package/tsconfig.json +13 -0
package/README.md CHANGED
@@ -1,3 +1,193 @@
1
- # Temporary Holding Version
1
+ # Debutly
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
+ [![Rehearsed with Debutly](https://debutly.dev/badge.svg)](https://debutly.dev)
4
+
5
+ **Rehearse your launch.** Debutly sends AI agents through your web app as if they were your first customers. In a real browser they sign up, confirm their email, pick a plan, invite teammates and use the product. Then they tell you what broke, where they got stuck and where they gave up, with the steps to reproduce it, screenshots, and how many agents hit each problem.
6
+
7
+ Run it before a launch, on every pull request, or on a schedule against a throwaway copy of your app.
8
+
9
+ > **Only point Debutly at a test, staging or throwaway copy of your app, never production.** Agents create accounts, submit forms and, in test mode, pay.
10
+
11
+ Website and docs: [debutly.dev](https://debutly.dev) ([quick start](https://debutly.dev/docs/quick-start)). Created by [Chetan Sroay](https://github.com/sroay). Status: early. Flags, the report format and the database schema may still change.
12
+
13
+ ## What it does
14
+
15
+ - **Customers in a real browser.** Agents (Playwright and Chromium) click, type, pick options in native and custom dropdowns, upload files (a sample photo or CV made up on the spot), follow links from emails, and wait for slow pages like a person would.
16
+ - **Business crews.** With `--unit business`, an owner signs up, chooses a plan within a budget and invites teammates. Each teammate accepts by email and uses the product in their own login, so invites, roles and shared workspaces get tested too.
17
+ - **Agents with access needs.** The first agents in each run act out an access need: one hears what a screen reader would and works by keyboard only; one works at about 200% zoom; one is on a throttled connection; one reads as a non-native English speaker. The screen-reader agent hears the names the browser gives assistive technology and works by keyboard only, so controls the keyboard can't reach are reported. The low-vision agent's pages are also measured at 320 pixels wide for sideways scrolling. Findings name the related WCAG criteria, for a person to check. They are not an accessibility audit.
18
+ - **Heard with a real screen reader.** `npx debutly hear` opens each page that had a screen-reader finding with NVDA (Windows) or VoiceOver (macOS) running, presses Tab through it, and marks each finding confirmed or not from what the screen reader said about that very control. On three open-source apps, NVDA bore out most such findings and showed which ones to leave out.
19
+ - **Findings with evidence.** Server and page errors, broken journeys, pages that take over 10 s to arrive, controls that something keeps covering, unlabeled buttons and fields, and agents going round in circles. Each comes with repro steps, screenshots and a confidence level.
20
+ - **Knows a test environment from a bug.** If your app has a sandbox that records what it blocked (emails, payments, outside APIs), Debutly reads it and files failures the test environment caused separately from real bugs.
21
+ - **What buyers think.** Cheap "skeptical buyer" evaluators judge your landing and pricing pages, grounded in competitors' own pricing pages. They compare A/B variants and work at the idea stage, before anything is built.
22
+ - **A dashboard.** Runs, findings across runs (new, recurring, gone), step-by-step replays with screenshots, and spend.
23
+ - **Costs under control.** Every run prints an estimate before it starts, and `--max-cost` refuses runs that could cost more. A key with a spending limit is checked before a run starts, and if the provider runs out of credit part-way, every agent stops at its next step and the report says the run was cut short. Bring your own model key; a quick run costs cents.
24
+
25
+ ## Quick start
26
+
27
+ Needs Node.js 20.12 or later. In your app's folder:
28
+
29
+ ```bash
30
+ npx debutly init # a few questions, then a debutly.json
31
+ ```
32
+
33
+ Put a model key in a `.env` file there (`DEBUTLY_API_KEY=sk-or-…`, from [openrouter.ai/keys](https://openrouter.ai/keys)); init keeps `.env` out of git. One key is all it needs: Debutly picks the models from it. Start a test copy of your app, then:
34
+
35
+ ```bash
36
+ npx debutly doctor # checks the key, the browser, the config and that the app answers
37
+ npx debutly # runs the agents
38
+ ```
39
+
40
+ The first run downloads Chromium (about 150 MB, once). The report lands in `.debutly/runs/<timestamp>/report.md`, next to `sessions.json`, `findings.json` and the screenshots. Flags override `debutly.json` for one run, for example `npx debutly --tier standard --max-cost 3`; `npx debutly --help` lists the commands.
41
+
42
+ `debutly.json` holds the settings, named like the flags below (`maxCost` for `--max-cost`):
43
+
44
+ ```json
45
+ {
46
+ "url": "http://localhost:3000",
47
+ "goal": "Sign up, choose a plan and invite a teammate",
48
+ "icp": "Owners of small marketing agencies, 2-15 people",
49
+ "unit": "business",
50
+ "tier": "quick",
51
+ "maxCost": 1
52
+ }
53
+ ```
54
+
55
+ ## Options
56
+
57
+ - `--unit individual` (default) simulates one person per unit. `--unit business` simulates business crews: an owner and `--employees` teammates (default 2, max 4; 0 = owner only). `--agents` is the number of units. Crews need `--mailpit`.
58
+ - `--tier quick|standard|deep` sets the run size: Quick is 3 units with owners only, Standard is 10 units with 2 employees each, Deep is 30 units with 3 each. `--agents` and `--employees` override it. `--max-cost 0.50` refuses to start a run that could cost more.
59
+ - `--inclusion off` skips the inclusion needs, which are on by default. The starting need rotates daily.
60
+ - `--languages ar,en` gives the customers first languages in turn. Arabic-first agents browse with their browser set to Arabic, use the site in Arabic when it offers it, write their names in Arabic script and type numbers with Arabic-Indic digits.
61
+ - `--mailpit http://127.0.0.1:54324` gives each agent its own inbox for magic links and confirmation emails, for example the Mailpit that `supabase start` runs.
62
+ - `--sandbox-outbox <url>` (with `DEBUTLY_SANDBOX_TOKEN` set) reads what your app's sandbox blocked during the run. Failures that happened while it was blocking an outside service, server errors saying a key is missing, and failures to reach a website an agent made up for its company are listed under "Caused by the test environment" instead of as findings.
63
+ - `--max-steps`, `--agent-token-cap 200000` and `--agent-minutes 15` cap each agent.
64
+ - Ctrl+C lets agents stop at their next step and still writes the report; a second Ctrl+C quits at once.
65
+
66
+ ## What buyers think: perception and experiments
67
+
68
+ Besides agents who use the product, breadth evaluators judge what it shows, like skeptical buyers on a budget. Each must name at least two concrete objections before scoring, and defaults to "no". They need no browser, so hundreds cost cents.
69
+
70
+ ```bash
71
+ # Your pages, grounded in competitors' own pricing pages:
72
+ npx debutly perceive --icp "…" --url https://app.test/ --url https://app.test/pricing \
73
+ --competitors https://rival.test/pricing,https://other.test/pricing
74
+ # An experiment: which version do buyers pick? (a URL or a text file per variant)
75
+ npx debutly perceive --icp "…" --variant A=https://app.test/pricing --variant B=pricing-b.md
76
+ # Idea stage, before anything is built:
77
+ npx debutly perceive --icp "…" --file pitch.md
78
+ # After a normal run: evaluators judge the pages the agents saw
79
+ npx debutly … --evaluators 50
80
+ ```
81
+
82
+ - **Sizes:** `--tier quick|standard|deep` gives 50, 300 or 1,500 evaluators.
83
+ - **The report** (`launch-readiness.md`) ranks blockers and objections, compares variants with a 95% interval (and says when a lead could be noise), and suggests fixes. It is always labelled as simulated evidence, with no conversion rates.
84
+ - **Predictions:** with `--store`, each prediction (winner, top objection, intent share) is saved. Record what really happened with `npx debutly predictions record <id> <actual>` and see accuracy with `npx debutly predictions accuracy`.
85
+
86
+ ## Run it on a schedule in GitHub Actions
87
+
88
+ The safest place to run Debutly is a throwaway copy of your app, built fresh on the CI runner and deleted afterwards: your real schema, an empty database, test keys only. Your code and keys never leave your own CI. `npx debutly init` can write this workflow for you.
89
+
90
+ ```yaml
91
+ # .github/workflows/debutly.yml in your app's repo, next to debutly.json
92
+ name: debutly
93
+ on:
94
+ schedule: [{ cron: "0 4 * * 1" }] # Mondays
95
+ workflow_dispatch:
96
+ jobs:
97
+ agents:
98
+ runs-on: ubuntu-latest
99
+ timeout-minutes: 45
100
+ steps:
101
+ - uses: actions/checkout@v4
102
+ - run: | # start a test copy of your app (seeded database, test keys only)
103
+ npm ci && npm run build
104
+ PORT=3000 npm start &
105
+ - uses: sroay/debutly@v0
106
+ with:
107
+ api-key: ${{ secrets.DEBUTLY_API_KEY }}
108
+ # store-url: ${{ secrets.DEBUTLY_STORE_URL }} # optional: record runs for the dashboard
109
+ ```
110
+
111
+ The action waits for the app to answer, runs the agents with the settings in `debutly.json`, puts the report on the run's summary page and attaches the screenshots as the `debutly-report` artifact. Its inputs (`url`, `goal`, `icp`, `tier`, `max-cost`, which defaults to 1.00, and `args` for any other flags) override `debutly.json`.
112
+
113
+ ## Dashboard
114
+
115
+ `dashboard/` is a Next.js app that reads the database runs are recorded into:
116
+ - **Overview:** each app's latest run, a trend of recent runs, and open bugs.
117
+ - **Runs:** every run, by app, with each business crew and agent and how far they got. Findings are split three ways: bugs in the app, doubtful, and caused by the test environment.
118
+ - **Replays:** each agent's run step by step, with the screenshot, what it did, why, and what happened next.
119
+ - **Findings:** every finding across runs, marked as new, recurring, or not in the latest run.
120
+ - **Spend:** model cost per day and app.
121
+
122
+ Any Postgres works, and a free one (Neon, Supabase) is enough. With `--store` and no S3 configured, screenshots are kept in the database as compact JPEGs and pruned after `--screenshot-days` (7 by default).
123
+
124
+ ```bash
125
+ # Record a run:
126
+ npx debutly … --store "$DATABASE_URL" --app my-app
127
+ # Load earlier runs from GitHub Actions report artifacts (needs the gh CLI):
128
+ npx debutly import --store "$DATABASE_URL" --github owner/repo --app my-app
129
+ # Run the dashboard locally (DATABASE_URL in dashboard/.env.local; pglite:<folder> works without a server):
130
+ npm run dashboard
131
+ ```
132
+
133
+ **Hosting on Vercel:** set the Root Directory to `dashboard` and add `DATABASE_URL` and `DASHBOARD_PASSWORD`. Connection strings can be pasted exactly as your host gives them. Without `DASHBOARD_PASSWORD`, a deployed dashboard refuses everyone; only `next dev` is open.
134
+
135
+ ## Self-hosted stack and scaling out
136
+
137
+ By default a run writes files and needs nothing else. To record every run in a database and spread agents over several workers:
138
+
139
+ ```bash
140
+ docker compose up -d --build # Postgres, Redis, S3-compatible storage, 1 worker (settings from .env)
141
+ docker compose up -d --scale worker=4 # more agents at once
142
+ docker compose --profile smoke run --rm smoke # end-to-end check, about $0.01 of model usage
143
+ ```
144
+
145
+ Then add `--store postgres://debutly:debutly@localhost:5433/debutly` and `--queue redis://localhost:6380` to a run. `npx debutly cancel <runId> --store <url>` stops a run from anywhere. Workers in Docker reach public (staging) URLs; for an app running on your machine, run workers natively with `npx debutly worker`.
146
+
147
+ ## Models and costs
148
+
149
+ Any OpenAI-compatible provider works (`DEBUTLY_PROVIDER=openai-compatible`, for example OpenRouter), or Anthropic (`DEBUTLY_PROVIDER=anthropic`). With OpenRouter, requests go only to providers that keep no copy of prompts and don't train on them (`DEBUTLY_ZERO_RETENTION=off` allows any); [Data and privacy](https://debutly.dev/docs/data-and-privacy) lists what leaves your machine. Set the model that drives the agents with `DEBUTLY_NAV_MODEL` and the one that judges and evaluates with `DEBUTLY_JUDGE_MODEL`.
150
+
151
+ What has worked well: `z-ai/glm-5.3-flash` with `DEBUTLY_REASONING_EFFORT=low` for the agents (allow about 40% more `--max-steps` than Gemini needs), and `deepseek/deepseek-v4-flash` for the judge and evaluators. `google/gemini-3.8-flash` is faster and needs fewer steps but costs about 4× as much per run; `DEBUTLY_NAV_ROUTING='{"order":["google-ai-studio/flex"]}'` halves its price, but Google AI Studio isn't among the providers that keep no data, so it also needs `DEBUTLY_ZERO_RETENTION=off`.
152
+
153
+ Models compared on the seeded-bug fixture (5 planted bugs, 3 agents), September 2026:
154
+
155
+ | Model | Bugs found (of 5) | Seconds per step | Cost |
156
+ |---|---|---|---|
157
+ | google/gemini-3.8-flash (flex tier) | 4 | 3.1 | $0.020 |
158
+ | z-ai/glm-5.3-flash | 4 | 3.8 | $0.004 |
159
+ | tencent/hy3 | 4 | 12.4 | $0.024 |
160
+ | qwen/qwen3.8-flash | 4 | 30.0 | $0.027 |
161
+ | qwen/qwen3.7-flash | 4 | 27.8 | $0.011 |
162
+ | inclusionai/ling-3.0-flash | 3 | 5.8 | $0.003 |
163
+ | bytedance-seed/seed-2.0-mini | 2 | 6.3 | $0.009 |
164
+ | xiaomi/mimo-v2.6-flash | 2 of 3 agents errored | 13.7 | $0.007 |
165
+
166
+ On a real SaaS app's nightly crew journey (2 owners, 4 teammates), GLM-5.3 Flash reached the same outcome and main finding as Gemini for $0.052 instead of $0.205, taking 224 steps instead of 128. DeepSeek V4 Flash caught the same fixture bugs as Gemini but averaged about 22 s a step, too slow to drive the agents in CI.
167
+
168
+ Compare models yourself (`model@endpoint` pins one OpenRouter provider endpoint):
169
+
170
+ ```bash
171
+ node --env-file=.env --import tsx scripts/compare-models.ts z-ai/glm-5.3-flash google/gemini-3.8-flash@google-ai-studio/flex
172
+ ```
173
+
174
+ `npx debutly costs --repo owner/app` shows your OpenRouter key's spend and what each app's latest nightly run cost.
175
+
176
+ ## Development
177
+
178
+ ```bash
179
+ git clone https://github.com/sroay/debutly.git && cd debutly && npm install
180
+ node bin/debutly.mjs --help # the debutly command, from source
181
+ npm test # includes the acceptance test: every seeded fixture bug must be caught
182
+ npm run typecheck
183
+ ```
184
+
185
+ `fixture/` is a small app with seeded bugs that the acceptance test runs agents against.
186
+
187
+ ## Contributing and security
188
+
189
+ Contributions are welcome: see [CONTRIBUTING.md](CONTRIBUTING.md). To report a vulnerability, see [SECURITY.md](SECURITY.md) rather than opening a public issue.
190
+
191
+ ## License
192
+
193
+ [AGPL-3.0](LICENSE). You can use, modify and self-host Debutly freely. If you run a modified version as a service for others, you must publish your changes under the same licence.
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env node
2
+ // The `debutly` command. Debutly is TypeScript run through tsx, so there is no build step. Its
3
+ // own tsconfig is named, so the tsconfig of the app it runs in never changes how it compiles.
4
+ import { fileURLToPath } from "node:url";
5
+ import { register } from "tsx/esm/api";
6
+
7
+ register({ tsconfig: fileURLToPath(new URL("../tsconfig.json", import.meta.url)) });
8
+ await import("../src/bin.ts");
@@ -0,0 +1,107 @@
1
+ CREATE TABLE "agents" (
2
+ "run_id" uuid NOT NULL,
3
+ "id" text NOT NULL,
4
+ "unit_id" text NOT NULL,
5
+ "name" text NOT NULL,
6
+ "role" text,
7
+ "inclusion" text,
8
+ "persona" jsonb NOT NULL,
9
+ CONSTRAINT "agents_run_id_id_pk" PRIMARY KEY("run_id","id")
10
+ );
11
+ --> statement-breakpoint
12
+ CREATE TABLE "customer_units" (
13
+ "run_id" uuid NOT NULL,
14
+ "id" text NOT NULL,
15
+ "kind" text NOT NULL,
16
+ "business" jsonb,
17
+ CONSTRAINT "customer_units_run_id_id_pk" PRIMARY KEY("run_id","id")
18
+ );
19
+ --> statement-breakpoint
20
+ CREATE TABLE "findings" (
21
+ "run_id" uuid NOT NULL,
22
+ "signature" text NOT NULL,
23
+ "kind" text NOT NULL,
24
+ "severity" text NOT NULL,
25
+ "confidence" text NOT NULL,
26
+ "title" text NOT NULL,
27
+ "detail" text NOT NULL,
28
+ "page_path" text NOT NULL,
29
+ "hit_by" text[] NOT NULL,
30
+ "visitors" integer NOT NULL,
31
+ "evidence" jsonb NOT NULL,
32
+ "sandbox_cause" text[],
33
+ CONSTRAINT "findings_run_id_signature_pk" PRIMARY KEY("run_id","signature")
34
+ );
35
+ --> statement-breakpoint
36
+ CREATE TABLE "runs" (
37
+ "id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
38
+ "target_url" text NOT NULL,
39
+ "goal" text NOT NULL,
40
+ "icp" text,
41
+ "tier" text,
42
+ "unit_kind" text,
43
+ "status" text DEFAULT 'queued' NOT NULL,
44
+ "model" text,
45
+ "estimate_low_usd" double precision,
46
+ "estimate_high_usd" double precision,
47
+ "cost_usd" double precision,
48
+ "input_tokens" integer,
49
+ "output_tokens" integer,
50
+ "report_md" text,
51
+ "created_at" timestamp with time zone DEFAULT now() NOT NULL,
52
+ "started_at" timestamp with time zone,
53
+ "finished_at" timestamp with time zone
54
+ );
55
+ --> statement-breakpoint
56
+ CREATE TABLE "sessions" (
57
+ "run_id" uuid NOT NULL,
58
+ "agent_id" text NOT NULL,
59
+ "goal" text NOT NULL,
60
+ "outcome" text,
61
+ "outcome_note" text,
62
+ "input_tokens" integer,
63
+ "output_tokens" integer,
64
+ "cost_usd" double precision,
65
+ "started_at" timestamp with time zone DEFAULT now() NOT NULL,
66
+ "finished_at" timestamp with time zone,
67
+ CONSTRAINT "sessions_run_id_agent_id_pk" PRIMARY KEY("run_id","agent_id")
68
+ );
69
+ --> statement-breakpoint
70
+ CREATE TABLE "side_effects" (
71
+ "id" integer PRIMARY KEY GENERATED ALWAYS AS IDENTITY (sequence name "side_effects_id_seq" INCREMENT BY 1 MINVALUE 1 MAXVALUE 2147483647 START WITH 1 CACHE 1),
72
+ "run_id" uuid NOT NULL,
73
+ "outcome" text NOT NULL,
74
+ "rule" text,
75
+ "channel" text NOT NULL,
76
+ "host" text NOT NULL,
77
+ "url" text NOT NULL,
78
+ "recipient" text,
79
+ "summary" text,
80
+ "at" timestamp with time zone DEFAULT now() NOT NULL
81
+ );
82
+ --> statement-breakpoint
83
+ CREATE TABLE "steps" (
84
+ "run_id" uuid NOT NULL,
85
+ "agent_id" text NOT NULL,
86
+ "index" integer NOT NULL,
87
+ "url" text NOT NULL,
88
+ "title" text,
89
+ "action" jsonb NOT NULL,
90
+ "reasoning" text,
91
+ "observation" jsonb NOT NULL,
92
+ "signals" jsonb NOT NULL,
93
+ "error" text,
94
+ "blocked" text,
95
+ "screenshot_url" text,
96
+ "created_at" timestamp with time zone DEFAULT now() NOT NULL,
97
+ CONSTRAINT "steps_run_id_agent_id_index_pk" PRIMARY KEY("run_id","agent_id","index")
98
+ );
99
+ --> statement-breakpoint
100
+ ALTER TABLE "agents" ADD CONSTRAINT "agents_run_id_runs_id_fk" FOREIGN KEY ("run_id") REFERENCES "public"."runs"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
101
+ ALTER TABLE "customer_units" ADD CONSTRAINT "customer_units_run_id_runs_id_fk" FOREIGN KEY ("run_id") REFERENCES "public"."runs"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
102
+ ALTER TABLE "findings" ADD CONSTRAINT "findings_run_id_runs_id_fk" FOREIGN KEY ("run_id") REFERENCES "public"."runs"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
103
+ ALTER TABLE "sessions" ADD CONSTRAINT "sessions_run_id_runs_id_fk" FOREIGN KEY ("run_id") REFERENCES "public"."runs"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
104
+ ALTER TABLE "side_effects" ADD CONSTRAINT "side_effects_run_id_runs_id_fk" FOREIGN KEY ("run_id") REFERENCES "public"."runs"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
105
+ ALTER TABLE "steps" ADD CONSTRAINT "steps_run_id_runs_id_fk" FOREIGN KEY ("run_id") REFERENCES "public"."runs"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
106
+ CREATE INDEX "runs_created_at_idx" ON "runs" USING btree ("created_at" DESC NULLS LAST);--> statement-breakpoint
107
+ CREATE INDEX "side_effects_run_idx" ON "side_effects" USING btree ("run_id");
@@ -0,0 +1,14 @@
1
+ CREATE TABLE "predictions" (
2
+ "id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
3
+ "run_id" uuid NOT NULL,
4
+ "metric" text NOT NULL,
5
+ "claim" text NOT NULL,
6
+ "predicted" jsonb NOT NULL,
7
+ "actual" jsonb,
8
+ "correct" boolean,
9
+ "created_at" timestamp with time zone DEFAULT now() NOT NULL,
10
+ "checked_at" timestamp with time zone
11
+ );
12
+ --> statement-breakpoint
13
+ ALTER TABLE "predictions" ADD CONSTRAINT "predictions_run_id_runs_id_fk" FOREIGN KEY ("run_id") REFERENCES "public"."runs"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
14
+ CREATE INDEX "predictions_run_idx" ON "predictions" USING btree ("run_id");
@@ -0,0 +1,15 @@
1
+ CREATE TABLE "screenshots" (
2
+ "run_id" uuid NOT NULL,
3
+ "key" text NOT NULL,
4
+ "content_type" text NOT NULL,
5
+ "data" "bytea" NOT NULL,
6
+ "created_at" timestamp with time zone DEFAULT now() NOT NULL,
7
+ CONSTRAINT "screenshots_run_id_key_pk" PRIMARY KEY("run_id","key")
8
+ );
9
+ --> statement-breakpoint
10
+ ALTER TABLE "runs" ADD COLUMN "app" text;--> statement-breakpoint
11
+ ALTER TABLE "runs" ADD COLUMN "trigger" text;--> statement-breakpoint
12
+ ALTER TABLE "runs" ADD COLUMN "ci_url" text;--> statement-breakpoint
13
+ ALTER TABLE "screenshots" ADD CONSTRAINT "screenshots_run_id_runs_id_fk" FOREIGN KEY ("run_id") REFERENCES "public"."runs"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
14
+ CREATE INDEX "screenshots_created_at_idx" ON "screenshots" USING btree ("created_at");--> statement-breakpoint
15
+ CREATE INDEX "runs_app_created_at_idx" ON "runs" USING btree ("app","created_at" DESC NULLS LAST);