Skip to content

remote agents

Remote agent environments — Claude Code on the web, Codex cloud, CI runners, devcontainers — start from a fresh, ephemeral machine on every session. Nothing interactive survives between runs, so Mossbear is set up from the environment’s startup or setup script instead of by hand.

Both recipes below need one thing from the dashboard: a CLI token, from Settings → Developer → CLI Token. Mint it on the same dashboard the container will talk to — staging and production have separate databases, so a production token is not valid on staging.

Pick your provider. The two differ in where the setup script lives, how credentials are stored, and what the container is allowed to reach on the network — so each recipe stands on its own rather than sending you between tabs.

Claude Code on the web runs each session on a fresh Anthropic-managed VM with your repo already cloned. One environment dialog holds everything Mossbear needs, and the steps below follow it top to bottom — the hosts the container may reach, the variables the CLI reads, then the script that installs it.

At claude.ai/code, select the cloud icon showing the current environment’s name to open the selector, then choose Add environment — or hover an existing environment and click the settings icon on the right. The dialog that opens holds every field in the steps below: name, network access, environment variables, and setup script.

Network access is the first field under the name, and it is the one people skip. The default Trusted level allows npm, so the install succeeds and the sync is what fails later — a failure that looks like a bad token. Select Custom, then add one host per line under Allowed domains:

app.mossbear.io

Add staging.mossbear.io too if you point sessions at staging. That is the whole list: the CLI talks to your dashboard and nothing else, and grading runs there rather than from this machine, so no LLM provider host is involved. These are domains, not URLs, and * works as a wildcard.

3. add your token as an environment variable

Section titled “3. add your token as an environment variable”

Paste this into Environment variables, the next field down. It takes .env format — one KEY=value per line, and no quotes around values, since quotes are stored as part of the value:

Terminal window
MOSSBEAR_TOKEN=your-cli-token
MOSSBEAR_DASHBOARD_URL=https://app.mossbear.io

Only the token is required. MOSSBEAR_DASHBOARD_URL defaults to https://app.mossbear.io, so set it only to point the container somewhere else.

The last field in the dialog. Setup scripts run as root on Ubuntu 24.04 before Claude Code launches, and their filesystem is cached and reused by later sessions. Four lines:

#!/bin/bash
npm install -g mossbear
mossbear init --no-prompt --dashboard-url "${MOSSBEAR_DASHBOARD_URL:-https://app.mossbear.io}" || true
mossbear sync || true
mossbear doctor || true

mossbear init registers the hooks and installs the mossbear-hook binary’s wiring, also migrating any .claude/settings.json still naming the logger by an absolute path from another machine. Passing –dashboard-url explicitly matters even when it is the default: a cached filesystem can carry a dashboardUrl from an earlier build, and config outranks the CLI’s baked-in default.

5. commit the hooks, and check the sync one is there

Section titled “5. commit the hooks, and check the sync one is there”

The container is destroyed when the session ends, and anything still on disk inside it goes with it — which is why mossbear init writes a Stop hook that pushes the session before that happens. Step 4 has already put it in your repo’s .claude/settings.json:

{
"hooks": {
"Stop": [
{
"hooks": [{ "type": "command", "command": "mossbear sync", "timeout": 180 }]
}
]
}
}

Commit that file. It lives in the repo rather than in the environment, so the same hooks fire on your own machine, and a session resumed from the cached filesystem still has them.

Track the whole file, every hook in it. Everything mossbear init writes there is machine-independent: the logger runs as the bare command mossbear-hook, resolved from your PATH, so the file is byte-identical on your laptop and in the container and stays that way.

6. keep the CLI current in resumed sessions

Section titled “6. keep the CLI current in resumed sessions”

The setup script installs Mossbear once per environment, not once per session. Its filesystem is snapshotted and reused, and a resumed session never re-runs it — so the version installed on the day you built the environment is the version every later session gets, however many releases have shipped since. A SessionStart hook is the part that runs every time, because it lives in your repo rather than in the environment. Add it to the same file as step 5:

{
"hooks": {
"SessionStart": [
{
"matcher": "startup|resume",
"hooks": [
{
"type": "command",
"command": "[ \"$CLAUDE_CODE_REMOTE\" = true ] && mossbear update --yes || true",
"timeout": 600
}
]
}
],
"Stop": [
{
"hooks": [{ "type": "command", "command": "mossbear sync", "timeout": 180 }]
}
]
}
}

mossbear update compares against the dist-tag matching the version you are running, so a prerelease container stays on its own channel, and it installs only a strictly newer release — a private or lagging npm mirror cannot walk it backwards. It also restamps the generated hook script, which a plain npm install leaves running the previous version’s code.

The setup script’s output appears in the session log, and mossbear doctor is the part to read. All checks passed plus a healthy dashboard line means the loop is connected. If the connection line reports the dashboard as refused by something between your machine and it — explicitly not a rejected token — step 2 is the fix.

  • –no-prompt — skip all interactive questions.
  • –dashboard-url — point the CLI at a different dashboard instance.
  • –no-skill / –no-eval-hook — skip installing the Claude Code skill or the session-end evaluation hook if the environment doesn’t need them.
  • –force — overwrite config left over from a previous image layer.

Init needs no token — everything it does is local. To sync verdicts, store a CLI token as a secret in your environment’s variables rather than committing it. The CLI reads both of these directly, so no command in either recipe needs a flag:

Terminal window
MOSSBEAR_TOKEN=... # CLI token — required to sync
MOSSBEAR_DASHBOARD_URL=https://app.mossbear.io # optional — override the dashboard

A token from the environment is never written to ~/.mossbear/config.json — the environment owns the credential, so revoking it there ends access everywhere it was used. A –token flag still takes precedence and is still remembered after a successful sync; an explicit –dashboard-url likewise overrides the variable.

Many cloud environments route outbound traffic through a proxy that only allows approved hosts, and a blocked host is refused with a 403. Package registries are usually allowed by default, so the install succeeds and the sync is what fails. mossbear doctor tells these apart: a blocked host is reported as refused by something between your machine and the dashboard, explicitly not a rejected token. When you see that, allow these hosts in your environment’s network settings:

  • your dashboard host — sync, guide pull, and the doctor connection check.
  • your eval provider host — only for LLM-graded checks. Pattern-matched checks need no network at all.

Hooks log actions and queue verdicts locally under ~/.mossbear/ inside the container. They reach your dashboard when mossbear sync runs — at session end via a Stop hook, or explicitly as a step in your script. Verdicts that cannot be sent stay queued and go out on the next successful sync:

Terminal window
mossbear sync

Pattern-matched checks run with no API key at all. For LLM-graded checks the CLI calls your configured provider, which in remote environments is easiest to configure through environment variables:

Terminal window
MOSSBEAR_EVAL_PROVIDER=anthropic # openrouter | anthropic | openai-compatible | google | ollama
MOSSBEAR_EVAL_MODEL=claude-sonnet-4-6
ANTHROPIC_API_KEY=sk-ant-... # or the matching provider key

MOSSBEAR_EVAL_API_KEY and MOSSBEAR_EVAL_BASE_URL override the provider-specific variables when set. Provider calls send action metadata and guide text only — never file contents or transcripts.

New to Mossbear? Start with getting started for the basics.