Command reference
Every nebula-ai command and subcommand, plus the global flags, environment variables, JSON output for scripting, shell completion, and the logs.
Every nebula-ai command, what it does, and the flags that apply everywhere. Run nebula-ai <command> --help for the options on any one of them - that output is generated from the binary you have, so it's always current.
Not installed yet? Install the CLI first, then sign in with nebula-ai login.
Commands
| Command | What it does |
|---|---|
login | Authenticate with Nebula via device-flow pairing |
logout | Clear stored credentials |
status | Show CLI status overview |
open <link> | Open a nebula://open link in the full-screen app - --json prints the entity instead |
chat | Send a message to an agent DM and print the reply |
call | Voice calls - see below |
channels | Manage channels and how they're set up - see below |
messages | Send, read, edit, share and react to messages, and title or close the thread under one - see below |
inbox | The threads addressed to you, and their Done list - see below |
tasks | Start, follow and organise tasks - see below |
jobs | Scheduled tasks - see below |
agents | Create, read and configure agents - see below |
miniapps | The workspace's apps - see below |
skills | Workspace and personal skills - see below |
workspace | Manage workspaces - list, switch, create |
local-device | Manage computer use and the local device daemon - see below |
install | Set up computer use - an alias of local-device enable |
uninstall | Turn off computer use, stop the daemon, and remove this device |
capabilities | Probe and print this host's capability snapshot |
logs | Inspect Nebula log files on disk - logs path prints the directory |
update | Check for a newer CLI version and install it |
completion | Generate a shell completion script |
acp | Run Nebula as an editor agent over the Agent Client Protocol |
Run nebula-ai with no command at all to open the full-screen app.
Agents
Everything except list and create takes the agent's ID or handle as its first argument.
| Command | What it does |
|---|---|
agents create <name> -d <description> | Create an agent and print its ID - --model, --channel <handle> to put it on a channel's team, --toolkit <slug> (repeat for more), and --access none|read|write for what the rest of the workspace may do with it |
agents list | List the workspace's agents |
agents get <agent> | Get an agent's details |
agents update <agent> | Update an agent - --name, --description, --model |
agents enable <agent> | Enable an agent |
agents disable <agent> | Disable an agent |
agents remove-toolkit <agent> <toolkit> | Take a toolkit away from an agent, by toolkit slug |
agents delete <agent> | Delete an agent |
agents skills list <agent-id> | List skills attached to an agent |
agents skills detach <agent-id> <skill> | Detach a skill from an agent |
Asking Nebula for the agent you need in any conversation still works, and creates it with whatever detail you describe. Connected apps aren't managed from the shell either: connect them in the full-screen app under Settings → Integrations, or see Connections.
To give an agent a new skill, ask Nebula to install it from a link, or save
one yourself with skills save. See
Skills and slash commands.
Channels
channels manages channels and how they're set up - the same changes as a channel's settings in the full-screen app. Messages live under messages, and a channel's tasks and calls under tasks list --channel and call list --channel. Everything except list, create and archived takes the channel's handle as its first argument, and home names your own Nebula. (--help calls that argument <space>.)
| Command | What it does |
|---|---|
channels list | List your channels, with handle, access, unread count, whether its heartbeat is on, and description |
channels create <name> | Create a channel - --kind private keeps it to invited members; shared is the default |
channels join <channel> | Join an open channel you aren't in yet, by handle or name |
channels rename <channel> <new-name> | Rename a channel |
channels delete <channel> | Delete a channel |
channels archived | List archived channels |
channels unarchive <channel> | Bring an archived channel back |
channels purpose <channel> <purpose> | Set what a channel is for - its Purpose |
channels heartbeat <channel> <on|off> | Switch the channel's heartbeat on or off - its Autonomous mode |
channels miniapps <channel> | List the apps available from a channel |
channels add-miniapp <channel> <miniapp> | Put one of the workspace's apps on a channel, by ID or name |
channels remove-miniapp <channel> <miniapp> | Take an app off a channel - the app itself stays |
channels model <channel> <model> | Set the model for new tasks in a channel, or Home's own model with home |
channels default-model <channel> <model> | Set the default model for new tasks in a channel |
channels appearance <channel> | Set a channel's icon and colour - --icon and --color are both required |
channels agents <channel> | List a channel's agents |
channels add-agent <channel> <agent> | Add an agent to a channel, by agent ID |
channels remove-agent <channel> <agent> | Remove an agent from a channel |
channels devices <channel> | List the devices linked to a channel |
channels add-device <channel> | Add a cloud device to a channel - --size <size>, small by default - or this computer with --local |
channels remove-device <channel> <device> | Remove a device from a channel |
channels default-device <channel> [device] | Make one of a channel's linked devices the default for its new tasks, by device ID - leave the device off to clear the default |
channels members <channel> | List the members of a private channel |
channels invite <channel> <member> | Invite a workspace member to a private channel |
channels remove-member <channel> <member> | Remove a member from a private channel |
channels member-role <channel> <member> <role> | Make a private channel's member an admin or a member |
Whether you can rename or delete a channel is Nebula's call for that channel, not the CLI's - when you can't, the command prints the reason it was given.
CLI 0.1.24 moved messages, and a channel's tasks and calls, out of
channels. Scripts that sent or listed them there need messages send,
messages list, tasks list --channel and call list --channel now. Start a
call in a channel with call start --channel <handle>.
Messages
Every message command works in a channel - your own Nebula unless you pass
--channel <handle> - or inside a task with --task <id>.
| Command | What it does |
|---|---|
messages send [text] | Send a message - pipe it in on standard input when you leave the text off. --agent <handle> tags an agent in it |
messages list | Read recent messages - --limit <n>, 30 by default |
messages replies <id> | Read the replies to a message, oldest first - --limit <n>, 50 by default |
messages edit <id> <text> | Edit one of your messages |
messages delete <id> | Delete one of your messages |
messages react <id> <emoji> | React to a message with an emoji |
messages unreact <id> <emoji> | Take your reaction off a message |
messages share <id> --to <channel> | Share a message into another channel, or home - it shows there with the original's author and text |
messages close <root-id> | Close a thread for everyone in it - a reply or a new task reopens it. While any of its tasks are running it refuses, unless you pass --stop to stop them first |
messages threads | List the threads you're part of - --channel <handle> for every one in a channel, --all adds the ones a reply only mentioned you in, --closed lists closed ones, --limit <n> |
messages title <root-id> <title> | Title a thread, for everyone in it |
A thread is addressed by the ID of the message that started it, which
messages list prints.
Inbox
The inbox holds the threads addressed to you, the same list the full-screen app's rail shows. A thread marked Done leaves your inbox until something new arrives in it.
| Command | What it does |
|---|---|
inbox list | List the threads in your inbox - ! needs you, * is unread. --sort created|updated picks arrival or latest activity, --limit <n> (50 by default) |
inbox list --done | List the threads you marked Done instead, newest first |
inbox done <root-id> | Mark a thread Done - it leaves your inbox until something new arrives |
inbox restore <root-id> | Move a thread you marked Done back to the top of your inbox |
Tasks
A task is one piece of work with its own conversation. Everything except list and create takes the task's ID as its first argument - tasks list prints it in the ID column, newest first.
| Command | What it does |
|---|---|
tasks list | List your tasks - --channel <handle> for one channel's, --limit <n> (20 by default) |
tasks create <message> --agent <handle> | Start a task for an agent on the channel's team, and print its ID - --channel <handle> places it (your own Nebula when you leave it off) |
tasks get <id> | Show a task's title, channel, agent and work status, its number in its thread, and the thread it lives in |
tasks rename <id> <title> | Rename a task |
tasks stop <id> | Stop the work running on a task |
tasks model <id> <model> | Pin the model a task runs on |
tasks read <id> | Mark a task read |
tasks archive <id> | Archive a task |
tasks list --json and tasks get --json also print task_number,
thread_root_id, waiting_on_user_id and created_at.
Read a task's conversation with messages list --task <id>, and add to it with
messages send --task <id>.
nebula-ai chat --task <id> "…" sends to a task without opening it, and
nebula-ai chat --resume <task-id> opens that task directly in the full-screen app.
Calls
The calls page covers what each of these feels like to use.
| Command | What it does |
|---|---|
call start | Start a call in --channel <slug> and open the call screen; --json returns its details without opening the app |
call join <task> | Join an existing call |
call list | List the workspace's calls, live ones first - --channel <handle> for one channel's, --limit <n> (20 by default) |
call chat <task> | Send a one-shot typed message into a call |
call leave <task> | Leave a call you're in |
Scheduled tasks
The jobs commands manage scheduled tasks. Everything
except list and create takes the job's ID or slug.
| Command | What it does |
|---|---|
jobs list | List the scheduled tasks you can see |
jobs get <job> | Show one |
jobs create | Create one as a draft - --name and --cron <expression> are required; --agent names the agent that runs it, --timezone the zone the schedule is read in, --description what it does |
jobs update <job> | Change its --name, --description, --cron or --agent |
jobs run <job> | Run it now |
jobs pause <job> | Pause it |
jobs resume <job> | Resume it |
jobs delete <job> | Delete it |
A new job starts as a draft: its agent writes the steps, and jobs resume
turns it on.
Apps
The miniapps commands work on the workspace's apps.
Put one on a channel with channels add-miniapp.
| Command | What it does |
|---|---|
miniapps list | List the workspace's apps |
miniapps get <app> | Show an app, by ID or name |
miniapps create <name> --agent <agent> | Create an app - the agent you name (not Nebula) builds it. --description says what it's for |
miniapps delete <app> | Delete an app |
Skills
Skills for the whole workspace, or with
--scope personal just for you.
| Command | What it does |
|---|---|
skills list | List skills - a personal one that is one of your / commands prints as /name |
skills save [name] --file <path> | Create a skill from a SKILL.md, or replace the one with the same name. The name defaults to the one in the file. --command makes a personal one a / command, --no-command keeps it a plain skill |
skills delete <name> | Delete a skill |
Local device
The computer use page explains when you'd reach for each.
| Command | What it does |
|---|---|
local-device enable | Turn on computer use and start the daemon |
local-device disable | Turn off computer use and stop the daemon |
local-device status | Show computer-use and daemon status, and check with the server which workspace this machine is bound to |
local-device logs | View daemon logs |
local-device start | Start the daemon |
local-device stop | Stop the daemon |
local-device restart | Restart the daemon |
local-device exec-mode get | Show the current execution mode |
local-device exec-mode set <mode> | Set whether agents can run commands on this host |
local-device claude-code get | Show where claude resolves on this machine, and its version |
Account and workspace settings
Your profile, billing, connected apps, models, variables and devices aren't
shell commands since CLI 0.1.24. Change them in the full-screen app
under Settings, or in the desktop or mobile app. Product analytics can be
turned off under Settings → Preferences → Telemetry, or with the
DO_NOT_TRACK environment variable.
Billing
Settings → Billing in the full-screen app shows the Nebula Credits balance with the Tool Credits row under it, the auto top-up settings, and the latest credit transactions. Three actions sit under them: Edit auto top-up, Add balance and Refresh.
Billing is owner-only here, as it is in the desktop app. Anyone else - and a member whose role hasn't loaded yet - still sees the screen, with Edit auto top-up and Add balance greyed out and "Only the workspace owner can manage billing." beside them, rather than hidden.
Edit auto top-up sets whether auto top-up runs, the balance it tops up at and how much it adds, then saves them for Nebula Credits through the same billing rules the desktop app uses. It needs a card Stripe has on file: until the workspace has one, the toggle stays locked and the form says to subscribe or make a top-up first. A workspace with nothing saved starts at the defaults, a $1 threshold and a $10 top-up amount.
Add balance opens the web billing page in your browser, and prints the address when no browser can be opened. Adding a card and buying credits stay on the web, so the terminal never asks for card details.
Using Nebula from your editor
nebula-ai acp runs Nebula as an agent over the Agent Client Protocol,
speaking on standard input and output rather than drawing anything itself. Point
an editor that speaks ACP at that command and Nebula answers inside the editor,
with the same agents and channels you get everywhere else.
Each session is scoped to the directory the editor opens it in, and that
directory becomes the working folder the agent reads and writes in. The scoping
comes from computer use, so run
nebula-ai local-device enable first - without a registered device, sessions
fail with "Nebula local device is not configured."
Run it by hand and it will sit there silently waiting for protocol messages. That's correct behaviour, not a hang - press Ctrl C to exit.
Global flags
These work on every command.
| Flag | What it does |
|---|---|
--json | Output raw JSON |
--workspace <id-or-slug> | Run against a specific workspace, ignoring the active one |
-v, --verbose | Verbose output - the same as --log-level=debug |
--log-level <level> | One of error, warn, info, debug, trace |
--no-color | Disable colours |
--api-url <url> | Point at a different API host |
Environment variables
Useful when you can't pass flags - CI, containers, a shared shell profile.
| Variable | What it does |
|---|---|
NEBULA_AUTH_TOKEN | Use a pre-minted token instead of the stored credential. Takes precedence over whatever login saved |
NEBULA_API_BASE | Point at a different API host - the same thing --api-url does |
NEBULA_WEB_URL | Point the links the CLI opens, such as sign-in, at a different Nebula host |
NEBULA_HOME | Override ~/.nebula, where credentials, settings, and logs live |
NEBULA_LOG_LEVEL | One of error, warn, info, debug, trace - the env form of --log-level |
NEBULA_DEBUG | Set to true for verbose logging - the same as -v |
DO_NOT_TRACK | Set to 1 to turn product analytics off. NEBULA_DO_NOT_TRACK works too |
NEBULA_AI_NO_UPDATE_CHECK | Set to 1 to skip the daily update check |
NEBULA_AI_CACHE_DIR | Override where npx nebula-ai caches the downloaded binary |
NEBULA_AI_DOWNLOAD_BASE | Download that binary from a mirror instead - useful behind a strict firewall |
NEBULA_AUTH_TOKEN is the one to reach for in CI. It skips the device-flow
browser handoff entirely, which a build agent can't complete anyway.
Scripting
--json turns any command into something you can pipe. It's a global flag, so it works the same everywhere.
tasks list --json emits a top-level array, so .[] works for the example above. A command that reads one thing, such as agents get, prints one object instead. Since CLI 0.1.22 the list and lookup commands print a fixed set of snake_case fields and nothing else, so a field the server adds later never shows up in your script; times are epoch milliseconds, and a field with no value is null. One that gets no answer within 30 seconds fails with "No answer came back in 30 seconds. Try again."
The columns a command prints don't always match its JSON field names. Run the command once with --json and read the shape before writing the jq.
Combine --json with --workspace in CI so a script never depends on whichever workspace happened to be active on that machine.
Exit codes and errors
A script can branch on the exit code instead of parsing what the command printed.
| Exit code | What it means |
|---|---|
0 | It worked |
1 | Something failed - including a chat turn that failed |
3 | You're not signed in, or the saved session can't be used. Run nebula-ai login |
4 | chat stopped on a decision you have to make in Nebula, such as an approval - a question from the agent doesn't stop it |
5 | The message went out, but what became of it isn't known |
Exit 5 is the one to handle with care: sending again could repeat the work. Check nebula-ai messages list --task <id> first. nebula-ai status exits 3 when you're signed out, which makes it a cheap sign-in check.
Under --json, results stay on standard output and a failure is exactly one JSON line on standard error, with no colour codes:
The code is one of error, usage, auth_required or outcome_unknown. chat --json prints one object with thread_id, agent, status, final_message, events and pending - pending names the decision it's waiting on when status is waiting, and is null otherwise. A question the agent asks shows up in pending too, but status keeps reporting the turn itself and chat waits for the turn to finish instead of exiting 4 - the human-readable output tells you to answer it in Nebula or with nebula-ai chat --resume <id>.
Shell completion
nebula-ai completion prints a completion script for bash, zsh, or fish - source it from your shell profile.
When something goes wrong
nebula-ai status shows whether you're signed in and which workspace you're pointed at - most surprises are one of those two. nebula-ai capabilities reports what this machine supports, like whether ffmpeg is available for camera.
nebula-ai logs path prints the directory the log files live in (~/.nebula/logs/), ready to pipe into your pager. Re-run a failing command with -v for the detail.
nebula-ai update checks for a newer version and installs it. Worth trying before reporting anything.
Still stuck? Ask Nebula directly - it's good at drafting a support email with the right detail in it. For bugs or anything unresolved, email support@nebula.gg.
Related
Put Nebula to work
Get Nebula on your computer or phone, then create your first channel and set its goal.
Nebula CLI
Run Nebula from your terminal. Install the nebula-ai CLI, sign in once, and use the full-screen app to chat, join calls, and drive your workspace.
Calls from the terminal
Start, join, and run Nebula calls from your shell. Chat-first by default, with voice as a two-step opt-in and a headless mode for servers.