Sandboxes And Previews
Sandbox commands validate and start runtime environments for a workspace. Preview commands expose selected service ports through private tailnet URLs.
Sandbox Commands
x4 sandbox run "frontend, backend, and admin dashboard"
x4 sandbox up
x4 sandbox wait
x4 sandbox status
x4 sandbox logs
x4 sandbox down
x4 sandbox destroy
x4 sandbox clear
x4 sandbox run is the agentic, goal-first interface. It asks the X4 AI
harness to prepare a runnable profile for the current workspace goal, validates
the proposed registry profile, writes it, and then calls the same deterministic
x4 sandbox up runner.
If startup or readiness fails, sandbox run collects the failure message,
sandbox state, remote SSH logs, and Docker Compose logs when available. It then
starts another AI profile attempt with that feedback. The default limit is
three attempts; change it with --ai-attempts <count>. Each attempt writes a
separate harness run under .x4/ai/runs/, and failed sandbox state is cleaned
before the next attempt. The AI still cannot run arbitrary shell or change the
selected repo set; it can only propose a revised validated sandbox profile.
x4 sandbox run "frontend, backend, and admin dashboard" \
--repo-env-source web=/path/to/web/.env.test \
--repo-env-source api=/path/to/api/.env.test \
--ai-attempts 3
Use x4 sandbox up when you already know the profile and want a deterministic
scriptable command with no AI preparation.
Common startup:
x4 sandbox up \
--profile azure-remote \
--wait
azure-remote and env-file are metadata-only starter profiles unless the
registry adds services. They validate workspace/env wiring and write sandbox
metadata, but they do not start frontend, API, worker, database, or dashboard
servers.
For a user-ready sandbox, add a profile with
sandboxProfiles.<id>.services[], then run it on a host with Docker Compose:
x4 sandbox up \
--profile local-preview \
--repo-env-source app=/path/to/app/.env.test \
--repo-env-source api=/path/to/api/.env.test \
--filter-forbidden-env \
--serve-preview \
--preview-backend tailnet-proxy \
--wait
If the current host is a control server without Docker, run the same profile on a Docker-capable X4 worker/testbox instead:
x4 sandbox up \
--backend ssh \
--target x4-testbox-standard-1 \
--profile local-preview \
--serve-preview \
--preview-backend tailnet-proxy \
--wait
Inspect the running sandbox:
x4 sandbox status
x4 sandbox logs --tail 100
x4 sandbox status prints the profile, compose project, local service URLs,
private preview routes, runtime env file paths, and Docker Compose state. Secret
values are never printed. For service profiles, status also checks Docker for
X4-labeled containers before it reports a sandbox as running. If the workspace
state says running but the containers are gone or stopped, X4 marks the
sandbox and preview stopped and hides service and preview URLs from the normal
status output.
AI can draft the first service profile when the selected workspace repos do not have a deterministic setup yet. It does not select the repos; it infers startup commands, ports, routes, and dependencies for the repo set already in the workspace:
x4 ai sandbox-plan --entry "$PWD" --run
x4 ai sandbox-profile \
--entry "$PWD" \
--profile local-preview \
--ai-engine codex-sdk \
--write
x4 registry validate --registry ./registry/x4-pilot-registry.yaml
The model returns strict JSON for a registry profile. X4 validates the proposed repo ids, service ids, commands, ports, preview routes, and inline environment values before writing anything to the registry.
For the longer-term tool loop and Mastra harness boundary, see AI Harness.
For trial workflows and lower-level debugging, sandbox up also accepts an
experimental --ai flag. It is shorthand for generating and writing the
selected profile with x4 ai sandbox-profile --write, then continuing with
normal deterministic sandbox startup. x4 sandbox run is the preferred
human-facing wrapper around this shape:
x4 sandbox up \
--profile local-preview \
--ai \
--ai-engine codex-sdk \
--backend ssh \
--target x4-testbox-standard-1 \
--serve-preview \
--preview-backend tailnet-proxy \
--wait
--ai does not execute arbitrary AI output. AI output must still validate as a
registry sandbox profile before sandbox up runs. The AI goal, prompt,
response, validated proposal, and run state are written under
.x4/ai/runs/<run-id>/.
AI engines:
| Engine | Use |
|---|---|
codex-sdk | Preferred when the host is already authenticated with Codex/ChatGPT. No X4 API key is needed. |
direct-model | Uses the X4 configured OpenAI-compatible or Azure OpenAI chat-completions provider. |
--ai always initializes a Mastra Harness session with inspect,
propose-profile, and verify modes before running the selected engine.
For remote sandbox execution:
x4 sandbox up \
--backend ssh \
--target x4-testbox-standard-1 \
--profile local-preview \
--install eager \
--git-auth app
Clearing Running Sandboxes
Use destroy when you are cleaning the current workspace:
x4 sandbox destroy --force --prune-artifacts
Use clear when a Docker host or worker has leftover X4 sandbox containers from
multiple workspaces. Always inspect first:
x4 sandbox clear --all --dry-run
Then remove only X4-labeled sandbox resources on the current Docker host:
x4 sandbox clear --all --force
For a worker/testbox:
x4 sandbox clear \
--target x4-testbox-standard-1 \
--all \
--dry-run
x4 sandbox clear \
--target x4-testbox-standard-1 \
--all \
--force
Narrow the cleanup when needed:
x4 sandbox clear --all --repo-set x4-demo --dry-run
x4 sandbox clear --all --workspace-id x4-demo-app-npm-2026-06-17-259515 --force
sandbox clear removes Docker containers carrying X4 labels, their Compose
networks and volumes, and X4 tailnet preview proxy processes. It does not remove
repo worktrees. Use x4 cleanup --dry-run for workspace worktree cleanup.
After a forced clear, x4 sandbox status should report the affected workspace
as stopped rather than continuing to show live preview URLs.
Preview Commands
x4 preview up
x4 preview serve
x4 preview down
Tailnet preview:
x4 preview serve \
--host x4-devbox-main.tailbba365.ts.net \
--http-port 80
URL Safety Rule
X4 must not post these as tester-facing GitHub URLs:
localhost127.0.0.10.0.0.0- Docker-internal hostnames
- container-only URLs
- placeholder preview URLs
GitHub comments should include only recognized private tailnet URLs, such as
Tailscale 100.64.0.0/10 addresses or MagicDNS .ts.net hostnames. Backend
services should post health/API/log evidence instead of fake frontend previews.