# Maritime CLI: instructions for AI agents Copy this file into your agent's context (CLAUDE.md, AGENTS.md, or a system prompt), or let the agent fetch it from https://maritime.sh/docs/cli/llms.txt. It teaches an LLM to operate Maritime (https://maritime.sh): a cloud that hosts AI agents in serverless micro-VMs with persistent storage at /data. Agents sleep when idle, wake in about a second on the next message or trigger, and hosting is flat-priced with no usage metering. The same contract is available offline: `maritime guide` prints a paste-able version of this file, and `maritime guide --json` emits the full command and flag manifest, introspected live from the installed CLI, so it can never drift. Prefer that manifest over guessing flags. ## Setup 1. Install: npm install -g maritime-cli (the npm package is maritime-cli; the command is maritime; needs Node 20.12+) 2. Authenticate with an environment variable, never interactive login: - A human mints a long-lived API key with: maritime keys create --name my-agent --json (the mk_... key is shown once and never expires), or grabs a token at https://maritime.sh/cli/auth - export MARITIME_TOKEN=mk_... 3. Verify: maritime whoami --json (exit code 2 means the token is missing, expired, or wrong) MARITIME_API_URL overrides the API base (default https://api.maritime.sh). ## The contract - Pass --json on EVERY command. Success: one JSON value on stdout, stderr empty. Failure: {"ok": false, "error": {"code": "...", "message": "...", "status": 401}} on stderr, stdout empty. Read stdout for results, branch on the exit code, never scrape human text. - Exit codes: 0 success, 1 generic error (request/server/network), 2 auth, 3 not found (no such agent), 4 usage (missing or invalid arguments). Caveat: flag-parse errors (unknown option, missing required argument) exit 1 with PLAIN TEXT on stderr even with --json; only CLI-validated errors use exit 4 and the JSON error shape. Treat unparseable stderr as a usage bug. - Anywhere a command takes , pass the exact agent name or an ID prefix. Inside a directory linked with maritime init/link, the agent argument can be omitted; the CLI resolves the linked agent. ## Core tasks # Discover templates, create an agent, wait for it, talk to it: maritime templates --json maritime create my-agent --template openclaw --json maritime status my-agent --json # wait for "active" maritime chat my-agent "introduce yourself" --json | jq -r '.response' # Deploy your own code (any framework; Dockerfile at the repo root): maritime create my-bot --json maritime deploy my-bot --source github --repo https://github.com/you/agent --branch main --wait --json # Serve a repo on a public no-login URL (sleeps idle, wakes on the next visit): maritime create my-app --repo https://github.com/you/app --public --port 3000 --json # Encrypted env vars (secret by default; --reload pushes into the running agent): maritime env set my-agent OPENAI_API_KEY=sk-... --reload --json maritime env import my-agent ./prod.env --reload --json maritime env list my-agent --json # Inspect and debug: maritime list --json maritime logs my-agent --level error --json maritime info my-agent --json maritime history my-agent --json # build/deploy attempts + buildLog maritime exec my-agent ls /data --json | jq -r '.stdout' # Message an agent AS one of your end users (sticky per-user routing through # the project front door; same --user always reaches the same instance): maritime message my-agent --user cust_42 "where is my order?" --json | jq -r '.reply' # Lifecycle (rarely needed; agents sleep and wake on their own): maritime start my-agent --json maritime sleep my-agent --json maritime restart my-agent --json # also picks up new env vars maritime delete my-agent --yes --json # --yes is REQUIRED non-interactively ## Scheduling Timers inside a sleeping agent do not fire. Put scheduled work on platform triggers: maritime triggers list , and maritime triggers create --type cron --cron "0 9 * * *". A cron trigger wakes the agent; set config.prompt via the API to also deliver a message on each fire. A custom container can instead serve GET /schedules and Maritime registers the wakes for it. Details: https://maritime.sh/docs/triggers ## Gotchas - create and delete never prompt: a missing name or a missing --yes exits with code 4 instead of hanging. - Env changes apply on the next boot unless you pass --reload (or run maritime env reload ). - If chat fails with error.code "agent_unavailable", the agent is not running: maritime start , wait a few seconds, retry. - A 404 or "not running" on file/exec operations usually means the agent is asleep or errored: start it and retry; do not recreate it. - mk_ keys never expire; browser-login tokens do. Use mk_ for automation. - LLM access: most templates work with no model key (Maritime's metered LLM proxy). The claude_code template is the exception: it always needs your own ANTHROPIC_API_KEY as a secret env var. ## More - Human-readable CLI reference: https://maritime.sh/docs/cli - Drive-Maritime-from-an-AI-agent guide: https://maritime.sh/docs/ai-agents - REST API: https://maritime.sh/docs/api - Building a product where every customer gets an agent? Use the SDK from your backend instead: https://maritime.sh/docs/build