Worker brief: Link In Bio follow-on, Brand picker + gusoutdoor.co second domain¶
main. NEVER deploy to prod. NEVER run migrations against the prod DB (lifeos). NEVER commit secrets (~/.forge-secrets/*.env).
- Doctrine: robust over quick (no band-aids, no --no-verify), fail loud, idempotent by default, test the path before claiming done. No em dashes. snake_case [source]_[entity]_[state]. Flat verbose filenames.
- Commit OFTEN. The dev-slot reaper deletes idle (45m) / over-cap worktrees and eats uncommitted work.
cd /home/justinwieb/creatortrack
2. scripts/forge_creatortrack_agent_bootstrap.sh links-brand-picker 3063 (worktree on branch links-brand-picker + own dev DB clone). --no-server if you do not need the server yet.
3. Worktree dev-server: next dev --webpack (turbopack symlink bug); watch stale .next-dev types.
4. Dev auth: WORKSPACE_DEV_AUTH=1; NEVER fresh-login over http.
Read before planning:
- /home/justinwieb/creatortrack/AGENTS.md (BEGIN:link-in-bio-module, ~lines 116-140)
- forge/memory/general/reference_links_module.md (note the control model + brand/workspace section)
- forge/memory/plans/affiliate-click-foundation-2026-07-08.md (this is the noted follow-on, not a numbered phase)
- CT app: app/(suite)/link-in-bio/*, components/apps/link-in-bio/*, lib/links-store.ts, lib/links/{render,cf,brands,bio-css}.ts, app/api/links/{route,publish/route}.ts
- Schema: db/schema.ts (links pgSchema; links.pages.brand distinguishes gusthebass vs gusoutdoor)
- Edge worker: forge/infra/links-edge/src/{index,capture,cors,page}.ts, wrangler.toml
- Sync + Mautic fan-out: forge/scripts/forge_links_sync.py (BRAND_WORKSPACE map, per-brand Mautic segment/tag)
Current state: both Gus brands live in ONE workspace (Gus The Bass, lifeos id 85); links.pages.brand already distinguishes gusthebass vs gusoutdoor. KV page key is already host-scoped (page:<host>:<slug>), which lets a second domain slot in. What is missing: an editor brand picker, gusoutdoor.co routed on the edge, and "send as either brand" for captures.
links.pages.brand. Respect existing per-app permission (Michael stays Gus-scoped). Keep it obvious which brand a page publishes as.
2. Second routed domain gusoutdoor.co: wire the edge worker CORS + routes (gusoutdoor.co/{<slug>,r/*,c}) in forge/infra/links-edge/{wrangler.toml,src/cors.ts} and make the publish path (lib/links/cf.ts / render.ts) target the right host so page:<host>:<slug> and capture CORS resolve correctly per brand. Do NOT deploy prod routes or change DNS yourself (Justin-only); prepare config + a deploy note.
3. "Send as either brand" for email captures: ensure a capture on a gusoutdoor page fans to the correct Mautic segment/tag. Update forge_links_sync.py BRAND_WORKSPACE / brand->segment mapping so gusoutdoor routes correctly; unknown brand must skip loudly, never misroute.
Process:
1. Read all references.
2. Run /feature-plan; write spec + task list to forge/memory/plans/links-brand-picker-2026-07-11.md. Then implement (authorized); keep the plan as contract.
3. Implement task by task, commit each boundary (feat(links): ...). Migrations to your dev clone ONLY.
4. Verify end-to-end: create a gusoutdoor-brand page, publish (dev dry-run), confirm the host-scoped KV key + capture CORS + Mautic segment resolve for the second brand. Confirm gusthebass still works (no regression). Script the checks.
5. Write forge/memory/handoffs/links-brand-picker-status-2026-07-11.md: built / tested / EXACT Justin-only unblock (DNS + CF route add for gusoutdoor.co; edge wrangler deploy) / branch name. Leave committed on links-brand-picker. Do NOT merge, deploy, or touch prod.
6. /notify low "links-brand-picker worker" "Brand picker + gusoutdoor.co build done, see handoff" when finished.
Execute now.