nebula-ai 0.1.20 → 0.1.21

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/README.md +132 -70
  2. package/package.json +1 -1
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # nebula-ai
2
2
 
3
- Command-line interface and terminal UI for [nebula.gg](https://nebula.gg) — a platform for building, running, and orchestrating AI agents that can chat, use tools, and execute long-running tasks on your behalf.
3
+ Command-line interface and terminal UI for [nebula.gg](https://nebula.gg), a platform for building, running, and orchestrating AI agents that can chat, use tools, and execute long-running tasks on your behalf.
4
4
 
5
5
  ## Quick start
6
6
 
@@ -10,7 +10,7 @@ npx nebula-ai
10
10
 
11
11
  The first run downloads the matching native binary for your platform (~60 MB compressed), verifies it against a signed manifest, caches it, and execs it. Subsequent runs are instant.
12
12
 
13
- Sign in with email + a 6-digit code, then either drop into the interactive TUI or run one-off commands from the shell:
13
+ Run `npx nebula-ai login`. The terminal shows a short code and opens your browser to approve it. Then use the interactive TUI or run commands from the shell:
14
14
 
15
15
  ```sh
16
16
  npx nebula-ai login
@@ -18,13 +18,13 @@ npx nebula-ai # interactive TUI
18
18
  npx nebula-ai chat "summarize the open issues in repo X"
19
19
  ```
20
20
 
21
- The auth token is persisted as an encrypted file at `~/.nebula/auth-token` (mode `0600`). The encryption key is derived from your hostname and OS user via HKDF-SHA256, so backups/syncs of `~/.nebula/` to a different machine yield ciphertext that won't decrypt on the target — the binding is intentional, not a bug. See [ADR-0054](../../docs/adr/0054-encrypted-file-token-store-no-keychain.md) for the threat-model details.
21
+ The auth token is persisted as an encrypted file at `~/.nebula/auth-token` (mode `0600`). The encryption key is derived from your hostname and OS user via HKDF-SHA256, so backups/syncs of `~/.nebula/` to a different machine yield ciphertext that won't decrypt on the target, the binding is intentional, not a bug. See [ADR-0054](../../docs/adr/0054-encrypted-file-token-store-no-keychain.md) for the threat-model details.
22
22
 
23
23
  **Supported platforms:** macOS (arm64, x64), Linux (x64, arm64), Windows (x64).
24
24
 
25
25
  ## Install via Homebrew
26
26
 
27
- macOS and Linux users can also install through a managed Homebrew tap — same native binary, no Node dependency, landed straight on `$PATH`:
27
+ macOS and Linux users can also install through a managed Homebrew tap, same native binary, no Node dependency, landed straight on `$PATH`:
28
28
 
29
29
  ```sh
30
30
  brew install agent-labs-dev/nebula/nebula-ai
@@ -36,9 +36,9 @@ brew install nebula-ai
36
36
  brew upgrade nebula-ai
37
37
  ```
38
38
 
39
- The Homebrew channel ships prod releases only. Dev builds remain on npm — install with `npm i -g nebula-ai@dev` (or `npx nebula-ai@dev`). Windows users: use `npx nebula-ai` as shown above.
39
+ The Homebrew channel ships prod releases only. Dev builds remain on npm, install with `npm i -g nebula-ai@dev` (or `npx nebula-ai@dev`). Windows users: use `npx nebula-ai` as shown above.
40
40
 
41
- If you've installed via both `brew` and `npm i -g`, whichever prefix appears first on your `PATH` wins — this is normal for multi-source CLIs.
41
+ If you've installed via both `brew` and `npm i -g`, whichever prefix appears first on your `PATH` wins, this is normal for multi-source CLIs.
42
42
 
43
43
  ### Alongside Nebula Desktop
44
44
 
@@ -46,49 +46,49 @@ The [Nebula Desktop app](https://github.com/agent-labs-dev/nebula-desktop/releas
46
46
 
47
47
  ## Interactive TUI
48
48
 
49
- The TUI opens straight into your Channel — the ongoing conversation for whichever Channel you were last in. On the left, the Channel rail lists Home, Mentions, your Channels and the people in your workspace, with the backend's unread and mention counts. Across the top, the Channel's view strip holds its conversation, its views, and the tabs you opened from it. Everything is reachable from the keyboard.
49
+ The TUI opens straight into your Channel, the ongoing conversation for whichever Channel you were last in. On the left, the Channel rail lists Home, Mentions, your Channels and the people in your workspace, with the backend's unread and mention counts. Across the top, the Channel's view strip holds its conversation, its views, and the tabs you opened from it. Everything is reachable from the keyboard.
50
50
 
51
51
  ### Getting around
52
52
 
53
53
  Up and down is the rail; left and right is the view strip. These work everywhere, including while you are typing a message:
54
54
 
55
- - **Alt+↑ / Alt+↓** (or **Alt+k / Alt+j**) — previous / next Channel or person in the rail.
56
- - **Alt+u** — the next Channel with unread messages or mentions.
57
- - **Alt+h / Alt+l** — previous / next view or open tab. Outside the composer, **Alt+← / Alt+→** do the same.
58
- - **Ctrl+/** (or **Ctrl+K**; **Cmd** on macOS terminals that pass it through) — search for any Channel, person, Task, or place (Settings, Notifications, Workspaces). Ctrl+/ is the one to reach for when your terminal or tmux keeps Ctrl+K. Esc returns to your draft.
59
- - **Ctrl+W** — close the open tab.
55
+ - **Alt+↑ / Alt+↓** (or **Alt+k / Alt+j**), previous / next Channel or person in the rail.
56
+ - **Alt+u**, the next Channel with unread messages or mentions.
57
+ - **Alt+h / Alt+l**, previous / next view or open tab. Outside the composer, **Alt+← / Alt+→** do the same.
58
+ - **Ctrl+/** (or **Ctrl+K**; **Cmd** on macOS terminals that pass it through), search for any Channel, person, Task, or place (Settings, Notifications, Workspaces). Ctrl+/ is the one to reach for when your terminal or tmux keeps Ctrl+K. Esc returns to your draft.
59
+ - **Ctrl+W**, close the open tab.
60
60
 
61
61
  When you are not typing:
62
62
 
63
- - **1–9** — open that view: `1` Chat, `2` Tasks (with the Channel's jobs and Calls under it), `3` Files, `4` Channel (members, agents, apps, model, devices, and the rest of its settings). Tabs you open (Replies, a Task, a Call) follow them on the strip from `5`.
64
- - **,** — open Settings.
65
- - **Esc** — back to the conversation.
66
- - **Ctrl+B** — hide or show the rail, remembered between launches. Below 100 columns it folds away by itself and the workspace name moves into the title.
67
- - **i / Enter** — type in the composer; **Esc** leaves it.
68
- - **↑ / ↓ or j / k** — select a message for replies (`t`), reactions (`r`) or copy (`y`). PgUp / PgDn and Ctrl+U / Ctrl+D scroll without moving the selection.
69
- - **Mouse** — click a rail row, a view, or a tab's `×`.
70
- - **Status bar** — mode badge (`NAV` / `INSERT` / `HITL`), where you are, the next few keys, and the connection dot.
63
+ - **1-9**, open that view: `1` Chat, `2` Tasks (with the Channel's jobs and Calls under it), `3` Files, `4` Channel (members, agents, apps, model, devices, and the rest of its settings). Tabs you open (Replies, a Task, a Call) follow them on the strip from `5`.
64
+ - **,**, open Settings.
65
+ - **Esc**, back to the conversation.
66
+ - **Ctrl+B**, hide or show the rail, remembered between launches. Below 100 columns it folds away by itself and the workspace name moves into the title.
67
+ - **i / Enter**, type in the composer; **Esc** leaves it.
68
+ - **↑ / ↓ or j / k**, select a message for replies (`t`), reactions (`r`) or copy (`y`). PgUp / PgDn and Ctrl+U / Ctrl+D scroll without moving the selection.
69
+ - **Mouse**, click a rail row, a view, or a tab's `×`.
70
+ - **Status bar**, mode badge (`NAV` / `INSERT` / `HITL`), where you are, the next few keys, and the connection dot.
71
71
  - **q** quits from navigation mode; **Ctrl+C** twice quits from anywhere. **?** opens the full shortcut reference.
72
72
 
73
73
  ### Chat
74
74
 
75
- - **Channel mentions** — type `#` to pick a Channel by name or handle. Renames change the displayed name; messages send the permanent handle.
76
- - **Markdown rendering** — agent responses display bold, italic, inline code, headings, and clickable links.
77
- - **Model selection** — press `m` to choose from Nebula tiers, curated vendor models, and custom models. Named Channels save your personal session preference; Home, DMs, and Tasks save their conversation preference. Workspace defaults live in Settings.
78
- - **File attachments** — drop file paths into the Channel composer to upload and stage them for your next message. Task composers can also use files through your connected local device.
79
- - **Activity log** — tool calls and execution details are surfaced inline in chat, with `Enter` on a completed turn opening the full activity log.
80
- - **Entity navigation** — press `Tab` on a selected message to cycle through referenced agents, triggers, files, and skills; `Enter` opens the detail view.
81
- - **Channel messages** — use `↑`/`↓` in navigation mode to select a message, `t` to open its replies, `r` to react, `y` to copy, and `d` to delete one of your own (Enter or `y` confirms, Esc keeps it). Inside replies, `i` composes, `j`/`k` scroll, `d` deletes your selected reply, `p` loads earlier replies, and `Esc` returns. `Ctrl+/` also lists open Channels you have not joined; Enter joins and opens one. In the Apps view (Channel → Apps), `a` adds a workspace app to the Channel and `x` removes the selected one.
82
- - **Interactive prompts (HITL)** — when an agent asks a multi-choice question or requests plan approval, it renders as a widget with option descriptions, number-key shortcuts (1–9), and an "Other" free-text fallback.
83
- - **Archive** — press `Shift+A` in any channel to archive it with a confirm prompt. **Shift+R** renames it, **Shift+P** pins it.
84
- - **Live updates** — Channel messages and board state follow Zero; typing and in-progress activity arrive over LiveKit.
85
- - **Start in the composer** — configurable in Settings → CLI & TUI → Preferences. When disabled, chats open in navigation mode; press `i` to start typing.
75
+ - **Channel mentions**, type `#` to pick a Channel by name or handle. Renames change the displayed name; messages send the permanent handle.
76
+ - **Markdown rendering**, agent responses display bold, italic, inline code, headings, and clickable links.
77
+ - **Model selection**, press `m` to choose from Nebula tiers, curated vendor models, and custom models. Named Channels save your personal session preference; Home, DMs, and Tasks save their conversation preference. Workspace defaults live in Settings.
78
+ - **File attachments**, drop file paths into the Channel composer to upload and stage them for your next message. Task composers can also use files through your connected local device.
79
+ - **Activity log**, tool calls and execution details are surfaced inline in chat, with `Enter` on a completed turn opening the full activity log.
80
+ - **Entity navigation**, press `Tab` on a selected message to cycle through referenced agents, triggers, files, and skills; `Enter` opens the detail view.
81
+ - **Channel messages**, use `↑`/`↓` in navigation mode to select a message, `t` to open its replies, `r` to react, `y` to copy, and `d` to delete one of your own (Enter or `y` confirms, Esc keeps it). Inside replies, `i` composes, `j`/`k` scroll, `d` deletes your selected reply, `p` loads earlier replies, and `Esc` returns. `Ctrl+/` also lists open Channels you have not joined; Enter joins and opens one. In the Apps view (Channel → Apps), `a` adds a workspace app to the Channel and `x` removes the selected one.
82
+ - **Interactive prompts (HITL)**, when an agent asks a multi-choice question or requests plan approval, it renders as a widget with option descriptions, number-key shortcuts (1-9), and an "Other" free-text fallback.
83
+ - **Archive**, press `Shift+A` in any channel to archive it with a confirm prompt. **Shift+R** renames it, **Shift+P** pins it.
84
+ - **Live updates**, Channel messages and board state follow Zero; typing and in-progress activity arrive over LiveKit.
85
+ - **Start in the composer**, configurable in Settings → CLI & TUI → Preferences. When disabled, chats open in navigation mode; press `i` to start typing.
86
86
 
87
87
  ### Workspace & session
88
88
 
89
- - **Rail and view strip** — click the workspace name at the top of the rail to switch workspaces. Each Channel keeps the tabs opened from it.
90
- - **Drafts** — text drafts stay with their workspace and conversation during navigation. Opening search or shortcut help keeps the current composer and staged files intact. Drafts are held for this process, not persisted across restarts.
91
- - **Session restore** — enable in Settings to automatically reopen your readers and navigation state when you restart the CLI. Session state is also flushed on clean Ctrl+C / SIGTERM.
89
+ - **Rail and view strip**, click the workspace name at the top of the rail to switch workspaces. Each Channel keeps the tabs opened from it.
90
+ - **Drafts**, text drafts stay with their workspace and conversation during navigation. Opening search or shortcut help keeps the current composer and staged files intact. Drafts are held for this process, not persisted across restarts.
91
+ - **Session restore**, enable in Settings to automatically reopen your readers and navigation state when you restart the CLI. Session state is also flushed on clean Ctrl+C / SIGTERM.
92
92
 
93
93
  ### Theming
94
94
 
@@ -102,18 +102,18 @@ npx nebula-ai user config set theme tokyo-night
102
102
 
103
103
  Press `,`, or search for `Settings` with Ctrl+/; a Channel's own settings are its `4` view:
104
104
 
105
- - **CLI & TUI → Preferences** — this app's own settings: theme, hiding the Channel rail, starting in the composer, session restore, log level, telemetry, the shortcut reference, and a reset.
105
+ - **CLI & TUI → Preferences**, this app's own settings: theme, hiding the Channel rail, starting in the composer, session restore, log level, telemetry, the shortcut reference, and a reset.
106
106
 
107
- - **Profile & Account** — username, email, display name.
108
- - **Models** — the workspace's model catalog: what is selectable, which
107
+ - **Profile & Account**, username, email, display name.
108
+ - **Models**, the workspace's model catalog: what is selectable, which
109
109
  model is the workspace default, which vendor models are curated, and
110
110
  bring-your-own routing aliases and endpoints.
111
- - **Local Device** — daemon status, start/stop/restart controls, device ID.
112
- - **Files** — browse and manage files stored on the platform.
111
+ - **Local Device**, daemon status, start/stop/restart controls, device ID.
112
+ - **Files**, browse and manage files stored on the platform.
113
113
 
114
114
  ## Local device
115
115
 
116
- For long-running tasks, agents can execute code on your own machine directly — this is opt-in via the **computer use** prompt during onboarding (`exec_mode = host`). Skip the prompt or pick "No" and the daemon refuses every exec / file / service RPC with `exec_host_disabled` until you opt in from Settings.
116
+ For long-running tasks, agents can execute code on your own machine directly, this is opt-in via the **computer use** prompt during onboarding (`exec_mode = host`). Skip the prompt or pick "No" and the daemon refuses every exec / file / service RPC with `exec_host_disabled` until you opt in from Settings.
117
117
 
118
118
  ```sh
119
119
  npx nebula-ai local-device enable # turn on computer use + start the daemon
@@ -122,35 +122,35 @@ npx nebula-ai local-device disable # turn it off again (also stops the daemon)
122
122
  npx nebula-ai uninstall # remove this device entirely (use --keep-data to keep config/logs)
123
123
  ```
124
124
 
125
- The daemon runs under your user account with no root prompt and is owned by whichever surface started it: the interactive TUI spawns it detached (it keeps running after you close the terminal; the TUI's **Settings → Local Device** screen starts/stops/restarts it), while the Nebula desktop app runs it inside the app itself (quit the app — after its warning — to stop it). Each app runs its own daemon per signed-in account: the CLI's lock is `~/.nebula/daemon.cli.<account>.pid`, and a desktop app's daemon is filed under its release channel and the account it serves, so no two ever signal each other's. Commands start in the directory where you opened the CLI. Computer Use can either stay limited to that folder or allow your home directory in whole-system mode.
125
+ The daemon runs under your user account with no root prompt and is owned by whichever surface started it: the interactive TUI spawns it detached (it keeps running after you close the terminal; the TUI's **Settings → Local Device** screen starts/stops/restarts it), while the Nebula desktop app runs it inside the app itself (quit the app, after its warning, to stop it). Each app runs its own daemon per signed-in account: the CLI's lock is `~/.nebula/daemon.cli.<account>.pid`, and a desktop app's daemon is filed under its release channel and the account it serves, so no two ever signal each other's. Commands start in the directory where you opened the CLI. Computer Use can either stay limited to that folder or allow your home directory in whole-system mode.
126
126
 
127
127
  ## CLI commands
128
128
 
129
129
  The same surface is available from the command line:
130
130
 
131
- - `chat` — send a message to an agent (`-a/--agent`, `-t/--task`, `--no-stream`). The old `-c/--channel <task-id>` remains a hidden alias for `--task`. Use `channels message <name> <message>` to write to a Channel.
132
- - `call` — voice calls. `call start` / `call join <thread>` open the TUI's call screen (`--headless` runs the audio engine with no TUI — the edge-speakerphone mode; `--chat` joins data-only); `call list/status <thread>` inspect calls; `call chat <thread> -m "…"` pipes a one-shot typed message into a live call; `call leave/end <thread>`.
133
- - `channels` (alias `spaces`) — the Channel board from the command line: `list`, `create`, `join`, `rename`, `delete`, `message`, `tasks`, `files`, `calls`, `call`, `miniapps`/`add-miniapp`/`remove-miniapp`, `model`, `appearance`, `agents`/`add-agent`/`remove-agent`, `default-model`, `default-device`, `devices`/`add-device`/`remove-device`, and for named Channels `members`/`invite`/`remove-member`/`member-role`.
134
- - `tasks` — list, create, get, delete, archive, unarchive, share, update, and read a Task's messages. `tasks create --channel <name>` places a Task in that Channel; omitting it uses Home. `--space` remains an alias. Use `--workspace <slug> chat --resume <task-id>` to open a Task directly in a chosen workspace; `--json tasks status <task-id>` exposes the canonical Task work state for launchers.
135
- - `agents` — list, create, update, delete, enable/disable, view logs/errors, manage triggers, and attach/detach skills.
136
- - `user` — profile, account, and platform-side resources.
137
- - `user update` — change username or display name.
138
- - `user config` — list, get, set, and reset CLI configuration values; list available AI models.
139
- - `user variables` — manage global or agent-scoped variables and secrets.
140
- - `user billing` — check balance, view transaction history, and configure auto top-up.
141
- - `user files` — upload, download, list, share, and manage files and folders.
142
- - `user devices` — manage your cloud devices (info, start, stop, rename, visibility, file browse/search, and long-running services: create, start, stop, logs).
143
- - `models` — the workspace's model catalog.
144
- - `models list` — every selectable model (Nebula tiers, curated vendor models, custom), with the workspace default marked.
145
- - `models default [model]` — show, or set, the workspace default model (admin/owner only). This is the model every conversation without its own pin runs on.
146
- - `models curate [--add <ids...>] [--remove <ids...>]` — choose which vendor models the workspace offers. The allowlist starts empty, so only the Nebula tiers are selectable until you add some.
147
- - `models custom list|add|remove` — bring-your-own models: a routing alias (`--alias <model-id>`) or an OpenAI-compatible endpoint (`--base-url`, `--model-id`, `--auth`). Add `--device <id>` to lock a model to one machine — required for a `localhost` endpoint — and `--share` to make it visible to the whole workspace.
148
- - `local-device` — manage computer use and the on-host daemon (enable, disable, status, logs, start, stop, restart, exec-mode get/set, claude-code get — where this device's Claude Code command resolves and its version; the command itself is set per harness under Settings → External agents).
149
- - `install` / `uninstall` — `install` is an alias of `local-device enable`; `uninstall` turns computer use off, stops the daemon, and removes this device.
150
- - `status` — current CLI, auth, daemon, device, and folder state.
151
- - `usage` — workspace token usage, cache savings, request count, and model cost (default: last 7 days; use `--days <n>`). Supports `--json` for launchers and dashboards.
152
- - `workspace list` — lists available workspaces; `--json workspace list` returns compact `{ id, name, slug, active }` rows for a workspace picker.
153
- - `login` / `logout` — authenticate or clear stored credentials.
131
+ - `chat`, send a message to an agent (`-a/--agent`, `-t/--task`, `--no-stream`). The old `-c/--channel <task-id>` remains a hidden alias for `--task`. Use `channels message <name> <message>` to write to a Channel.
132
+ - `call`, voice calls. `call start` / `call join <thread>` open the TUI's call screen (`--headless` runs the audio engine with no TUI, the edge-speakerphone mode; `--chat` joins data-only); `call list/status <thread>` inspect calls; `call chat <thread> -m "…"` pipes a one-shot typed message into a live call; `call leave/end <thread>`.
133
+ - `channels` (alias `spaces`), the Channel board from the command line: `list`, `create`, `join`, `rename`, `delete`, `message`, `tasks`, `files`, `calls`, `call`, `miniapps`/`add-miniapp`/`remove-miniapp`, `model`, `appearance`, `agents`/`add-agent`/`remove-agent`, `default-model`, `default-device`, `devices`/`add-device`/`remove-device`, and for named Channels `members`/`invite`/`remove-member`/`member-role`.
134
+ - `tasks`, list, create, get, delete, archive, unarchive, share, update, and read a Task's messages. `tasks create --channel <name>` places a Task in that Channel; omitting it uses Home. `--space` remains an alias. Use `--workspace <slug> chat --resume <task-id>` to open a Task directly in a chosen workspace; `--json tasks status <task-id>` exposes the canonical Task work state for launchers.
135
+ - `agents`, list, create, update, delete, enable/disable, view logs/errors, manage triggers, and attach/detach skills.
136
+ - `user`, profile, account, and platform-side resources.
137
+ - `user update`, change username or display name.
138
+ - `user config`, list, get, set, and reset CLI configuration values; list available AI models.
139
+ - `user variables`, manage global or agent-scoped variables and secrets.
140
+ - `user billing`, check balance, view transaction history, and configure auto top-up.
141
+ - `user files`, upload, download, list, share, and manage files and folders.
142
+ - `user devices`, manage your cloud devices (info, start, stop, rename, visibility, file browse/search, and long-running services: create, start, stop, logs).
143
+ - `models`, the workspace's model catalog.
144
+ - `models list`, every selectable model (Nebula tiers, curated vendor models, custom), with the workspace default marked.
145
+ - `models default [model]`, show, or set, the workspace default model (admin/owner only). This is the model every conversation without its own pin runs on.
146
+ - `models curate [--add <ids...>] [--remove <ids...>]`, choose which vendor models the workspace offers. The allowlist starts empty, so only the Nebula tiers are selectable until you add some.
147
+ - `models custom list|add|remove`, bring-your-own models: a routing alias (`--alias <model-id>`) or an OpenAI-compatible endpoint (`--base-url`, `--model-id`, `--auth`). Add `--device <id>` to lock a model to one machine, required for a `localhost` endpoint, and `--share` to make it visible to the whole workspace.
148
+ - `local-device`, manage computer use and the on-host daemon (enable, disable, status, logs, start, stop, restart, exec-mode get/set, claude-code get, where this device's Claude Code command resolves and its version; the command itself is set per harness under Settings → External agents).
149
+ - `install` / `uninstall`, `install` is an alias of `local-device enable`; `uninstall` turns computer use off, stops the daemon, and removes this device.
150
+ - `status`, current CLI, auth, daemon, device, and folder state.
151
+ - `usage`, workspace token usage, cache savings, request count, and model cost (default: last 7 days; use `--days <n>`). Supports `--json` for launchers and dashboards.
152
+ - `workspace list`, lists available workspaces; `--json workspace list` returns compact `{ id, name, slug, active }` rows for a workspace picker.
153
+ - `login` / `logout`, authenticate or clear stored credentials.
154
154
 
155
155
  Every command supports `--json` for machine-readable output, `-v/--verbose` for extra detail, `--no-color` to disable ANSI styling, and `--api-url <url>` to point at a non-default backend.
156
156
 
@@ -240,6 +240,9 @@ arguments.
240
240
  | `channels invite <channel> <member>` | `{ "invited": true }` | `{ "ok": true, "id" }` | `Invited <member> to <channel>` |
241
241
  | `channels remove-member <channel> <member>` | `{ "removed": true }` | `{ "ok": true, "id" }` | `Removed <member> from <channel>` |
242
242
  | `channels member-role <channel> <member> <role>` | `{ "role" }` | `{ "ok": true, "id" }` | `<member> is now a <role> in <channel>` |
243
+ | `user config set <key> <value>` | `{ "key", "value" }` | `{ "ok": true }` | unchanged |
244
+ | `user config reset` | `{ "reset": true }` | `{ "ok": true }` | unchanged |
245
+ | `logout` | `null` | `{ "ok": true }` | unchanged |
243
246
 
244
247
  `tasks share` and `user files share` print the server's answer under
245
248
  `--json`, as before. Without `--json` they now print the link instead of the whole body.
@@ -249,15 +252,74 @@ A create prints the id of the row it made, whoever minted it. `call start`,
249
252
  join credential. A cloud device added with `channels add-device` prints no
250
253
  id, because the server mints it after the command returns.
251
254
 
252
- The table covers all 53 kernel writes that print the envelope. The two
253
- floor commands above make 55 kernel writes in total.
255
+ The table covers all 56 kernel writes that print the envelope. The two
256
+ floor commands above make 58 kernel writes in total.
257
+
258
+ ### Changelog: what a read prints under `--json`
259
+
260
+ Every read command now prints a fixed list of fields under `--json`, not
261
+ the server's whole response. A list prints a bare array and a single read
262
+ prints one object, with no `result`, `success` or `message` wrapper around
263
+ either. A field the server adds later does not appear until the CLI
264
+ declares it. Keys are snake_case. A timestamp is epoch milliseconds, as the
265
+ REST response had it.
266
+
267
+ A read that gets no answer in 30 seconds exits 1 with `error` and prints
268
+ nothing on stdout. A single read that finds nothing, such as
269
+ `user devices info` with no device, exits 1 with `error` too.
270
+
271
+ Each read keeps the fields its text output shows, plus the row's id. The
272
+ table lists the keys it stopped printing. `tasks share` and
273
+ `user files share` follow the same rule: they still print their link.
274
+
275
+ | Command | Prints now | Stopped printing |
276
+ | --- | --- | --- |
277
+ | `usage` | `period_days`, `total_cost_dollars`, `request_count`, `total_tokens`, `billable_tokens`, `total_input_tokens`, `total_output_tokens`, `total_cached_tokens`, `cache_hit_percentage`, `estimated_savings_dollars` | `user_id`, `start_date`, `end_date`, `daily_avg_tokens`, `daily_avg_requests`, `total_reasoning_tokens` |
278
+ | `tasks list` | `id`, `title`, `channel`, `updated_at` | `user_id`, `title_source`, `slug`, `is_title_placeholder`, `source`, `source_channel_name`, `source_workspace_name`, `is_shared`, `is_pinned`, `can_share`, `can_archive`, `extended_thinking_enabled`, `target_agent_id`, `assigned_agent_id`, `is_agent_dm`, `working_dir`, `device_id`, `active_device`, `device_label`, `plan_mode`, `model_preference`, `archived_at`, `created_at`, `message_count`, `last_message`, `last_activity_at`, `channel_label`, `channel_id`, `origin_root_message_id`, `origin_call_id`, `channel_auto_routed`, `channel_description`, `tags`, `thread_summary`, `chapters`, `chapters_covered_up_to`, `unread_count`, `last_read_at`, `has_unread`, `first_unread_message_id`, `voice_status`, `voice_call_id`, `state`, `miniapp_id`, `miniapps`, `visibility`, `participant_user_ids`, `participant_agent_ids`, `display_summary`, `feed_bucket`, `is_channel`, `room_kind`, `dm_agent`. The text table's Agent column, which the response never filled, is now Channel. |
279
+ | `tasks get <id>` | `id`, `title`, `channel`, `feed_bucket`, `created_at`, `updated_at`, `archived_at` | the keys `tasks list` stopped printing, less `archived_at`, `created_at` and `feed_bucket` |
280
+ | `tasks status <id>` | `id`, `last_activity_at`, `state` with `feed_bucket`, `turns` (`work_status`, `state_seq`, `open_turns[]` of `user_message_id`, `status`, `started_at`, and `last_outcome` of `outcome`, `turn_id`, `settled_at_ms`) and `unread` (`count`, `has_unread`) | `state.visibility`, `state.turns.composer_block`, `state.unread.last_read_at`, `state.unread.first_unread_message_id`; on each open turn `user_id`, `agent_id`, `task_id`, `trigger_id`, `coalescible`, `expires_at`, `todo_progress`, `latest_activity`, `wait_id`, `wait_condition`, `wait_timeout_at_ms`, `holder`; on `last_outcome` `terminal_event_id`, `task_id` |
281
+ | `tasks messages <id>` | `id`, `role`, `content`, `created_at` | `agentDisplayName`, `agentId`, `agentAvatarUrl`, `agentIsSubAgent` |
282
+ | `tasks share <id>` | `share_url`, `is_shared` | `can_share`, `restriction_reason`, `source_display` |
283
+ | `call list <task>` | `call_id`, `thread_id`, `status`, `started_at`, `ended_at`, `duration_ms`, `participant_user_ids`, `participant_agent_ids`, `summary` | `work_thread_ids`, `started_by_user_id`, `room_name`, `transcript_message_count`, `member_user_ids`, `member_agent_ids`, `final_summary`, `transcript_file_path`, `summary_file_path`, `thread_title`, `thread_summary_title`, `thread_summary`, `visibility` |
284
+ | `call status <task>` | one object: `status`, `call_id`, `started_at`, `participants[]` of `kind`, `id`, `display_name`, `connected`, `posture` | the `{ "status": {…}, "participants": {…} }` wrapper; `room_name`, `session_id`, `background_agent_ids`, `silent_agent_ids`, `listen_only_agent_ids`, `audio_output_off_agent_ids`, `wake_config`, `personas`, `monitors`, `summary`; on each participant `is_active`, `is_creator` |
285
+ | `agents list` | `id`, `name`, `slug`, `visibility`, `is_disabled`, `updated_at`, `can_run`, `run_blocked_detail`, `run_scope_detail` | `description`, `icon_url`, `workspace_access`, `my_access`, `is_system`, `is_user_agent`, `toolkit_count`, `trigger_count`, `user_id`, `is_orchestrator`, `is_channel_agent`, `device_id`, `external`, `owner_display_name`, `created_at`, `display_name` |
286
+ | `agents get <id>` | `id`, `name`, `slug`, `description`, `visibility`, `is_disabled`, `effective_model`, `updated_at`, `external_runtime`, `can_run`, `run_blocked_detail`, `run_scope_detail` | `user_id`, `interaction_prefs`, `website_scope`, `icon_url`, `device_id`, `model_preference`, `workspace_access`, `my_access`, `is_system`, `is_user_agent`, `is_channel_agent`, `summary`, `prompts`, `tools`, `memories`, `wallets`, `oauth_connections`, `toolkits`, `toolkit_details`, `account_links`, `linked_accounts`, `skills`, `cost_per_million_input_tokens`, `pricing_display`, `knowledge_base`, `external`, `integration_backend`, `is_legacy`, `created_at`, `display_name` |
287
+ | `agents logs <id>`, `agents errors <id>` | a bare array of `id`, `task_id`, `created_at`, `log_level`, `is_error`, `message`, `tool_name` | the `logs`, `total` and `has_more` wrapper; on each log `agent_id`, `user_id`, `agent_name`, `agent_owner_id`, `success`, `message_type`, `tool_args`, `tool_result`, `tool_duration_ms`, `error_details`, `duration_ms`, `token_usage` |
288
+ | `agents accounts <id>` | `account_id`, `toolkit`, `display_name`, `status` | `account` and `accountId`, renamed to the response's `display_name` and `account_id` |
289
+ | `agents triggers <id>` | `id`, `name`, `kind`, `is_active`, `status_label`, `schedule_label`, `event_label`, `last_run_at`, `next_run_at` | every other key of the trigger, `webhook_secret` included: `user_id`, `last_task_id`, `slug`, `description`, `cron_expression`, `data`, `options`, `external_trigger_id`, `deactivation_reason`, `last_execution_status`, `run_count`, `max_runs`, `starts_at`, `ends_at`, `deleted_at`, `created_at`, `updated_at`, `agent_id`, `goal_status`, `goal_success_criteria`, `goal_memory`, `goal_memory_summary`, `goal_iteration_count`, `goal_max_iterations`, `goal_next_check_at`, `goal_met_at`, `goal_plan`, `job_lifecycle`, `event_config`, `trigger_type`, `filtering_prompt`, `task_content`, `plan_mode`, `timezone`, `toolkit_slug`, `monitoring`, `thread_id`, `channel_id`, `thread_summary`, `thread_last_activity_at`, `channel`, `channel_label`, `is_agent_dm`, `target_agent_id`, `agent_display_name`, `latest_run`, `task_title`, `task_prompt`, `task_steps`, `webhook_secret`, `webhook_url`, `is_legacy`, `owner_display_name`, `is_private`, `workspace_access`, `my_access`, `can_manage`, `manage_blocked_reason`, `recipe_approval`, `lifecycle_label`, `lifecycle_tone`, `job_status`, `status_tone`, `activity_sort_priority`, `activity_sort_at` |
290
+ | `agents skills list <agent-id>` | a bare array of `name`, `description`, `origin`, `version` | the `success`, `message`, `skills`, `total` and `error` wrapper; on each skill `path`, `file_id`. The list now comes from the local store, not `GET /agents/{id}/skills`. Text mode prints a table instead of the response. |
291
+ | `channels list` | `id`, `name`, `slug`, `kind`, `unread_count`, `description` | `unreadCount`, renamed `unread_count` |
292
+ | `channels tasks <channel>` | `kind`, `id`, `title`, `feed_bucket`, `status_label` | the `{ "kind", "value": {…} }` nesting and every camelCase key inside `value` |
293
+ | `channels files <channel>` | `id`, `name`, `content_type`, `size_bytes`, `thread_id`, `created_at` | `contentType`, `sizeBytes`, `threadId`, `createdAt` (renamed), `agentName` |
294
+ | `channels calls <channel>` | `call_id`, `thread_id`, `title`, `status`, `started_at`, `ended_at`, `duration_ms`, `summary` | `callId`, `threadId`, `startedAt`, `endedAt`, `durationMs` (renamed) |
295
+ | `channels miniapps <channel>` | `id`, `name`, `status`, `description`, `public_url` | `publicUrl` (renamed), `iconUrl`, `hasUnread` |
296
+ | `channels agents <channel>` | `agent_id`, `name`, `description`, `disabled`, `is_orchestrator`, `can_run`, `run_blocked_detail` | `agentId`, `isOrchestrator`, `canRun`, `runBlockedDetail` (renamed), `avatarUrl`, `accessible`, `runScopeDetail` |
297
+ | `channels devices <channel>` | `device_id`, `name`, `device_type`, `is_default`, `addressable` | `deviceId`, `deviceType`, `isDefault` (renamed), `addedByUserId` |
298
+ | `channels members <channel>` | `user_id`, `name`, `online` | `userId` (renamed), `avatarUrl` |
299
+ | `integrations list` | `provider`, `account`, `connected`, `you` | nothing |
300
+ | `user` and `profile get` | `id`, `is_admin`, `profile` with `username`, `first_name`, `last_name`, `email`, `email_verified`, `timezone` | `agents`, `usage_limits_enabled`, `needs_balance`, `needs_device`, `needs_seat`; in `profile` `id`, `icon_url`, `preferences`, `updated_at`, `display_name` |
301
+ | `user variables list` | `id`, `variable_name`, `variable_value`, `is_secret` | `display_name`, `user_tool_id`, `is_managed`, `browser_urls`, `linked_tools`, `linked_agents` |
302
+ | `user config list` | a bare array of `key`, `value` | the object keyed by setting name |
303
+ | `user config get <key>` | `key`, `value` | the bare value. Text mode still prints the bare value. |
304
+ | `user config models` | a bare array of `model_id`, `provider`, `is_default`, `input_cost_per_1m_tokens`, `output_cost_per_1m_tokens` | the `models` and `default_model_id` wrapper, and any other key of a model. Text mode drops the "Default model" line; the Default column marks it. |
305
+ | `user billing balance` | `nebula_credit_balance_dollars`, `standard_credit_balance_dollars` | `nebula_credit_balance_microcents`, `nebula_granted_balance_dollars`, `nebula_purchased_balance_dollars`, `standard_credit_balance_microcents`, `credits_pooled`. Text mode prints both balances; it used to print `Balance: $0.00` whatever the balance was. |
306
+ | `user billing history` | `id`, `amount_dollars`, `source`, `created_at` | `payment_provider`, `bucket` |
307
+ | `user billing auto-topup` with no flags | `is_enabled`, `threshold_dollars`, `topup_amount_dollars`, `has_payment_method` | `has_stripe_payment_method`, `bucket`, `max_period_spend_dollars` |
308
+ | `user files list`, `user files get <id>` | `id`, `filename`, `content_type`, `size_bytes`, `folder_path`, `description`, `created_at`, `updated_at` | `user_id`, `thread_id`, `task_id`, `user_message_id`, `file_extension`, `s3_key`, `source`, `visibility`, `tags`, `deleted_at`, `device_id`, `content`, `content_encoding`, `agent_id`, `agent_name`, `category`, `syntax_language` |
309
+ | `user files content <id>` | `content` | the bare body. Text mode still prints the text. |
310
+ | `user files folders` | a bare array of `folder_path` | the `success`, `folders` and `error` wrapper |
311
+ | `user files share <id>` | `share_url`, `expires_at`, `message` | `success`, `share_token`, `error` |
312
+ | `user devices info` | the device: `id`, `name`, `status`, `visibility`, `device_type` | the `success`, `device` and `message` wrapper; on the device `is_primary`, `workspace_access`, `my_access`, `size`, `user_id`, `cpu`, `memory`, `storage`, `storage_size`, `cpu_cores`, `memory_bytes`, `storage_bytes`, `disk_total_bytes`, `disk_available_bytes`, `disk_stats_at`, `platform`, `arch`, `agent_version`, `capabilities`, `host_home_dir`, `home_dir`, `sandbox_id`, `vm_name`, `ssh_public_key`, `region`, `last_active_at`, `last_reachable_at`, `created_at`, `updated_at`, `assigned_agent_count`, `harnesses`, `tools`, `agents`, `unattended_exec`, `terminal` |
313
+ | `user devices files`, `user devices search <pattern>` | a bare array of `name`, `path`, `is_dir`, `size`, `content_type` | `search` drops its `success`, `files`, `path` and `total` wrapper; on each file `mod_time`, `permissions`, `file_id`, `description`, `tags`, `source`, `agent_id`, `agent_name`, `thread_id`, `task_id`, `created_at`, `category`, `syntax_language`. `search` text mode prints a table. |
314
+ | `user devices services list`, `user devices services get <name>` | `name`, `cmd`, `http_port`, `public_url`, `state` with `status`, `started_at` | `args`, `needs`, `cwd`, `app_type`, `state.pid`; `get` drops its `success`, `message`, `service` and `url` wrapper |
315
+ | `user devices services logs <name>` | `stdout`, `stderr` | `success` |
254
316
 
255
317
 
256
318
  ## Privacy and telemetry
257
319
 
258
320
  The CLI collects anonymized usage analytics (via PostHog) to help improve the product. You can opt out at any time:
259
321
 
260
- - Toggle telemetry off in the TUI under **Settings → Configuration**
322
+ - Toggle telemetry off in the TUI under **Settings → CLI & TUI → Preferences**
261
323
  - From the CLI: `npx nebula-ai user config set telemetry false`
262
324
  - Or set `DO_NOT_TRACK=1` (or `NEBULA_DO_NOT_TRACK=1`) in your environment
263
325
 
@@ -275,7 +337,7 @@ No events are sent when telemetry is disabled.
275
337
  | `NEBULA_AI_NO_UPDATE_CHECK` | Set to `1` to suppress the daily update check. Already suppressed under `npx`, CI, or a non-TTY stderr. |
276
338
  | `NEBULA_API_BASE` | Override the Nebula API base URL (alternative to the `--api-url` flag). |
277
339
  | `NEBULA_WEB_URL` | Override the web origin `login` sends you to for approval. Unset, the CLI trusts the URL the API returns, which is right for every backend, including `--api-url` ones. Set it only when the web app you want to approve on is not the one the API names. |
278
- | `NEBULA_AUTH_TOKEN` | Use a pre-minted auth token instead of the stored credential. Scripting / CI escape hatch — takes precedence over the encrypted on-disk store. |
340
+ | `NEBULA_AUTH_TOKEN` | Use a pre-minted auth token instead of the stored credential. Scripting / CI escape hatch, takes precedence over the encrypted on-disk store. |
279
341
  | `NEBULA_DEBUG` / `DEBUG=nebula-cli` | Enable verbose logging (same effect as `-v/--verbose`). |
280
342
  | `DO_NOT_TRACK` / `NEBULA_DO_NOT_TRACK` | Set to `1` to disable product telemetry. |
281
343
 
@@ -283,6 +345,6 @@ No events are sent when telemetry is disabled.
283
345
 
284
346
  This CLI is developed in the [`nebula-desktop`](https://github.com/agent-labs-dev/nebula-desktop) Bun-workspaces umbrella alongside the desktop app and shared packages. Contributor docs:
285
347
 
286
- - [`AGENTS.md`](./AGENTS.md) — CLI-specific build, dev, and architecture conventions.
287
- - [`docs/`](./docs/) — working notes (local-device backend contracts, RPC port mappings).
348
+ - [`AGENTS.md`](./AGENTS.md), CLI-specific build, dev, and architecture conventions.
349
+ - [`docs/`](./docs/), working notes (local-device backend contracts, RPC port mappings).
288
350
  - The [workspace README](../../README.md) and [root `AGENTS.md`](../../AGENTS.md) cover umbrella-level conventions (gates, releases, packages).
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nebula-ai",
3
- "version": "0.1.20",
3
+ "version": "0.1.21",
4
4
  "description": "CLI/TUI for the nebula.gg AI task orchestration platform",
5
5
  "type": "module",
6
6
  "bin": {