local-dev-stack
Why It Exists
local-dev-stack is the operational counterpart to runtime-env-config: that
skill is the app-side loader chain (@cogs/config → process.env →
EnvProvider), and this skill is everything that loader depends on being
already running — the stage files on disk, the process orchestration, and the
database it talks to. Both trace back to the same origin,
docs/sessions/2026-08-02-env-stack-migration/ARCHITECTURE.md, which documents
workloom as "repo 1 of ~12" — the concrete instantiation every invariant in
this skill was extracted from, with its diff serving as the literal migration
template for the other 11 repos in the rollout.
The skill's tenth invariant — verify a repo's own onboarding docs against
process-compose.yml directly, rather than trusting them — was added later,
in commit e3f255f, after a 13-repo rollout turned up something concrete: more
than one repo's README/CLAUDE.md/SETUP.md still described a completely
different, superseded local-dev flow (Postgres plus a generic process
supervisor, predating the migration to this skill's process-compose.yml
pattern) that a new developer would have followed to stand up the wrong stack
entirely. That same rollout also upgraded the port-block invariant from a
theoretical concern to a documented, live-confirmed one: two real repos
independently defaulted to the identical 3010/4010 dev-server ports, a
collision that had nothing to do with Supabase's own 54N2x port block and
needed its own separate allocation table.
What It Does
Lays out the four things that have to work together before an app can boot
locally: which .env files are committed vs. gitignored (split by the env
registry's type), the .gitignore negation block that keeps stage files
tracked without leaking secrets, a process-compose.yml that boots Supabase
then runs the database and seed steps in strict dependency order, and a
per-repo port-block convention — for both Supabase's own ports and the app's
own dev-server ports — so multiple stacks can run on one machine without
colliding.
How To Use It
Trigger phrases: "process-compose", "Procfile to process-compose", "local Supabase ports", "port is already allocated", "supabase start fails / migrations before tables", "db:post", "apply-post-schema", "RLS out of migrations", "commit .env.dev but not the secrets", ".gitignore .env negation", "ENV stage secret split", "two local Supabase stacks at once", or standing up a local dev stack.
skills add git@github.com:catesandrew/next-starters.git --skill skills/local-dev-stack -g
npm install @next-starters/skill-local-dev-stack
/plugin marketplace add catesandrew/next-starters
/plugin install local-dev-stack@next-starters
Gotchas & Invariants
ENVis neverlocal—.env.localis the personal-override slot, and anENV=localstage file would collide with it.- Only env-registry entries with
type:'public'are safe to auto-commit;type:'connection'values are treated as potentially credential-bearing and flagged for manual review rather than committed automatically. - Anything that depends on app tables existing — RLS
ENABLE, grants, an auth hook — cannot live insupabase/migrations, becausesupabase startruns migrations at boot, beforedb:pushcreates those tables. It moves to an idempotentdb:poststep that runs after the schema exists, both locally and in prod. - Local Supabase's
service_rolekey and JWT secret go in.env.<stage>.localonly — never printed, never committed, never even present in the committed.env.<stage>file. - Seeded accounts must be created via
supabase.auth.admin.createUser(...), not a plain Drizzle seed insert — a plain seed writes app rows with random UUIDs that map to no realauth.usersrow, so those accounts can neither log in nor resolve an org/role. This step is guarded to refuse running against anything but alocalhost/127.0.0.1Supabase URL. - Even with the membership correctly keyed to a real auth UID, RLS on
organization_membershipscan silently block the access-token hook unlesssupabase_auth_adminhas an explicit permissiveSELECTpolicy — a bareGRANTis not enough, and the failure mode is a login that "succeeds" but resolves an empty org/default role.
Related Skills
- runtime-env-config — the app-side loader
and
EnvProviderchain that reads the stage files this skill lays out. - prod-deploy — the production counterpart: the
same
db:poststep re-run asdb:deployagainst Supabase Cloud, and every local-only convenience (captcha off, auto-confirm) reversed for prod.
Sourced from: skills/local-dev-stack/metadata.json, skills/local-dev-stack/SKILL.md, docs/sessions/2026-08-02-env-stack-migration/ARCHITECTURE.md, docs/sessions/2026-08-05-fleet-migration-progress/SUMMARY.md, git commit e3f255f