Raw capture โ€” raw/navaris.md


url: https://github.com/erans/navaris date_fetched: 2026-07-05 backfilled: true


A sandbox control plane for managing isolated execution environments across multiple backends.

Running untrusted or experimental code safely requires strong isolation โ€” but the tooling to manage that isolation is fragmented. Incus gives you system containers, Firecracker gives you microVMs, and each has its own API, lifecycle model, and operational quirks.

Navaris provides a single control plane that abstracts over these backends. You get a unified REST API and CLI for creating, snapshotting, and managing sandboxes regardless of whether they run as containers or microVMs. The same workflow that creates an Incus container also works for a Firecracker VM โ€” same endpoints, same state machine, same tooling.

This matters when you need to:

Navaris supports two isolation backends. You can enable one or both when starting the daemon โ€” the API and CLI work identically regardless of which backend is running underneath. When both are enabled, each sandbox is routed to the correct backend automatically.

Incus runs sandboxes as system containers using LXC. Containers share the host kernel but get their own filesystem, process tree, and network namespace.

Strengths:

Best for: development environments, CI runners, trusted workloads where speed and density matter more than hard isolation boundaries.

Firecracker runs sandboxes as lightweight virtual machines using KVM. Each sandbox gets its own guest kernel, providing hardware-level isolation.

Strengths:

Best for: running untrusted code, multi-tenant environments, security-sensitive workloads where isolation guarantees matter.

Consideration Incus Firecracker
Startup time ~1s ~2-3s
Memory overhead Minimal ~30MB per VM (guest kernel)
Isolation level Namespace/cgroup Hardware (KVM)
Host kernel shared Yes No
Requires /dev/kvm No Yes
Image management Built-in image server Manual rootfs + kernel
Live snapshots Native support Memory + disk snapshot
Density (sandboxes per host) Higher Lower

You can run both backends in a single Navaris instance โ€” containers for speed, microVMs for security โ€” behind one API. Backend selection happens automatically based on image format, or you can specify it explicitly per sandbox.

navaris (CLI)  โ”€โ”€HTTPโ”€โ”€โ–ถ  navarisd (daemon)  โ”€โ”€โ–ถ  Incus / Firecracker
                              โ”‚
                              โ”œโ”€โ”€ REST API + WebSocket events
                              โ”œโ”€โ”€ Service layer (business logic)
                              โ”œโ”€โ”€ SQLite (state persistence)
                              โ”œโ”€โ”€ Async dispatcher (operation queue)
                              โ””โ”€โ”€ OpenTelemetry (metrics + traces)

For Firecracker, a lightweight guest agent (navaris-agent) runs inside each VM and communicates with the daemon over vsock for command execution and session management.

The fastest way to try Navaris is the prebuilt all-in-one image on Docker Hub:

docker run --rm -it \
  --privileged \
  --device /dev/kvm \
  -p 8080:8080 \
  erans/navaris:latest

The image bundles both backends (Incus + Firecracker), the embedded Web UI, and a Firecracker-compatible kernel. Multi-arch โ€” linux/amd64 and linux/arm64 are both published.

Key flags:

Pin to a specific release for reproducibility:

docker run --rm -it --privileged --device /dev/kvm -p 8080:8080 \
  erans/navaris:v0.1.0

Available tags are listed at https://hub.docker.com/r/erans/navaris/tags. The image is built from the top-level Dockerfile by the Publish Docker image GitHub Actions workflow on each tagged release.

For native Linux installs with systemd, release packaging notes live in docs/native-install.md.

Release tarballs also include scripts/install-native.sh for direct host installation.

# Incus backend only
go build -tags incus -o navarisd ./cmd/navarisd
# Firecracker backend only
go build -tags firecracker -o navarisd ./cmd/navarisd
# Both backends (recommended)
go build -tags firecracker,incus -o navarisd ./cmd/navarisd
# CLI (no build tags needed)
go build -o navaris ./cmd/navaris
# MCP stdio binary (for AI agents โ€” see docs/mcp.md)
go build -o navaris-mcp ./cmd/navaris-mcp
# Guest agent (for Firecracker VMs)
GOOS=linux GOARCH=amd64 go build -o navaris-agent ./cmd/navaris-agent
# With Incus only
./navarisd --incus-socket /var/lib/incus/unix.socket --auth-token mysecret
# With Firecracker only (requires /dev/kvm)
./navarisd \
  --firecracker-bin /usr/local/bin/firecracker \
  --jailer-bin /usr/local/bin/jailer \
  --kernel-path /var/lib/firecracker/vmlinux \
  --image-dir /var/lib/firecracker/images \
  --auth-token mysecret
# Both backends simultaneously
./navarisd \
  --incus-socket /var/lib/incus/unix.socket \
  --firecracker-bin /usr/local/bin/firecracker \
  --jailer-bin /usr/local/bin/jailer \
  --kernel-path /var/lib/firecracker/vmlinux \
  --image-dir /var/lib/firecracker/images \
  --auth-token mysecret

When both --incus-socket and --firecracker-bin are provided, navarisd enables both backends. If KVM is not available, Firecracker is disabled with a warning and Incus continues to work.

Backend selection for new sandboxes follows this priority:

Flag Default Description
--listen :8080 Address to listen on
--db-path navaris.db Path to SQLite database
--log-level info Log level (debug, info, warn, error)
--auth-token (empty) Bearer token for API auth (empty = no auth)
--incus-socket Path to Incus unix socket
--firecracker-bin Path to Firecracker binary
--jailer-bin Path to jailer binary
--kernel-path Path to vmlinux kernel
--image-dir Directory containing rootfs images
--chroot-base /srv/firecracker Jailer chroot base directory
--snapshot-dir /srv/firecracker/snapshots Snapshot storage directory
--host-interface (auto-detect) Network interface for masquerade
--enable-jailer true Use the Firecracker jailer (disable for Docker)
--firecracker-default-vcpu 1 Default vCPU count for Firecracker sandboxes when cpu_limitis unset on the API
--firecracker-default-memory-mb 256 Default memory (MB, treated as MiB by Firecracker) when memory_limit_mbis unset
--storage-mode auto CoW backend selection: auto(probe) /copy/reflinkโ€” see docs/storage-backends.md
--incus-strict-pool-cow false Fail startup if the Incus storage pool driver is not CoW-capable (default: warn only)
--concurrency 8 Max concurrent operations
--gc-interval 5m Operation garbage collection interval
--otlp-endpoint (empty) OTLP collector endpoint (empty = telemetry disabled)
--otlp-protocol grpc OTLP transport: grpcorhttp
--service-name navarisd Service name in telemetry data
--mcp-enabled false Mount the embedded MCP endpoint (see docs/mcp.md)
--mcp-read-only false Hide mutating MCP tools when --mcp-enabledis set
--mcp-path /v1/mcp Path to mount the MCP endpoint at
--mcp-max-timeout 10m Cap on per-tool timeout_secondsfor MCP calls

Navaris ships with an optional web UI for inspecting projects, sandboxes, and events, triggering lifecycle actions, and attaching to sandbox terminals. It is disabled by default.

Pass --ui-password to navarisd:

navarisd --ui-password "$(openssl rand -base64 24)" --auth-token your-tokenThe UI is served from the root of the listen address. Visit http://HOST:8080/, sign in with the password, and you're in. API endpoints for the UI itself live under /ui/ (/ui/login, /ui/logout, /ui/me) and are not meant to be visited directly.

Flag Env var Description
--ui-password NAVARIS_UI_PASSWORD Password required to sign in. Leaving it unset disables the UI entirely.
--ui-session-key NAVARIS_UI_SESSION_KEY Base64-encoded 32-byte key used to sign session cookies. Auto-generated at startup if omitted โ€” existing sessions are invalidated on every restart in that case.
--ui-session-ttl NAVARIS_UI_SESSION_TTL How long a session cookie is valid (default 24h).

make web-deps web-build build-uiThe SPA sources live in web/. See web/MANUAL_TERMINAL_SMOKE.md for a manual smoke-test procedure.

Navaris exposes its API as a Model Context Protocol server so AI agents (Claude Desktop, Claude Code, and other MCP clients) can manage sandboxes as tools. 22 tools cover the full lifecycle: projects, sandboxes, sessions, snapshots, images, and operations.

Two transports are supported:

# Embedded mode โ€” same listener as the REST API
./navarisd --auth-token mysecret --mcp-enabled
# /v1/mcp now accepts MCP requests with Authorization: Bearer mysecret
# Read-only mode hides every mutating tool
./navarisd --auth-token mysecret --mcp-enabled --mcp-read-only

Security:Running--mcp-enabledwithout--auth-tokenexposes mutating tools to unauthenticated requests; the daemon logs a warning at startup when this combination is detected.

See docs/mcp.md for the full tool catalog, env-var reference, and per-tool argument schemas.

Navaris ships a Claude Code skill pack (navaris-cli) so you can ask Claude Code in plain English to drive the CLI for you โ€” "spin up an alpine sandbox and run my tests", "snapshot this sandbox before I upgrade it". Install with:

/plugin marketplace add erans/navaris
/plugin install navaris-cli@navaris

See docs/claude-skills.md for the full skill list, install/uninstall, and MCP-vs-skill tradeoffs.

Configure the CLI via flags or environment variables:

export NAVARIS_API_URL=http://localhost:8080
export NAVARIS_TOKEN=mysecret
# Create a project
navaris project create --name my-project
# Create an Incus container (auto-detected from image format)
navaris sandbox create --project <project-id> --name dev --image alpine/3.21
# Create a Firecracker VM (auto-detected from image format)
navaris sandbox create --project <project-id> --name secure --image alpine-3.21
# Or specify backend explicitly
navaris sandbox create --project <project-id> --name dev --image alpine/3.21 --backend incus
# Wait for it to start, then run a command
navaris sandbox exec --sandbox <sandbox-id> -- echo "hello from the sandbox"
# Create a snapshot
navaris snapshot create --sandbox <sandbox-id> --label checkpoint-1
# Stop and destroy
navaris sandbox stop <sandbox-id>
navaris sandbox destroy <sandbox-id>
Command Description
project create/list/get/update/delete Manage projects
sandbox create/list/get/start/stop/destroy/exec Manage sandboxes
sandbox wait-state <id> --state running Block until a sandbox reaches a target state
sandbox attach <id> Attach a TTY to a sandbox session over WebSocket
snapshot create/list/get/restore/delete Manage snapshots
image list/get/promote/register/delete Manage base images
session create/list/get/destroy Manage interactive sessions
operation list/get/wait/cancel Track async operations ( waitblocks until terminal)
port create/list/delete Manage port bindings

Use navaris <command> --help for detailed usage of each command. Pass --quiet (-q) on operation commands to print only the resulting ID, useful for shell pipelines.

All endpoints are under /v1/. Authentication is via Authorization: Bearer <token> header when --auth-token is set.

Method Path Description
GET /v1/health Health check
POST /v1/projects Create project
GET /v1/projects List projects
GET /v1/projects/{id} Get project
PUT /v1/projects/{id} Update project
DELETE /v1/projects/{id} Delete project
POST /v1/sandboxes Create sandbox
POST /v1/sandboxes/from-snapshot Create sandbox from snapshot
POST /v1/sandboxes/from-image Create sandbox from image
GET /v1/sandboxes List sandboxes
GET /v1/sandboxes/{id} Get sandbox
POST /v1/sandboxes/{id}/start Start sandbox
POST /v1/sandboxes/{id}/stop Stop sandbox
POST /v1/sandboxes/{id}/destroy Destroy sandbox
POST /v1/sandboxes/{id}/exec Execute command
POST /v1/sandboxes/{id}/snapshots Create snapshot
GET /v1/sandboxes/{id}/snapshots List snapshots
GET /v1/snapshots/{id} Get snapshot
POST /v1/snapshots/{id}/restore Restore snapshot
DELETE /v1/snapshots/{id} Delete snapshot
POST /v1/images Promote snapshot to image
POST /v1/images/register Register external image
GET /v1/images List images
GET /v1/images/{id} Get image
DELETE /v1/images/{id} Delete image
POST /v1/sandboxes/{id}/sessions Create session
GET /v1/sandboxes/{id}/sessions List sessions
GET /v1/sessions/{id} Get session
DELETE /v1/sessions/{id} Delete session
POST /v1/sandboxes/{id}/ports Publish port
GET /v1/sandboxes/{id}/ports List ports
DELETE /v1/sandboxes/{id}/ports/{target_port} Remove port
GET /v1/operations/{id} Get operation
GET /v1/operations List operations
POST /v1/operations/{id}/cancel Cancel operation
GET /v1/events Event stream (WebSocket)
GET /v1/sandboxes/{id}/attach Attach to a session over WebSocket
POST/GET /v1/mcp MCP server endpoint (mounted when --mcp-enabled; see docs/mcp.md)

Integration tests use Docker Compose to spin up the full stack.

# Incus backend
make integration-test
# Firecracker backend (requires /dev/kvm)
make integration-test-firecracker
# Mixed: both backends in one navarisd (requires /dev/kvm)
make integration-test-mixed

Dev environments for manual testing:

make integration-env                # Incus
make integration-env-firecracker    # Firecracker
make integration-env-down           # tear down Incus
make integration-env-firecracker-down  # tear down Firecracker

go test ./...Apache License 2.0 โ€” see LICENSE for details.