원클릭으로
devrouter
Work with devrouter for local dev routing (HTTP + TCP/Postgres + dependency-only Docker services)
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
메뉴
Work with devrouter for local dev routing (HTTP + TCP/Postgres + dependency-only Docker services)
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
SOC 직업 분류 기준
Build the frontend of a GBL platform game - player cockpit with status-switch pattern, admin pages, realtime wiring, and which components to reuse from @gbl-uzh/ui and @uzh-bf/design-system. Use when creating or changing game pages/components in apps/<game>/src.
Scaffold a new GBL platform game app inside this monorepo by copying apps/demo-game - file-by-file copy/rename checklist, prisma setup, local dev environment, and first-run verification. Use when starting a brand-new game.
Keep the GBL platform wiki (docs/) accurate and conformant with the Open Knowledge Format - the repo-specific extension of generic OKF/LLM-wiki practice - when to update it, how to fact-check against code, house conventions, and validation. Use whenever a change touches packages/platform, packages/ui, apps/demo-game behavior, or when doc-code drift is noticed.
Implement the backend of a GBL platform game - the six-module Services contract (Actions, Period, PeriodResult, Segment, SegmentResult, GameFacts), facts types with yup schemas, and seed data. Use when writing or changing game logic in apps/<game>/src/services.
Design a learning game for the GBL platform - check platform fit, map a game idea onto periods/segments/decisions/facts, and produce a build-ready game design. Use BEFORE writing any code for a new game.
Create, run, debug, review, and extend Playwright E2E tests for GBL games (the demo-game suite and specs adapted for new game apps). Use when working in playwright/tests, Playwright config/CI, local devrouter/devcontainer browser validation, multi-player game flows, OIDC mock auth, report/dice/countdown assertions, flaky Playwright failures, or GBL Cypress-to-Playwright coverage planning.
| name | devrouter |
| description | Work with devrouter for local dev routing (HTTP + TCP/Postgres + dependency-only Docker services) |
| user-invocable | false |
Local dev routing via a shared Traefik reverse proxy. Provides stable *.localhost hostnames for HTTP apps and TCP/Postgres multiplexing on shared ports (80, 443, 5432).
.devrouter.yml (single source of truth).~/.config/devrouter (never edit manually)..localhost (lowercase alphanumeric + hyphens only)..devrouter.yml entry schemaversion: 1
devrouter:
version: <semver> # required for devrouter -V / devrouter upgrade
project:
name: <string> # optional
apps:
- name: <string> # unique within repo
kind: app | dependency # optional, default: app
dependencies: # optional
- app: <other-name>
envMap: # optional; maps target env var name -> per-dep source var name
DATABASE_URL: <UPPER_DEP_NAME>_URL
# if kind=app:
host: <name>.localhost
protocol: http | tcp
runtime: host | docker | proxy
# if kind=app and runtime=proxy (protocol http or tcp):
upstream: 127.0.0.1:3000 # already-running port to route to; no lifecycle/deps
# Loopback (127.0.0.1/localhost) -> host.docker.internal (a published host
# port). A non-loopback name is passed verbatim and resolved over devnet —
# so a devcontainer container ON devnet (with a network alias) can be fronted
# by NAME with NO published host port: upstream: <alias>:3000. This is the
# collision-free way to run many apps at once (each its own *.localhost).
# upstream may use the ${WORKSPACE} placeholder (e.g. ${WORKSPACE}-app:3000)
# to target a per-workspace devcontainer alias — substituted with the resolved
# workspace token at runtime. See "Workspace isolation" below. Do NOT put
# ${WORKSPACE} in `host` (rejected); the host is auto-namespaced.
#
# proxy + tcp (front a DB in an externally-managed container, e.g. a
# devcontainer's Postgres on devnet) — no per-DB host port:
# protocol: tcp
# tcpProtocol: postgres # selects shared entrypoint :5432
# upstream: <db-alias>:5432 # devnet alias of the DB container
# Requires `devrouter tls install` (SNI is read from the TLS ClientHello). Connect
# with direct-SSL so the ClientHello carries SNI, e.g.:
# psql "host=db.<app>.localhost port=5432 sslmode=require sslnegotiation=direct ..."
# if kind=app and runtime=host (protocol must be http):
hostRun:
command: <string>
cwd: <string> # relative to repo root, must not escape it
portTimeout: 120 # seconds, optional
strategy:
type: auto
denyPorts: [80, 443, 5432]
allowPortRange: '1024-65535'
# if kind=app and runtime=docker:
docker:
service: <string>
internalPort: <number>
composeFiles: [<string>] # relative to repo root
router: <string> # optional
# if kind=app and protocol=tcp:
tcpProtocol: postgres # required; runtime must be docker OR proxy
# if kind=dependency:
runtime: docker
docker:
service: <string>
composeFiles: [<string>] # relative to repo root
Validation rules:
kind=app: host must end with .localhostkind=app: runtime=host supports protocol=http onlykind=app: runtime=proxy supports protocol=http or protocol=tcp, requires upstream (host:port), and forbids hostRun/docker/dependencies (it only registers a route to an externally-managed upstream). protocol=tcp additionally requires tcpProtocol and TLS (devrouter tls install)kind=app: protocol=tcp requires runtime=docker (devrouter-managed container) or runtime=proxy (externally-managed upstream), plus a supported tcpProtocol (postgres/redis/mariadb/mysql)kind=dependency: must use runtime=docker and does not allow routed fields (host/protocol/tcpProtocol/hostRun/docker.internalPort/docker.router)healthcheck. docker compose up --wait blocks until healthy; without one, wait returns immediately.POSTGRES_USER=prisma, POSTGRES_PASSWORD=prisma, POSTGRES_DB=prisma and create a shadow database. devrouter injects per-dep {PREFIX}_URL / {PREFIX}_SHADOW_URL with these credentials.docker compose down -v).Example healthcheck:
healthcheck:
test: ['CMD-SHELL', 'pg_isready -U prisma -d prisma']
interval: 5s
timeout: 3s
retries: 20
When a host app depends on a TCP Docker service, devrouter app run and devrouter app exec inject per-dep deterministic vars (where {PREFIX} = dep.name.toUpperCase().replace(/-/g, "_")):
| Variable | Value |
|---|---|
{PREFIX}_HOST | localhost |
{PREFIX}_PORT | random mapped port |
{PREFIX}_URL | protocol-specific URL (postgres, redis, mysql/mariadb) |
{PREFIX}_SHADOW_URL | postgres://prisma:prisma@localhost:<port>/shadow (postgres only) |
Host apps also receive PORT (random free port), HOSTNAME=0.0.0.0, HOST=0.0.0.0.
Config-level envMap on dependency references aliases per-dep vars to app-expected names (for example DATABASE_URL: DB_URL maps the per-dep DB_URL to DATABASE_URL).
Run several worktrees of one repo in parallel without host/route collisions. A workspace token spans the DevPod id, devrouter routes, ${WORKSPACE} proxy upstreams, and devcontainer aliases.
DEVROUTER_WORKSPACE may repeat the identity but cannot rename it. Ambiguous identities fail closed. The primary checkout remains non-namespaced.web.localhost → web.<ws>.localhost), ${WORKSPACE} in upstream is substituted with the token, and the docker router key is suffixed per workspace. The runtime config is computed in memory only — the committed .devrouter.yml is never rewritten.web.<ws>.localhost) are not covered by the *.localhost wildcard; devrouter auto-extends the mkcert cert SANs for active hosts when TLS is enabled.${localEnv:DEVCONTAINER_COMPOSE_OVERLAY:docker-compose.default.yml}; custom repositories may keep another default overlay. Selecting .devcontainer/docker-compose.devrouter.yml for linked worktrees must pass WORKSPACE and DEVROUTER_WORKSPACE across the combined base/overlay config and bind-mount ${DEVROUTER_GIT_COMMON_DIR} to the same absolute app-container path. The app exposes ${WORKSPACE}-app; the proxy uses upstream: ${WORKSPACE}-app:<port>.workspace up creates and starts a worktree; workspace ensure . starts/reconciles an existing linked worktree; workspace ls reports owner/Git/DevPod/route state; workspace stop stops DevPod/routes but keeps checkout, record, and data; full workspace down deletes runtime/routes and removes only a clean, unlocked worktree, then its record; down --keep-worktree keeps checkout and record. Dirty or locked full down fails before side effects.present, missing, locked, or conflict. workspace gc is a dry-run report; --yes deletes only exact ledger-owned missing/prunable resources and their records. GC never removes Git worktrees, branches, or prune state. Git has no worktree-removal hook..devrouter.yml folder without .git.secretManager.command in .devrouter.yml (include trailing --). devrouter wraps commands and re-injects dep env vars after the SM boundary.secretManager.defaultEnv: optional fallback environment for {env} template in command string.{env} template placeholder: secretManager.command: "infisical run --env {env} --" resolved at runtime. --env <env> CLI flag overrides defaultEnv.secretManager:
command: infisical run --env {env} --
defaultEnv: dev
envMap on dependency references to alias per-dep vars to app-expected names:
dependencies:
- app: db
envMap:
DATABASE_URL: DB_URL
DIRECT_URL: DB_URL
SHADOW_DATABASE_URL: DB_SHADOW_URL
infisical run or doppler run in sh -lc unless shell expansion is strictly required.devrouter app exec <app> --yes -- infisical run --projectId <id> --env=<env> -- pnpm payload migratedevrouter app exec <app> --yes -- printenv DB_URL DB_HOST DB_PORT DB_SHADOW_URLdevrouter app exec <app> --yes -- doppler run -- pnpm payload migratePROD_DATABASE_URL) and map intentionally via envMap.devrouter app exec --shell -- "<single command string>" only when shell expansion is required.envMap fails fast when source var is missing so migrations do not run with partial mapping..devrouter.yml metadata devrouter.version aligned with the currently applied devrouter release.devrouter -V (shows installed CLI version, local repo version, and next upgrade target).devrouter upgrade to list available upgrade targets and devrouter upgrade <version> to print that target's Agent Adaptation Prompt from upgrade-prompts/<version>.md.devrouter repo agents (or devrouter init --write-agents --write-skill).devrouter doctor --repo ., devrouter app ls --repo ., one representative devrouter app exec flow, and devrouter ls.devrouter init [--write-agents] [--write-skill]: print AI onboarding prompt (non-mutating by default)devrouter -V [--repo .]: show installed CLI version, local repo version, and next upgrade targetdevrouter upgrade [version] [--repo .]: list upgrade targets or print target Agent Adaptation Promptdevrouter setup --yes [--repo .] [--json]: first-run machine setup plus structured diagnosticsdevrouter up / devrouter down: start/stop shared Traefik routerdevrouter status: router/container/network/TLS healthdevrouter doctor [--repo .]: deep diagnostics (global + repo)devrouter ls: list active HTTP + TCP routesdevrouter open <name>: open HTTP route or print TCP connection hint (matches app name, then service/container/host identities)devrouter logs [-f]: Traefik access logsdevrouter tls install: install mkcert certs, enable HTTPS + TCP/SNIdevrouter repo init: create .devrouter.ymldevrouter repo inspect [--json]: inspect package, scripts, compose services, env names, devcontainer, devrouter config, and agent guidance for onboardingdevrouter repo devcontainer write --dry-run --json: plan conservative Node/pnpm/Postgres devcontainer/devrouter scaffold files without writingdevrouter repo devcontainer write --yes: write managed Node/pnpm/Postgres devcontainer/devrouter scaffold files when no custom-file conflicts existdevrouter repo devcontainer verify --json: emit read-only onboarding evidence for PRsdevrouter repo devcontainer verify --live --yes --json: register proxy routes and probe HTTP routes after the devcontainer is runningdevrouter repo agents: write devrouter section in AGENTS.md + install this skilldevrouter app add: add/update app entry in .devrouter.ymldevrouter app ls: list app entriesdevrouter app run <name> [--env <env>] [--workspace <slug>]: run app with dependency lifecycle (--env overrides SM defaultEnv; --workspace overrides the per-workspace token)devrouter app exec <name> [--shell] [--env <env>] [--workspace <slug>] -- <cmd>: one-shot command with resolved dep envdevrouter app rm <name> [--keep-config]: remove app entry (--keep-config frees only the live route/hostname, leaves .devrouter.yml untouched)devrouter workspace up <branch> [--path <dir>] [--no-devpod] [--open]: create a worktree and start/prove it unless create-only mode is requesteddevrouter workspace ensure [path] [--open]: start/reconcile and prove an existing linked worktree environmentdevrouter workspace ls [--json]: list ownership, Git, DevPod, route, path, and branch evidencedevrouter workspace stop <workspace|branch>: stop DevPod and routes; preserve checkout, owner record, and datadevrouter workspace down <workspace|branch> [--keep-worktree]: delete runtime/routes and optionally remove the clean worktree and recorddevrouter workspace gc [--json] [--yes]: report missing owners by default; apply exact eligible cleanup with --yesFor devcontainer onboarding:
devrouter setup --repo . --yes --jsondevrouter doctor --repo . --jsondevrouter repo inspect --repo . --jsondevrouter repo devcontainer write --repo . --dry-run --jsondevrouter repo devcontainer write --repo . --yesdevrouter repo devcontainer verify --repo . --jsondevrouter workspace ensure . (use devpod up . for a primary checkout)devrouter repo devcontainer verify --repo . --live --yes --jsonFor host/docker runtime apps only:
devrouter setup --repo . --yesdevrouter doctor --repo .devrouter app ls --repo .devrouter app run <host-app> --repo . --yesdevrouter lscurl -I https://<host>.localhostdevrouter open <name> for the connection hint.devrouter app run auto-starts Docker dependencies and waits for health. Host app runs stop auto-started docker deps on exit; docker app runs leave target services running until explicit cleanup.kind=dependency entries do not create routes and cannot be direct targets for devrouter app run, devrouter app exec, or devrouter open.kind=dependency services start as declared in compose (no Traefik label wiring, no random port publishing, no injected env vars).:5432 requires TLS/SNI (devrouter tls install). Standard app clients should use the injected random port instead.devrouter app exec follows the same dep lifecycle for one-shot commands and preserves argv semantics by default (shell: false).devrouter app exec --shell is explicit and requires exactly one command string after --.printenv DB_URL DB_HOST DB_PORT) before migrate/seed.