Reference manual

5dive CLI

The 5dive command runs on every 5dive runtime VM. It manages coding agents as Linux users + systemd units, handles non-TTY auth flows, installs Claude/OpenAI/Google CLIs on demand, and pairs each agent with a Telegram or Discord channel.

01

Overview

Every 5dive VM ships with a single Bash entry point at /usr/local/bin/5dive. It is the canonical way to create, inspect, and tear down agents on the host. The CLI is intentionally narrow — six top-level commands — and emits structured JSON whenever --json is passed, so it is safe to script against from a dashboard, a webhook, or another agent.

Each agent is one Linux user (agent-<name>) in the claude group, one systemd unit (5dive-agent@<name>.service), and one tmux session (agent-<name>). The unit runs the chosen CLI binary inside a tmux restart loop with the agent type's shared credentials injected via EnvironmentFile.

This page is the reference manual. It is written so an LLM can use the CLI without trial-and-error: every flag, every exit code, and every state path is listed below.

02

Quickstart

Install the CLI on any Linux host (requires sudo):

bash
curl -fsSL https://5dive.com/install.sh | sudo bash

From a fresh 5dive VM, the shortest path to a running agent paired to Telegram:

bash
# 1. Authenticate the Claude CLI once (covers every claude-typed agent)
sudo 5dive agent auth login claude

# 2. Spawn an agent named "scout" wired to Telegram
sudo 5dive agent create scout \
  --type=claude \
  --channels=telegram \
  --telegram-token=123456:ABC...

# 3. Pair the bot to your chat (DM the bot, then paste the code it replies)
sudo 5dive agent pair scout --code=AB12CD

# 4. Inspect — should print state=running
sudo 5dive agent stats scout

All four commands exit non-zero on failure with an exit code drawn from the table at the bottom of this page. Add --json to any of them to get a parseable envelope on stdout.

03

Concepts

Agents

An agent is a long-running tmux session running one of the supported coding CLIs (Claude Code, Codex, Gemini CLI, openclaw, hermes, opencode). It owns its own Linux user, its own home directory, and — when paired — its own bot/app token. Two agents of the same type can coexist on one host.

Accounts (named auth profiles)

By default every agent of a given type shares one set of credentials, stored under /etc/5dive/connectors/<type>.env. To run two agents of the same type against different accounts, create a named account once and bind agents to it: 5dive account add personal, 5dive account login personal --type=claude, then --auth-profile=personal on agent create (or 5dive agent set-account <agent> personal after the fact). See Accounts for the full surface. The lower-level auth set --auth-profile=<name> and auth login --auth-profile=<name>verbs still work and back the dashboard's device-code flow.

Channels

A channel is the inbound message surface the agent listens on. Today: telegram, discord, or none. Channels are only supported by agents whose CLI ships an MCP plugin contract — that is claude, openclaw, and hermes.

Workdir

The tmux session starts in the agent's workdir. Default is /home/claude/projects. Override at create time with --workdir=..., or change later with 5dive agent config <name> set workdir=....

04

JSON output

Pass --json as a global flag (anywhere on the command line) to switch stdout to a stable envelope. Progress lines (==>) keep going to stderr so the JSON on stdout is always parseable. The exit code matches error.code on failure.

success envelope
{
  "ok": true,
  "data": {
    "name": "scout",
    "type": "claude",
    "channels": "telegram",
    "workdir": "/home/claude/projects",
    "created": true
  }
}
error envelope
{
  "ok": false,
  "error": {
    "code": 6,
    "class": "auth_required",
    "message": "claude is not authenticated (missing) — run: sudo 5dive agent auth login claude"
  }
}

Branch on error.class for stable program flow — the human-readable message changes, the class does not.

05

Agent types

5dive agent types lists every supported CLI on the host along with auth state and an installed boolean. Types missing from disk are installed on demand the first time you agent create them.

TypeChannelsAuth flowNotes
claudeyessetup-token / API keyAnthropic Claude Code. Default for new agents.
codexnoOpenAI device flow / API keyOpenAI Codex CLI.
gemininoGoogle OAuth / API keyGoogle Gemini CLI.
hermesyesOpenAI device flowNous Research hermes harness.
openclawyesOpenAI device flowThird-party Claude harness, OpenAI-backed.
opencodenonone / optional API keyopencode.ai. Free models, no signup required.
06

Authentication

Auth is decoupled from agents. You authenticate a typeonce (optionally under a named profile) and every agent of that type inherits the credentials via systemd's EnvironmentFile.

Interactive login (TTY)

bash
sudo 5dive agent auth login claude

Hands this process off to the upstream CLI's interactive flow. Don't use this from a dashboard; use the device-code variant below instead.

API key

bash
# Direct
sudo 5dive agent auth set claude --api-key=sk-ant-...

# From stdin (recommended — keeps the key out of shell history)
echo "$KEY" | sudo 5dive agent auth set claude --api-key=-

Anthropic sk-ant-oat01-* tokens are routed to CLAUDE_CODE_OAUTH_TOKEN; everything else becomes ANTHROPIC_API_KEY.

Non-TTY device-code flow

The dashboard uses this flow because it runs without a PTY. Each call is async — start, poll until you get a URL, show the URL to the user, then submit the callback code the upstream login redirects to.

bash
# 1. Start a session — returns a session id
sudo 5dive agent auth start claude --json
# -> {"ok":true,"data":{"session":"01HXX..","state":"awaiting_url"}}

# 2. Poll until state=awaiting_code; data.url is what the user opens
sudo 5dive agent auth poll 01HXX.. --json

# 3. User pastes the callback code from the redirect URL back to you
sudo 5dive agent auth submit 01HXX.. --code=anthropic#abc123

# 4. (optional) cancel a pending session
sudo 5dive agent auth cancel 01HXX..

Status

bash
# Sentinel-only (fast)
sudo 5dive agent auth status

# Live probe — actually calls the API
sudo 5dive agent auth status --probe

# One type only
sudo 5dive agent auth status --type=claude --probe
07

Accounts

An account is a named bundle of credentials that one or more agents can share. Accounts are the user-facing surface over the lower-level auth profile primitive: the same on-disk storage, friendlier verbs.

Use accounts when you want two agents of the same type to authenticate against different sign-ins (e.g. personal + work Anthropic accounts), or when you want a single sign-in to feed many agents — re-authing the account heals every agent bound to it in one shot.

Create and sign in

bash
# 1. Create an empty account
sudo 5dive account add personal

# 2. Sign in interactively (TTY hand-off)
sudo 5dive account login personal --type=claude

# Or, set an API key non-interactively
echo "$KEY" | sudo 5dive agent auth set claude \
  --api-key=- --auth-profile=personal

Names: lowercase letters, digits, _, and -; must start with a letter; max 32 characters. The literal name defaultis reserved (it's the magic value agent set-account <agent> default uses to clear a binding).

Inspect

bash
sudo 5dive account list           # name, types signed in, # agents bound
sudo 5dive account show personal  # detail incl. env keys present
account list --json
{
  "ok": true,
  "data": [
    { "name": "personal", "types": ["claude"], "agents": ["scout","builder"] },
    { "name": "work",     "types": ["claude","codex"], "agents": ["work-bot"] }
  ]
}

Bind agents

bash
# At create time
sudo 5dive agent create scout --type=claude --auth-profile=personal

# After the fact (rebinds + restarts the agent to pick up the new env)
sudo 5dive agent set-account scout work

# Clear the binding (agent falls back to the shared default credentials)
sudo 5dive agent set-account scout default

Rename and remove

bash
# Rename — repoints every bound agent's symlink and restarts the units
sudo 5dive account rename personal primary

# Remove — refuses if any agents still bind to it
sudo 5dive account remove primary

account remove is a safety net: if any agent has its authProfile set to the account, the command fails with class conflict (exit 5) and prints the agent names. Rebind or delete those agents first.

Account vs `agent auth` (lower-level)

The legacy agent auth set/login/start/poll/submit/cancel verbs still work — they take an --auth-profile=<name>flag and back the dashboard's device-code flow. Prefer account for human-driven flows; reach for agent auth start|poll|submit when you need the non-TTY device-code lifecycle from a programmatic caller.

08

Agent lifecycle

Create

bash
sudo 5dive agent create <name> --type=<type> \
  [--channels=none|telegram|discord] \
  [--telegram-token=<bot-token>] \
  [--discord-token=<token>] \
  [--workdir=<absolute-path>] \
  [--auth-profile=<name>] \
  [--with-skills=<spec>[,<spec>...]] \
  [--no-skills]

Names: lowercase letters / digits / hyphens, must start with a letter, max 16 characters. The CLI installs the type binary on demand if it's missing, then refuses to create the agent unless the type is authenticated.

--with-skills preinstalls one or more skills on the new agent. Spec is either a bare id (defaults to 5dive-com/skills) or <owner/repo>:<id>. Multiple specs are comma-separated. When the create call is made by another agent on a claude-typed agent, the flag defaults to --with-skills=5dive-cli so spawned children inherit inter-agent comms knowledge automatically. Use --no-skills to opt out. A failed skill install warns but does not roll back the agent — rerun 5dive agent skill <name> add ... to retry.

List & inspect

bash
sudo 5dive agent list                # text or --json
sudo 5dive agent stats <name>        # state, restart count, last exit
sudo 5dive agent logs <name> --lines=200 [--follow] [--tmux]

--tmux dumps the tmux scrollback (what the user sees in the TUI). Without it, logs come from systemd / journalctl.

Start, stop, restart, remove

bash
sudo 5dive agent start   <name>
sudo 5dive agent stop    <name>
sudo 5dive agent restart <name>
sudo 5dive agent rm      <name>   # removes user, unit, tmux session, env

Reconfigure

bash
sudo 5dive agent config <name> set channels=<none|telegram|discord>
sudo 5dive agent config <name> set workdir=<path>           # "default" clears
sudo 5dive agent config <name> set auth-profile=<name>      # "default" clears
sudo 5dive agent config <name> set telegram.token=<token>
sudo 5dive agent config <name> set discord.token=<token>

# Shorter alias for the auth-profile case
sudo 5dive agent set-account <agent> <account|default>

Send input / attach

bash
# Inject a message into the running tmux session (sends keys + Enter)
sudo 5dive agent send <name> "implement the dashboard skeleton"

# Attach your terminal to the session — Ctrl-b d to detach
sudo 5dive agent <name> tui

When called from another agent, send auto-wraps the payload with a [5dive-msg from=<sender> id=<id>] envelope so the receiver knows who pinged it. Use --from=<label> to override and --raw to skip wrapping. See Inter-agent comms for the full protocol and the synchronous agent ask wrapper.

Clone

bash
sudo 5dive agent clone <src> <dst> [--channels=...] \
  [--telegram-token=...] [--discord-token=...] [--workdir=...]

Clones type, workdir, and auth profile from <src>. Channel + tokens must be passed fresh — two agents cannot share a Telegram bot.

09

Channels & pairing

A new agent created with --channels=telegram writes the bot token under /etc/5dive/connectors/telegram-<name>.env and starts an MCP plugin process inside the agent. The plugin is locked down by default — it ignores every chat until you pair one.

Pairing

bash
# Option A — give the user a 6-character code, they DM the bot, paste it back
sudo 5dive agent pair <name>                    # prints/returns code

# Option B — paste the bot's reply directly (dashboard flow)
sudo 5dive agent pair <name> --code=AB12CD

Allow-list

The plugin's allow-list lives at ~/.claude/channels/<channel>/access.json inside the agent's home. Pairing appends to allowFrom; rotate the bot token via 5dive agent config <name> set telegram.token=....

10

Skills

Skills are the skills.sh prompt-bundle format. A skill is a directory with a SKILL.mdat its root. Installing a skill on an agent drops it into the agent type's skills dir (~/.claude/skills/ for claude, ~/.hermes/skills/ for hermes, ~/.agents/skills/ for codex / gemini / opencode, ~/skills/ for openclaw) and makes it loadable on next prompt.

bash
# Install a skill on an agent
sudo 5dive agent skill <name> add \
  --source=<owner/repo> \
  --skill=<skill-id>

# List installed skills
sudo 5dive agent skill <name> list

# Remove a skill
sudo 5dive agent skill <name> rm <skill-id>

Tip: install the 5dive-cli skill from github.com/5dive-com/skills on any agent to teach it the 5dive command surface — agent lifecycle, JSON envelope, recovery on exit codes, and the --json orchestration loop:

bash
sudo 5dive agent skill <name> add \
  --source=5dive-com/skills \
  --skill=5dive-cli

With it installed, an agent can spawn its own subagents on the same host — see Spawning subagents.

11

Spawning subagents

Any agent on a 5dive VM can call 5diveto spawn more agents on the same host — that's how recursion works. The agent user (agent-<name>) is in the claude group and has sudo 5dive ... in its sudoers, so:

bash
# From inside one agent's tmux session — spawn a worker for a side task
sudo 5dive agent create worker-1 \
  --type=claude \
  --workdir=/home/claude/projects/myrepo \
  --json

# Send it a task
sudo 5dive agent send worker-1 "audit auth middleware for OWASP A01"

# Watch its output
sudo 5dive agent logs worker-1 --tmux --lines=50

# Tear it down when done
sudo 5dive agent rm worker-1

For LLM-driven orchestration, prefer --jsonon every call and branch on error.class rather than parsing the human stderr. The 5dive-cli skill packages this loop as a reusable prompt — install it on the parent agent and ask for “a worker that does X”.

12

Inter-agent comms

agent send and agent askform a tiny message bus between agents on the same host. There is no separate channel — messages land in the receiver's running CLI as if a human had typed them, but with an envelope that lets the receiver tell who is pinging it.

Auto-attributed sends

When the caller is an agent-* Linux user (i.e. one agent shelling out to talk to another), the CLI auto-detects the sender from $SUDO_USER and wraps the payload as:

bash
[5dive-msg from=<you> id=<8-hex>] <your text>

Humans calling sudo 5dive agent send directly are unaffected — only sends from agent users get the envelope. Override with --from=<label> or skip wrapping entirely with --raw.

Replying

A receiver that sees a wrapped message replies the same way it would talk to anything else — by name. The [re=<id>] prefix is convention, not enforced; it lets the sender match replies when juggling several outstanding asks.

bash
# Inside the receiver's session, after seeing
# [5dive-msg from=scout id=ab12cd34] please summarise the audit

sudo 5dive agent send scout "[re=ab12cd34] auth middleware looks clean except ..."

Synchronous request/response: agent ask

bash
sudo 5dive agent ask <name> "<prompt>" \
  [--from=<sender>] \
  [--timeout=120] \
  [--idle-secs=5] \
  [--poll-secs=2] \
  [--json]

Sends the wrapped envelope, then watches tmux capture-pane after the marker line until the slice has been quiet for --idle-secs (default 5s) — at which point it returns the reply body. Times out with class timeout (exit 11) if the receiver never goes idle within --timeout.

JSON envelope
{
  "ok": true,
  "data": {
    "name": "scout",
    "from": "coordinator",
    "msg_id": "ab12cd34",
    "reply": "auth middleware looks clean except for ..."
  }
}

Caveats

Idle-by-stability is heuristic. A receiver that streams progress continuously will keep ask awake until --timeout fires. For long agentic work, prompt the receiver for a terse final summary, or use plain send + logs and poll on your own schedule.

The reply is whatever was on screen. It includes any chrome the receiver CLI prints (cursor lines, status hints) — don't expect a clean JSON body unless the prompt explicitly asks for one.

No retries, no delivery confirmation. If the receiver crashed mid-reply you'll get a partial slice or a timeout, nothing in between.

When to use what

Fire-and-forget delegation: agent send, then poll agent logs --tmux at your own convenience. Need an answer before continuing: agent ask. Fan-out across N workers: loop agent send, or run several agent ask calls in parallel via & + wait.

13

Doctor & health

5dive doctor walks every dependency (tmux/jq/bun/python3/node/npm), every type binary, every live auth probe, registry integrity, and shelld reachability.

bash
# Read-only check
sudo 5dive doctor --json

# Fix what's fixable (apt installs, type installer recipes, registry reseed)
sudo 5dive doctor --repair

# Narrow the scope
sudo 5dive doctor --category=deps   # or types | auth | registry | shelld

Envelope is always {ok: true, data: {summary, checks}} with exit 0 — branch on data.summary.errors > 0 in CI.

14

Exit codes

Both shell exit code and error.code in the JSON envelope. Branch on error.class for human-stable matching.

CodeClassMeaning
0okSuccess
1genericCatch-all / internal error
2usageUnknown flag, missing arg, bad subcommand
3validationFormat check failed (name, workdir, token, lines)
4not_foundAgent/type/session doesn't exist
5conflictAlready exists (name collision)
6auth_requiredType not authenticated, bot token missing
7not_installedCLI binary missing, no installer recipe
8not_runningtmux session / systemd unit not active
9pairingPair code not pending or invalid
10permissionMust run as root
11timeoutPlugin didn't materialize within waitloop
15

State & paths

Useful only when debugging — every path below is managed by the CLI. Don't edit by hand.

/var/lib/5dive/agents.jsonAgent registry (versioned). Source of truth for `agent list`.
/var/lib/5dive/agents.d/<name>.envPer-agent systemd EnvironmentFile.
/var/lib/5dive/auth-profiles/<name>/Named auth profile env files + captured CLI config.
/var/lib/5dive/auth-sessions/<id>/Live device-code session state.
/etc/5dive/connectors/<type>.envShared auth env (default profile).
/etc/5dive/connectors/telegram-<name>.envPer-agent bot token.
/etc/systemd/system/5dive-agent@.serviceTemplated systemd unit. One instance per agent.
/var/log/5dive/agent-audit.logNDJSON audit trail of every mutating command.