# Getting started SpaceApp packages its application services and redistributable AI coding CLIs in Docker. The host needs Node.js only for the small `spaceapp` launcher, and enough resources for the stack. The launcher installs and starts Docker automatically when it is missing. ## Requirements Minimum (the `small` profile): - 4 CPU cores; - 8 GB-class system RAM (the launcher requires at least 7 GiB reported by the operating system); - 6.5 GiB free disk for a fresh installation; - Node.js 20.11 or newer. The `large` profile, which adds managed browser sessions, requires: - 8 CPU cores; - 15 GiB RAM; - 11 GiB free disk. ## Linux Install Node.js 20.11 or newer, then run as a normal non-root user: ```bash npx --yes run-spaceapp@latest install ``` Linux runs the containers directly through the host Docker Engine; SpaceApp does not create a second guest VM. The launcher runs as the current non-root user so the installation remains in that user's config directory. If Docker is missing on Ubuntu, Debian, Fedora, RHEL, or CentOS, the launcher adds Docker's official repository. On Arch-family systems, including CachyOS, it installs the native `docker` and `docker-compose` packages through `pacman`. It then starts the service. Before adding the current user to the `docker` group, it explains that the group grants root-level privileges, adds the user automatically, and continues in the same command. ## macOS Install Node.js 20.11 or newer, then run in Terminal: ```bash npx --yes run-spaceapp@latest install ``` If Docker is missing, the launcher asks you to review and accept Docker Desktop's terms, downloads the official architecture-specific DMG, verifies its code signature, installs it, starts it, and waits until it is ready. Docker Desktop uses its managed lightweight Linux environment. Apple Silicon uses the native `linux/arm64` images and Intel Macs use `linux/amd64`. ## Windows 11 — Command Prompt Enable hardware virtualization and install Node.js 20.11 or newer. Open **Command Prompt**, or select the **Command Prompt** profile in Windows Terminal, and run: ```bat npx --yes run-spaceapp@latest install ``` Do not run the universal command from a PowerShell profile whose execution policy is `Restricted`: Windows can block npm's `npx.ps1` before SpaceApp gets a chance to run. Command Prompt invokes npm's `npx.cmd` shim with the same universal command and needs no execution-policy change. If Docker is missing, the launcher asks you to review and accept Docker Desktop's terms, requests a Windows UAC approval when WSL2 or the package installation requires it, and prefers the official Docker Desktop package through Windows Package Manager. Windows Package Manager verifies the installer against its hash-pinned `Docker.DockerDesktop` manifest. If Windows Package Manager is unavailable or fails, the launcher downloads Docker Desktop from Docker's official distribution service and verifies its Authenticode signature before running it. The launcher then starts Docker Desktop and waits until it is ready. On the first launch, Docker Desktop may show a **Welcome to Docker** screen before starting the Engine. Select **Skip** in the top-right (or sign in), accept any remaining Docker prompt, and leave the terminal open. SpaceApp waits for up to ten minutes and continues automatically when Docker becomes ready. Windows may request a UAC approval or one restart. When WSL2 needs the restart, SpaceApp registers a one-time resume and asks before scheduling it. Save your work, approve the restart, and sign back in; the installer resumes automatically in Command Prompt without entering the command again. SpaceApp reuses Docker Desktop's WSL2 Linux environment and does not install a second full virtual machine. ## Installation profiles The universal install command defaults to `--profile auto`: | Profile | Services | CPU | Usable RAM | Fresh free disk | | --- | --- | --- | --- | --- | | `small` | core, OpenCode, PostgreSQL | 4 | 7 GiB | 6.5 GiB | | `medium` | small + Temporal/background integration workers | 4 | 11 GiB | 8 GiB | | `large` | medium + managed Chromium, larger resource limits | 8 | 15 GiB | 11 GiB | Auto chooses the largest profile that fits all three resources, then checks Docker's allocation. Existing installations preserve their profile during an upgrade. `light` and `standard` keep compatibility settings for older installs. Additional providers and companions install only when requested. ```bash npx --yes run-spaceapp@latest install --profile small npx --yes run-spaceapp@latest install --profile medium npx --yes run-spaceapp@latest install --profile large ``` Small limits core and CLI to 2 GiB each and PostgreSQL to 768 MiB. Medium adds background workflow/integration workers; large adds managed browser automation. Small disables those background services, including automatic Telegram delivery and streaming bot workers. Room/pane budgets and UI behavior are unchanged. Limits are upper bounds, not memory reserved at startup. ## Linux host access Installation profiles do not control filesystem permissions. Every profile uses isolated access by default, where only registered workspaces are mounted. Host-root access is meant for a disposable, trusted single-owner Linux machine: ```bash npx --yes run-spaceapp@latest install --access host-root ``` That mode remains one Docker-based SpaceApp build across Linux distributions. It mounts the host `/` at `/host`, read-only in the core service and read/write in the CLI service. The CLI service runs its sessions as container root only in this mode. On a normal rootful Docker Engine, this is equivalent to host-root file access: an agent can read credentials, change boot or package files, or destroy the operating system. The mode does not mount the Docker socket and does not enable `privileged`, host PID, host network, host IPC, or host device access. Those omissions reduce the attack surface but do not make a writable host root safe from a malicious or mistaken CLI command. Omitting `--access` preserves the current mode. New and migrated installations default to `isolated`. To remove the host root mount while preserving SpaceApp data, credentials, workspaces, secrets, and persistent volumes, run: ```bash npx --yes run-spaceapp@latest install --access isolated ``` Host-root is supported only on Linux with Docker (`--engine docker`); the launcher refuses it on macOS, Windows, and rootless Podman (`--engine podman`). ## Rootless Podman (`--engine podman`) SpaceApp supports rootless **Podman 5+** as a first-class container engine: ```bash npx --yes run-spaceapp@latest install --engine podman ``` If Docker is not installed and a working Podman 5+ runtime with `podman compose` is already on `PATH`, `run-spaceapp install` offers to use Podman automatically. Passing `--engine podman` skips the Docker installation flow, verifies `podman --version` (5+), `podman compose version`, and `podman info`, and records `"engine": "podman"` in `config.json`. - **Podman 5+ requirement**: Podman 4.x is rejected with upgrade instructions. The supported Compose provider is `podman compose` from Podman 5 or newer, backed by Docker Compose v2 or `podman-compose`. Podman 4.x is not supported. - **Workspaces & SELinux**: Registered workspace bind mounts include `:z` SELinux shared labels. `spaceapp-cli` uses `userns_mode: "keep-id:uid=10001,gid=10001"` so container UID `10001` maps to your host user. The published images start as root and `gosu` down to that user, so the Podman CLI service is written without `no-new-privileges` (that option makes the switch fail with "operation not permitted"). Other services keep `no-new-privileges`. - **macOS**: `install --engine podman` checks the running Podman machine's CPU, memory, and disk against the selected profile and prints a `podman machine set` command when the machine is too small. Disk size is only increased. - **Windows**: Podman is not supported. Use Docker Desktop. - **`--answers`**: `"engine": "podman"` in the answers file selects Podman the same way `--engine podman` does. When Docker is missing, an interactive install asks before using Podman; `--non-interactive` selects it. - **`--access host-root` limitation**: `--access host-root` is refused when `--engine podman` is selected because rootless user namespaces remap host UIDs. Use `--access isolated` and `spaceapp workspace add `. - **Engine migration**: Switching engines (`docker` ↔ `podman`) on an existing installation is refused so named-volume data is never silently orphaned. `uninstall --purge-data` removes that engine's containers and data volumes, but it leaves `config.json` and `backups/` in the installation root. Installing again in that same root still reads the old `engine` from `config.json`. A new `SPACEAPP_HOME` does not see backups that stayed in the old root. Before any command below, set `SPACEAPP_HOME` to the absolute installation root (`export SPACEAPP_HOME="$HOME/.config/spaceapp"`, or prefix one command with `SPACEAPP_HOME=/absolute/install`). The launcher reads that variable and has no `--root` flag. If `SPACEAPP_HOME` is unset, `$SPACEAPP_HOME/config.json` expands to `/config.json`. - Same root: run `spaceapp backup`. A backup does not include browser profiles, `google-oauth.json`, or Telegram bot secrets, so after `spaceapp restore` you must enter those secrets again and sign in to providers again ([docs/operations.md](operations.md)). Then run `spaceapp uninstall --purge-data` (type `DELETE` when asked). Remove `$SPACEAPP_HOME/config.json` and leave `$SPACEAPP_HOME/backups/` in place. Run `spaceapp install --engine `, then `spaceapp restore`. - New root: run `spaceapp backup`. With the old `SPACEAPP_HOME` still selected, stop that runtime so it releases `127.0.0.1:4911`: `spaceapp down`, or `spaceapp uninstall` without `--purge-data` (containers and the network are removed; `config.json`, secrets, and `backups/` stay). Copy or move the backup directory from the old `$SPACEAPP_HOME/backups/` into the new `$SPACEAPP_HOME/backups/`. Set `SPACEAPP_HOME` to the new root, then run `spaceapp install --engine ` and `spaceapp restore`. - **doctor**: Reports the engine, Podman version, rootless or rootful mode, cgroup version, and whether the `cpu` and `memory` controllers are delegated. `support-bundle` records the same facts and no secrets. The `npx` command is the universal one-command installer. To retain a global launcher for later operations, optionally run `npm install -g run-spaceapp`; this is not required for the first install. ## Disk usage Fresh installations use profile-specific free-space checks (6.5/8/11 GiB). The installer does not preallocate this space. Upgrades require only missing image layers, a database checkpoint and 0.5 GiB headroom. Target images already cached need no extra image space. Registry layer metadata excludes shared layers when available; offline/unknown metadata uses a conservative estimate. The launcher checks space again after pull and before cutover. Existing workspaces and volumes are retained in place, never duplicated or deleted for space. Docker's separate disk capacity is checked when measurable; an unavailable measurement is reported. Data size and optional companions can increase the requirement. On Windows and macOS, the number shown as Docker Desktop's disk limit is a maximum, not an immediate allocation: the managed sparse virtual disk grows as data is written. Removing images or volumes releases space inside Docker, but the host-side sparse file may require Docker Desktop's reclaim/compact action before its visible file size shrinks. ## What the command does The universal install command performs `initialize → prerequisites → doctor → pull → up → readiness → setup status → open`. It creates non-secret configuration, fresh database/session secrets, and a one-time setup token; installs Docker from official sources when required; checks CPU, RAM, free disk, Docker CLI, Compose, and engine readiness; downloads the selected images; starts the services; waits up to ten minutes for `/readyz`; verifies first-owner status; and opens `http://127.0.0.1:4911`. The command is idempotent. Running it again preserves the installation's long-lived secrets, data, and provider state. While the owner remains unclaimed, each successful install replaces only the setup token with a fresh 15-minute value after the database accepts it, then prints that value at the end. Use `--no-open` on headless machines. The default installation roots are: | Platform | Default path | | --- | --- | | Linux | `$XDG_CONFIG_HOME/spaceapp` or `$HOME/.config/spaceapp` | | macOS | `$HOME/Library/Application Support/SpaceApp` | | Windows | `%APPDATA%\SpaceApp` | To isolate an installation or clean-room test, set `SPACEAPP_HOME` to an absolute path before every launcher command. Before it first uses a SpaceApp version, the launcher checks its images' provenance on ghcr.io. Behind a proxy it uses `HTTPS_PROXY` and `NO_PROXY`, or else the proxy in `~/.docker/config.json`. On an air-gapped host, `SPACEAPP_IMAGE_VERIFY=off` skips that check; every launcher command then prints a warning. ## Register a workspace SpaceApp mounts no host project by default. Register only directories the CLI tools are allowed to read or modify: ```bash # Linux npx --yes run-spaceapp@latest workspace add /home/alice/code/example # macOS npx --yes run-spaceapp@latest workspace add /Users/alice/code/example # Windows PowerShell npx --yes run-spaceapp@latest workspace add "C:\Users\Alice\code\example" ``` Use `--read-only` when the tools should not modify the directory: ```bash npx --yes run-spaceapp@latest workspace add /absolute/path/to/reference --read-only npx --yes run-spaceapp@latest workspace list npx --yes run-spaceapp@latest workspace remove /absolute/path/to/reference ``` Adding a workspace grants the application CLIs access to that host directory. Repository files are untrusted input, so review the project and its agent instructions before allowing tools to operate on it. `workspace add` and `workspace remove` apply the change to the running services. Run `npx --yes run-spaceapp@latest up` only if the command says the services could not pick it up. On Linux the CLIs run as uid 10001 inside Docker, and a mounted folder keeps its host owner. When they cannot write to it, `workspace add` prints the command that gives them access without changing the owner (install the `acl` package if `setfacl` is missing): ```bash sudo setfacl -R -m u:10001:rwX -m u:$(id -u):rwX -m d:u:10001:rwX -m d:u:$(id -u):rwX /home/alice/code/example ``` ## First browser setup The install command starts the stack and opens the first-run page. If the browser was closed or `--no-open` was used, run `npx --yes run-spaceapp@latest open`. The application binds to `http://127.0.0.1:4911` by default. On the first page: 1. copy the one-time setup token printed at the end of the install command and paste it into the field with the same name; 2. create the owner email and a password of at least 12 characters; 3. sign in as that owner; 4. connect one CLI provider at a time, **starting with OpenCode** — its starter model is the free Big Pickle (`opencode/big-pickle`). On first launch SpaceApp checks it with a real tool call and falls back to another free model if it fails (see [CLI providers](cli-providers.md)), so no paid account or API key is required to get a working agent; 5. create a test room and verify the selected workspace; 6. run `npx --yes run-spaceapp@latest backup` before the first update. There is no default owner password or production development-login fallback. The setup claim is single-use. If the 15-minute token expires before the first owner is claimed, rotate it locally and use the newly printed value: ```bash npx --yes run-spaceapp@latest owner rotate-setup-token ``` Rotation is refused after an owner exists. ## Connect providers Open the CLI provider setup inside SpaceApp and use the provider's official OAuth, device-code, or login flow. **Connect OpenCode first**: the bundled OpenCode runtime starts on the free Big Pickle model, or on another free model that passes the first-launch check, which gives a working agent without a paid plan or API key. Then continue with the other providers as needed. For providers that support direct API keys, the launcher also accepts a value from masked standard input: ```bash npx --yes run-spaceapp@latest credentials list npx --yes run-spaceapp@latest provider install claude npx --yes run-spaceapp@latest credentials set claude npx --yes run-spaceapp@latest credentials set gemini ``` `credentials set claude` and `credentials set codex` store an Anthropic and an OpenAI API key; OpenCode uses the same two keys for its Anthropic and OpenAI models (choose them with `/models`). `credentials set opencode` takes an OpenCode Zen key only. Credentials are never accepted as command-line arguments. See [CLI providers](cli-providers.md) for bundled versus owner-installed versions, authentication methods, storage boundaries, and the experimental DeepSeek warning. ## Verify the installation ```bash npx --yes run-spaceapp@latest doctor npx --yes run-spaceapp@latest status npx --yes run-spaceapp@latest logs ``` `doctor` checks Node.js, Docker CLI, Docker Compose, Docker Engine, CPU, memory, and free disk exactly once each. It distinguishes a missing CLI or Compose plugin from an installed engine that is stopped or inaccessible. The `small` profile should show core, CLI, and PostgreSQL running; `medium` adds Temporal, and `large` also adds the browser service. If startup is still in progress, wait for the health checks and inspect bounded logs. ## Source-checkout test path A clean-room operator can also build the three images from a verified source commit with the exact tag expected by the launcher. Replace `` with `spaceappRuntimeVersion` from `packages/run-spaceapp/package.json`: ```bash npm ci docker build --target core --tag ghcr.io/oll4com/spaceapp-core: . docker build --target browser --tag ghcr.io/oll4com/spaceapp-browser: . docker build --target cli --tag ghcr.io/oll4com/spaceapp-cli: . npm install -g ./packages/run-spaceapp ``` Then set a new `SPACEAPP_HOME` and follow `init → doctor → workspace add → up → open` so the launcher uses the already-built local tags without a registry pull. This proves a source build; it does **not** prove the public npm tarball or GHCR manifests. Follow [Clean-room testing](clean-room-testing.md) for the complete acceptance checklist.