Imported from tomevault-io/tomes (
andriiklymiuk--corgi/skills/plugins-corgi-skills-run-skill-302d40f8cbbfaa77/SKILL.md). Install upstream withnpx skills add tomevault-io/tomes --skill plugins-corgi-skills-run-skill-302d40f8cbbfaa77. Copyright stays with the author.
Corgi run
Bring up a corgi stack — or a slice — from chat. Boot detached, wait until
healthy (timeout), flag stuck, report URLs + how to stop. What runs and how =
read from the repo (corgi-compose.yml, Makefile, README); never hard-coded,
never company-specific.
Guardrails (non-negotiable)
- Detached only — never a synchronous foreground
corgi run. Blocks indefinitely streaming logs; a sync Bash call hangs until the 10-min timeout and truncates boot output. Use--detach; on a cold stack launch withrun_in_background: true(Phase 2). See../corgi/references/long-running.md. - Never start a service the user wants pointed remote — a local run overrides the remote URL.
- Don't
--force/restarta live run without asking —corgi psfirst. - Diagnosis = the debug skill. Boot + quick stuck-triage here; real
investigation →
debug.
Phase 0 — Locate + first-run preflight
cwd must hold corgi-compose.yml (ls corgi-compose.yml *.corgi-compose.yml). None
→ tell the user to open the stack folder; don't guess a layout. Read only needed
keys — services.<name>.{path,cloneFrom,depends_on_services,depends_on_db,start,port, tunnel,manualRun,runner}, db_services, envTiers, useAwsVpn, useDocker,
init, required (schema: ../corgi/references/yml-schema.md).
- First run →
corgi initfirst.corgi runclones missing repos + runs the compose-levelbeforeStart, but NOT theinit:block (env gen, config copy) orrequired:installs — those run only oncorgi init. Most stacks: run target =corgi init && corgi run. Service dirs missing OR env files / generated config absent →corgi initfirst (cold machine = long: clones + installs). - corgi auto-handles VPN + Docker. Compose sets
useAwsVpn/useDocker(or any service uses thedockerrunner) →corgi runstarts VPN + Docker itself in preflight. Don't add a manual VPN/docker step.
Phase 1 — Resolve intent → command
Sources, priority: corgi-compose.yml authoritative (services/dbs/tunnels/tiers
- each
start:);Makefiletargets = the team's named shortcuts (grep -E '^[a-zA-Z][a-zA-Z0-9_-]*:' Makefile);README= remote URLs + host quirks. Match the user's words → translate to a detached command.
| Intent | Command |
|---|---|
| Whole stack | corgi run --detach |
| A subset | corgi run --services <a,b> --detach (--with-deps pulls each one's deps + dbs) |
| Frontend(s) → remote backend | corgi run --services <frontends> --dbServices none --detach. Backend excluded → its depends_on_services alias is not generated — the frontend uses ONLY its own env file. Read that env file (Read the frontend's source .env) and confirm the API URL is the remote one, not a localhost default corgi init seeded; if localhost, user sets the remote URL there before you declare success. (Don't use corgi env <frontend> for this — it ignores the run set and annotates vars with depends_on sources for the backend you excluded, so it misleads.) |
| + captured logs | add --logs |
| + webhook tunnel | can't combine with --detach — see Tunnel, Phase 2 |
| Staging/prod tier | --tier <name> if envTiers: defines it; else the repo's run<X>Staging make target's underlying corgi command (tier run usually --dbServices none — no local dbs) |
| One DB only | corgi run --dbServices <name> --services none --detach |
Names match compose keys exactly. --services/--dbServices = exact-name match.
A Makefile target may pass a non-key name (e.g. --dbServices supabase when the key
is <name>-supabase → selects nothing, stack boots with a dead db URL). Resolve
every name against corgi-compose.yml keys; or --with-deps to let corgi resolve
the db closure from depends_on_db instead of hand-listing.
Omitting a dependency from a hand-picked slice hard-fails preflight with
E_DANGLING_DEP: service "<x>" depends on unknown service/db_service "<y>" — corgi
validates the whole selected graph, and --services/--dbServices do not
auto-pull what the named services depends_on. Don't chase it by hand-listing every
dependency; corgi run --services <x> --with-deps --detach resolves the full
depends_on closure (services + their dbs) in one command. A runOnly<X> make target
that hand-lists --dbServices … --services <x> without --with-deps dangles the
moment <x> gains a new depends_on — prefer --with-deps.
Carry the Makefile target's env-var prefix verbatim. WEB_DEV_CMD=dev:host MOBILE_PLATFORM=android corgi run --services … sets process env vars a service's
start: reads (yarn ${WEB_DEV_CMD:-dev}, bun ${MOBILE_PLATFORM:-ios}). corgi
can't inject these (sources only the env file), so dropping the prefix silently
changes behavior — and corgi env won't show them (process env, not env-file). Grep
the matched start: for ${VAR placeholders; reproduce every prefix the target sets.
Host (mobile/device/emulator). Default localhost. corgi run --host <ip> =
blanket replace of every localhost in the service's generated .env — the API URL
AND its db-dependency URLs (e.g. Supabase). The db containers stay bound to the
host; only the URLs the service consumes are rewritten. Does NOT launch a
simulator/emulator, does NOT change start:.
- Android emulator → literal
--host 10.0.2.2(host-loopback alias) so both API and supabase resolve from inside the emulator — notauto. - Real device / LAN → an explicit IP the user names; API + any db it points at
must be reachable on that interface.
--host auto= first physical LAN IPv4 (en0/en1/eth0/wlan0), skips VPN/Docker/tunnel interfaces → a VPN address won't be picked byauto; pass it explicitly. - A "mobile" service whose
start:isexpo start --web/bun webis a web target — corgi only gives you that. Real native run:corgi run --services <mobile> --with-deps --host 10.0.2.2 --detach(--with-depslets corgi resolve the exact db key fromdepends_on_db— a hand-typed--dbServicestoken must be the exact compose key or it selects nothing; see the name rule above) for env + deps, then launch the native build yourself (cd <mobile> && expo run:android) or via a corgi script if one exists. corgi brought up env + deps + the web bundler only — the emulator launches separately and is not covered by the ready gate; don't claim it's running off a green web port. - Verify a host rewrite by Reading the written
<mobile-dir>/.env(Readlimit: ~40) —corgi envdoes NOT apply--host(shows localhost by design). Usecorgi envonly for the non-host remote-backend case above.
Run a branch / worktree — a feature/PR branch or an existing worktree
Run a service from code other than its compose path: — a feature/PR branch, or
an existing worktree dir — without touching the main checkout. Per-service,
repeatable, <svc>=<value>, mixable (named svcs from branch/dir, the rest from
compose path:); combine with --detach, --with-deps, --services.
Flag-existence guard (newer flags): corgi run --help | grep service-branch —
missing → no fallback; use git checkout <branch> && corgi run --services <svc>.
- Committed/pushed branch —
--service-branch <svc>=<branch>. corgi makes (or reuses) its own non-destructive worktree off that branch undercorgi_services/.worktrees/; main checkout untouched. Reviewer-facing shape (thestoriesPhase 5 "Run line"). Branch must exist locally; source must be a git repo (clones first if needed). Gotcha — fails if that branch is currently checked out in the main repo (git one-branch-one-worktree) → switch the main repo off it. Fresh worktree has nonode_modules(gitignored) → first run needs the service'sbeforeStart(e.g.npm install); reused worktrees keep it. - Existing worktree dir —
--service-dir <svc>=<path>. Runs that exact dir's env- beforeStart/afterStart + process; pure cwd swap, no git touch, no clone. Dir must
exist. For uncommitted/live code in a known worktree (
storiesPhase 3 shape,/tmp/corgi-wt/<wt-id>-<svc>). (--service-checkout <svc>=<branch>= in-place checkout of the service's own dir; refuses on a dirty tree, leaves the dir on that branch.)
- beforeStart/afterStart + process; pure cwd swap, no git touch, no clone. Dir must
exist. For uncommitted/live code in a known worktree (
--with-depsonly expands the--servicesset throughdepends_on— it does not auto-worktree pulled-in deps; you get a worktree/dir only for svcs you name.
# impacted services on a pushed branch (reviewer Run line)
corgi run --with-deps --detach \
--service-branch api=feature/ABC-200/user-phone \
--service-branch web=feature/ABC-200/user-phone
# live worktree code for some, compose path: for the rest
corgi run --detach \
--service-dir api=/tmp/corgi-wt/ABC-200-api \
--service-dir web=/tmp/corgi-wt/ABC-200-web
# admin, worker, db_services (unnamed) run from their compose path:
Cleanup (only --service-branch worktrees; --service-dir/in-place checkouts
leave nothing): corgi worktree list shows corgi-made worktrees, corgi worktree prune removes them + their git entries (corgi run --fromScratch / corgi clean
prune too).
Phase 2 — Launch detached
corgi run <flags> --detach [--logs] --json
Not instant on a cold stack. corgi run --detach runs every service's
beforeStart (bundle/yarn install, migrations, webpack, image pulls)
synchronously before it writes state and returns — minutes to tens of minutes on
a first run. Launch with run_in_background: true (or Bash timeout ≥ 600000ms),
poll corgi ps --json; don't assume a quick return or treat the wait as a hang.
Output: --detach --json prints the run-state object — services[] each
name/pid/port/status, plus dbServices[]; a service crashed on spawn shows
status:"crashed" in that array (no separate failed[]). E_ALREADY_RUNNING → a
run is already live: corgi ps to show it; ask before --force/corgi restart.
(Stale .state.json after a crash also triggers it — corgi ps reconciles,
--force clears it.)
Tunnel (if requested): --tunnel can't combine with --detach. Detach
services first, then — only after confirming the tunnel's hostname env resolves
(corgi env <svc>, from tunnel.hostname: ${VAR}) AND provider auth is done
(ngrok/cloudflared; corgi doctor) — background corgi tunnel <svc>
(run_in_background: true). Standalone corgi tunnel hard-fails (exit 1) on a
missing hostname var or missing auth (unlike corgi run --tunnel, which only
skips-with-warning) — don't background one that will die. After backgrounding, read
the shell output until ✓ <svc> :PORT → https://… (live) or ✗ …/process-exit
(died — fix env/auth); only then report the public URL.
Phase 3 — Ready gate (with a timeout)
corgi status --ready --json --timeout <T> [--service <started ones>]
<T> = a Go duration — always 120s/300s/10m, never a bare number. Size it:
warm stack ~120s; a first cold boot (clones repos / pulls images / builds a venv)
7–10 min+ → 600s+, or skip the strict gate and poll corgi status --json
every ~30s comparing the healthy count (rising = progress, not stuck). A multi-hour
DB dump/restore (make initDatabase-style) is separate, out-of-scope — never
block the gate on it.
- Healthy (exit 0) → report. Uptime (
startedAt)/ports fromcorgi ps --json. But the gate only probes targets with a declaredport:. No port-bearing service in the started slice (status prints "No services with ports declared — nothing to check", exits 0) → the gate verified nothing: fall back tocorgi ps --json(status running + a live pid) + a boundedcorgi logs --service <x> --idle 2s. A port-less db whose port comes from a driver default (notably thesupabasedriver) is invisible to the gate even when others are probed — cross-check out-of-band (curlits health URL /corgi ps --json/docker ps). Never report ready on a no-op exit 0. - Timeout (exit 1) — don't hang, don't retry blindly. Final JSON lists each
target
healthy:false. Before handing off, separate crashed-after-boot from never-opened-its-port:corgi ps --jsonstatus:"crashed"only for pid-tracked services — db_services and docker-runner/pid-0 services never show "crashed", judge those bycorgi statushealthy:false+docker ps. Triage:corgi doctor+ a boundedcorgi logs --service <X> --idle 2s. Name the likely cause, pass the crashed-vs-never-opened distinction along, hand a real investigation to thedebugskill. - Partial ready → backends healthy but a frontend bundler (Expo/Vite first build) still warming: report what's up + what's warming rather than failing the whole gate; re-poll the warming one.
Phase 4 — Report
- What's up (services + ports + URLs), what's down/warming.
- Some services open a browser themselves in
start:(open -a Chrome <url>) — note it so the user isn't surprised (harmless headless). - Watch logs:
corgi logs --service <x>(detached always captures logs). Stop:corgi stop(orcorgi stop --service <x>; runsafterStart, brings dbs down). Unhealthy → "run the debug skill //corgi-debug".
Source: Andriiklymiuk/corgi — distributed by TomeVault.