Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.mirage.strukto.ai/llms.txt

Use this file to discover all available pages before exploring further.

The mirage CLI is a thin httpx wrapper over the Mirage daemon. It auto-spawns the daemon on first workspace create, and the daemon auto-exits 30 seconds after the last workspace is deleted. Most users never type a daemon command directly. Output is structured JSON to stdout for every verb — pipe to jq, save to file, or read it directly.

Install

curl -fsSL https://strukto.ai/mirage/install.sh | sh
Or via your package manager of choice:
npm install -g @struktoai/mirage-cli
uv add mirage-ai
pip install mirage-ai
uvx mirage-ai
npx mirage
Verify:
mirage --help

Define a workspace in YAML

A workspace is a set of prefixed mounts plus some workspace-level settings. Save this as workspace.yaml:
mode: WRITE

mounts:
  /:
    resource: ram
    mode: WRITE
  /s3:
    resource: s3
    mode: READ
    config:
      bucket: ${AWS_S3_BUCKET}
      region: ${AWS_DEFAULT_REGION}
      aws_access_key_id: ${AWS_ACCESS_KEY_ID}
      aws_secret_access_key: ${AWS_SECRET_ACCESS_KEY}
${VAR} placeholders are interpolated from your shell environment at mirage workspace create time. Missing vars fail fast with the full list, not lazily on first use.

Walkthrough

A guided tour from creating a workspace to snapshotting it. Each step builds on the previous one; you can copy them in order. For a runnable end-to-end version against a real multi-mount workspace (/s3, /gdrive, /gmail, /slack, /discord), see examples/python/cross/README.md.

1. Source env and create a workspace

The YAML’s ${...} placeholders resolve from your shell at create time, so source your env first. The daemon auto-spawns on the first create.
set -a && source .env.development && set +a

mirage workspace create workspace.yaml --id demo

2. Inspect

list is one line per workspace; get returns the full mount and session detail.
mirage workspace list
mirage workspace get demo

3. Run commands against your mounts

execute runs a shell command inside the workspace. Paths resolve through the mount registry (/s3/... hits S3, / hits the RAM backing, etc.).
mirage execute --workspace_id demo --command "ls /s3/"
mirage execute --workspace_id demo --command "head -n 1 /s3/data/example.jsonl"

4. Pipe stdin

When stdout isn’t a TTY, the CLI forwards stdin to the command automatically.
echo -e "a\nb\nc" | mirage execute --workspace_id demo --command "wc -l"

5. Dry-run with provision

provision returns a ProvisionResult (network bytes, cache hits, estimated cost) without running the command — handy for predicting spend before kicking off an expensive read.
mirage provision --workspace_id demo \
  --command "cat /s3/data/example.jsonl | wc -l"

6. Cache: network → hit after a real read

After a real cat, provision flips that path from a network read to a cache hit (cache_hits=1).
mirage execute  --workspace_id demo --command "cat /s3/data/example.jsonl > /dev/null"
mirage provision --workspace_id demo --command "cat /s3/data/example.jsonl"

7. Session traces

Every session writes a JSONL trace under /.sessions/<utc-yyyy-mm-dd>/.
mirage execute --workspace_id demo --command "ls /.sessions/"
DAY=$(date -u +%Y-%m-%d)
mirage execute --workspace_id demo --command "head -n 1 /.sessions/$DAY/*.jsonl" \
  | jq -r .stdout | jq

8. Background jobs

Long-running commands take --background and return a job_id immediately. mirage job wait blocks until it’s done.
JOB=$(mirage execute --workspace_id demo --background \
  --command "wc -l /s3/data/example.jsonl" \
  | jq -r .job_id)
mirage job wait $JOB

9. Snapshot to disk

mirage workspace snapshot demo /tmp/demo.tar

10. Restore from snapshot

Snapshots redact cloud creds at save time, so loading needs fresh creds via --override. The same workspace YAML is a valid override.
mirage workspace load /tmp/demo.tar \
  --id demo_loaded \
  --override workspace.yaml

mirage workspace get demo_loaded --verbose
mirage execute --workspace_id demo_loaded \
  --command "head -n 1 /s3/data/example.jsonl"
--override is required for any mount whose resource declares needs_override=True (S3, GDrive, Slack, Discord, Redis, …). The snapshot stores "<REDACTED>" in place of secrets at save time. Loading without --override 400s with the list of prefixes that need fresh creds. Local resources (RAM, Disk) restore as-is with no override needed.

11. Clean up

The daemon exits ~30s after the last workspace is deleted.
mirage workspace delete demo
mirage workspace delete demo_loaded

Verbs at a glance

VerbWhat it does
mirage workspace create FILE [--id NAME]Build resources from YAML, register a workspace, return its id.
mirage workspace listBrief one-line summary per active workspace.
mirage workspace get ID [--verbose]Full detail (mounts, sessions, optionally cache / dirty / history internals).
mirage workspace delete IDStop the workspace; daemon may exit on the idle timer.
mirage workspace clone ID [--id NAME] [--override FILE]Fresh local backings, shared remote resources; partial-config override swaps creds or buckets.
mirage workspace snapshot ID PATH.tarSnapshot to a tar file.
mirage workspace load PATH.tar [--id NAME] [--override FILE]Restore from tar; override re-supplies redacted creds.
mirage session create WS [--id NAME]Add a named session (own cwd + env).
mirage session list WSList sessions for a workspace.
mirage session delete WS SESSIONClose a session.
mirage execute --workspace_id WS [--session_id S] [--background] --command "..."Run a command. Pipes stdin automatically when stdout is not a TTY.
mirage provision --workspace_id WS [--session_id S] --command "..."Dry-run / cost estimate — returns a ProvisionResult shape (network bytes, cache hits, estimated cost) without running the command.
mirage job list [--workspace_id WS]List jobs the daemon has run, plus their status.
mirage job get JOBDetail for one job.
mirage job wait JOB [--timeout SECS]Block until the job is done; returns the result.
mirage job cancel JOBCancel a running job.

Daemon control

Most users never run these directly — the daemon auto-spawns on first workspace create and auto-exits after the idle timer fires (default 30s after the last workspace is deleted). When you need to intervene — typically during development, when you want code changes to take effect:
mirage daemon status              # health, PID, uptime, workspace count
mirage daemon stop                # graceful: trip exit event, falls back to SIGTERM after --timeout (default 5s)
mirage daemon restart             # stop + lazy respawn (add --eager to spawn now)
mirage daemon kill                # SIGKILL via PID file -- last resort
VerbWhat it does
mirage daemon statusDaemon health, PID, uptime, workspace count. Exit 1 if daemon not reachable.
mirage daemon stopPOST /v1/shutdown to trip the daemon’s exit event. Daemon snapshots active workspaces (if persist_dir set), closes them, exits. Falls back to SIGTERM on --timeout.
mirage daemon restartStop, then either wait for next workspace create to auto-spawn (default) or --eager to spawn immediately. Workspaces are LOST unless persist_dir is configured.
mirage daemon killSIGKILL via PID file at ~/.mirage/daemon.pid. Skips graceful shutdown — use only when stop hangs.
When you change Mirage’s source code (commands, providers, etc.), the running daemon won’t see your changes — it loaded the old code at startup. Run mirage daemon restart to pick up new code. Same situation as dockerd after recompiling Docker.

Where the daemon lives

Most users never need to think about the daemon. If you do:
  • It listens on http://127.0.0.1:8765 by default.
  • Override via MIRAGE_DAEMON_URL env var or ~/.mirage/config.toml:
    [daemon]
    url                = "http://127.0.0.1:8765"
    idle_grace_seconds = 30
    
  • Logs go to ~/.mirage/daemon.log when the CLI auto-spawns it.
  • It exits 30 seconds after the workspace count hits zero (configurable).