A kubernetes-like control plane for AI agent workloads. Manages the full lifecycle of BYOA (Bring Your Own Agent) sessions: scheduling, configuration, process management, health monitoring, and rolling shifts.
Where kubernetes orchestrates containers across nodes, marvel orchestrates agent sessions across tmux panes.
brew tap arcavenae/tap # one-time (Homebrew >= 6.0 needs the tap trusted first)
brew install arcavenae/tap/marvelThe tap's marvel formula currently tracks the latest alpha release. A dedicated stable formula will be added when the first v* release ships.
mise is a polyglot version manager. It reads a per-project mise.toml, pulls the binary directly from GitHub Releases, and verifies GitHub Artifact Attestations natively — no Homebrew tap required.
Alpha channel (prereleases from main) — the first stable release is pending, so opt into prereleases per-tool:
# mise.toml
[tools]
"github:ArcavenAE/marvel" = { version = "latest", prerelease = true }mise install
marvel versionStable (when a v* release ships) — drop the prerelease = true flag:
mise use github:ArcavenAE/marvel@latestMarvel's alpha assets are not -a-suffixed, so stable and alpha share the same marvel shim — mise pins one version at a time per mise.toml, and switching channels swaps the underlying binary.
macOS troubleshooting — if a quarantine-aware host copies the mise install and Gatekeeper blocks launch, clear the xattr once:
xattr -d com.apple.quarantine "$(mise which marvel)"Download the latest release from GitHub Releases. Binaries are available for macOS (arm64, amd64) and Linux (amd64, arm64 — Raspberry Pi 3/4/5 64-bit, AWS Graviton, etc.). macOS binaries are code-signed and Apple-notarized.
# Build
just build
# Start the daemon
marvel daemon &
# Load a manifest
marvel work examples/demo.toml
# Watch sessions
marvel get sessions -w
# Trigger a rolling shift (replace all sessions with fresh ones)
marvel shift demo/squad
# Clean up
marvel stop --teardownWorkspace isolation boundary (k8s namespace)
└─ Team cohesive unit of agents (k8s deployment)
└─ Role one kind of agent: name, replicas, runtime, healthcheck
└─ Session one agent process in a tmux pane (k8s pod)
A team contains heterogeneous roles. A review team might have 1 supervisor, 3 reviewers, and 1 architect — each with its own runtime, replica count, restart policy, and healthcheck config.
Resources are declared in TOML manifests:
[workspace]
name = "my-project"
[[team]]
name = "review-squad"
[[team.role]]
name = "reviewer"
replicas = 3
[team.role.runtime]
command = "/usr/local/bin/forestage"
args = ["--persona", "dune/reviewer"]
[team.role.healthcheck]
type = "heartbeat"
timeout = "30s"
failure_threshold = 3
[[team.role]]
name = "supervisor"
replicas = 1
restart_policy = "always"
[team.role.runtime]
command = "/usr/local/bin/forestage"
args = ["--persona", "dune/supervisor"]# Daemon and manifests
marvel daemon # start the daemon
marvel work <manifest.toml|.yaml> # load manifest, reconcile desired state
marvel stop # stop daemon, detach (agents keep running, adopted on restart)
marvel stop --teardown # stop daemon and end every agent
# Inspect
marvel get sessions # list sessions (-w for watch mode); shows CPU% and RSS per session
marvel get teams # list teams and roles
marvel get workspaces # list workspaces
marvel get endpoints # list endpoints
marvel describe session <key> # session details
marvel events # recent session/team state-transition events (incl. agent.* for observed runtimes)
# Lifecycle
marvel scale <ws/team> --role <r> --replicas N # scale a role
marvel shift <ws/team> [--role <r>] # rolling shift
marvel run <cmd> [args...] --role <r> # one-off session
marvel kill <session-key> # kill a session (alias: delete session)
marvel delete <resource> <key> # delete a session, team, or workspace
# Session interaction
marvel capture <session-key> # capture a session's pane content
marvel inject <session-key> <keys> # send keystrokes to a pane (executive privilege)
# Remote daemons (named clusters)
marvel config add-cluster <name> ... # add or update a cluster
marvel config list # list configured clusters
marvel config current # show the current cluster
marvel config use-cluster <name> # switch the current cluster
marvel config remove-cluster <name> # remove a cluster
# SSH keys (client auth to a daemon)
marvel keys generate # generate a client keypair
marvel keys show # print a client public key to share with a daemon admin
marvel keys list # list local client keypairs
marvel keys trust <cluster> # record a cluster's host key in known_hosts
marvel keys authorize <pubkey> # authorize a client's key on this daemon
marvel keys authorized # list clients authorized on this daemon
marvel keys revoke <fingerprint> # revoke a client
marvel keys doctor # audit (and optionally fix) permissions under ~/.marvel/
# Version and self-upgrade
marvel version # print version and channel
marvel upgrade # upgrade to the latest releasestop defaults to detach: the daemon checkpoints state and exits while
agents keep running; the next marvel daemon adopts the live panes. Use
--teardown to end every agent and leave the machine clean.
marvel events includes agent.* events (session start/end with cost and
timing, tool calls, permission prompts) for runtimes marvel can observe,
today a headless stream-json launch (see examples/claude-headless.toml).
Shifts are rolling replacements of agent sessions. Agent sessions accumulate context, drift, and stale mental models. A shift starts fresh sessions, verifies they're running, then drains the old ones — preserving team identity.
# Shift all roles (workers first, supervisor last)
marvel shift my-project/review-squad
# Shift only one role
marvel shift my-project/review-squad --role reviewerSessions track their generation (visible in marvel get sessions as the GEN
column). During a shift, old-generation sessions drain one per reconciliation
tick while new-generation sessions are already running.
Roles can configure healthchecks. Currently supported: heartbeat (agent must
send periodic heartbeats to the daemon) and process-alive (tmux pane exists).
[team.role.healthcheck]
type = "heartbeat" # "heartbeat" or "process-alive"
timeout = "30s" # heartbeat staleness threshold
failure_threshold = 3 # consecutive failures before actionRestart policies control what happens when a session is unhealthy:
always(default): delete and recreateon-failure: delete and recreate only if failednever: mark failed, don't restart
Sessions without a configured healthcheck stay in unknown health state
and are never restarted by health evaluation.
| Manifest | What it shows |
|---|---|
examples/demo.toml |
3 agents + chaos supervisor with healthchecks |
examples/demo2.toml |
5 agents + chaos supervisor (larger team) |
examples/review-team.toml |
Multi-role team: reviewers, architect, supervisor |
examples/shift-demo.toml |
Minimal team for demonstrating shifts |
examples/claude.toml |
Real Claude Code agents (requires claude CLI) |
just build # build marvel + simulator
just test # run all tests
just demo # load demo manifest, show state
just demo-shift # demonstrate shift lifecycle
just watch # watch sessions (interactive)
just shift <team> # trigger a shift
just scale <t> <r> <n> # scale a role
just start # start daemon (foreground)
just stop # stop daemon
just clean # kill tmux sessions, remove binariesWritten in Go. The daemon manages agent sessions through a tmux substrate:
- Reconciliation loop (2s interval): compares desired state (manifests) with actual state (running sessions), creates/deletes to match
- Health evaluation: checks heartbeat staleness, applies restart policies
- Shift state machine: launching → draining → complete, driven by the reconciliation loop
- Usage accountant: derives context-window occupancy from each harness's own usage reporting, feeding the CTX% column (see user-guide)
- Simulator: context pressure simulation for testing without real agents
Marvel works with any BYOA console that accepts a prompt on stdin:
forestage, zclaude, dclaude, bare claude CLI, or custom agents.
The runtime is just a command path + args. Marvel doesn't care what
the agent is — it manages the process lifecycle.
- Go 1.25+
- tmux
just(command runner)