Loopfund MVP: spec and status

Updated 2 September 2026, 7:50 pm CT. Three internal pages: this one is what we're building and where it stands (product, phases, decisions, next steps); /implementation is how the machine runs (architecture, the loop, money plumbing, observability, for engineers); /brand is how we talk and look (voice, vocabulary, pitch, palette, type).

What Loopfund is

Kickstarter, except the money can never reach the creator. Backers buy compute; that compute runs a hosted machine where AI agents build the creator's game against a visual bar the creator set; every dollar is visible as it is spent; whatever isn't spent is refunded. The creator's cash-out is $0 by rule, which is what lets strangers fund a project from someone they've never heard of.

Internally the build method is a Gauntlet Loop: one lead agent splits work between builder agents and fresh-context critic agents; critics compare the build blind against reference frames and can never edit; the loop runs unattended, wave after wave, until it ships, is paused, or the pot is empty. Three invariants hold everywhere:

Public copy says "project", "build", "round", "judge". "Loop", "wave", "critic", "harness" and "sandbox" are for this page and the implementation notes.

Status board

Live on loopfunder.com
Money in
  • Browse, search, category filter
  • Campaign page with real pot, backer wall, split
  • Stripe Checkout, live mode, 85/15 ledger
  • Receipt page
  • Creator sign-in (Clerk, dev instance), wizard, drafts, dashboard, direct uploads
  • Two seeded campaigns with AI-generated pitch video and target frames
Proven locally, not yet hosted
The machine
  • Docker harness: Claude Code 2.1, Chromium, hooks, loopd wave supervisor
  • Claude Code talking to OpenRouter by direct model slug (Fable 5.1, Haiku 4.5) from inside the image
  • Critic edit-denial hook, event log, per-agent token attribution from transcripts
Still mock
Run state
  • Start run, Booting, Run console, Watch pages are static screens
  • No orchestrator: nothing mints a key, boots a machine, or writes a wave yet
  • Refunds are manual in Stripe
The first end-to-end demo we're driving toward: a real pledge lands in a pot, the creator presses Start, a hosted machine boots, wave 1 appears on the watch page, and the pot goes down by exactly what the wave cost.

Phases

Re-sequenced on 2 September to Miguel's priorities: money and posting first, then the machine, then run-state surfaces. Checked items shipped; half-filled boxes are partly done.

Phase A: backers can pay live

Phase B: creators can post live

Phase 0: harness in a box gate passed, first full run pending

Phase 1: hosted machine and brakes

Phase 2: run-state surfaces

Phase 3: later

Surfaces and mocks

Every screen was mocked first, then rebuilt as HTML, then wired to the API where the backend exists. Tags say where each one is today.

RouteWhat it isState
/Browse: featured project with pitch video, funding grid, search and categories, where the money goeslive
/projects/:slugCampaign (server-rendered head for link previews): pitch, target frames, pot, split, backer wall, creator card, FAQlive run sections hidden until a run exists
/checkoutAmount, email, backer-wall choice, hands off to Stripelive
/thanksReceipt: what was paid, split, next stepslive
/creatorsFor creators: what you bring, what you get, four steps, FAQlive
/dashboardCreator's drafts and live campaignslive
/onboard-goal, /onboard-bar, /onboard-fuelWizard: project and video, the bar, funding and publishlive
/onboard-start, /onboard-bootStart run confirmation, boot sequencemock
/consoleCreator run console: artifact, shot comparison, nudge box, wave log, controls, spend by rolemock
/watchPublic live view: workbench, judge grid, verdict log, spendmock
01 Browse. Rebuilt as the homepage; the featured block is now the campaign's own video.
02 Campaign page. Live at /project.
03 Checkout. Card entry moved to Stripe's hosted page.
04 Creator: destination. Live as onboard-goal.
05 Creator: the bar. Live as onboard-bar; frames go to a private bucket.
06 Waiting for funding. Folded into the dashboard.
07 Start run. Mock; becomes real with the orchestrator.
08 Booting. Mock.
09 Creator funding view. Folded into the dashboard.
10 Run console. Mock at /console.
11 The harness as it runs today, locally.
12 Shot set: named angles the judges compare.
13 Hosted machine vs the creator's laptop.
14 Sandbox console. Bar thumbnails allowed here, never on /watch.
15 Credentials card. GitHub is the verified credential.
16 Watch. Mock at /watch.
17 Ledger with per-call rows. Requires the Phase 1 proxy.

State machine

One run per campaign in the MVP. Three resources are bound to a run and move together: the machine (disk and memory), the OpenRouter key, and the Claude Code session. Campaign states up to FUNDED are live today; everything from PROVISIONING on is Phase 1.

stateDiagram-v2 [*] --> DRAFT: wizard DRAFT --> FUNDING: publish (needs GitHub) FUNDING --> FUNDED: pledges reach threshold FUNDING --> CANCELLED: 60 d without threshold, or creator cancels FUNDED --> PROVISIONING: creator presses Start FUNDED --> CANCELLED: 14 d without Start PROVISIONING --> RUNNING: mint key, boot machine, loopd heartbeat RUNNING --> PAUSED_POT: key limit reached RUNNING --> PAUSED_PROVIDER: 6 wave failures after failover RUNNING --> PAUSED_CREATOR: creator pauses at wave boundary RUNNING --> PAUSED_PLATEAU: 5 flat waves RUNNING --> PAUSED_PLATFORM: incident PAUSED_POT --> RUNNING: top-up raises limit, machine resumes PAUSED_PROVIDER --> RUNNING: retry every 15 min PAUSED_CREATOR --> RUNNING: creator resumes PAUSED_PLATEAU --> RUNNING: creator resumes PAUSED_PLATEAU --> SHIPPED: creator ships PAUSED_PLATFORM --> RUNNING RUNNING --> SHIPPED: creator ships PAUSED_POT --> CANCELLED: 60 d paused PAUSED_PLATEAU --> CANCELLED: creator silent 14 d SHIPPED --> SETTLED: final build to CDN, release tagged, pro-rata refunds CANCELLED --> SETTLED: full or pro-rata refunds SETTLED --> [*]
StateMachineKeySessionBackers see
FUNDING / FUNDEDnonenonenonepot meter, goal, creator card
PROVISIONINGcreate from template, clone repo, write bar and agent configminted, limit = pot minus reservenoneBooting
RUNNINGrunningenabledone long session, resumed each waveworkbench, judge grid, verdicts, spend
PAUSED (pot)paused with memorydisabledfrozenPaused, add funds to resume
PAUSED (provider)pausedenabledfrozenProvider outage, retrying
PAUSED (creator / plateau)paused at wave boundaryenabledfrozenPaused by creator
SHIPPEDfinal capture and build to CDN, deleted after 7 ddisabled then deletedarchivedplayable, final episode, refund notice

Money

Charge now, refund if it never starts. A backer pays through Stripe Checkout and is charged immediately. 15% is the all-in fee (card processing, gateway, hosting, platform); 85% is credited to the campaign's pot. Loopfund is merchant of record; nothing is transferred to the creator, ever. Unused pot is refunded pro-rata at ship or cancel; if a run never starts, everything is refunded in full and Loopfund absorbs the card fees.

The key limit is not the pot. When a run starts, an OpenRouter key is minted with a dollar limit equal to the pot minus a reserve for in-flight requests. Spend is reconciled from three sources: the key's usage counter, Claude Code transcripts (per agent), and, from Phase 1, per-call rows from the pass-through proxy.

Ledger rows are the source of truth: pledge_captured, platform_fee, pot_credit today; key_minted, spend_reserved, spend_settled, refund with the run. Every row carries a Stripe or OpenRouter reference so the chain can be audited end to end.

$85pot, spent only as model tokens on this project $15fee, all in $0to the creator
Rough unit cost of a wave
Typical wave, Fable 5.1 everywhereabout $41
Fable critics, Opus buildersabout 35% less
$500 goal after feeabout 10 waves
Hosted machine, 4 vCPU / 8 GB, no GPUcents per hour, inside the fee

Architecture

flowchart LR B[Backer browser] -->|Stripe Checkout| S[Stripe] S -->|webhook| API C[Creator browser] -->|Clerk session| API subgraph Vercel API[api/* functions] end API --> DB[(Supabase Postgres\ncampaigns, pledges, ledger, runs, waves)] API --> ST[Supabase Storage\npitch-video public, bar private, snapshots] API -.Phase 1.-> ORCH[Run orchestrator] ORCH -->|mint key, limit = pot| OR[OpenRouter] ORCH -->|boot from template| VM[E2B machine\nClaude Code + loopd + hooks] VM -->|Anthropic protocol, per-run key| OR VM -->|wave results, snapshots| API VM -->|Release per wave| GH[GitHub] W[Watch page] --> ST

Static HTML pages fetch JSON from Vercel functions. Supabase holds the data and files. Stripe holds the money. Clerk holds identity. The machine is a Docker image today and an E2B template next; it talks to OpenRouter directly with a per-run key whose limit is the pot. The orchestrator is the one missing service.

The build loop, as it runs

loopd is the wave supervisor and lives outside Claude Code, because Claude Code's own stop hook can only block a fixed number of times and the loop must be unbounded. Each wave: loopd appends any queued creator notes to NUDGES.md, starts Claude Code with --resume on the run's session at max effort, waits for the lead to write WAVE.json (score, best frames, cost), captures the workbench, tags a GitHub Release, posts the wave to the API, and starts the next one. It stops only on pot_empty, a creator pause, or a provider failure it can't route around.

Decisions

TopicDecisionWhy
Hosted machineE2B first, Daytona as tested fallbackMost-used Claude Code templates, memory-preserving pause, Node SDK. The 24 h runtime clock is handled by loopd.
Pledge modelCharge now; refund in full if never startedMiguel accepts eating card fees on campaigns that never start.
Fee15% all inOne number backers can read before paying.
Critic modelAlways Fable 5.1Builders may be routed cheaper in experiments; judges never.
Per-call ledgerPass-through proxy in front of OpenRouter, Phase 1Exact per-call cost and reserve/settle rows; optional via env so Phase 0 talks to OpenRouter directly.
"Escrow"Never in copy. "Held for this project."Legal shape and plain language.
Session strategyOne long session per run, resumed each waveClosest to the runs the method was proven on; WAVE.json and the repo are the durable memory if a session must be rebuilt.
Backer inputCreator-only notes in MVP; votes laterNudge text is a prompt-injection surface. Creator is semi-trusted; backers get no free text yet.
Plateau5 flat waves pauses and notifies; advisory; auto-cancel after 14 days of creator silenceNever binding while the creator is responsive; never auto-kill an improving run.
Reference IPCopyrighted references allowed, stored privately, never publishedHomages are fine; copies are not. The judge grid shows our frames only.
AuthClerk (GitHub, Google, email); GitHub required to publishGitHub is the verifiable creator credential backers see.
Models via OpenRouterDirect slugs pinned in env, not presetsPresets aren't available on this account; slugs give the same routing with less indirection.

Open questions

  1. Legal shape of prepaid balances. "Prepaid compute, earmarked, refundable if unused" avoids the crowdfunding money-transmitter shape, but stored-value and gift-card statutes need counsel. Refund SLA copy: initiated within 5 business days; Stripe settlement time disclosed.
  2. Sales tax. Digital service; Stripe Tax not yet on.
  3. Creator KYC threshold. GitHub OAuth only in MVP. At what goal size does Stripe Identity kick in? Proposed: above $2,500, plus manual review for the first 50 campaigns.
  4. 24-hour machine clock. E2B caps continuous runtime; pause/resume around it vs Fly Sprites which don't cap. Decide on Phase 1 chaos-test results and price.
  5. Workbench serving. Snapshots on a CDN, never a live tunnel into the machine. Snapshot cadence and cost to be set.
  6. Playable hosting for backers. Needs a static build target and signed URLs; implied by "early access" but not designed.
  7. No GPU. Stills and captures are fine; frame-rate claims aren't reproducible. Wizard says so; is that enough?
  8. Abuse and content policy. Egress allowlist and CPU quotas are planned; what the loop is allowed to build follows Anthropic's usage policy as we are the API customer. Written policy pending.
  9. Ops at 3 a.m. A run PAUSED(provider) for hours: retry, notify the creator, never refund on a provider outage. Runbook to write.
  10. Capture shrinkage. Not an issue with charge-now, but declined top-ups mid-run need a UX.
  11. Cloud-agent PR #1. Close without merging; add branch protection so agents open PRs and can't deploy.

Next steps

  1. OpenRouter Management key MiguelFrom the keys page, Management API section. Lets each run mint its own capped key instead of sharing the inference key.
  2. The first real Gauntlet LoopRun the harness locally for $25 against a folder of reference frames. Pass: 3 or more unattended waves, critic denied at least once, stops on pot_empty, transcript spend within 5% of key usage. This is the Phase 0 gate.
  3. One real backingA $5 charge on Claude of the Wild with a real card, watching the ledger, wall and receipt land.
  4. E2B template and orchestratorSame Dockerfile as a template; POST /api/runs/start; loopd posts waves back; pause and resume with the key disabled.
  5. Run-state surfacesStart run, Booting, Console and Watch read real state; watch page from snapshots; releases per wave.
  6. RefundsOps endpoint for full and pro-rata refunds; auto-cancel timers for 60 days unfunded and 14 days unstarted.
  7. Deferred on purposeBacker votes, Stripe Identity, categories beyond games, Twitch.

Tests that matter

TestPhasePass condition
Stripe payment becomes potAledger chain pledge_captured, platform_fee, pot_credit unbroken; wall and receipt update passed with a signed synthetic event
Critic never edits0hook denial count above 0 in a run where the lead tried; zero critic-authored diffs
Unbounded loop03 or more waves with no human input; stop reason pot_empty
Spend attribution0transcript total within 5% of OpenRouter key usage
Empty-pot pause keeps disk1workspace hash identical before pause and after resume; session resumes
429s don't kill the harness1zero loopd restarts; at most one wave retry; provider handoff visible in the ledger
Key can't spend past the pot1OpenRouter usage at or under limit; reserve covers observed overrun
Nudges land at wave boundaries only2NUDGES.md modification times match wave starts only
Backers never see break-glass2watch payload contains no break_glass events