How the “Plausible” plan was built

A cold agent — given only our public guide and the Plausible source — reconstructed the team’s product plan through the API, single-agent, in one clean run. Shown as it ran; the only touch is cosmetic: we standardized the project names.

The finished plan, live: productbrain.com/shared/qteAh8suYRyuf9bb5CPKY (the transcript below ends on the staging link the run minted; this is the same plan on the public host).

Your ProductBrain API key is in $PB_API_KEY and the base URL in $PB_API_URL. Use them via those env vars; never print, echo, or hard-code the key. If $PB_API_KEY is NOT set, STOP and tell me — do NOT search the filesystem, env files, or credential stores for credentials. 1. Read the guide at https://productbrain.com/docs/llm-guide.md — it is the full contract for reading and writing a ProductBrain plan. 2. Clone https://github.com/plausible/analytics (a shallow clone is fine) and study it enough to understand what the product does and what the team is actually building and shipping. 3. Create a project named "Plausible" and build a ProductBrain plan for it through the API. Build the plan the product genuinely warrants — don't hold back to keep it small, and don't pad it to look thorough. 4. When the plan is in, mint a share link (POST /share) and give me the URL as the deliverable.
bash if [ -z "$PB_API_KEY" ]; then echo "PB_API_KEY_NOT_SET"; else echo "PB_API_KEY is set (length ${#PB_API_KEY})"; fi; echo "PB_API_URL=$PB_API_URL"

Key is set. Let me read the guide and start the clone in parallel.

bash cd /tmp && rm -rf analytics && git clone --depth 1 https://github.com/plausible/analytics.git 2>&1 | tail -5 && echo "DONE"

Now let me read the guide.

fetch https://staging.productbrain.com/docs/llm-guide.md

The guide is a summary. Let me get exact request/response schemas for the key write operations, and explore the repo in parallel.

fetch https://staging.productbrain.com/docs/llm-guide.md
bash cd /tmp/analytics && echo "=== README head ===" && head -60 README.md 2>/dev/null; echo "=== top-level ==="; ls; echo "=== CHANGELOG head ==="; head -80 CHANGEL …

I have the schemas and a good picture. Let me study the codebase structure and changelog more deeply to understand the real feature areas and what's actively being shipped.

bash cd /tmp/analytics && echo "=== lib structure ==="; ls lib/ 2>/dev/null; echo; echo "=== plausible domains ==="; ls lib/plausible/ 2>/dev/null; echo; echo "=== w …
bash cd /tmp/analytics && echo "=== version ==="; grep -m1 version mix.exs; echo; echo "=== release tags in changelog ==="; grep -E '^## ' CHANGELOG.md | head -25; e …

Let me look at the major v3.0.0 release and key domain areas to understand the product's real shape.

bash cd /tmp/analytics && awk '/^## v3.0.0/,/^## v2.1.5/' CHANGELOG.md | head -90
bash cd /tmp/analytics && echo "=== stats ==="; ls lib/plausible/stats/ | head -40; echo "=== teams ==="; ls lib/plausible/teams/ 2>/dev/null | head; echo "=== billi …

I have a thorough understanding now. Let me get the exact `batch` mutation schema so I can create the tree efficiently within rate limits, then verify auth details.

fetch https://staging.productbrain.com/docs/llm-guide.md

Batch id-ordering is unspecified, so I'll create each layer then read it back via `GET /nodes` to map labels→ids reliably. Let me confirm tooling and empirically verify the API with the required `addProject` call.

bash which python3 && python3 --version; which jq && jq --version
write /work/pb.py
bash python3 pb.py addProject

Project created. Now let me verify the node add/read shapes with a single goal before building the full tree.

bash python3 -c " import pb, json r = pb.mutate({'action':'add','projectId':'plausible','node':{'type':'goal','data':{'label':'__probe goal__','description':'temp'}} …

Add works and returns the id. Let me test the `batch` response shape and clean up the probe.

bash python3 -c " import pb, json r = pb.mutate({'action':'batch','projectId':'plausible','mutations':[ {'action':'add','node':{'type':'goal','data':{'label':'__prob …

Batch returns `results` in order with ids. Let me delete the 3 probe goals, then build the full tree.

bash python3 -c " import pb, json r = pb.mutate({'action':'batch','projectId':'plausible','mutations':[ {'action':'delete','nodeId':'goal-1'}, {'action':'delete','no …

Clean slate confirmed. Now I'll build the full plan. Let me write the plan definition and orchestration script.

write /work/build_plan.py

Let me clean up one leftover expression before running.

edit /work/build_plan.py
bash python3 build_plan.py

Everything created. Let me verify integrity — node counts, no orphans, iterations, and spot-check a subtree.

bash python3 -c " import pb, json r = pb.req('/nodes?projectId=plausible') meta = r['_meta'] print('nodeCounts:', meta.get('nodeCounts')) print('iterations:', meta.g …

Plan is coherent and fully linked. Let me confirm approaches carry their required fields, then mint the share link.

bash python3 -c " import pb, json r = pb.req('/nodes?projectId=plausible&type=approach') ap = r['nodes'] missing = [a['id'] for a in ap if not a['data'].get('measure …

Done. The plan is built and the share link is minted. ## Deliverable — share link **https://staging.productbrain.com/shared/QtFBDhDaOaGJ9UlQtpnKa** (Public, read-only, no expiry. It can be revoked with `DELETE /share?projectId=plausible&token=…` if you want it locked down or time-boxed — say the word.) ## What I did 1. **Read the ProductBrain LLM guide** — captured the model (Goal → Need → Approach → Job + standalone Tasks), the field rules (kano/size/measure/approachStatus on approaches, maturity/iteration/status on jobs), and the write/share API contract. 2. **Shallow-cloned `plausible/analytics`** and studied it: the Elixir/Phoenix codebase (`lib/plausible/*` domains — stats, ingestion, segments, teams, billing, shield, imported, goals, funnel) plus 6 years of `CHANGELOG.md`. Plausible is a privacy-first, cookie-free, GDPR/CCPA/PECR-compliant Google Analytics alternative, sold as managed cloud + self-hosted Community Edition. 3. **Created the project** with the exact id/name you specified (`plausible` / "Plausible") and built the plan through the API. ## The plan (136 nodes) - **3 Goals** — the real business outcomes: *switch teams off Google Analytics*, *make privacy the durable differentiator*, *run a sustainable independent business*. - **10 Needs** — the opportunities under them (first insight in minutes, painless GA migration, attribution marketers trust, developer data access, provable compliance, featherweight/reliable tracking, clean data, self-serve billing, team access control, self-host success). - **32 Approaches** — the bets, each with a `measure`, `kano`, `size`, and `approachStatus` (e.g. single-page dashboard, GA4 import, acquisition channels, revenue attribution, Stats API v2, cookie-free measurement, engagement-based metrics, segments, teams/RBAC, Community Edition). - **91 Jobs** — verifiable checkpoints traced to actual code/changelog items. **73 are `status: done`** (shipped, mapped across four value-themed phases); **18 are open** and sit in the current cycle phase **"Deeper comparisons & revenue reporting,"** which mirrors the changelog's *Unreleased* section (AI Assistants channel, revenue-with-visit-dimensions, Last 24 Hours, ResizeObserver scroll depth, segment-scoped shared links, etc.). - **5 value-themed phases** (plus the system "Later" inbox), named by user value rather than sprint numbers per the guide. Integrity verified: correct node counts, zero orphaned parents, every approach carries measure+kano, and jobs distribute sensibly across phases. All writes were tagged with `X-Agent-Id: claude-plausible-planner`. The API key was only ever read from `$PB_API_KEY` — never printed or hard-coded. One judgment call worth flagging: I treated changelog *Unreleased* items as in-flight (open jobs in the current phase) rather than `done`, since they aren't in a tagged release yet. If you'd rather they count as live-on-cloud (`done`), I can flip those 18 in one batch call.

Same prompt each time — only the repo and the project name change. ← all three · back to the demo