Reference 48 pages
On this page

Reference

Command Line (CLI)

Install the cyborg CLI, log in to the relay, and drive workspaces, agents, tasks and terminals on any daemon you have access to.

The cyborg CLI lets you work from a terminal: log in to the relay and drive workspaces, channels, agents, persistent agents, tasks, and terminals running on any daemon you have access to. Anything you can do in the app, you can script from the shell.

Install

On Linux the CLI ships with the headless daemon installer (it bundles its own runtime, so no system Node is required):

curl -fsSL https://raw.githubusercontent.com/Cyborg7-com/cyborg7-releases/main/cyborg-cli/install.sh | sh

On macOS and Windows the desktop app bundles the same cyborg binary: Settings → System → Command line → Command-line tool → Install links ~/.local/bin/cyborg to it (if ~/.local/bin is not on your PATH yet, click Add to PATH), so the CLI and the app’s daemon are always the same version. See Manage sessions from the CLI for a walkthrough.

Authenticate

cyborg login signs in with a 6-digit code sent to your email, the same way the app does, and saves the result locally. Point at a self-hosted relay with --url.

cyborg login                                  # prompts for your email, then for the code
cyborg login --email you@example.com          # prompts only for the code

Without a terminal (a script, CI), sign in in two steps: the first run only sends the code, the second redeems it without asking for a new one.

cyborg login --email you@example.com                  # sends the code
cyborg login --email you@example.com --code 123456    # redeems it

If you already hold a relay token, pass it together with the id of its user; both are required:

cyborg login --token <token> --user-id <user-id>

For a single command you can also supply the token through CYBORG_TOKEN or --token-stdin (see Where commands connect).

Check who you are logged in as and the daemon and relay connectivity:

cyborg whoami   # show the logged-in user
cyborg status   # show daemon + relay status

Global flags

Every command accepts these output controls, which make the CLI scriptable:

FlagPurpose
-o, --format <table|json|yaml>Output format (default table)
--jsonShorthand for -o json
-q, --quietMinimal output, IDs only
--no-headersOmit table headers
--no-colorDisable colored output

Where commands connect

After cyborg login, workspace commands go through the relay with your saved login, with no --host and no --token. The local daemon is used only by cyborg daemon … and by cyborg terminal … without --workspace.

  • --relay-url <url> (on the relay commands: agent:alias, agent:aliases, rpc) points one command at a different relay, such as a dev or staging one; your saved login is sent only to the relay that issued it.
  • --host <host> overrides the target: a relay URL (wss://relay.example.com/api/ws) or a daemon (host:port, tcp://host:port?ssl=true&password=…). Your saved login is sent only to the relay you logged in to, never to another host.
  • Credentials, in order: --token (last resort, because argv is visible to other users in ps), --token-stdin (reads the first line of stdin), the CYBORG_TOKEN environment variable, then the saved login. A saved login that the relay rejects is refreshed once automatically.
  • Environment: CYBORG_HOST (same as --host; the old PASEO_HOST still works), CYBORG_TOKEN, CYBORG_DAEMON_HOME (the daemon’s state directory; the old PASEO_HOME still works). CYBORG_HOME is the directory holding your login (~/.cyborg), not the daemon’s.

Manage the daemon

A daemon is the agent host. It runs agents and terminals on a machine and connects them to your workspaces through the relay. On a server, manage it with the cyborg daemon group:

cyborg daemon start --replace --foreground   # run in the foreground (systemd, containers)
cyborg daemon status               # running? which port/home?
cyborg daemon doctor               # version, relay link, online state, update available
cyborg daemon restart
cyborg daemon reload               # re-read config.json without restarting
cyborg daemon stop

Useful start flags: --port <port> / --listen <target> (listen target), --home <path> (state directory, default ~/.cyborg7), --replace (take over from an already-running daemon after an update), --relay / --no-relay (enable or disable the relay connection; --no-relay is fully local), --relay-use-tls (wss:// relay connection), --no-mcp (turn off the agent MCP HTTP endpoint), --no-inject-mcp (do not auto-add that MCP to new agents), --web-ui / --no-web-ui (the bundled daemon web UI), and --hostnames <hosts> (comma-separated hostnames the daemon accepts).

Update

cyborg daemon update

Pulls the latest published bundle (or the latest code, in a source checkout), restarts the daemon onto it, verifies it comes back online, and rolls back if it doesn’t. Live terminals survive the restart because they run in a detached pty host process, not in the daemon itself.

Flags: --force (update and restart even when already on the latest version), --no-build (skip the build step in a source install), --timeout <seconds> (how long to wait for the old daemon to stop, default 15), --verify-timeout <seconds> (how long to wait for the new one to come online before rolling back, default 30), plus --home, --port and --listen.

Claim a daemon

claim attaches a headless daemon to your account and points it at the Cyborg7 relay. It writes daemon-owner and cyborg-relay-url into the daemon home. The relay is resolved once, at boot, so restart the daemon after claiming it.

cyborg daemon claim          # claim it for the currently logged-in user
cyborg daemon restart        # required: the relay is resolved at boot
cyborg daemon set-password   # protect direct (non-relay) connections

Claiming is how a headless daemon shows up in the app’s machine list. If the daemon is already claimed by another user, cyborg daemon claim --force reassigns it to you. See Add a daemon for the full walkthrough.

Join with a setup code

A workspace can hand out a one-time setup code (CYB-XXXX-XXXX) for a worker machine. Redeeming it needs no account and no login on that machine:

cyborg daemon join --code CYB-XXXX-XXXX       # or set CYBORG_SETUP_CODE
cyborg daemon restart

--relay <url> picks another relay, --home <path> the state directory, and --force rebinds a machine that is already claimed.

cyborg daemon pair is retired in the cyborg command: it prints a pointer to claim and exits with status 1. Use claim or join.

Workspaces & channels

Most commands take a workspace id as their first argument. Get one with ws:list.

cyborg ws:list
cyborg ws:create "My Team"
cyborg ch:list <workspace-id>
cyborg ch:create <workspace-id> engineering
cyborg ch:update <workspace-id> <channel-id> --name ops --description none --private
cyborg ch:archive <workspace-id> <channel-id>            # --unarchive to bring it back
cyborg ch:delete <workspace-id> <channel-id> --yes
cyborg ch:members <workspace-id> <channel-id>
cyborg ch:add-member <workspace-id> <channel-id> <user-id>
cyborg ch:remove-member <workspace-id> <channel-id> <user-id> --yes

Members and invitations

cyborg member:list <workspace-id>
cyborg member:invite <workspace-id> someone@example.com [--role admin|member|viewer] [--channel <channel-id>]
cyborg member:role <workspace-id> <user-id> admin     # owners only
cyborg member:remove <workspace-id> <user-id> --yes
cyborg memory:purge-person <workspace-id> <user-id> --yes  # admins: erase a person's memory, counts only
cyborg memory:purge-person <workspace-id> <user-id> --dry-run [--offboard]  # preview the counts; changes nothing
cyborg invite:list <workspace-id>                     # pending invitations
cyborg invite:resend <workspace-id> <invitation-id>
cyborg invite:cancel <workspace-id> <invitation-id>
cyborg join:list <workspace-id> [--status pending]    # requests from your claimed email domain
cyborg join:approve <workspace-id> <request-id> [--role viewer]
cyborg join:reject <workspace-id> <request-id>

Commands that cannot be undone from here (ch:delete, ch:remove-member, member:remove, memory:purge-person, msg:delete, schedule:delete, machine:revoke, cybo:delete, task:delete, task:view-delete, page:delete, skill:delete) ask for confirmation at a terminal; in a script (stdin is not a terminal) they refuse with CONFIRMATION_REQUIRED unless you pass --yes, and a “no” at the prompt exits with CONFIRMATION_DECLINED. The relay decides who may do what; its refusal exits non-zero with its code (FORBIDDEN, PRO_REQUIRED, SEAT_LIMIT_REACHED, …).

memory:purge-person and the compliance delete in Settings remove the memory at once. Deleted memory is removed immediately; encrypted database backups keep copies for up to 14 days before they expire.

Messaging

cyborg send <workspace-id> <channel-id> "deploy is out"
cyborg listen <workspace-id> <channel-id>            # stream messages live (Ctrl-C to stop)
cyborg slash <workspace-id> <channel-id> summarize   # run a channel slash command, wait for the result
cyborg msg:list <workspace-id> <channel-id> [--limit 50] [--cursor <message-id>]
cyborg msg:get <workspace-id> <message-id>
cyborg msg:edit <workspace-id> <message-id> "fixed text"   # your own messages
cyborg msg:delete <workspace-id> <message-id> --yes
cyborg msg:react <workspace-id> <message-id> 👍             # toggles your reaction
cyborg msg:pin <workspace-id> <channel-id> <message-id>    # --unpin to undo
cyborg thread:list <workspace-id> [--unread] [--cursor <cursor>]
cyborg thread:get <workspace-id> <root-id>
cyborg thread:reply <workspace-id> <channel-id> <root-id> "on it"   # waits for the relay to confirm
cyborg thread:follow <workspace-id> <root-id>              # --off to stop

msg:list and thread:list read a page at a time. With --json they print { messages | threads, nextCursor }; in a table or with -q the next page’s full command goes to stderr.

slash accepts --no-wait (dispatch only) and --timeout <seconds> (default 120). Set model preferences for channel AI commands like /summarize:

cyborg slash:model <workspace-id> <provider> <model>                 # your personal preference
cyborg ch:model <workspace-id> <channel-id> <provider> <model>       # per-channel override

Run either without provider/model to see the current value; pass --clear to reset (back to auto-resolve / the inherited default).

Agents

An agent is a live AI session running on a daemon.

cyborg agent:create <workspace-id> --provider claude --channel <channel-id> --cwd ~/repo
cyborg agent:create <workspace-id> --daemon <machine-id>  # on another machine (cwd: its ~)
cyborg agent:list <workspace-id> [--daemon <machine-id>]
cyborg agent:prompt <workspace-id> <agent-id> "run the test suite and summarize failures"
cyborg agent:stop <workspace-id> <agent-id>               # interrupt a stuck run
cyborg agent:mode <workspace-id> <agent-id> acceptEdits   # default | plan | acceptEdits | bypassPermissions
cyborg agent:model <workspace-id> <agent-id> <model>      # 'default' clears the override
cyborg agent:alias <workspace-id> <agent-id> "Reviewer"   # your own name for a session; --clear removes it
cyborg agent:aliases                                       # the names you have given

agent:prompt streams the reply. --wait prints only the final reply, --json prints { reply, promptId, promptAttemptId }, --timeout <seconds> bounds the wait (default 120), and --no-stream only dispatches. For a busy agent: --steer joins the running turn, --queue waits for it to end, and the default interrupts it. <agent-id> may be a unique id prefix.

Sessions on any machine

Every command here takes a session id or a unique prefix (the first 8 characters are enough) and searches all your workspaces unless you pass --workspace <id>.

cyborg session:list [--workspace <id>] [--archived]   # your sessions, every machine
cyborg agent:history <agent> [--before <cursor>] [--full] [--raw]
cyborg agent:follow <agent> [--forever] [--timeout <s>]   # stream the live turn
cyborg agent:wait <agent> [--until idle|running] [--timeout <s>]
cyborg agent:state <agent>                    # status, model, mode, attention, context use
cyborg agent:receipt <agent> <prompt-id>      # did that prompt reach the model?
cyborg agent:context <agent>                  # context an ephemeral agent session started with
cyborg agent:subagents <agent>
cyborg agent:archive <agent>
cyborg agent:restore <workspace-id> <session-id> [--daemon <machine-id>]
cyborg agent:reload <agent> [--rehydrate]      # restart a stuck session in place: same id, same history
cyborg agent:clone <agent> [--title <t>] [--dry-run]   # copy a session, history included, into a new one
cyborg agent:rewind <agent> <turn> [--mode conversation|files|both] [--dry-run]
cyborg agent:thinking <agent> [level]         # set the thinking level; no level lists the model's levels

--rehydrate also re-reads the provider’s history, for a session that is out of sync. <turn> for agent:rewind is the prompt’s SEQ number in agent:history or its message id; --mode files (and both) rolls back files too and works with Claude only. --dry-run shows what would happen and changes nothing. session:list is also available as sessions, agent:list as agents and ws:list as ws; session:list takes --limit <n>.

Machines

cyborg machine:list <workspace-id>                         # online, version, your access
cyborg provider:list <workspace-id> --daemon <machine-id>  # what that machine can run
cyborg ws:swarm <workspace-id> [on|off]                    # agents waking agents without an @-mention
cyborg machine:rename <workspace-id> <machine-id> "Studio Mac"
cyborg machine:grant <workspace-id> <machine-id> <user-id> --scopes chat,spawn   # full access: --scopes admin
cyborg machine:revoke <workspace-id> <machine-id> <user-id> --yes
cyborg machine:requests <workspace-id>                     # pending access requests you can see
cyborg machine:request <workspace-id> <machine-id> --scopes chat
cyborg machine:approve <workspace-id> <request-id> [--scopes chat]
cyborg machine:deny <workspace-id> <request-id>
cyborg provider:refresh <workspace-id> [provider...] --daemon <machine-id>
cyborg provider:install <workspace-id> opencode --daemon <machine-id>   # claude, codex, copilot, opencode, pi
cyborg provider:sign-in <workspace-id> claude --daemon <machine-id>     # prints the link, waits

machine:grant refuses without --scopes: an omitted flag never becomes full access. provider:install installs a key other than claude/codex only on a machine whose daemon offers it (PROVIDER_NOT_INSTALLABLE otherwise). provider:sign-in supports --no-wait, --operation <id> --code <code> (paste the code the provider’s page shows), --operation <id> --cancel, and --verify (exits 1 when the machine is not signed in); Ctrl-C cancels the sign-in on the machine. While it waits, the link and code go to stderr in every output mode, so --json keeps stdout to the one result; --no-wait --json returns them (with the operation id) on stdout instead.

Schedules

cyborg schedule:list <workspace-id> [--cybo <agent-id>]
cyborg schedule:runs <workspace-id> <schedule-id> [--limit 20]
cyborg schedule:create <workspace-id> <agent> --cron "0 9 * * 1-5" --prompt "Summarize yesterday" [--channel <id>] [--tz America/La_Paz]
cyborg schedule:update <workspace-id> <schedule-id> --cron "0 8 * * *" [--channel none]
cyborg schedule:pause <workspace-id> <schedule-id>        # schedule:resume to undo
cyborg schedule:run <workspace-id> <schedule-id>          # once, now
cyborg schedule:delete <workspace-id> <schedule-id> --yes

A schedule the machine refuses (a bad cron, one you cannot see) exits 1 with SCHEDULE_REFUSED.

A machine that takes a request and does not answer fails with an error naming the machine and the request, never a hang.

Persistent agents

Persistent agents are reusable templates: identity, personality and provider defaults.

cyborg cybo:create <workspace-id> reviewer "Code Reviewer"
cyborg cybo:list <workspace-id>
cyborg cybo:spawn <workspace-id> reviewer --channel <channel-id> --cwd ~/repo
cyborg cybo:spawn <workspace-id> reviewer --daemon <machine-id>
cyborg cybo:update <workspace-id> reviewer --soul-file soul.md --model default
cyborg cybo:delete <workspace-id> reviewer --yes

cybo:create and cybo:update take --tool-grants <json|@file> for Composio tool grants.

Tasks

The same task board the app shows, scriptable:

cyborg task:create <workspace-id> "Fix login redirect" \
  --description "302 loops on expired session" \
  --assignee <user-or-agent-id> --priority high --label bug
cyborg task:list <workspace-id>
cyborg task:update <workspace-id> <task-id> --state <state-id>
cyborg task:archive <workspace-id> <task-id>       # --unarchive to restore
cyborg task:bulk-update <workspace-id> <id1> <id2> --priority low
cyborg task:comment <task-id> "shipped in #2573"   # lands in the task's Activity feed
cyborg task:delete <workspace-id> <task-id> --yes
cyborg task:get <workspace-id> <task-id>
cyborg task:search <workspace-id> "login redirect" [--limit 20]   # title, description or project key (e.g. CYBORG-202)
cyborg task:activity <task-id>       # changes and comments
cyborg task:links <task-id>
cyborg task:attachments <task-id>
cyborg task:states <project-id>      # workflow states, the ids for --state
cyborg project:list <workspace-id>
cyborg project:create <workspace-id> "Mobile app" [--color "#a78bfa"]
cyborg project:update <workspace-id> <project-id> [--name <name>] [--color <hex>]

Saved views: task:views <project-id> lists them, task:view-create <project-id> <name> saves one, task:view-update <view-id> changes one and task:view-delete <view-id> --yes removes it. The view commands take --layout (list, board, calendar, spreadsheet, gantt), --group-by, --sub-group-by, --order-by, --order-dir, --filters <json> and --display <json>.

task:create also supports --due <iso>, --start <iso>, --parent <task-id> (subtasks), --channel, --project, --cycle, and repeatable --label / --module.

Pages

Pages are the project docs you see in the app. A project is identified by its id (from project:list).

cyborg page:list <project-id>                          # alias: pages; shown as a tree
cyborg page:get <page-id> [--raw]                      # body as markdown (--raw: as stored)
cyborg page:create <project-id> "Runbook" --file runbook.md [--parent <page-id>] [--visibility private|public] [--icon 📘]
cyborg page:update <page-id> [--title <t>] [--file <path>] [--visibility private|public] [--icon <emoji|none>]
cyborg page:move <page-id> --parent <page-id|root> [--sort-order <n>]
cyborg page:delete <page-id> --yes
cyborg page:search <workspace-id> "runbook" [--limit 20]   # page titles across a workspace
cyborg page:access <page-id>                           # who can read a private page, and who asked to

--file - reads the body from stdin. New pages are private unless you pass --visibility public.

Skills

Skills are SKILL.md instructions you can give to agents. <slug> is the skill’s slug or id.

cyborg skill:list <workspace-id> [--project <project-id>]     # alias: skills
cyborg skill:get <workspace-id> <slug>                        # prints its SKILL.md
cyborg skill:create <workspace-id> <slug> --file SKILL.md [--name <n>] [--description <d>] [--scope workspace|project] [--project <project-id>]
cyborg skill:update <workspace-id> <slug> [--file SKILL.md] [--name <n>] [--description <d>]
cyborg skill:delete <workspace-id> <slug> --yes
cyborg skill:import <workspace-id> --url <url>                # or --github owner/repo --ref main --path <folder>; --dry-run previews
cyborg skill:sync <workspace-id> ./skills [--dry-run]         # upsert every <dir>/<slug>/SKILL.md
cyborg skill:assign <workspace-id> <slug> <agent>             # give an agent the skill
cyborg skill:unassign <workspace-id> <slug> <agent>
cyborg skill:search <workspace-id> "code review"              # public skill marketplaces

Creating, changing, deleting, importing, syncing, assigning and unassigning skills need workspace admin rights.

Anything else: cyborg rpc

rpc is an escape hatch that sends any request a signed-in client can send to the relay. Prefer the typed commands above; use rpc for what they do not cover yet.

cyborg rpc cyborg:list_channels '{"workspaceId":"<workspace-id>"}'
cyborg rpc <type> '<payload-json>' --dry-run     # validate the payload locally, send nothing

Only read requests (types starting fetch_, list_, get_, search or read_) run as they are; any other type needs --yes. rpc works through the relay only.

Terminals

The cyborg terminal command group drives real terminals running on any daemon you have access to. You can open one, send keystrokes, and read its output from the CLI without a GUI. Input is gated by ownership: you can only write to terminals you own.

Commands that take a <terminal-id> accept a full ID, a unique ID prefix, or the terminal’s name. Add --host <host> to target a specific daemon.

List terminals

Lists terminals in the current workspace directory. Add --all to list across all workspaces and daemons, or --cwd <path> to scope to a directory.

cyborg terminal ls [--all] [--cwd <path>]

Create a terminal

Opens a new terminal. --cwd sets the working directory (defaults to the current one) and --name gives it a name you can reference later.

cyborg terminal create [--cwd <path>] [--name <name>]

Send keystrokes

Writes input into a terminal. Special tokens like Enter, Tab, Escape, and C-c are interpreted as the matching control sequences; pass --literal to send them verbatim instead.

cyborg terminal send-keys <terminal-id> "<keys>" [Enter] [--literal]

Capture output

Reads the terminal’s current screen. Add --scrollback to read from the beginning of history, --ansi to keep color/escape codes, or --json for machine-readable output.

cyborg terminal capture <terminal-id> [--scrollback] [--history] [--keep-volatile] [--ansi] [--json]

A full-screen program (Claude Code, vim, less, htop) draws on the terminal’s alternate screen, which has no scrollback: a capture shows its current screen and nothing it drew before. Add --history to get everything the daemon still holds as an in-order transcript instead. With --workspace, that is every screen in the daemon’s output ring (the last 256 KiB of the terminal’s output), each line once, so earlier screens of a full-screen program are included. Without --workspace the local daemon keeps no output ring, so --history reads its scrollback, the same as --scrollback.

Follow a terminal

Prints a terminal’s output as it arrives, until you press Ctrl-C, --duration runs out, or the terminal exits. It starts with the current screen, then prints each line the first time it appears, in order, like tail -f. Screens a full-screen program redraws in place are read one by one, so nothing it shows between two of your reads is lost.

cyborg terminal watch <terminal-id> [--history] [--output <file>] [--text | --raw] [--keep-volatile] [--duration <time>] [--json]
OptionWhat it does
--historyStart with everything the daemon still holds (see capture --history) instead of the current screen.
--output <file>Append to a file instead of printing.
--textRendered lines, each printed once. This is the default.
--rawThe terminal’s raw output, escape codes included, as it arrives (with --history, the saved output first).
--keep-volatileAlso print lines that are only counters, and every tick of a status row (see below).
--duration <time>Stop after 30, 30s, 5m or 1h.
--jsonOne JSON object per line: {"ts", "kind": "lines" | "exit" | "error", "lines"}.

To keep a log of a Claude Code session running in a terminal on another machine:

cyborg terminal watch <terminal-id> --workspace <ws-id> --daemon <machine-id> --history --output session.log

watch uses the same access as capture: only the terminal’s owner can follow it. If the connection drops, watch stops with an error; run it again with --history to catch up.

On a slow connection the relay can drop a piece of live output. watch notices the missing piece, stops printing, subscribes again, and rebuilds from the output the daemon still holds, so nothing is skipped or printed out of order. With --raw it lines up the daemon’s saved output with the bytes already written and writes only what follows them. If that is not possible (the saved output no longer reaches back that far, or the match is ambiguous), it writes a line --- gap: N output frame(s) may be missing --- where the gap is and carries on. The same line marks the gap in text output if the daemon does not answer within a few seconds.

The text output is meant to read like what the session said, so it leaves out what only moves:

  • Output is printed once the terminal has been quiet for a moment (at most a second later), so a screen that is still being redrawn is never read half-painted.
  • A status row whose only changes are a timer, a token count or a spinner (Claude Code’s ✻ Thinking… (12s · ↓ 1.2k tokens)) is printed once, not on every tick.
  • A line that is only numbers and units (42m 3s, 1.6k tokens) is skipped.
  • A long line (40 characters or more) is printed once, even if the program draws it again later, for example when it redraws a view you already scrolled past.
  • Blank lines are skipped.
  • With --history, the daemon keeps only the end of the terminal’s output, so the oldest part starts in the middle of a screen. A line in that part is printed only once it has been drawn whole, which can be later than when it first appeared.

--keep-volatile turns these three filters off. A line whose text changes in other ways (a progress bar, a line being typed in) is still printed each time it changes.

Kill a terminal

Closes the terminal and frees its process.

cyborg terminal kill <terminal-id>

Workspace terminals (via the relay)

Pass --workspace <id> to route through the relay instead of the local socket. The command reaches whichever daemon hosts the terminal, from any machine you’re logged in on, with your saved login (no --token needed). A terminal created with --workspace is bound to that workspace and appears in the app’s sidebar for its members, so the CLI and the app share one source of truth. When several daemons are connected, pick one with --daemon <id>.

cyborg terminal create --workspace <ws-id> --name deploy --cwd /srv/app
cyborg terminal ls --workspace <ws-id>
cyborg terminal send-keys deploy --workspace <ws-id> "systemctl status app" Enter
cyborg terminal capture deploy --workspace <ws-id>
cyborg terminal watch deploy --workspace <ws-id> --duration 5m

End-to-end example

Open a terminal, run a command in it, and read the result:

# 1. Create a named terminal and note its id
cyborg terminal create --name demo

# 2. Type a command and press Enter
cyborg terminal send-keys demo "ls -la" Enter

# 3. Read what the terminal printed
cyborg terminal capture demo

# 4. Close it when you're done
cyborg terminal kill demo

Terminals are referenced by name or ID prefix, so the same flow works against a terminal on any daemon you have access to. Add --host (direct) or --workspace (via the relay).