Skip to content

Worktree Dev Agents (CreatorTrack Parallel Multi-Agent Dev)

URL: https://mkdocs.justinsforge.com/memory/general/reference_creatortrack_parallel_dev/

Canonical name: "Worktree Dev Agents" (Justin's term, 2026-06-20). When he says "spin up N Worktree Dev Agents on ", "what are the worktree agents working on", "merge the worktree dev agents", or "tear down the WDAs", he means this pattern: N isolated agents, each a /spawn-style session PLUS its own git worktree + DB clone + dev server, building in parallel on one app, then a serial AI-reconciled merge. Shorthand accepted: "worktree agents", "dev agents", "WDAs". Each WDA = the heaviest isolation tier (vs a bare subagent, a plain /spawn, or a Workflow fan-out).

Tooling to run several AI agents in parallel on the one integrated CreatorTrack app (/home/justinwieb/creatortrack, Next 16, RLS Postgres on CT 109), each fully isolated, then merge. Design briefing: parallel-agent-creatortrack-workflow-2026-06-18. The DB+server rig is CreatorTrack-specific today; generalize to forge_agent_slot.sh <repo> <base-db> <dev-cmd> <port> when a 2nd stateful app wants WDAs.

Scripts (canonical, in forge/scripts/)

  • forge_creatortrack_dev_base.sh [--force] , builds creatortrack_dev_base, the idle template DB. Created UTF8 / C.UTF-8 from template0 to match live lifeos (template1 here is SQL_ASCII, which made psycopg hand text back as bytes , fixed 2026-06-20). Schema-only copy of lifeos (NO production data) + forge_workspace_seed.py so the WORKSPACE_DEV_AUTH login ([email protected]) works on every clone + baselines existing suite migrations as applied (so clones don't re-run already-baked schema). Built because lifeos has live connections, so it can't be TEMPLATE-cloned directly.
  • forge_creatortrack_agent_bootstrap.sh <branch> <port> [--no-server] , one isolated slot: git worktree at ~/forge-suite-wt/<branch>/, DB ct_<branch> (TEMPLATE clone of base, lock-free/instant), .env.local (PGDATABASE + PORT + dev-auth), node_modules symlinked to main, and next dev --webpack -H 0.0.0.0 -p <port>. Preview at http://<tailscale-ip>:<port> (tailnet, no public tunnel needed for a trial). --no-server (added 2026-07-01, round-4 default): worktree + DB only, no dev server; agents build + typecheck, visual QA happens once on :3060 post-merge. The server line also got </dev/null so a started server can never hold the caller's stdout pipe open (looked like a bootstrap hang on 2026-07-01; slots were actually fine).
  • forge_workspace_new_migration.py "<desc>" [--branch B] [--dir D] , creates a collision-proof migration file in the worktree's db/migrations/, named <UTC-stamp>_<branch>_<desc>.sql. Two agents can never pick the same name (no 0041 clash), no lock needed; lexical sort = apply order. Writes into the CURRENT worktree so the schema change commits + merges WITH its feature code.
  • forge_workspace_migrate.py , gained a migrations-dir override (--dir / $WORKSPACE_MIGRATIONS_DIR, default = forge spine dir) and --baseline (mark applied without running). An agent applies its own worktree's migrations: cd <worktree> && PGDATABASE=ct_<branch> WORKSPACE_MIGRATIONS_DIR=db/migrations python3 ~/forge/scripts/forge_workspace_migrate.py.

Enabling patch (already applied)

Both DB connection helpers were patched to let standard PG* env vars override ~/.forge-secrets/forge-data.env (additive, backward-compatible , unset = old behavior): - forge-suite/lib/secrets.ts forgeDataEnv() , so an agent's dev server hits its own DB. - forge/scripts/forge_workspace_db.py _load_env() , so PGDATABASE=ct_<branch> python3 forge_workspace_migrate.py applies migrations to that agent's own clone.

Port / preview convention

  • main = :3060 / dev.creatortrack.ai (systemd dev server, owned by whoever holds main).
  • agents = :3061+ , preview http://100.97.43.104:<port> (Console tailscale IP).

Migrations (decision A, 2026-06-20)

New schema changes live in the suite repo forge-suite/db/migrations/, NOT the forge spine dir, so a migration commits and merges WITH the feature code that needs it. Model: - Spine history (forge/data/workspace/migrations/ 0001-0040) stays the legacy DDL stream applied directly to lifeos; the base DB carries it via the schema dump. - The base DB baselines the suite migrations that are already baked in, so a clone only runs what its branch ADDS. - Agents create files with forge_workspace_new_migration.py (collision-proof <stamp>_<branch>_<desc>.sql) and apply with the WORKSPACE_MIGRATIONS_DIR=db/migrations override. Write idempotent DDL (IF NOT EXISTS). - core.schema_migrations PK = filename; the runner decodes bytes defensively so an encoding quirk can't make applied files look pending.

Hardware ceiling (Finn 128 GB since 2026-06-20; Console 50 GB)

Pre-upgrade this was 32 GB total / Console ~12 GB; the 128 GB upgrade is what unblocked the trial. DB clones live on CT 109 (12 GB, tuned; free shared buffers). Dev servers are the only Console squeeze (~1-2 GB each under compile); 50 GB comfortably runs the full 3-agent trial with previews hot. Still idle unused dev servers (kill the PID on its port) when not watching; bootstrap restarts in ~300ms.

Merge

Serial + AI-reconciled (catches git's clean-but-wrong auto-merges). Each agent leaves a 3-5 line intent note; integrator reviews the full combined diff against intents, validates migrations on a fresh base clone (timestamp names mean no collision to collapse), then promotes.

Rig gotchas / required server config (found 2026-06-21, first slot)

A slot served over plain http on the tailnet hit three latent blockers; all fixed, but two are easy to lose: 1. pg_hba on CT 109 (NOT in any repo, survives only as live config): the RLS app role lifeos_app was pinned to the lifeos DB, so it was rejected (FATAL 28000) connecting to clone DBs and every page 500'd. Required rule: host "/^ct_" lifeos_app 192.168.86.50/32 scram-sha-256 (regex-scoped to clones), reload with select pg_reload_conf(). Re-add this if CT 109 / pg_hba is ever rebuilt. 2. allowedDevOrigins in next.config.ts must include Console's tailscale (100.97.43.104) + LAN (192.168.86.50) IPs, or Next blocks the slot's dev/HMR assets from any other device. 3. proxy.ts route gate must honor dev-auth: if (NODE_ENV==='development' && WORKSPACE_DEV_AUTH==='1') return withPath(); before the /login redirect. Otherwise dev-auth resolves identity for queries but never sets the cookie the proxy gates on, looping /login <-> /. Double-gated so :3060 (dev-auth off) keeps its signed-out gate testable. Items 2+3 live in the suite repo and ride into main via the first slot's branch merge.

Browser testing for agents (see + click their own preview)

Agents verify their own slot visually with one of two tools (both drive the page via the accessibility tree, deterministic, NOT pixels, unlike the buggy claude-in-chrome extension which is retired for agents). Console is headless (no DISPLAY), so both run headless.

  • Vercel agent-browser (everyday driver, lightweight) , CLI, no install: npx agent-browser open http://127.0.0.1:<port> then snapshot / click "@e3" / screenshot <path> / close --all. Compact @e refs (~93% less context) = good for long agent runs. Self-loads usage via npx agent-browser skills get core --full. Proven against :3061 2026-06-21 (read sidebar, clicked Workspace button).
  • Playwright MCP (depth) , project-scoped in .mcp.json (@playwright/[email protected] --headless --isolated), so every Claude Code agent in this repo gets it as native MCP tools. Reach for it over agent-browser when a task needs: network inspection/mocking (did rename actually PATCH + 200?), page-load video/trace (catch the ~0.5s sidebar flash frame-by-frame), multi-tab/OAuth popups, smarter waiting, or codegen of a saved regression test. First call per session downloads its browser (~30-60s, one-time). A running agent must restart its session to pick up a newly-added .mcp.json.

Rule of thumb: agent-browser for routine look-and-click; Playwright MCP for network truth, load-timing bugs, popups, and persistent tests.

Teardown

git -C ~/forge-suite worktree remove ~/forge-suite-wt/<branch> + DROP DATABASE ct_<branch>; (as lifeos_admin). Base DB persists for reuse.

[Claude Code]