Bifrost debug
Boot an isolated, hot-reload Bifrost dev stack for the current worktree via ./debug.sh. Use when the user wants to click around the UI, view a feature in the browser, screenshot something, or otherwise needs the dev stack running. Per-worktree isolation lets multiple worktrees run dev stacks in parallel. Trigger phrases - "open the app", "let me click around", "spin up debug", "test in the browser", "show me the UI", "/bifrost-debug".From its SKILL.md
npx -y skills add gobifrost/bifrost --skill bifrost-debugAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
SKILL.md
9.0 KB, as published. Nobody here has run it
Bifrost Debug
Bring up a per-worktree, hot-reload Bifrost dev stack via ./debug.sh. Hand the user the URL. Don't restart containers for code changes (hot reload handles it).
When to activate
- User wants to click around the UI: "open the app", "let me try this in the browser", "show me the form", "I want to test this".
- User wants screenshots of a feature.
- User explicitly invokes
/bifrost-debug. - Before manually verifying a UI change at the end of a feature (per
bifrost-testingDefinition of Done).
Do not activate for backend-only work that can be verified via tests, type generation, or curl against a running stack.
Two boot modes (auto-detected)
./debug.sh picks the mode based on whether NETBIRD_SETUP_KEY is available in the env (process env, or ~/.config/bifrost/debug.env):
- Mode A — netbird: key present. The peer joins the private NetBird mesh and creates an ephemeral public HTTPS URL with
netbird expose. No host ports, durable Admin proxy mappings, or NetBird API key are required../debug.sh statusreports both URLs. - Mode B — port: no key. Client exposed on a deterministic free host port (30000–39999, hashed from worktree path). Reachable at
http://localhost:<port>. Default for most local development.
The user picks the mode by setting (or not setting) NETBIRD_SETUP_KEY in ~/.config/bifrost/debug.env. Don't try to switch modes for them.
Mode A stores a strong generated admin password per worktree under the user's local state directory and reports it from ./debug.sh status. Never replace it with the shared password development credential while public exposure is active.
Optional in Mode A: NETBIRD_EXTRA_DNS_LABELS in ~/.config/bifrost/debug.env adds private-mesh DNS aliases for the peer (comma-separated, e.g. bifrost,debug-current → bifrost.netbird.cloud, debug-current.netbird.cloud). Wildcards work (*.myserver). Don't set this for the user — they manage it themselves.
The basic flow
-
Check status first. Don't re-boot if already up.
./debug.sh statusIf the output shows
Status: UP, parse theOpen:line and hand the URL straight to the user. Stop. -
If down, boot it (backgrounded).
./debug.sh uprunsdocker compose up -d --buildand then waits up to 180s for the API health check. First boot can take 1-3 minutes for the image build, so use a background shell:# Bash(run_in_background=true) ./debug.sh upTail the background output with BashOutput until you see one of:
Open: http://...— success. Hand the URL to the user.ERROR: api did not become ready— failure. Run./debug.sh logs apiand report what's wrong.
-
Tell the user the credentials. Login is
[email protected]/password. MFA is off. No setup wizard. Mention this once with the URL. -
Point at logs if they ask.
./debug.sh logs <service>— services includeapi,client,worker,scheduler,postgres,rabbitmq,redis,minio.
Connect the CLI
Bifrost can keep credentials for several instances. Only .env in the exact
invocation directory selects the URL for commands run there; ancestor dotenv
files are never discovered implicitly. Credentials remain in the global store
keyed by URL. Otherwise the CLI uses the user's saved default. Debug should use
its own scratch-directory selector and must not change that saved default.
After the stack is up, create one scratch directory for this worktree. Never
run debug CLI commands from bare /tmp.
mkdir -p /tmp/bifrost-cli-<worktree-name>
cd /tmp/bifrost-cli-<worktree-name>
touch .env
python3 -m venv .venv
./.venv/bin/pip install --quiet --upgrade pip
./.venv/bin/pip install --quiet "<URL_FROM_DEBUG_STATUS>/api/cli/download"
./.venv/bin/bifrost login --url <URL_FROM_DEBUG_STATUS> \
--email [email protected] --password password
The scratch directory's own .env is the only local selector the CLI reads;
ancestor dotenv files are ignored. Login writes only this debug stack's URL
there and stores its credentials globally under that URL. Run all later
debug-instance CLI commands from the same scratch directory with
./.venv/bin/bifrost ....
Run ./debug.sh commands from the worktree, never from the scratch directory.
If the connection is ever unclear, bifrost auth default is a read-only check:
the Current connection line is what commands in that folder will use.
When explicitly tearing down the stack, clear its folder binding before or
after ./debug.sh down:
cd /tmp/bifrost-cli-<worktree-name>
./.venv/bin/bifrost logout --url <URL_FROM_DEBUG_STATUS> --yes
Lifecycle: who tears down what
- The stack outlives this Claude session. Closing or clearing the session does NOT tear it down. This is intentional — the user might come back, or have another Claude session attach to the same stack.
- To tear down explicitly:
./debug.sh down. This removes containers and volumes (postgres data is lost — fine for a debug stack; not fine for the prod stack). - If the user says "stop the debug stack" or "wipe the debug data," run
./debug.sh down. - If a second Claude session or a new conversation comes up while the stack is already running, that's fine —
./debug.sh statuswill reveal it. Don't call./debug.sh upredundantly; just hand over the URL fromstatus.
Hot reload — don't restart for code changes
Same rule as the dev stack always had:
- API, scheduler, worker:
watchmedo/ uvicorn--reloadwatches/app/srcand/app/shared. Saves cause an automatic restart. - Client: Vite HMR. Browser updates instantly.
Never run docker compose restart api (or any service) just because you edited Python. Restart only when:
- New Python dependency in
pyproject.toml(then rebuild:docker compose -f docker-compose.debug.yml up -d --build api). - New alembic migration (then
docker compose -f docker-compose.debug.yml restart initto apply, thenrestart api).
Set the user's expectation: "your edit will be live in a few seconds, no restart."
Multi-worktree
Two worktrees can run debug stacks in parallel. They get different Compose project names (bifrost-debug-<hash>), separate volumes, separate ports. To list all running debug stacks:
docker ps --filter "name=bifrost-debug-" --format "{{.Names}}"
Group by project name to find each worktree's URL: cd <worktree> && ./debug.sh status.
Common failures
API won't come up:
./debug.sh logs init— migrations failing? Comparegit log origin/main -- api/alembic/versions/against the worktree../debug.sh logs api— usually a config / import error. The traceback is usually in the first 30 lines of output after the start banner.
Login still shows the setup wizard:
- The seed-user provisioning runs on every API boot. If the wizard appears, the seed env vars probably aren't loaded — check
docker compose -f docker-compose.debug.yml exec api env | grep BIFROST_DEFAULT_USER. If empty,.env.debugisn't being sourced; investigateload_env_filesindebug.sh. - "User already exists" on the wizard: a previous (broken) seed user lingers without an org. Run
./debug.sh down(wipes the DB volume) and./debug.sh upagain.
Mode A can't be reached at the public URL:
- Run
./debug.sh status. If it only shows the private URL, inspect./debug.sh logs netbirdfor Peer Expose permissions or certificate provisioning errors. - Confirm Peer Expose is enabled for the setup key's peer group under NetBird Settings → Clients.
- The public service is ephemeral. Restarting the NetBird container issues a new URL;
debug.shapplies it toBIFROST_PUBLIC_URLautomatically.
Mode A can't be reached at the private hostname:
- DNS propagation in Netbird takes a few seconds after first peer enrollment. Wait 30s and retry.
- Confirm the peer is registered:
docker compose -f docker-compose.debug.yml logs netbird | tail -20. Look forPeer registration completed.
Mode B port not reachable:
./debug.sh statusre-reads the published port fromdocker port. IfOpen:shows nothing, the client container didn't start —./debug.sh logs client.
What this skill does NOT do
- Doesn't manage NetBird account settings. Peer Expose must already be enabled for the debug peer group.
- Doesn't set up
~/.config/bifrost/debug.env— point the user at it, don't write keys there for them. - Doesn't run tests. That's the
bifrost-testingskill's job. - Doesn't reset DB state.
./debug.sh downwipes the volume; there's no fast in-place reset (unlike./test.sh stack reset).