> ## Documentation Index
> Fetch the complete documentation index at: https://docs.tuturuuu.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Remote Devboxes

> Run heavy Tuturuuu development workflows on containerized self-hosted remote runners.

## Overview

Remote devboxes let internal root workspace members offload expensive local work
to self-hosted runner machines. A runner connects outbound to `tuturuuu.com`,
receives a synced dirty checkout, runs commands in an isolated container, streams
logs, stores artifacts, and releases the lease automatically for one-off work.

V1 is intentionally self-hosted. It does not provision cloud machines. Any
runner host should have Node.js, Bun, Docker, and Git available.

## Quick Start

```bash theme={null}
ttr login
ttr box doctor
ttr box setup
ttr box setup --dir .
ttr box setup --dir . --clone-into ./tuturuuu
ttr box agent register --name "ci-lab-1"
ttr box agent start --token <runner-token>
ttr box repair --dir .
ttr box upgrade --runner <runner-id>
TUTURUUU_DEVBOX_RUNNER_TOKEN=<runner-token> ttr box shutdown
```

`ttr box setup` is the default bootstrap for a runner host. It first checks
whether the current directory is already a Tuturuuu platform checkout. If it is,
setup reuses that checkout. Otherwise it can clone or reuse
`https://github.com/tutur3u/platform.git`, install dependencies with
`bun install --frozen-lockfile`, start local Supabase with `bun sb:start`,
verify `supabase status -o json`, and write local Supabase connection values
into ignored `apps/*/.env.local` files. Secret values are redacted from human
and JSON output.

Pass `--dir <path>` for a specific checkout. If the target exists but is not a
valid Tuturuuu checkout, interactive setup asks whether it should clone into a
nested `tuturuuu` directory. In non-interactive shells, pass
`--clone-into <path>` explicitly:

```bash theme={null}
ttr box setup --dir . --clone-into ./tuturuuu
```

Use `--yes` only when the host should install detected missing prerequisites
automatically. Runner registration and service installation are separate
choices.

To register the machine and install a boot-starting runner service in one
non-interactive command after login:

```bash theme={null}
ttr box setup --agent --service --runner-name "$(hostname)-devbox" --yes
```

The setup command stores the runner token in a restricted local env file and
installs a system-level runner service on Linux systemd or macOS launchd. The
service starts after reboot and restarts automatically if the runner exits.
Runner heartbeats report a small observability snapshot, including `ttr`, Bun,
Node, Docker, Git, OS, CPU, RAM, load average, and uptime. Root workspace admins
can inspect those fields from Infrastructure > Devboxes.

Devbox agent poll and heartbeat traffic is blocked by default at the platform
API boundary. Set `TUTURUUU_DEVBOX_AGENT_API_ENABLED=true` on the web app before
starting or repairing runners. When the flag is absent, agent poll and heartbeat
requests return `403` before runner tokens are authenticated or runner state is
updated.

If a host completed `ttr box setup` but does not appear in Infrastructure >
Devboxes, confirm it was registered as a runner. Plain setup prepares the
checkout, dependencies, local Supabase, and ignored env files only; it does not
create a `private.devbox_runners` row. Run setup with `--agent --service`, or
register and start the agent manually, then confirm `ttr whoami` on that host is
pointing at the same production origin and root workspace user.

If the host appears as registered but shows no heartbeat, inspect the installed
service on that host:

```bash theme={null}
sudo systemctl status --no-pager --full tuturuuu-devbox-runner.service
sudo journalctl -u tuturuuu-devbox-runner.service -n 80 --no-pager
```

The runner service reads its token from the local `devbox-runner.env` file. If
the journal shows a missing runner token or stale wrapper, upgrade the CLI and
repair the service. Repair reuses the existing token file; it does not register
a new runner token or create another runner row.

```bash theme={null}
ttr upgrade
ttr box repair --dir .
```

Use dry-run first when you want to confirm the checkout, token file, service
manager, wrapper path, and service path without writing files or calling sudo:

```bash theme={null}
ttr box repair --dir . --dry-run
```

Upgrade a runner's global CLI through the same brokered queue:

```bash theme={null}
ttr box upgrade --runner <runner-id>
```

The upgrade command queues `bun i -g tuturuuu` for the selected runner, waits
for completion, and returns the remote command logs and exit code.

Remove a runner from the cluster from the runner host with its runner token:

```bash theme={null}
TUTURUUU_DEVBOX_RUNNER_TOKEN=<runner-token> ttr box shutdown
```

Shutdown deletes the runner's server-side token rows and marks the runner
revoked. If the host installed a systemd or launchd runner service, stop and
disable that service as well so the OS does not keep restarting an invalid
agent process.

Run heavy commands remotely:

```bash theme={null}
ttr box run -- bun check
ttr box run -- bun sb:reset
ttr box run -- bun test:e2e
ttr box build --cwd apps/web
```

By default, `ttr box run` creates an auto lease, waits for an authenticated
runner to claim the job, streams recorded logs after completion, and releases
the lease after one-off work. Use `--keep` for repeated sync/run work:

```bash theme={null}
ttr box run --keep --preview-port 7803 -- bun test:e2e
ttr box sync --lease <lease-id> --watch
ttr box preview --lease <lease-id> --port 7803
ttr box release <lease-id>
```

## Build, Serve, And Tunnel

Use `ttr box build` for common build workloads without spelling the full remote
command every time:

```bash theme={null}
ttr box build
ttr box build --cwd apps/web
ttr box build --build-command "bun turbo:local run build -F @tuturuuu/web"
```

Use `ttr box serve` when the remote devbox should build an app, start the
server, and keep the run alive. It defaults to `apps/web` on port `7803`, stores
the preview port on the run, and returns immediately unless `--wait` is passed:

```bash theme={null}
ttr box serve --cwd apps/web --port 7803
ttr box preview --lease <lease-id> --port 7803
ttr box logs <run-id>
ttr box stop <run-id>
```

`ttr box build`, `ttr box serve`, and `ttr box tunnel` do not set a remote
command timeout by default. Pass `--timeout <duration>` only when the run should
be killed automatically.

To expose a served app through a Cloudflare tunnel, keep the token in a local
environment variable and pass the variable name to the devbox. The queued
command references `$CLOUDFLARED_TOKEN`; the raw token is delivered only as
run-scoped env and is redacted from logs.

```bash theme={null}
export CLOUDFLARED_TOKEN=<token-from-cloudflare>
ttr box serve --cloudflared --cloudflared-token-env CLOUDFLARED_TOKEN
ttr box tunnel --cloudflared-token-env CLOUDFLARED_TOKEN
```

`ttr box tunnel` runs a dockerized `cloudflare/cloudflared` container with host
networking on the runner. The command policy blocks inline `cloudflared --token ...` arguments, so operators should use `--cloudflared-token-env` or
another local environment variable indirection rather than pasting raw tokens
into commands.

## Container Boundary

Commands run in a per-lease Docker container or Compose project. The runner
mounts only the synced workspace and named cache volumes. Host execution is not
exposed in v1, and arbitrary host path mounts are blocked unless an operator
explicitly allowlists them.

Allowed remote workflows include:

* `bun check`, `bun test`, and package-local Bun commands
* `bun test:e2e` and Docker-backed Playwright workflows
* `bun sb:start`, `bun sb:reset`, `bun sb:up`, and `bun sb:typegen`

Blocked defaults include privileged Docker containers, Docker prune-all style
commands, absolute host mounts, `sudo`, and host-destructive filesystem
operations.

## Env And Secrets

Remote env is explicit. Local `.env*` files are never synced automatically.
The setup command only prepares ignored app env files inside the runner
checkout so local Supabase-backed apps and E2E workflows can use that runner's
own Supabase stack.

```bash theme={null}
ttr box run --env DATABASE_URL=postgres://remote -- bun check
ttr box run --database-url-env DEVBOX_DATABASE_URL -- bun check
ttr box serve --database-url-env DEVBOX_DATABASE_URL
ttr box run --env-file .env.remote -- bun test:e2e
ttr box env set --lease <lease-id> API_TOKEN=value
ttr box env unset --lease <lease-id> API_TOKEN
```

Brokered env values are scoped to the run or lease, delivered only to the
claimed runner, and redacted from command logs.

For split-resource development, run Supabase or another database on one devbox,
publish its reachable URL as `DEVBOX_DATABASE_URL` on the operator machine, and
queue the app devbox with `--database-url-env DEVBOX_DATABASE_URL`. This lets a
database-heavy runner and a Next.js runner share work while the current machine
only brokers commands and opens previews.

## Cache Policy

Runners use named cache volumes for Bun installs, Turbo, Playwright browsers,
Supabase Docker state, package manager cache, and optional `node_modules`.
Cache keys include the repo fingerprint, lockfile hash, runtime image digest,
platform, command profile, Bun/Node versions, and cache schema version.

Cleanup runs on runner startup, after runs, and during heartbeat maintenance.
The runner evicts incompatible caches first, including legacy Bun install caches
when the Bun version, lockfile hash, package profile, or cache schema changes.
It then enforces cache budgets with least-recently-used eviction while keeping a
small set of recent compatible caches to avoid thrashing.

Operators can inspect and prune cache metadata:

```bash theme={null}
ttr box cache list
ttr box cache doctor
ttr box cache prune
```

## Access

Remote devbox API routes require a Tuturuuu CLI/app session and root workspace
membership with `workspace_members.type = 'MEMBER'`. Guests and non-root
workspace users cannot create runs, leases, previews, or runner tokens.

## Local Executable Verification

Use an isolated CLI config when testing local `apps/web` so the production CLI
session is not overwritten:

```bash theme={null}
bun sb:status
docker exec supabase_db_tuturuuu psql -U postgres -d postgres -tAc "select to_regclass('private.devbox_leases'), exists (select 1 from supabase_migrations.schema_migrations where version = '20260603171600')"
TUTURUUU_CONFIG=/tmp/ttr-devbox-local-config.json bun ttr login --base-url http://localhost:7803
TUTURUUU_CONFIG=/tmp/ttr-devbox-local-config.json bun ttr box agent register --name local-devbox
TUTURUUU_CONFIG=/tmp/ttr-devbox-local-config.json bun ttr box agent start --token <runner-token>
TUTURUUU_CONFIG=/tmp/ttr-devbox-local-config.json bun ttr box run -- bun --version
```

The final command should print the remote command logs and exit with the remote
command's exit code. In local Supabase, `private.devbox_runs.status` should end
as `succeeded` with `exit_code = 0`.

## Production Readiness

The production API needs migration
`20260603171600_create_private_devboxes.sql` before any `ttr box` command can
create leases or runs. If the CLI prints a schema-cache error such as
`private.devbox_leases` not being found, first confirm the production migration
workflow ran for the deployed SHA. If the table exists but PostgREST still
returns the schema-cache error, refresh the schema cache from Supabase SQL
Editor:

```sql theme={null}
select to_regclass('private.devbox_leases');
select version from supabase_migrations.schema_migrations
where version = '20260603171600';
notify pgrst, 'reload schema';
```
