Minimal control plane for multi-VM Claude Code orchestration
Project description
ocaptain
O Captain! my Captain! our fearful Claude Code session is done, The repo has weather'd every rack, the prize we sought is won.
Minimalist multi-coding agent control plane built on sprites.dev VMs with Tailscale mesh networking. Orchestration is managed by Claude Code's built-in task list feature: work is distributed by the ocaptain CLI to cloud VMs ("ships") that work in parallel on a plan you generate with Claude.
No Kubernetes, no local sandboxes, no containers, no asking for permissions.
Table of Contents
What it does
Provisions a fleet of VMs on sprites.dev, each running an autonomous Claude Code agent. Ships sync files via Mutagen and coordinate through a shared task list—no central scheduler, just agents racing to complete work.
You (local) → ocaptain sail → sprites.dev VMs → Ships claim tasks → Code syncs back
Why?
- Deploy parallel, autonomous Claude Code instances with one command
- No container complexity: full Linux VMs with direct access
- Watch Claude Code sessions in real-time via tmux
- Task-based coordination means no conflicts, no merge hell
- Local storage with Mutagen sync—no storage VM required
- Built-in OpenTelemetry observability
Quickstart
Prerequisites
- sprites.dev account with
spriteCLI installed - Tailscale installed and running
- Mutagen installed (
brew install mutagen-io/mutagen/mutagen) - Claude Code long-lived OAuth token (subscription required, from
claude setup-token) - Tailscale OAuth secret for ephemeral auth keys
Install
# Clone and install
git clone https://github.com/smithclay/ocaptain.git
cd ocaptain
uv sync
Set credentials
# Claude Code OAuth token (from `claude setup-token`)
export CLAUDE_CODE_OAUTH_TOKEN="your-token-here"
# Tailscale OAuth secret (for ephemeral ship auth keys)
export OCAPTAIN_TAILSCALE_OAUTH_SECRET="tskey-client-xxxx"
# sprites.dev org
export OCAPTAIN_SPRITES_ORG="your-org"
# Optional: GitHub token for private repos
export GH_TOKEN="ghp_xxxx"
Check prerequisites
uv run ocaptain doctor
Make a plan
At the moment, you need to use Claude Code to create a detailed dependency plan to pass to ocaptain.
Use an existing plan
For convenience, example plans are available in the examples/generated-plans directory.
Create a custom plan
In Claude Code, run the following then restart:
/plugin marketplace add smithclay/skills
/plugin install ocaptain-skills@smithclay-skills
You're now ready to generate a detailed plan in Claude Code using /voyage-plan:
Plan a voyage with ocaptain: take an empty repository and make a to-do list app.
Launch a voyage
# A plan is required, see "Make a plan" above
uv run ocaptain sail ./examples/generated-plans/multilingual-readme
# Monitor status
uv run ocaptain status
# Attach to a ship's tmux session to watch Claude work
uv run ocaptain shell voyage-abc123 ship-0
# View aggregated logs
uv run ocaptain logs voyage-abc123 --follow
# Clone the workspace when done
uv run ocaptain clone voyage-abc123
# Scuttle the fleet
uv run ocaptain sink voyage-abc123
Architecture
flowchart TB
subgraph Local["Local Machine"]
CLI[ocaptain CLI]
Voyages[(~/voyages/)]
Telemetry[OTLP Collector]
end
subgraph Tailscale["Tailscale Mesh"]
TS[100.x.x.x]
end
subgraph Sprites["sprites.dev"]
subgraph Fleet["Ship VMs"]
S0[Ship 0<br/>Claude Code]
S1[Ship 1<br/>Claude Code]
S2[Ship N<br/>Claude Code]
end
end
CLI -->|Mutagen Sync| TS
TS -->|Workspace + Tasks| Fleet
Fleet -->|Telemetry| Telemetry
S0 & S1 & S2 -->|tmux sessions| CLI
Components
| Component | Description |
|---|---|
| Local Voyages | ~/voyages/<voyage-id>/ contains workspace, tasks, logs, and artifacts |
| Ship VMs | sprites.dev VMs running Claude Code autonomously in tmux sessions |
| Tailscale Mesh | Ships join tailnet with ephemeral keys for direct connectivity |
| Mutagen Sync | Two-way file sync between laptop and ships (workspace + tasks) |
| Task List | Shared JSON files in ~/.claude/tasks/. Ships race to claim pending tasks |
Voyage Lifecycle
- Setup — Local voyage directory created, repo cloned, tasks seeded
- Bootstrap — Ship VMs provisioned in parallel, join Tailscale, install Claude
- Sync — Mutagen sessions established for workspace and tasks
- Launch — Claude starts in tmux on each ship (autonomous operation)
- Work — Ships claim tasks, do work, changes sync back via Mutagen
- Complete — All tasks done, workspace ready to clone
- Sink — VMs destroyed, Tailscale nodes removed
CLI Reference
ocaptain sail <plan>
Launch a new voyage from a plan directory.
uv run ocaptain sail ./plans/add-auth --ships 5
| Option | Description |
|---|---|
--ships, -n |
Override recommended ship count |
--no-telemetry |
Disable OTLP telemetry collection |
ocaptain status [voyage_id]
Show voyage status derived from task list. Auto-selects if only one active voyage.
uv run ocaptain status
uv run ocaptain status voyage-abc123
ocaptain logs <voyage_id>
View aggregated logs from all ships.
uv run ocaptain logs voyage-abc123
uv run ocaptain logs voyage-abc123 --follow --grep "error"
| Option | Description |
|---|---|
--ship, -s |
Filter to specific ship |
--follow, -f |
Stream logs in real-time |
--grep, -g |
Filter log lines by pattern |
--tail, -n |
Show last N lines |
ocaptain tasks <voyage_id>
Display task list with status, assignees, and blockers.
uv run ocaptain tasks voyage-abc123
uv run ocaptain tasks voyage-abc123 --status pending
ocaptain shell <voyage_id> [ship_id]
Attach to a ship's tmux session to observe Claude working.
uv run ocaptain shell voyage-abc123 ship-0 # Attach to ship's tmux
uv run ocaptain shell voyage-abc123 ship-0 --raw # Direct SSH
ocaptain clone [voyage_id]
Clone the workspace from local voyage storage.
uv run ocaptain clone # Auto-select if one voyage
uv run ocaptain clone voyage-abc123 -d ./my-copy
ocaptain sink <voyage_id>
Destroy voyage VMs and clean up.
uv run ocaptain sink voyage-abc123 # Destroy ships
uv run ocaptain sink --all -f # Destroy ALL ocaptain VMs
| Option | Description |
|---|---|
--all |
Destroy ALL ocaptain VMs |
--force, -f |
Skip confirmation |
ocaptain doctor
Check system prerequisites and configuration.
uv run ocaptain doctor
ocaptain telemetry-start / telemetry-stop
Start or stop the local OTLP telemetry collector.
uv run ocaptain telemetry-start
uv run ocaptain telemetry-stop
Configuration
Environment Variables
| Variable | Required | Description |
|---|---|---|
CLAUDE_CODE_OAUTH_TOKEN |
Yes | Claude Code authentication token |
OCAPTAIN_TAILSCALE_OAUTH_SECRET |
Yes | Tailscale OAuth secret for ephemeral keys |
OCAPTAIN_SPRITES_ORG |
Yes | sprites.dev organization name |
GH_TOKEN |
No | GitHub token for private repos |
OCAPTAIN_DEFAULT_SHIPS |
No | Default ship count (default: 3) |
sprites.dev Setup
Install the sprite CLI and authenticate:
# Test connectivity
sprite list -o your-org
# Create a test sprite
sprite create -o your-org test-sprite
Tailscale Setup
- Create an OAuth client in the Tailscale admin console with
devices:writescope - Set
OCAPTAIN_TAILSCALE_OAUTH_SECRETto the client secret - Ensure your laptop is connected to the tailnet
Security
Token Handling
- OAuth tokens passed via environment variables, not command args
- Tailscale ephemeral keys expire automatically when ships are destroyed
Network Isolation
- Ships communicate only via Tailscale mesh (no public IPs)
- Each ship is a full Linux VM with its own filesystem
- Mutagen sync scoped to specific directories
Repository Access
- Private repos require
GH_TOKEN - Token validity checked before VM provisioning
- Clone failures surface immediately, not after fleet deploys
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file ocaptain-0.0.2.tar.gz.
File metadata
- Download URL: ocaptain-0.0.2.tar.gz
- Upload date:
- Size: 9.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: uv/0.9.27 {"installer":{"name":"uv","version":"0.9.27","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
13619d4373afe1ef839220d4c368264a99b4b3722decab01c41d73127e65a4b0
|
|
| MD5 |
b2d661aad05bfd6019cb425d6f4a85b9
|
|
| BLAKE2b-256 |
3bc58a5b7ba9f2b5363467475085c947ebb9cc5346a90acee8d91aaa043633c9
|
File details
Details for the file ocaptain-0.0.2-py3-none-any.whl.
File metadata
- Download URL: ocaptain-0.0.2-py3-none-any.whl
- Upload date:
- Size: 10.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: uv/0.9.27 {"installer":{"name":"uv","version":"0.9.27","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
4bd1bd4f3d7a0e1413989869a5edcc81ed15b3809eb763f1eb0ecf2754a180d5
|
|
| MD5 |
e2b905320d06d30d78c6d3264f968b5f
|
|
| BLAKE2b-256 |
11e3c5c0101e9329df6cf897f761855519bee872c8ee7189d830bd5af1c3a1f3
|