Skip to content

Latest commit

 

History

History
189 lines (156 loc) · 7.85 KB

gui-setup.md

File metadata and controls

189 lines (156 loc) · 7.85 KB

GUI setup

GUI index | Getting started | Operations

This page is for operators preparing the static GUI and the optional gui_server binary. The GUI Cargo feature is not a default feature.

Guided setup and preflight

From a new checkout, the setup script can build the export and server, create an independent private extension root, write a config example only when none exists, and create a 0600 Trial token file without printing its value:

./scripts/setup.sh --gui \
  --base-path /proxy/commandagent/ \
  --extension-root /srv/commandagent/extensions \
  --write-config \
  --gui-token-file "$HOME/.config/commandagent/gui-token"

The final summary prints separate preflight and start commands. Run preflight first. gui_server --check does not bind a port; it reports ok or ng for the static export/base path, static GUI / server contract version, pairwise-disjoint roots, commandagent --version, and token/Origin settings. Green exits 0, ng exits 1, malformed arguments exit 2, and --check --json emits the same result as JSON.

Delegated runs need the OS sandbox

The GUI delegates a run to the commandagent CLI and always passes --sandbox required. If the OS isolation cannot be applied, the run still starts, but every Bash and verifier command is refused with bash_sandbox_unavailable: <reason>. The run cannot execute commands or verify its work and fails: the GUI never runs a model's commands without isolation and never does so silently (Issue #502, decision 1). This happens where no backend is available, for example inside a nested sandbox (a sandboxed container or an IDE that already uses Seatbelt), or on a Linux kernel without Landlock or with it disabled.

commandagent --doctor does not probe the OS sandbox, so it cannot tell you this in advance. Read the run's bash_sandbox_status event: applied=false plus reason says the isolation is not in force and why. You can also start a CLI run outside the GUI, in a scratch workspace, with --sandbox required; for a run that uses Bash, its commands either run or are refused with bash_sandbox_unavailable and the reason (a run that never calls Bash cannot tell you). Fix the environment (run outside the nested sandbox, or use a kernel with Landlock enabled) rather than looking for a GUI switch that turns the isolation off; there is none.

Rebuild the static GUI and server together

The static export and gui_server carry the same GUI contract marker. Rebuild both from one checkout whenever either side changes; the server build must keep the non-default gui feature enabled:

cd gui
GUI_BASE_PATH=/ npm ci
GUI_BASE_PATH=/ npm run build
cd ..
cargo build --bin commandagent
cargo build --features gui --bin gui_server
target/debug/gui_server --check \
  --base-path / \
  --static-dir gui/out \
  --repository-root . \
  --commandagent-bin target/debug/commandagent

Use the deployment prefix instead of / for both GUI_BASE_PATH and --base-path. A mismatch makes static.contract_version fail in --check. If the server is started without preflight, the browser shows 「GUI と gui_server の版が一致していません」 when runtime-status reports a missing or different marker. Rebuild both artifacts, rerun --check, and only then restart the server; clearing browser cache is not a substitute for a matched rebuild.

An existing .commandagent/config.toml or token file is never overwritten. The setup script displays a proposed config diff and leaves existing files unchanged.

The three roots

Root Purpose Write owner
repository root Read-only documentation, run reports, contracts, packs, and measurement projections normal repository workflows, never GUI Trial
execution root Trusted container for isolated sessions/<session-id>/ CLI workspaces and central .commandagent/runs/<session-id>/ GUI run records confirmed GUI Trial delegation only
extension root Private packs/, profiles/, pins, retirement markers, and journal.jsonl SupplyRoot lifecycle API only

All three must be pairwise disjoint, including canonicalized symlink aliases. The extension root must not be the Trial execution root.

By default, each confirmed Trial runs with <execution-root>/sessions/<session-id>/ as both its process working directory and CLI --cwd. The Trial form can instead select an existing directory below the execution root by relative path. Gate 1 binds that canonical directory, and confirmed additional requests and history reconnects reuse it. Absolute paths, traversal, symlinks, runtime directories, missing directories, and paths outside the execution root are rejected.

Generated source plus the selected workspace's .commandagent/plans, evidence, and repairs stay below that working directory. Automatically generated completion contracts follow the same boundary; these products are never shared at the execution-root top level. Confirmations, events.jsonl, summary.md, and directive state remain in the central <execution-root>/.commandagent/runs/<session-id>/ record used by the GUI APIs. The legacy .anvil/runs/<session-id>/ location remains read-only compatibility input for older records.

Serve at /

cd gui
GUI_BASE_PATH=/ npm run build
cd ..
cargo run --features gui --bin gui_server -- \
  --port 4173 \
  --base-path / \
  --static-dir gui/out \
  --repository-root . \
  --execution-root /path/to/trial-workspace \
  --extension-root /path/to/commandagent-extensions \
  --trial-token-auth off \
  --commandagent-bin target/release/commandagent

Open http://127.0.0.1:4173/. The server binds only to 127.0.0.1. With authentication off, the token field is hidden, but every POST still requires a same-host or allowlisted Origin. Read-only recovery documents are also available without a bearer token in this mode. Use this only for a trusted loopback session. If --execution-root is omitted, read-only dashboards remain available and all Trial APIs fail closed.

Serve below a reverse-proxy path

The build path and server path must name the same prefix. The build accepts a trailing slash; the server uses the canonical form without it:

cd gui
GUI_BASE_PATH=/proxy/commandagent/ npm run build
cd ..
export GUI_TRIAL_TOKEN="$(openssl rand -hex 32)"
GUI_TRIAL_ALLOWED_ORIGINS='https://admin.example.com' \
cargo run --features gui --bin gui_server -- \
  --port 4173 \
  --base-path /proxy/commandagent \
  --static-dir gui/out \
  --repository-root . \
  --execution-root /path/to/trial-workspace \
  --extension-root /path/to/commandagent-extensions \
  --trial-token-auth on \
  --commandagent-bin target/release/commandagent

The proxy must preserve the prefix:

location /proxy/commandagent/ {
    proxy_pass http://127.0.0.1:4173;
}

Do not derive origin or prefix from X-Forwarded-*. Set both explicitly.

CommandMate and Cloudflare route map

CommandMate is external orchestration and is not the GUI server. Keep the three hops distinct:

Layer Example public/path value Destination
browser / Cloudflare Access https://admin.example.com/proxy/commandagent/ authenticated tunnel route
tunnel or reverse proxy preserve /proxy/commandagent/ http://127.0.0.1:4173/proxy/commandagent/
gui_server --base-path /proxy/commandagent static export built with GUI_BASE_PATH=/proxy/commandagent/

Require an administrator access policy at Cloudflare or the chosen tunnel. A valid GUI Trial token does not replace upstream authentication. CommandMate may start or supervise a local process only through an explicitly authorized operator workflow; it does not change base-path, Origin, token, or root isolation contracts.

See operations for token and Origin policy and Two-basePath smoke for verification.