Skip to main content

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:

InputWho creates itWhat it does
X4 CLIDeveloper or devbox installerProvides the x4 command.
Base repo clonesDeveloperNormal Git checkouts of each repo, usually under ~/dev/repos/.
X4 registry YAMLRepo owner, platform owner, or onboarding developerTells 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.

  1. 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
  1. 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
  1. 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.

  1. Validate the registry:
x4 registry validate --registry "$X4_REGISTRY_PATH"
  1. 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.

  1. 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.

  1. 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 par is 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 setup and test commands non-interactive;
  • start with defaultInstallMode: skip if install commands are slow or flaky, then move to eager once the repo set is stable;
  • do not copy production env files;
  • keep envBundle.allowMissing: true until the required non-production key list is known;
  • use azure-remote or 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 status lists every repo in the repo set;
  • all workspace repos are on the same branch;
  • attached repos exist under .x4/repos/;
  • .x4/context.md lists setup and test commands;
  • x4 test --dry-run prints 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-plan builds 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-profile asks 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.
  • --write stores the reviewed profile in sandboxProfiles.<profile-id> in the workspace registry. The registry remains the source of truth that a user or agent can inspect and edit.
  • x4 sandbox up renders 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 as local-preview locally.
  • --wait keeps the command open until Docker services are running or healthy. --serve-preview creates 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 /web or /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 --version works on the developer machine;
  • x4 doctor host passes, and x4 doctor devbox passes 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.yaml are generated;
  • x4 status lists every repo and a shared branch;
  • x4 test --dry-run prints the right commands;
  • at least one real x4 test --continue-on-error run produces artifacts;
  • cleanup dry-run shows only generated X4 resources;
  • Codex/Cursor/VS Code setup commands include the correct X4_REPO_SET and X4_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.

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.