Linear ticket → orchestrator picks it up → Claude Code writes the feature in an isolated worktree → CodeRabbit reviews it → auto-merge to main. The system runs continuously, handles dozens of tickets in parallel, and costs roughly zero minutes of direct human time per ticket.
Every ticket flows through the same path. The orchestrator on PKX owns scheduling and spawning. Claude Code owns implementation. CodeRabbit owns review. Auto-merge owns landing.
/home/paulk/polyprint-worktrees/pol-N per ticket.
node_modules symlinked from main when package-lock matches.
Title has [Phase N] prefix. Body may include target_branch: token.
Python daemon on PKX, systemd service. DAG scheduler decides: pick up, defer, or escalate.
Headless, --permission-mode bypassPermissions. Worktree has CLAUDE.md + failure-modes.md loaded.
Invoked in parallel when ticket touches unfamiliar framework surface. Returns ~500-word distilled brief.
Main Claude writes the feature. Writes are sequential — reads and verifies are parallel.
Runs lint + check + test. PASSED or FAILED. Never touches files. Loops with main Claude on failure.
Runs the same battery on git push. Rejects push if any step fails. Cannot be bypassed without --no-verify.
Fires on task completion signal. Third battery of the same checks. Belt-and-braces: catches "declared done, never pushed" cases.
Inline comments on the PR. Findings ranked 🔴 Critical / 🟠 Major / 🟡 Minor.
If 🔴/🟠 findings exist, a second Claude Code turn launches with findings JSON. Addresses them, pushes. Max 1 drain per PR.
GitHub Actions. Runs independently of pre-push hook. Auto-merge is gated on green CI.
Refuses if last commit author is coderabbitai[bot] (prevents autofix ping-pong). Squashes to main, deletes branch.
Orchestrator detects merge on next tick, advances state. Discord notification fires.
When orchestrator/ changed: backup + syntax-check + rsync + restart. Zero-touch orchestrator updates.
.claude/failure-modes.md for the 747-line stack error catalog.
target_branch: pol-X-orchestrator attach to an existing PR instead of opening a new one.
.claude/ or .husky/ are intercepted and pinged to a human — Claude Code hard-blocks writes to those paths.
[ci-nudge] commit. Max 1 per PR.
Defensive layers that compound. Advisory guidance in CLAUDE.md + mechanical enforcement via hooks + sub-agent verification before completion. Each layer catches a different class of failure.
Non-negotiable gates at the top. Failure-mode dictionary catalogs every stack-specific error Claude has ever hit
(SvelteKit routing, Vitest $app/* imports, Durable Object migrations, D1 batch transactions).
Imports .claude/failure-modes.md for the full catalog.
--no-verify
Runs pnpm lint && pnpm check && pnpm test -- --run && pnpm build locally before every push.
The build step is non-negotiable — it catches server/client boundary violations,
SSR errors, and bundle-time regressions that lint/check/test silently miss.
If any step fails, the push is rejected. This is the load-bearing gate.
Orthogonal to the git hook: fires when Claude says the task is complete, not when pushing. Runs the same lint+check+test+build battery. Catches "Claude wrote code, never pushed, but declared done" edge cases. Belt-and-braces complement.
Each sub-agent gets a fresh 200K context window, a narrow tool allowlist, and explicit "DO NOT" constraints. Main Claude delegates specialized work to preserve its context for implementation. Read-only agents use Haiku (cheap); write agents use Sonnet (capable).
Runs lint + check + test + build. Returns PASSED or FAILED with error. Never writes files, commits, or pushes.
Writes Vitest tests for a new feature given feature description and file paths. Returns test file content.
Rebases branches onto main. Resolves conflicts when semantics are clear, escalates when they aren't.
Verifies PR diff matches ticket acceptance criteria. Returns checklist with 🔴 violations and file:line refs.
Fetches framework docs (SvelteKit, Workers, Vitest) and cross-references local patterns. Returns ~500 word distilled summary.
Writes D1 migration SQL files from schema diffs. Enforces no-interactive-transactions rule automatically.
Runs vite build + wrangler deploy --dry-run. Catches Workers-specific failures unit tests miss.
Reviews diff for repo convention violations: business logic in route handlers, DB queries outside src/lib/db/, DO state leaks.
A ~1200-line Python daemon running as a systemd user service. Ticks every 60s, polls Linear, applies DAG rules, spawns Claude Code per ticket in isolated worktrees.
Fetches up to 100 Ready tickets, orderBy createdAt ASC (oldest first). Phase N+1 tickets defer until all Phase <N+1 tickets are Done, Canceled, or Duplicate.
Each ticket gets its own worktree branched from origin/main. Symlinks
node_modules from main when package-lock matches — saves 30-90s per pickup.
Won't pick a ticket if a Phase N-1 prereq isn't Done. Won't parallelize two tickets touching the
same file. Serializes tickets that touch CRITICAL_PATHS (package.json, wrangler.toml,
svelte config, etc.) — these run alone.
Tickets with target_branch: pol-X-orchestrator in their body attach the worktree to
an existing remote branch and push to it instead of opening a new PR. Used for lint fixes and
rebases.
State machine per in-flight ticket. 5-min CodeRabbit timeout. Detects "Claude Code exited without pushing" and marks the ticket Blocked with an escalation comment.
.claude/ and .husky/ paths
Tickets modifying these paths are auto-intercepted — Claude Code hard-blocks writes to
.claude/ even in bypass mode. Orchestrator posts to Discord and moves to Blocked
with "needs-morty-hands" marker.
Three cron-driven loops keep everything live without intervention.
Watches origin/main. When orchestrator/ changes, pulls, syntax-checks Python,
rsyncs to ~/polyprint-orch/, and systemctl --user restart. Zero-touch
orchestrator updates.
Scans recently-merged PRs for CR findings that weren't addressed during the initial drain. Files new Linear tickets for the un-addressed items so they get picked up next cycle.
When GitHub's pull_request.synchronize events go missing (GHA queue glitches),
orchestrator pushes an empty [ci-nudge] commit to re-trigger. Max 1 per PR to
avoid loops.
Drains /tmp/polyprint-orch/pending_notifications.jsonl and posts to the team channel.
Ticket picked up, completed, escalated, or merged — all show up in chat.
An internal prediction market for Blueprint Equity, written by the orchestrator. All on Cloudflare's edge.
$state, $derived, $effect. Typed routes with resolve().
No React, no Tailwind — plain CSS with design tokens.
SSR at the edge. @sveltejs/adapter-cloudflare. Deploy via wrangler-action on merge to main.
One MarketDO per market — holds live pool state + hibernatable WebSocket broadcast. D1 is source of truth for users, bets, resolutions.
@blueprintequity.com Google Workspace domain. Edge-verified email injected via
Cf-Access-Authenticated-User-Email header.
Two Vitest projects: client (jsdom + sveltekit plugin) and workers
(@cloudflare/vitest-pool-workers). Playwright for smoke tests.
Parimutuel invariant (sum(outcome.pool) == total_pool), immutable resolutions,
DO as source of truth, Access gates everything. Violations fail PR review.
Linear tickets are phase-tagged in their title. DAG scheduler enforces phase ordering.
| Phase | Name | Focus |
|---|---|---|
| 0 | Repo + infra | SvelteKit, wrangler, D1 schema, MarketDO skeleton, CI pipeline |
| 1 | Design system port | Cards, nav, shared primitives from mockup |
| 2 | Auth + users + wallet | Cloudflare Access integration, user bootstrap, 10k airdrop, wallet API |
| 3 | Markets (read) | List page SSR, detail page, WebSocket client, seed data, error pages |
| 4 | Betting engine | placeBet in DO, API, WebSocket broadcast, UI modal, parimutuel math |
| 5 | Positions page | User's open bets, implied-payout drift calc, position card |
| 6 | Admin | Create + resolve markets, admin dashboard, resolution flow |
| 7 | Leaderboard | Compute query, leaderboard page, badges / achievements |
| 8 | Polish + launch | Responsive, a11y audit, SEO, E2E test suite |
Two runs of the same orchestrator, same stack, different baseline. The gates are the delta.
| Metric | Pre-gate baseline | Post-gate baseline |
|---|---|---|
| Fix-ticket ratio | ~60% of PRs needed a follow-up fix | ~0% |
| Wall-clock per ticket | ~15 min | ~6 min |
| Manual interventions per hour | ~3 | 0 |
| Parallel Claudes saturated | Rarely 3 / 3 | 3 / 3 consistently |
| Orchestrator self-heals | No | autodeploy + auto-nudge + auto-escalate |
CLAUDE.md is read and may be ignored around turn 30 of a long ticket. Every rule you care about needs a mechanical enforcer (hook, sub-agent, CI). Advisory prose is not a control.
Hardest rules go at the TOP of CLAUDE.md. Imports go at the BOTTOM. Nothing load-bearing in the middle. Frontier models reliably follow ~150 instructions; burn your budget on the top third.
They're about context durability. Each gets a fresh 200K window; parent only sees the summary. For multi-hour tickets, this is the difference between completing and auto-compacting.
Sub-agents cannot spawn sub-agents. Everything that needs coordination comes back to main. Don't design towers of abstraction.
Sub-agents have 20-60K setup overhead and return lossy summaries. Rule: ≥10 files to explore, ≥3 independent chunks, or need an unbiased reviewer. Otherwise stay inline.
If the DAG scheduler treats Canceled tickets as "not Done," the pipeline stalls permanently on superseded work. Canceled means "covered elsewhere, unblock."
build is a pre-push gate, not a CI nicety
Lint + typecheck + unit tests can all pass while the production bundle fails on
server/client boundary violations, SSR errors, or circular imports. Only npm run build
catches those. It belongs in Husky, the Stop hook, AND the pre-push-verifier sub-agent —
three independent gates. Removing it from any one is fine; removing it from all means the
product silently fails to deploy while the board reports "complete."
The Linear board is the source of truth for the work. It is NOT the source of truth for the deploy. Every meaningful status report must additionally check: when was the last successful production deploy? Does the URL return the real app or a 404 behind auth? The pipeline's definition of done should include "the user can actually use it," not just "CI passed."
continue-on-error is a landmine
CI jobs marked continue-on-error: true while waiting to "stabilize" become
invisible. They fail silently for days while status dashboards report green. If a job is
flaky, fix the flake. If it's new, require it from day one and let early failures be loud.
Hiding failures is strictly worse than having them.