CLI Reference
The Maritime CLI lets you deploy and manage agents from your terminal. First time here? The quickstart walks the happy path; this page is the full reference.
Driving this CLI from an LLM? There's a ready-made instructions file at maritime.sh/docs/cli/llms.txt. Copy it into your agent's context (CLAUDE.md, AGENTS.md, or a system prompt) and it knows the auth flow, the JSON contract, and the gotchas. Guide: Drive Maritime from an AI agent.
Installation
npm install -g maritime-cliRequires Node.js 18 or later. The package installs a native binary for macOS, Linux or Windows (x64 and arm64).
Authentication
maritime login
With no flags the CLI prints a short code and a URL. Approve the code in any signed-in browser (Google and GitHub accounts work too) and the CLI saves the issued token. This works on headless servers and over SSH. Email and password accounts can sign in without a browser. For CI, skip login and set MARITIME_TOKEN.
maritime login # code + URL, approve in a browser
maritime login --json # code and URL as one JSON line on stderr
# Email/password accounts, no browser:
maritime login --email user@example.com --password '...'
# CI: no stored login, the CLI reads the env var first
export MARITIME_TOKEN=mk_xxxxxxxxxxxx| Flag | Description |
|---|---|
| --email, --password | Sign in with email and password, no browser |
| --device | Use the device-code approval (the default flow) |
| --native | Use Maritime's own login even when the API offers Okibi Identity |
| --headless | Use a non-browser login path |
A new account must click the link in its verification email before it can create, deploy or mint keys. To get the email again, sign in at maritime.sh/login; the page offers to resend it.
maritime signup
Create a Maritime account with email and password and save its session. -e and -p are required; the CLI does not prompt.
maritime signup -e user@example.com -p 'a long password' -n "Jane Doe"| Flag | Description |
|---|---|
| -e, --email | Email address (required) |
| -p, --password | Password (required) |
| -n, --name | Display name (optional) |
maritime logout
Log out and clear stored credentials.
maritime logoutmaritime whoami
Show the current credential: its source (MARITIME_TOKEN or a saved login), the user, and the expiry. With --json it prints { authenticated, source, method, expires_at } (plus email when known). It exits 4 when no credential is set or a login token has expired. It reads the credential locally and does not call the API, so a revoked mk_ key still shows as authenticated; maritime doctor checks auth against the API.
maritime whoami --json
maritime doctormaritime keys
Mint a long-lived API key (mk_…) for non-interactive use. Set it as MARITIME_TOKEN so an AI agent, script, or CI never runs an interactive login. Keys never expire unless you pass --expires-in-days; revoke anytime.
# Mint a key (shown once, store it securely):
maritime keys create --name my-agent --json
# Default is FULL access (provision,deploy,secrets,manage). Narrow it for
# anything you hand to an agent or CI ("manage" can mint further keys):
maritime keys create --name ci-deploy --scopes deploy
# Expire after 30 days, or restrict to one project:
maritime keys create --name temp --expires-in-days 30
maritime keys create --name tenant --project-id <project_id>
# Use it everywhere:
export MARITIME_TOKEN=mk_xxxxxxxxxxxx
# List / revoke:
maritime keys list
maritime keys revoke <key_id>Projects: a directory is an agent
Like vercel or railway, you can link a directory to an agent. After that, the agent argument is optional on every command; the CLI resolves the linked agent by walking up from the current folder. Two files: maritime.json (committed config: name, template, persona, env keys) and .maritime/ (the machine-local link, git-ignored).
maritime init support-bot # scaffold maritime.json + AGENTS.md, create & link
maritime chat "what's open?" # talks to support-bot, no name needed
maritime logs # support-bot's logs
maritime deploy # reconcile the agent to maritime.json, then redeploymaritime init
Scaffold maritime.json + AGENTS.md (and the Claude Code skill for this CLI), create the agent, and link this directory to it. Defaults the template to openclaw and the name to the folder.
maritime init # name from the folder
maritime init support-bot # explicit name
maritime init support-bot --instructions "Answer support tickets"
maritime init bot --framework custom # your own code, no template
maritime init bot --no-create # just write the config filesmaritime link
Link this directory to an existing agent (interactive picker if no name is given). Re-run to change it.
maritime link support-bot
maritime link # pick from your agentsAgent Management
maritime create
Create a new agent. Just give it a name: the platform picks an applicable size for the framework, and the agent auto-sleeps when idle and wakes on the next message. No sizing required.
maritime create my-agent
# From a template (see maritime templates):
maritime create researcher --template openclaw
# With initial environment variables:
maritime create my-agent -e OPENAI_API_KEY=sk-... -e MY_VAR=hello
# From a GitHub repo (must contain a Dockerfile), served on a public URL:
maritime create my-app --repo https://github.com/you/app --public --port 3000Serving a repo on a public URL is covered in Public web agents.
| Argument / flag | Description |
|---|---|
| <name> | Agent name (positional) |
| -t, --template | Template to base the agent on (see maritime templates) |
| -e, --env | Environment variables as KEY=value (repeatable) |
| -r, --repo | Deploy from a GitHub repo (must contain a Dockerfile) |
| -b, --branch | Git branch to deploy (with --repo) |
| --public | Serve a public, no-login web URL for this agent (web apps) |
| --port | Port your app listens on (exposed publicly; default 8080) |
| --count | Create N identical agents named <name>-1 to <name>-N |
| --claim-later | No account needed: create one agent under a temporary account for 72 hours. The response carries a claimUrl the user opens to keep it, and a temporary token for that agent |
Advanced: per-agent resource overrides. All optional; omit them and the agent gets the platform defaults. Useful for hand-tuning a single agent (e.g. a reseller dialing resources per client).
maritime create acme-bot --ram 2048 --cpu 1.5 --idle 600 --disk 20| Flag | Description |
|---|---|
| --ram | RAM in MB (per-agent override of the default) |
| --cpu | vCPU cores, e.g. 0.5 or 2 (per-agent override) |
| --idle | Auto-sleep N seconds after the last request |
| --disk | Workspace SSD in GB (clamped to your plan cap) |
| --framework | Framework when not using a template (default: custom) |
Network settings
What the agent may reach on the internet, where its traffic exits, and which of your private systems it may use. The same flags work on maritime agents create, maritime agents update, and maritime computers create. Read what is in force with maritime agents network <agent_id> and try a destination from inside with maritime agents network test <agent_id> <host:port>. Presets live under maritime network presets, and maritime connect makes this machine a private network your agents can reach. Full reference: Networks.
maritime agents create --name worker --template-id codex \
--internet list --network-policy coding --allow-out api.example.com
maritime agents update <agent_id> --egress fixed --access db.office.private
maritime agents network test <agent_id> api.example.com:443
maritime network presets list
maritime network presets create --name internal --allow '*.corp.example.com' --deny 169.254.0.0/16
maritime connect --allow localhost:5432 # runs until Ctrl+C| Flag | Description |
|---|---|
| --internet | all, none, or list. --allow-out implies list |
| --allow-out | One allow entry, repeatable: domain, *.domain, IPv4 address, or CIDR; none clears |
| --deny-out | One deny entry (IPv4 address or CIDR), repeatable; deny wins over allow; none clears |
| --network-policy | A preset by name or id (coding, llm-apis, or your own); none clears |
| --egress | shared, fixed, country:<CC>, or through:<network> |
| --access | One private resource by address or id, repeatable; none clears |
maritime list
List your agents: a table on a terminal, JSON when piped or with --json. Alias: maritime ls
maritime list
maritime list --json | jq -r '.results[].name'maritime deploy
Deploy an agent. Accepts an agent name or ID prefix.
maritime deploy my-agent
# Deploy from a GitHub repo:
maritime deploy my-agent --source github --repo https://github.com/user/repo
# Deploy a specific Docker image:
maritime deploy my-agent --source docker --image myimage:latest| Flag | Description |
|---|---|
| --source | Deploy source: template, github, or docker |
| --repo | GitHub repository URL |
| --image | Docker image name |
| --branch | Git branch (for GitHub deploys) |
| -w, --wait | Block until the deployment completes (useful in scripts and CI) |
maritime start / stop / restart
Manual lifecycle control, rarely needed. Serverless agents auto-sleep when idle and auto-wake on the next message or trigger; reach for these for ops or debugging.
maritime start my-agent
maritime stop my-agent
maritime restart my-agentmaritime delete
Delete an agent. On a terminal it asks you to type the agent name; without a terminal it refuses (exit 2) unless --yes is passed.
maritime delete my-agent
# Skip confirmation:
maritime delete my-agent --yesTalking to agents
maritime chat
Send a message to a running agent and print its reply. Reads the message from arguments or stdin (handy for long prompts). Sleeping serverless agents auto-wake. Alias: maritime send.
maritime chat my-agent "summarize today's incidents"
# Long prompt via stdin:
cat prompt.txt | maritime chat my-agent
# Multi-turn with a conversation id:
maritime chat my-agent "and the one before?" --conversation-id abc123
# Machine-readable (returns { agent_id, agent_name, conversation_id, response }):
maritime chat my-agent "hi" --json
# Inside a linked directory every argument is the message, so name another agent with -a:
maritime chat -a other-agent "hi"maritime message
Send a message through an agent's project front door as one of your end users. The same --user always reaches the same instance. --wait is 0 to 60 seconds (default 30).
maritime message my-agent --user cust_42 "where is my order?" --json | jq -r '.data.reply'Your end users
An end user is one of your users, keyed by the id you already hold for them. Their agents, spend caps, delegated tokens and costs hang off that record; the Users page shows the same list and the SDK guide covers the model. The CLI is for support work and scripts.
maritime end-users
Alias: maritime users. Commands that take a body read it from --body-json (or --stdin); the fields are the ones in the REST API.
# Create or update one (safe to run on every sign-in):
maritime users upsert user_42 --display-name "Ada" --tags pro
# Their agent, exactly once (a repeat call returns the same agent):
maritime users create user_42 --body-json '{"templateId":"openclaw"}'
maritime users agents user_42
# Caps and sizing, applied to every agent they own (set-policy replaces the whole policy):
maritime users set-policy user_42 --body-json '{"policy":{"llm_spend_cap_cents_per_month":500,"wakes_per_hour":60}}'
maritime users policy user_42
maritime users clear-policy user_42
# A short-lived eu_ token for their own browser or app (shown once):
maritime users token user_42 --body-json '{"scopes":["chat","files"],"ttlSeconds":900}' --json
maritime users revoke-token user_42
# Find, inspect, suspend, resume, delete:
maritime users list --limit 50
maritime users get user_42
maritime users suspend user_42
maritime users resume user_42
maritime users delete user_42 # agents and tokens go with itPolicy fields: llm_spend_cap_cents_per_month, compute_minutes_cap, wakes_per_hour, idle_sleep_seconds, mem_mb, vcpus, disk_gb. Token scopes: chat, files, console, logs, app; the TTL is 30 to 3600 seconds (default 900).
Observability
maritime logs
View logs from an agent.
maritime logs my-agent
# Show last 100 lines:
maritime logs my-agent -n 100
# Filter by level:
maritime logs my-agent --level error
# Stream logs live:
maritime logs my-agent -f| Flag | Description |
|---|---|
| -n, --lines | Number of log lines to show (default: 50) |
| --level | Filter by level: info, warn, error, or debug |
| -f, --follow | Follow log output (stream new lines as they arrive) |
maritime env
Manage environment variables for an agent.
# List variables:
maritime env list my-agent
# Set one or more (marked secret + encrypted by default):
maritime env set my-agent OPENAI_API_KEY=sk-... ANOTHER=value
# Bulk import from a .env file (or stdin), then hot-reload:
maritime env import my-agent ./prod.env --reload
# Set a non-secret variable:
maritime env set my-agent LOG_LEVEL=debug --no-secret
# Remove a variable:
maritime env remove my-agent LOG_LEVEL
# Apply pending changes to a running agent without a full restart:
maritime env reload my-agent
# Pull the agent's env into a local .env file (secret values are masked):
maritime env pull my-agent .envEnv changes apply on the next container boot unless you pass --reload (or run maritime env reload). Secrets behavior is covered in Env vars & sizing.
maritime status
Print one agent's record from the API, including its status.
maritime status my-agentmaritime usage
What your agents cost over a range: usage get per agent, usage daily per day. --from and --to take ISO dates (default: the last 30 days). Every agent row carries its externalUserId; group on it for a per-user bill. Under a seat plan the hosting number is your plan price allocated over your agents day by day; AI is the real spend from your credits.
maritime usage get --json # last 30 days, per agent
maritime usage daily --from 2026-10-01 --to 2026-10-08
maritime usage get --from 2026-09-01 --to 2026-10-01 --json \
| jq '.results.agents | group_by(.externalUserId) | map({user: .[0].externalUserId, cents: (map(.totalCostCents) | add)})'maritime info
Show an agent with its env var count, triggers, and last deployment.
maritime info my-agentmaritime history
Show deployment history for an agent: every build/deploy attempt with its outcome.
maritime history my-agent
# Show last 30 deployments:
maritime history my-agent -n 30maritime triggers
Manage the cron/webhook/telegram/discord triggers wired to an agent. Subcommands, not a bare argument:
maritime triggers list my-agent
maritime triggers create my-agent --type cron --cron "0 9 * * *" --prompt "post the daily digest"
maritime triggers create my-agent --type webhook
maritime triggers delete my-agent <trigger-id>A cron trigger wakes the agent on schedule and delivers --prompt as a message on each fire, or the agent can publish its own schedule (see Triggers & schedules).
Lifecycle
maritime sleep
Put an active agent to sleep. Sleeping agents keep their full state, still count against your plan, and auto-wake on triggers. (Wake timings and the full model are in How Maritime works.)
maritime sleep my-agentmaritime open
Open the agent's dashboard page in your default browser.
maritime open my-agentDiscovery
maritime templates
List available agent templates. This command does not require authentication.
maritime templatesmaritime guide
Print the machine-readable usage guide for driving the CLI from code or an AI agent. --json emits a one-shot manifest of every command, flag, and the contract, introspected live so it can't drift.
maritime guide # human-readable contract
maritime guide --json # full command/flag manifestmaritime exec
Runs a non-interactive command in an agent. It takes the full agent ID (no name lookup) and a required --body-json with the REST exec body: command (a string or an array of strings), and optionally detached and timeout in seconds (default 60 attached, 3,600 detached). Words after the agent ID are not sent.
maritime exec <agent_id> --body-json '{"command":"ls /data"}' --json | jq -r '.results.stdout'
maritime exec <agent_id> --body-json '{"command":"npm run build","detached":true,"timeout":600}'The result has executionId, status, exitCode, stdout, and stderr. A detached call returns the ID at once; fetch or cancel the run through the REST API. Older agents return combined output in stdout and omit executionId and status.
More commands
These take IDs, not names. Run any of them with --help for every flag, and --dry-run to print the request without sending it.
# Agents by ID
maritime agents update <agent_id> --instructions "..." --name new-name
maritime agents url visibility <agent_id> public
maritime agents url share <agent_id> --ttl-seconds 86400 --end-user customer_42
maritime agents upload-source ./my-harness # then agents create --upload-key
maritime agents create --name my-harness --from-dir ./my-harness
# Files in an agent's volume
maritime files list <agent_id> --path /data
maritime files upload <agent_id> ./report.pdf --dest-dir /data/reports
maritime files download <agent_id> --path /data/out.csv
maritime files write <agent_id> --path /data/notes.md --content "hello"
# Computers (os: linux, windows or android; arch: x86_64 or arm64 for android)
maritime computers create --body-json '{"name":"desk-1","os":"windows"}'
maritime computers list
maritime computers get <computer_id>
maritime computers delete <computer_id>
# Ephemeral sandboxes: a sandbox (sbx-...) that ends when its lifetime ends
maritime sandboxes ephemeral create --name job-42 --lifetime 30m --size small
maritime sandbox exec <sandbox_id> -- uname -a
maritime sandboxes ephemeral extend <sandbox_id> --lifetime 1h
maritime sandboxes ephemeral kill <sandbox_id>
# Swarms: one command on many ephemeral sandboxes
maritime swarms run --count 10 --command "python eval.py" --wait
maritime swarms run --inputs inputs.jsonl --command "python eval.py" --size 2x4 --timeout 10m
maritime swarms list
maritime swarms get <swarm_id>
maritime swarms cancel <swarm_id>
maritime swarms results <swarm_id> -o results.jsonl
# Outbound webhooks, projects, deployments
maritime webhooks create --body-json '{"url":"https://example.com/hook","events":[]}'
maritime projects list
maritime projects instances <project_id>
maritime deployments for-agent <agent_id>
maritime deployments create --agent-id <agent_id> --repo https://github.com/acme/agent --branch main
# Health and tools
maritime env pull my-agent .env -f # -f overwrites an existing file
maritime doctor # auth and connectivity
maritime mcp # serve these commands as MCP tools over stdioScripting & AI agents
Handing the CLI to Claude, Cursor, or another assistant? There's a ready-made prompt and a walkthrough on Drive Maritime from an AI agent; the tables below are the underlying contract.
The CLI is built to be driven non-interactively. Authenticate with the MARITIME_TOKEN env var (an mk_… key from maritime keys create), pass --json on every command, and branch on the exit code.
With --json, results go to stdout. Reads print { meta, results }; writes print { action, resource, path, status, success, data }; chat, status and whoami print their object directly. Errors print Error: ... on stderr, with the HTTP status and the API's response body for API errors. A 409 also prints {"error": "...", "code": 5} on stdout. The global --agent flag sets --json --compact --no-input --no-color --yes at once; --compact keeps only key fields, so leave it off when you need the full response.
export MARITIME_TOKEN=mk_xxxxxxxxxxxx
# results on stdout, errors on stderr, branch on exit code:
maritime list --json | jq -r '.results[] | select(.status=="error") | .name'
reply=$(maritime chat my-agent "status?" --json | jq -r '.response')| Exit code | Meaning |
|---|---|
| 0 | success |
| 1 | other error (network, unexpected) |
| 2 | usage (unknown flag, missing argument, missing --yes) |
| 3 | not found (HTTP 404, no such agent) |
| 4 | auth (no credential, expired, HTTP 401 or 403, including email_not_verified) |
| 5 | API error (other HTTP errors, such as 402, 409, 422, 5xx) |
| 6 | partial failure (the API accepted a batch but some items failed) |
| 7 | rate limited (HTTP 429, after three retries) |
| 10 | config (the config file could not be read) |
Agent name resolution
The top-level agent commands (chat, logs, status, env, delete and the rest) accept the full agent name or an ID prefix, matched by exact name first and then by ID prefix. If you omit it inside a linked directory, the CLI uses the linked agent. Commands that show <agent_id> in their help (exec, files, agents ...) need the full ID.


