---
title: Server & CLI
icon: terminal
description: Daemon + CLI for managing workspaces from the shell.
---

## Overview

Two companion packages to the core SDK:

- **[`@struktoai/mirage-server`](https://github.com/strukto-ai/mirage/tree/main/typescript/packages/server)**, a Fastify daemon that owns workspaces in-process and exposes them over HTTP (`/v1/workspaces`, `/v1/jobs`, ...).
- **[`@struktoai/mirage-cli`](https://github.com/strukto-ai/mirage/tree/main/typescript/packages/cli)**, a `commander` CLI that speaks to the daemon. Mirrors Python's `mirage` CLI 1:1.

The CLI is stateless. Long-running state lives in the daemon; the CLI auto-spawns one on the first `mirage workspace create` if none is running.

## Install

```bash
npm install -g @struktoai/mirage-cli
```

This pulls in `@struktoai/mirage-server` transitively (the CLI spawns the daemon from the server package's installed `bin/daemon.js`).

## Create a workspace

Write a YAML config:

```yaml
# config.yaml
mounts:
  /:
    resource: ram
    mode: write
```

Then:

```bash
mirage workspace create config.yaml
```

The CLI:
1. Validates the YAML + interpolates `${VAR}` env references (fails fast if any are missing).
2. Auto-spawns a daemon on `127.0.0.1:8765` if none is reachable.
3. Sends `POST /v1/workspaces` and prints the returned detail as JSON.

## Run commands in a workspace

```bash
# synchronous, blocks until the command finishes
mirage execute -w <workspace-id> -c "ls /"

# background, returns a job id immediately; poll/wait later
mirage execute --bg -w <workspace-id> -c "wc -l /large.csv"
mirage job wait <job-id>
```

## Workspace lifecycle

| Command | Purpose |
|---|---|
| `mirage workspace create <config.yaml>` | Create; auto-spawns daemon if needed. |
| `mirage workspace list` | List active workspaces. |
| `mirage workspace get <id> [--verbose]` | Show one workspace's detail. |
| `mirage workspace delete <id>` | Stop and remove. |
| `mirage workspace clone <src> [--id NEW] [--at REF]` | New workspace from the source; `--at REF` clones a past version, else the live state. |
| `mirage workspace snapshot <id> <out.tar>` | Snapshot to tar. |

## Versioning

Each workspace has a git-backed history kept by the daemon (under
`~/.mirage/repos/<id>`; set `MIRAGE_VERSION_ROOT` to relocate). Same verbs and
semantics as the [Python CLI](/home/cli#versioning).

```bash
mirage workspace commit <id> -m "first"            # commit live state
mirage workspace log <id> [-b branch]              # versions, newest first
mirage workspace diff <id> [a] [b]                 # changed paths; no refs = live vs HEAD
mirage workspace branch <id> <name> [--from b]     # fork a branch
mirage workspace checkout <id> <ref>               # restore in place (version id or branch)
mirage workspace clone <src> --at <ref> --id new   # new workspace from a past version
```

| Command | Purpose |
|---|---|
| `mirage workspace commit <id> [-m MSG] [-b BRANCH]` | Commit the live state as a version. |
| `mirage workspace log <id> [-b BRANCH]` | List versions on a branch, newest first. |
| `mirage workspace diff <id> [a] [b] [-b BRANCH]` | Changed paths (added/modified/deleted). |
| `mirage workspace branch <id> <name> [--from BRANCH]` | Fork a branch at a branch's current version. |
| `mirage workspace checkout <id> <ref>` | Restore the live state in place to a version or branch. |

## Sessions

```bash
mirage session create <workspace-id> --id agent_a
mirage session list <workspace-id>
mirage session delete <workspace-id> <session-id>
```

## Daemon lifecycle

```bash
mirage daemon status      # health + PID + uptime
mirage daemon stop        # graceful shutdown (POST /v1/shutdown + SIGTERM fallback)
mirage daemon restart     # stop; next CLI command auto-spawns fresh
mirage daemon kill        # SIGKILL; last resort
```

## Configuration

Precedence (highest first):

1. **`MIRAGE_DAEMON_URL`** env var, e.g. `http://127.0.0.1:9000`.
2. **`MIRAGE_TOKEN`** env var, bearer token passed as `Authorization: Bearer <token>`.
3. **`~/.mirage/config.toml`** `[daemon]` table, managed with
   `mirage config list|get|set|unset` (per key: env var >
   `config.toml` > default; `mirage config list --resolved` shows the
   effective values and origins):
   ```toml
   [daemon]
   url = "http://127.0.0.1:8765"
   auth_token = ""
   idle_grace_seconds = 30
   port = 8765
   version_root = "/data/repos"
   ```
   The daemon validates the table at startup and refuses to start on
   unknown keys or malformed TOML. The full key list and semantics
   match the Python CLI docs.

## Python parity

The daemon speaks the same `/v1/...` protocol as Python's `mirage` CLI. A Python CLI client can talk to a Node daemon and vice versa. The CLI subcommand tree matches Python's `mirage/cli/*.py` file-for-file.

## Where things live

| File | Purpose |
|---|---|
| [`packages/server/src/app.ts`](https://github.com/strukto-ai/mirage/blob/main/typescript/packages/server/src/app.ts) | Fastify app factory. |
| [`packages/server/src/routers/`](https://github.com/strukto-ai/mirage/tree/main/typescript/packages/server/src/routers) | health / workspaces / sessions / execute / jobs. |
| [`packages/server/src/bin/daemon.ts`](https://github.com/strukto-ai/mirage/blob/main/typescript/packages/server/src/bin/daemon.ts) | `mirage-daemon` bin. |
| [`packages/cli/src/main.ts`](https://github.com/strukto-ai/mirage/blob/main/typescript/packages/cli/src/main.ts) | CLI program wiring. |
| [`packages/cli/src/{workspace,session,execute,provision,job,daemon}.ts`](https://github.com/strukto-ai/mirage/tree/main/typescript/packages/cli/src) | Per-subcommand modules. |
| [`packages/cli/src/client.ts`](https://github.com/strukto-ai/mirage/blob/main/typescript/packages/cli/src/client.ts) | HTTP client + auto-spawn. |
