X4 Onboarding Guide
This is the practical guide for onboarding a developer or repo owner into X4 so they can use it with the repos they are actively working in.
X4 is a CLI-first framework for turning normal Git repos into one coordinated
multi-repo workspace. Editors, Codex, Cursor, VS Code, GitHub automation, and
remote workers are adapters over the same CLI and generated .x4/ metadata.
Start Here: Open A Workspace In Cursor
Use this path when you know nothing about X4 and only want to open the right multi-repo workspace in Cursor.
What You Need Before Running X4
You need three inputs:
| Input | Who creates it | What it does |
|---|---|---|
| X4 CLI | Developer or devbox installer | Provides the x4 command. |
| Base repo clones | Developer | Normal Git checkouts of each repo, usually under ~/dev/repos/. |
| X4 registry YAML | Repo owner, platform owner, or onboarding developer | Tells X4 which repos belong together and what commands to run. |
The registry is not generated by x4 workspace bootstrap. It is an input file
that you create once per repo set or get from your team. X4 can generate a
starter registry with x4 registry init, but you should still review it because
setup commands, test commands, env policy, and sandbox profiles are repo-owned
decisions. X4 reads that registry and then generates the per-workspace .x4/
files.
What X4 generates during bootstrap:
<entry-repo>/
.x4/
context.md
commands.md
agent-instructions.md
workspace.yaml
workspace.lock.yaml
x4-workspace.code-workspace
repos/<attached-repo>/
Cursor opens the generated file:
.x4/x4-workspace.code-workspace
Cursor Quickstart
Replace current-work, repo URLs, and paths with the actual repos you want to
use together.
- Install X4:
git clone https://github.com/Machenta/x4.git ~/.local/share/x4
cd ~/.local/share/x4
pnpm install --frozen-lockfile
pnpm build
mkdir -p ~/.local/bin
ln -sfn ~/.local/share/x4/dist/cli.js ~/.local/bin/x4
export PATH="$HOME/.local/bin:$PATH"
x4 --version
- Clone the base repos:
mkdir -p ~/dev/repos
git clone git@github.com:Example/app.git ~/dev/repos/app
git clone git@github.com:Example/api.git ~/dev/repos/api
- Generate or obtain the registry file:
mkdir -p ~/dev/x4
x4 registry init \
--repo ~/dev/repos/app \
--repo ~/dev/repos/api \
--repo-set current-work \
--output ~/dev/x4/current-work.registry.yaml \
--install skip
export X4_REGISTRY_PATH="$HOME/dev/x4/current-work.registry.yaml"
export X4_REPO_SET="current-work"
Open the generated file and review it. Use the registry example in Generate Or Create The Registry if you need to understand or edit the generated fields.
- Validate the registry:
x4 registry validate --registry "$X4_REGISTRY_PATH"
- Bootstrap the workspace from one repo:
cd ~/dev/repos/app
x4 workspace bootstrap \
--entry "$PWD" \
--repo-set "$X4_REPO_SET" \
--feature first-x4-workspace \
--install skip \
--sandbox-profile azure-remote \
--registry "$X4_REGISTRY_PATH"
Use --install eager instead of --install skip once the registry setup
commands are known to work.
- Open the generated workspace in Cursor:
cursor .x4/x4-workspace.code-workspace
If you are already inside Cursor, choose File -> Open Workspace from File and
select .x4/x4-workspace.code-workspace.
- Confirm it worked:
x4 status
x4 test --dry-run
You are ready to work when x4 status lists every repo in the repo set and the
same feature branch is checked out in each one.
What X4 Adds
X4 is useful when a task crosses repo boundaries, needs repeatable setup/test commands, or needs validation evidence that can be posted back to PRs and issues.
The core value is:
- one feature branch shared across all repos in a repo set;
- attached worktrees created under
.x4/repos/; - generated agent/editor context under
.x4/; - repo-specific setup and test commands from one registry;
- split commits and split PRs per repo;
- sandbox, preview, remote validation, and evidence commands that all read the same workspace state;
- cleanup that knows which worktrees, sandboxes, previews, and artifacts X4 created.
X4 does not replace Git, package managers, CI, GitHub permissions, or secret management. It coordinates them.
Essential Pieces
1. The X4 CLI
Everything starts with the installed x4 command. Install it from the private
X4 repo:
git clone https://github.com/Machenta/x4.git ~/.local/share/x4
cd ~/.local/share/x4
pnpm install --frozen-lockfile
pnpm build
mkdir -p ~/.local/bin
ln -sfn ~/.local/share/x4/dist/cli.js ~/.local/bin/x4
x4 --version
x4 doctor host
Developer devboxes should also pass:
x4 doctor devbox
See docs/install.md for the full install/update flow.
2. A Registry For The Repos
The registry is the contract between X4 and the repos. It tells X4:
- which repos belong together;
- how to detect each repo by Git remote;
- where the stable base clone lives;
- which branch template to use;
- which setup and test commands are valid;
- which env files may be copied from the base clone;
- which sandbox profile to use;
- which worker-local env bundle to use for remote tests/previews.
X4 can create a conservative first draft, but it should not silently guess the whole contract from GitHub or the filesystem. The registry contains policy choices: which repos belong together, which commands count as setup/test, which env files may be copied, and which credentials are forbidden.
Use x4 registry init to create the first draft from local checkouts:
x4 registry init \
--repo ~/dev/repos/app \
--repo ~/dev/repos/api \
--repo-set current-work \
--output ~/dev/x4/current-work.registry.yaml \
--install skip
The generated registry is intentionally conservative. It infers repo ids,
Git remotes, default branches, package-manager setup commands, basic test
commands, env allowlists, an env bundle placeholder, and a metadata-only
azure-remote sandbox profile. Review it before team use.
For the parts that are not reliably deterministic, use the AI setup assistant:
x4 ai doctor
x4 ai sandbox-plan --entry /path/to/workspace --run
x4 ai sandbox-profile --entry /path/to/workspace --profile local-preview
This writes:
.x4/ai/sandbox-setup-prompt.md
.x4/ai/sandbox-setup-response.md
.x4/ai/local-preview-sandbox-profile-prompt.md
.x4/ai/local-preview-sandbox-profile.json
The prompt includes repo structure, package scripts, dependency names, current
registry YAML, README/setup snippets, small contract/job/spec snippets, and env
key names only. It deliberately does not include .env values. Treat the AI
response and profile JSON as drafts. The repo set is still selected by you and
the registry; AI only helps infer server commands, ports, routes, env keys, and
service dependencies for those selected repos. Then write the reviewed profile
into the registry, validate it, and run X4 deterministically:
x4 ai sandbox-profile --entry /path/to/workspace --profile local-preview --write
x4 registry validate --registry /path/to/workspace/registry/x4-pilot-registry.yaml
x4 sandbox up \
--entry /path/to/workspace \
--profile local-preview \
--serve-preview \
--preview-backend tailnet-proxy \
--wait
The AI setup assistant is useful for drafting preview commands, ports,
service relationships, health paths, and sandboxProfiles for the repos already
in the workspace. It should not decide which repos are part of the repo set.
x4 sandbox up still runs only the reviewed registry.
Default registry lookup order:
X4_REGISTRY_PATH
./registry/x4-pilot-registry.yaml
/home/dev/work/setup/registry/x4-pilot-registry.yaml
handoff fallback path
For custom repo sets, prefer setting X4_REGISTRY_PATH explicitly or passing
--registry /path/to/registry.yaml during bootstrap. After bootstrap, X4 records
the registry path in .x4/workspace.yaml, so workspace commands keep using the
same registry.
If the registry is shared by a team, keep it in a stable setup repo or checked
into the X4 repo. If it is local to one developer, put it somewhere explicit
such as ~/dev/x4/current-work.registry.yaml and export X4_REGISTRY_PATH.
3. Stable Base Clones
Every repo in the repo set needs a normal base checkout. The registry field
localMainPath points at that checkout.
Example:
~/dev/repos/app
~/dev/repos/api
X4 creates feature worktrees from those base clones. The entry repo can be any repo in the repo set.
4. Generated .x4/ Workspace State
Bootstrap writes:
.x4/context.md
.x4/commands.md
.x4/agent-instructions.md
.x4/workspace.yaml
.x4/workspace.lock.yaml
.x4/x4-workspace.code-workspace
.x4/repos/<attached-repo>
.x4/workspace.yaml is machine-readable source of truth.
.x4/context.md and .x4/agent-instructions.md are for humans and agents.
.x4/x4-workspace.code-workspace opens the generated multi-root workspace in
VS Code or Cursor.
Generated .x4/ files are intentionally untracked. X4 adds .x4/ to local
.git/info/exclude instead of editing the repo's tracked .gitignore.
See Paths And State for the full .x4/
folder contents, runtime state, and sandbox cleanup commands.
5. Environment Contract
X4 does not own secret values. It validates and injects env files by key name.
For local devbox work, repos can keep using existing local .env files. For
remote workers, use worker-local non-production bundles such as:
/etc/x4/env/<repo-set>.env
The registry controls required keys, optional keys, forbidden patterns, and whether a missing bundle is allowed. X4 should never print secret values.
Key commands:
x4 env doctor --entry "$PWD"
x4 env doctor --bundle <bundle-id>
x4 env install-bundle \
--bundle <bundle-id> \
--source /path/to/non-production.env \
--target x4-testbox-standard-1 \
--filter-forbidden
See docs/env-contract.md for the full contract.
Host Dependencies
Minimum local development dependencies:
- Git access to every repo in the repo set;
- Node 22+ for the X4 CLI;
- Corepack and pnpm for installing/building X4;
- whatever package managers each repo's setup/test commands require, such as
pnpm,npm,yarn, or language-specific tools; - shell access to run setup/test commands non-interactively.
Recommended devbox dependencies:
- Docker, when using container sandboxes;
- Tailscale, when using private previews or remote workers;
gh, when using GitHub CLI auth for PR/comment commands;- GitHub App credentials, when using app auth, control submissions, poller automation, or workers without developer SSH keys;
- Bubblewrap and uidmap (
bubblewrap,uidmap,newuidmap,newgidmap) for Codex Linux sandbox support; - Azure CLI only when the current repo's non-production infrastructure requires Azure-side operator tasks, such as firewall allowlisting.
Optional workspace backend:
par, if installed, is used automatically for attached local worktrees;- native Git worktrees are used when
paris not present; - force native mode with
X4_WORKSPACE_BACKEND=native.
Remote validation dependencies:
- Tailscale reachability from devbox/control to worker;
- SSH access to the control node and worker nodes declared in
infra/execution/x4-execution-model.yaml; - X4 installed on workers/control;
- worker-local env bundles for any remote jobs that need runtime env values.
Onboard A New Repo Set
Use this path when someone wants X4 in the repos they are using now.
1. Pick The Repo Set
Start with the smallest real workflow. A good first repo set is two or three repos that commonly change together.
Define:
- repo ids, stable lowercase names such as
app,api,shared-ui; - canonical GitHub remotes;
- default branches;
- local base checkout paths;
- setup commands;
- test commands;
- env files that may be copied into worktrees;
- forbidden env files and key patterns;
- whether the default sandbox is metadata-only or container-backed.
2. Generate Or Create The Registry
Start by generating a draft:
x4 registry init \
--repo ~/dev/repos/app \
--repo ~/dev/repos/api \
--repo-set current-work \
--output ~/dev/x4/current-work.registry.yaml \
--install skip
Then open the file and adjust setup, test, env, sandbox, and preview values for the actual repos. The generated file should look like this shape:
If you are writing the file manually, start from this same shape:
version: 1
repoSets:
current-work:
description: "Repos used together for current feature work"
repos:
- app
- api
envBundle: current-work
defaultSandboxProfile: azure-remote
defaultInstallMode: eager
branchTemplate: "feat/{featureSlug}"
fallbackBranchTemplate: "x4/{developer}/{date}-{entryRepo}-{shortId}"
repos:
app:
displayName: "app"
canonicalRemote: "git@github.com:Example/app.git"
aliases:
- "https://github.com/Example/app.git"
- "git@github.com:Example/app.git"
defaultBranch: "main"
packageManager: "pnpm"
localMainPath: "~/dev/repos/app"
setup:
- "corepack enable"
- "pnpm install"
test:
- "pnpm test"
env:
copyFromMain:
- ".env"
- ".env.test"
- ".env.local"
forbid:
- ".env.production"
- ".env.prod"
mustBeIgnored:
- ".env"
- ".env.test"
- ".env.local"
dev:
command: "pnpm dev"
port: 3000
preview:
command: "pnpm dev"
port: 3000
api:
displayName: "api"
canonicalRemote: "git@github.com:Example/api.git"
aliases:
- "https://github.com/Example/api.git"
- "git@github.com:Example/api.git"
defaultBranch: "main"
packageManager: "npm"
localMainPath: "~/dev/repos/api"
setup:
- "npm install"
test:
- "npm test"
env:
copyFromMain:
- ".env"
- ".env.test"
- ".env.local"
forbid:
- ".env.production"
- ".env.prod"
mustBeIgnored:
- ".env"
- ".env.test"
- ".env.local"
dev:
command: "npm run dev"
port: 4000
preview:
command: "npm run dev"
port: 4000
sandboxProfiles:
azure-remote:
description: "Default profile: no local sidecars; use existing test services."
composeProfiles: []
requiredEnvFiles: []
env-file:
description: "Inject a selected non-production env file without starting services."
envBundle: current-work
composeProfiles: []
requiredEnvFiles: []
envBundles:
current-work:
description: "Worker-local non-production env bundle for current-work."
path: "/etc/x4/env/current-work.env"
allowMissing: true
required: []
optional: []
forbiddenPatterns:
- "[Pp][Rr][Oo][Dd]([Uu][Cc][Tt][Ii][Oo][Nn])?"
- "[Ll][Ii][Vv][Ee]"
Registry rules that matter:
- generated registries are a starting point, not an authority;
- keep repo ids stable once people use them;
- include both SSH and HTTPS aliases when developers use mixed Git remote styles;
- make
setupandtestcommands non-interactive; - start with
defaultInstallMode: skipif install commands are slow or flaky, then move toeageronce the repo set is stable; - do not copy production env files;
- keep
envBundle.allowMissing: trueuntil the required non-production key list is known; - use
azure-remoteor another metadata-only profile before building a container sandbox.
Validate it:
export X4_REGISTRY_PATH=/path/to/registry.yaml
x4 registry validate --registry "$X4_REGISTRY_PATH"
Expected result:
ok registry valid: /path/to/registry.yaml
ok repo set current-work: app, api
3. Prepare Base Clones
Clone or refresh every repo at the registry's localMainPath:
mkdir -p ~/dev/repos
git clone git@github.com:Example/app.git ~/dev/repos/app
git clone git@github.com:Example/api.git ~/dev/repos/api
git -C ~/dev/repos/app fetch --all --prune
git -C ~/dev/repos/api fetch --all --prune
Verify that the actual remotes match the registry aliases:
git -C ~/dev/repos/app remote -v
git -C ~/dev/repos/api remote -v
4. Bootstrap The First Workspace
From any repo in the repo set:
cd ~/dev/repos/app
export X4_REGISTRY_PATH=/path/to/registry.yaml
x4 workspace bootstrap \
--entry "$PWD" \
--repo-set current-work \
--feature first-x4-proof \
--install skip \
--sandbox-profile azure-remote \
--registry "$X4_REGISTRY_PATH"
Use --install eager after the setup commands are known to be reliable.
Verify:
x4 status
test -f .x4/context.md
test -f .x4/workspace.lock.yaml
find .x4/repos -maxdepth 2 -type d | sort
x4 test --dry-run
Expected:
x4 statuslists every repo in the repo set;- all workspace repos are on the same branch;
- attached repos exist under
.x4/repos/; .x4/context.mdlists setup and test commands;x4 test --dry-runprints the registry test commands without running them.
5. Run A Real Smoke
Once dry-run looks right:
x4 test --continue-on-error
x4 cleanup --dry-run
Review the cleanup plan. For a disposable proof workspace:
x4 cleanup --force --prune-artifacts
Do not use --delete-entry unless the entry repo is a disposable linked
worktree and removing that folder is intentional.
Daily Developer Flow
Start or refresh workspace:
x4 workspace bootstrap --entry "$PWD"
x4 status
If the workspace was created by Codex before the task name was known, it may be
on a temporary x4/session/... branch. Rename all repo branches together:
x4 feature name "short task name"
Work normally across the entry repo and attached repos. Then run:
x4 status
x4 test --continue-on-error
Create split commits:
x4 workspace commit -m "Describe the change"
Plan linked PRs:
x4 workflow submit-pr --title "Describe the feature"
Execute draft PR creation:
x4 workflow submit-pr \
--title "Describe the feature" \
--execute \
--push
Submit remote validation through control, when available:
x4 control submit test --control x4-control-1 --install eager
x4 control submit status <submission-id>
x4 control submit logs <submission-id>
x4 control submit artifacts <submission-id>
Post validation evidence to PRs or issues:
x4 pr comment-status --submission <submission-id> --pr app=123 --dry-run
x4 pr check-run --submission <submission-id> --repo app --dry-run
Clean up after merge or abandonment:
x4 cleanup --dry-run
x4 cleanup --force --prune-artifacts
Codex, Cursor, And VS Code Setup
Use the CLI as the integration point. Cursor and VS Code do not own X4 state; they open the workspace file that X4 generated.
Cursor Without The Extension
This is the most reliable first-time path:
export X4_REGISTRY_PATH="$HOME/dev/x4/current-work.registry.yaml"
export X4_REPO_SET="current-work"
cd ~/dev/repos/app
x4 workspace bootstrap \
--entry "$PWD" \
--repo-set "$X4_REPO_SET" \
--feature short-task-name \
--install eager \
--sandbox-profile azure-remote \
--registry "$X4_REGISTRY_PATH"
cursor .x4/x4-workspace.code-workspace
After Cursor opens, use its terminal to run:
x4 status
x4 test --continue-on-error
Cursor Or VS Code Extension
Install the editor extension adapter on the devbox:
x4-install-editor-extension
Then reload/reconnect Cursor or VS Code.
The extension exposes commands such as:
X4: Bootstrap Workspace
X4: Bootstrap And Open Multi-Repo Workspace
X4: Open Generated Multi-Repo Workspace
X4: Status
X4: Submit PR Workflow
X4: Cleanup
For custom repo sets, make sure the editor extension process can see the same environment values:
X4_REGISTRY_PATH=/path/to/registry.yaml \
X4_REPO_SET=current-work \
X4_SANDBOX_PROFILE=azure-remote \
X4_INSTALL_MODE=eager \
x4-workspace-bootstrap
If the extension cannot see those environment values, run the direct CLI
bootstrap first, then use X4: Open Generated Multi-Repo Workspace or Cursor's
File -> Open Workspace from File.
For tools that accept a direct setup command, this is equivalent:
x4 workspace bootstrap \
--entry "$PWD" \
--repo-set current-work \
--install eager \
--sandbox-profile azure-remote \
--registry /path/to/registry.yaml
Codex instructions for the user or project:
Read .x4/context.md and .x4/agent-instructions.md first. Keep changes, tests,
commits, and PR summaries split by repo. Use X4 commands for status, tests,
sandbox, preview, PR workflow, remote validation, and cleanup.
Install the Codex plugin/skills adapter on a devbox when using Codex:
x4-install-codex-plugin
After bootstrap, Cursor or VS Code can open:
.x4/x4-workspace.code-workspace
Repo-Level Agent Pointer
Each repo should have a stable AGENTS.md pointer that tells agents to use
generated X4 context when present. X4 can check and bootstrap the pointer:
x4 doctor agents --entry "$PWD"
x4 agents bootstrap-pr --entry "$PWD" --dry-run
The tracked AGENTS.md should stay general. Do not write feature-specific
instructions into it; .x4/context.md is regenerated per workspace.
See Agent Awareness Adoption for the
first-time adoption flow and why normal workspace bootstrap only warns when the
pointer is missing.
Sandboxes And Previews
Start with metadata-only:
x4 sandbox up --profile azure-remote
Metadata-only profiles validate env and registry wiring, but they do not start
app servers. A user-ready sandbox needs a service profile with
sandboxProfiles.<id>.services[].
Use AI to prepare the first service profile when the repos do not have an obvious, deterministic setup:
x4 ai doctor
x4 ai sandbox-plan --entry "$PWD" --run
x4 ai sandbox-profile --entry "$PWD" --profile local-preview
How the AI path works:
x4 ai sandbox-planbuilds a redacted workspace summary from the registry, package scripts, dependency metadata, repo trees, docs, contracts, jobs, specs, and env key names. Env values are not included.x4 ai sandbox-profileasks the model for strict JSON, not a shell script. The workspace repo set is already fixed; AI is only used to infer which selected repos run long-lived services and what commands, ports, routes, and service dependencies they need. X4 validates the proposed repo ids, service ids, commands, images, Dockerfiles, ports, and inline environment values before it can be written.--writestores the reviewed profile insandboxProfiles.<profile-id>in the workspace registry. The registry remains the source of truth that a user or agent can inspect and edit.x4 sandbox uprenders that registry profile into.x4/sandbox/docker-compose.yaml, mounts each repo into its service container, injects the selected env files under.x4/sandbox/env/, and runs Docker Compose on the current host unless--backend ssh --target <worker>is used. A control server without Docker can run metadata-only profiles, but cannot run service profiles such aslocal-previewlocally.--waitkeeps the command open until Docker services arerunningorhealthy.--serve-previewcreates private tailnet tester URLs for the frontend, dashboard, API evidence routes, or other useful services.
Review .x4/ai/local-preview-sandbox-profile.json. The important fields are:
repo: workspace repo id that owns the service;command: command run inside the sandbox container;containerPort: port the app listens on inside the container;routePath: private preview route, for example/webor/backend;dependsOn: service startup relationship;environment: non-secret runtime values such as relative API URLs.
After review:
x4 ai sandbox-profile \
--entry "$PWD" \
--profile local-preview \
--ai-engine codex-sdk \
--write
x4 registry validate --registry ./registry/x4-pilot-registry.yaml
For the normal interactive path, ask X4 for the outcome you want and let the agent prepare the profile before deterministic startup:
x4 sandbox run "frontend, backend, and admin dashboard" \
--ai-engine codex-sdk \
--preview-backend tailnet-proxy
During early adoption and lower-level debugging, you can also use the
temporary --ai shortcut on sandbox up to run the same profile-generation
step before startup:
x4 sandbox up \
--profile local-preview \
--ai \
--ai-engine codex-sdk \
--serve-preview \
--preview-backend tailnet-proxy \
--wait
This remains a reviewed registry flow: AI proposes a profile, X4 validates it,
writes it into the registry, and only then runs the normal sandbox command.
The goal, prompt, model response, validated proposal, and run state are written
under .x4/ai/runs/<run-id>/.
See AI Harness for the planned local/Mastra runner
contract behind this flow.
Run the container-backed sandbox on a host with Docker Compose:
x4 sandbox up \
--profile local-preview \
--env-source /path/to/non-production.env \
--filter-forbidden-env \
--serve-preview \
--preview-backend tailnet-proxy \
--wait
If you are on a control server without Docker, run it on a Docker-capable X4 worker/testbox:
x4 sandbox up \
--backend ssh \
--target x4-testbox-standard-1 \
--profile local-preview \
--serve-preview \
--preview-backend tailnet-proxy \
--wait
For multi-repo stacks that need different env files per repo, pass one env file per workspace repo:
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
In Cursor or VS Code, use X4: Sandbox Run for the agentic path. It asks what
you want to run, then prepares and starts the sandbox through X4. Use
X4: Sandbox Up when you already know the exact registry profile and want the
deterministic command. If the registry env bundle is not the file you want,
select one env file per repo from discovered workspace files such as
.env.test, pick one global dotenv for every repo, browse for another
non-production dotenv file, or continue without injecting an env file.
When the sandbox is running, X4 prints local service URLs such as
api: http://127.0.0.1:<port>. With --serve-preview, it also prints private
tailnet tester/evidence URLs.
Use x4 sandbox status after startup to see the same information again: the
active profile, Docker Compose project, services, local URLs, private preview
routes, runtime env file paths, and current Compose state. Status verifies the
saved running state against Docker labels; if the containers are gone or stopped,
it marks the sandbox and preview stopped and hides service and preview links in
the normal stopped status output.
Expected useful output looks like:
ok sandbox running: x4_<workspace-id>
api: http://127.0.0.1:<host-port>
web: http://127.0.0.1:<host-port>
ok tailnet preview proxy running: http://<tailnet-host>:3000
preview web: http://<tailnet-host>:3000/web/
preview api: http://<tailnet-host>:3000/backend/
sandbox readiness: ok
The 127.0.0.1 URLs are only local to the machine running the sandbox. If the
sandbox runs on a worker/testbox, open the printed preview ... tester URL from
a browser on the tailnet. Use x4 status to see the current sandbox and preview
state.
Remote worker sandbox:
x4 sandbox up \
--profile <profile-id> \
--target x4-testbox-standard-1 \
--env-bundle <bundle-id> \
--filter-forbidden-env \
--serve-preview \
--preview-backend tailnet-proxy \
--wait
Preview rule: only post tailnet/private tester URLs. Never post localhost,
127.0.0.1, 0.0.0.0, Docker-internal names, container-only names, or
placeholder URLs to GitHub.
Inspect and clean up:
x4 status --entry "$PWD"
x4 sandbox status --entry "$PWD"
x4 sandbox logs
x4 sandbox wait --entry "$PWD"
x4 sandbox down
x4 sandbox destroy --force --prune-artifacts
On a control host without Docker, use a host-process preview instead of a container-backed sandbox:
x4 preview up --entry "$PWD" --repo <frontend-repo-id> --visibility tailnet --start
x4 status --entry "$PWD"
This starts the registry preview.command in the background and exposes the
private tailnet URL for a user to open.
GitHub And Orchestration
For repo-local validation policy, use:
x4 orchestration policy init --repo "$PWD" --apply
x4 orchestration policy validate --repo "$PWD"
x4 orchestration policy validate --entry "$PWD"
Preferred policy path:
.github/x4/policy.yml
X4 also reads legacy .github/code-assist/policy.yml during migration.
GitHub App auth is required for app-mode PRs, issue comments, check runs, control poller automation, and workers/control hosts that need short-lived Git access without developer SSH keys.
Validate app access:
x4 github app validate \
--env /path/to/provisioning.env \
--repo Example/app \
--repo Example/api
Definition Of Done For Onboarding
A repo set is onboarded when all of this is true:
x4 --versionworks on the developer machine;x4 doctor hostpasses, andx4 doctor devboxpasses where applicable;- the registry validates;
- every repo has a base clone at
localMainPath; - bootstrap works from each likely entry repo;
.x4/context.md,.x4/workspace.yaml, and.x4/workspace.lock.yamlare generated;x4 statuslists every repo and a shared branch;x4 test --dry-runprints the right commands;- at least one real
x4 test --continue-on-errorrun produces artifacts; - cleanup dry-run shows only generated X4 resources;
- Codex/Cursor/VS Code setup commands include the correct
X4_REPO_SETandX4_REGISTRY_PATH; - no secret values, production env files, or local-only preview URLs appear in logs, comments, PR bodies, or artifacts.
Troubleshooting
no X4 registry found
Set X4_REGISTRY_PATH or pass --registry /path/to/registry.yaml.
unknown repo set
The installed x4-workspace-bootstrap wrapper defaults to
mealweek-mastra-pilot. Set X4_REPO_SET=<your-set> or pass
--repo-set <your-set>.
could not match entry repo remote to registry
Add the entry repo's actual git remote -v URL to canonicalRemote or
aliases, then validate the registry again.
Attached repo clone/worktree fails
Check localMainPath, Git access, default branch, and whether another worktree
already has the target branch checked out. Try --workspace-backend native if a
par issue is suspected.
Setup fails during bootstrap
Retry with --install skip, then run setup commands manually in each repo until
they are non-interactive and reliable. Move back to eager after that.
Env file did not copy
Only files listed in env.copyFromMain are copied, and files listed in
env.forbid are refused. The files must be ignored by Git when
mustBeIgnored is configured.
Codex says local environments are unavailable
Open the actual repo root, not a parent folder. Then check:
codex sandbox linux /bin/true
x4 doctor host
Remote validation cannot reach the worker
Check Tailscale, SSH, worker id, control host, and the execution model:
x4 remote plan
x4 doctor control
x4 doctor worker
x4 control workers
GitHub app validation fails
Confirm the app is installed on every repo in the repo set and has the needed permissions for contents, pull requests, issues, statuses/checks, and metadata.
Recommended First Hour
For a new developer:
x4 --version
x4 doctor host
export X4_REGISTRY_PATH=/path/to/registry.yaml
x4 registry validate --registry "$X4_REGISTRY_PATH"
cd ~/dev/repos/<entry-repo>
x4 workspace bootstrap --repo-set <repo-set> --install skip --registry "$X4_REGISTRY_PATH"
x4 status
x4 test --dry-run
x4 feature name "x4 onboarding proof"
x4 cleanup --dry-run
After that works, run one real test:
x4 test --continue-on-error
If the repo set passes that flow, X4 is adding value: it can identify the active repo set, create a coordinated workspace, preserve context for tools and agents, run the correct validation commands, and clean up safely.