[READ-ONLY] Mirror of https://github.com/sxzz/devbox. Declarative Docker setup for a paseo agent dev environment

README.md

devbox #

A declaratively maintained development environment for coding agents, built with Docker: a paseo daemon plus a shared Chromium, running on the local OrbStack.

  • The repo holds only declarations: the image, tool versions, agent config and compose file all live here. Changes take effect after scripts/rebuild.
  • State lives outside the repo: $DATA_DIR (default ~/app/paseo) holds credentials, the browser profile and, under paseo-home/workspace, the projects (/workspace inside the container is a symlink to ~/workspace). Rebuilds don't touch it.
  • Isolation: the container mounts only directories under $DATA_DIR. It does not mount ~/.ssh, ~/.config/gh or docker.sock. Other services may run on the same Docker daemon, so never give the container Docker access.

Layout #

Path Purpose
image/Dockerfile Based on the official paseo image (latest); installs the latest mise and apt packages
image/mise.toml Tool list: agent-browser, gh, gogcli, pnpm, claude-code, codex, pi, grok, playwright-mcp, all at latest
image/apt.txt Extra Debian packages
config/AGENTS.md Instructions for agents, synced on start to the global instruction files of claude, codex and pi, and to ~/.grok/rules/devbox.md for grok
config/mcp.json MCP servers, merged into mcpServers in ~/.claude/.claude.json and ~/.pi/agent/mcp.json
config/codex.toml Managed block written into ~/.codex/config.toml
config/grok.toml Overwrites ~/.grok/managed_config.toml, the layer below ~/.grok/config.toml; also turns off Grok's scan of ~/.claude
config/gitconfig Included from ~/.gitconfig: git defaults for agents and the gh credential helper
config/claude-settings.json Deep-merged into ~/.claude/settings.json; keys here override existing values
image/rootfs/usr/local/bin/devbox-activate Runs on every container start and syncs config/ into home
compose.yml Three services: tailscale (owns the network and is its own tailnet node), browser (Chromium) and paseo; the latter two share tailscale's network

Config falls into two kinds:

  • Files and blocks managed by config/ are overwritten on every start. Change them in the repo, not inside the container.
  • Everything else (login credentials, state agents write at runtime) is kept in $DATA_DIR/paseo-home.

Daily use #

scripts/rebuild           # build from the current tree, tag devbox:<commit>, then restart
scripts/rollback          # list existing tags
scripts/rollback <tag>    # switch back to an older image
scripts/shell             # open a shell in the container as the paseo user
scripts/shell gh auth status

Upgrading: the paseo base image, mise and everything in image/mise.toml track latest, so every scripts/rebuild pulls the newest base image and reinstalls the newest versions. If an upgrade breaks something, use scripts/rollback to return to an older image.

Access #

Service Address
paseo daemon 127.0.0.1:6767, or $TAILSCALE_IP:6767 over Tailscale; password is PASEO_PASSWORD. There is no bundled web UI; use the hosted app.paseo.sh, the desktop app or the mobile app
Dev servers http://devbox:<port> (MagicDNS) or the container's own tailnet IP, from any device in the tailnet. Servers must listen on 0.0.0.0, not just localhost
Browser desktop https://127.0.0.1:6901, self-signed certificate, username devbox, password is BROWSER_PASSWORD

app.paseo.sh, the mobile app and the desktop app can all connect directly with the address and password above (from inside the tailnet). For devices outside Tailscale, run scripts/shell paseo daemon pair to enable the relay, then paste the pairing link.

For everyday chats that don't involve code, use the /workspace/chat project (a plain directory, not a git repo).

First-time setup #

  1. cp .env.example .env, generate the two passwords and fill them in along with TAILSCALE_IP and TS_AUTHKEY (an auth key from the Tailscale admin console; the container joins the tailnet as devbox, and the login persists in $DATA_DIR/tailscale, so the key can be removed from .env afterwards), run chmod 600 .env, then run scripts/rebuild.
  2. Agent login (credentials are stored in $DATA_DIR/paseo-home): run scripts/shell, then claude, codex, pi and grok in turn.
  3. GitHub bot:
    • Register a bot account and add it as a collaborator with Write access to the target repos.
    • Fill in DEVBOX_GIT_NAME/DEVBOX_GIT_EMAIL in .env, then run scripts/rebuild.
    • Run scripts/shell gh auth login (with a fine-grained PAT). The credential helper is already set up by config/gitconfig; there's no need to run gh auth setup-git.
  4. Google (gogcli):
    • Fill in GOG_KEYRING_PASSWORD in .env (generate like the others), then run scripts/rebuild. Tokens go to gog's encrypted file keyring under $DATA_DIR/paseo-home.
    • In a Google Cloud project, enable the APIs you need, set the OAuth consent screen to External and publish it (Testing apps get refresh tokens that expire after 7 days), then create a Desktop app OAuth client and download its JSON.
    • Copy the JSON into the container's home, then run scripts/shell gog auth credentials ~/client_secret.json and scripts/shell gog auth add you@gmail.com --services gmail,calendar,drive --gmail-scope readonly --extra-scopes https://www.googleapis.com/auth/gmail.modify --manual. Open the printed URL in any browser, grant access, and paste the final redirect URL back. Check with scripts/shell gog auth doctor --check.
    • Gmail is draft-only for agents. The OAuth grant is gmail.modify without the settings scopes (no permanent delete, filters or forwarding), and /usr/local/lib/devbox/bin/gog shadows the real binary to block sending and trashing. Agents leave drafts; you send them from Gmail. The token itself can still send, so this guards against mistakes, not against an agent that bypasses gog.
  5. Browser: open the browser desktop and sign in to the sites you need by hand. Agents use the same browser session over CDP (127.0.0.1:9222): the agent-browser CLI is pointed at it through AGENT_BROWSER_CDP, and the playwright MCP is configured for claude, codex, pi and grok as a fallback.

Known limitations #

  • There is no Docker in the container; agents can't run docker.
  • The tailscale container needs /dev/net/tun and NET_ADMIN; restarting it also restarts browser and paseo's network, so run scripts/rebuild (or docker compose up -d) rather than restarting it alone.
  • paseo's built-in browser tools need a connected browser host (the desktop app). This deployment doesn't enable it; browser automation goes through agent-browser and the playwright MCP against the shared Chromium.

License #

MIT