@tabbio-technologies/cli 1.2.8

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.
package/README.md ADDED
@@ -0,0 +1,763 @@
1
+ # Tabbio CLI
2
+
3
+ `tabbio` puts your whole Tabbio account in the terminal: every tool the Tabbio
4
+ MCP server exposes (CVs, profile, jobs, applications, messages, skills,
5
+ automations, memory and more), streaming chat with the Tabbio agent, approvals
6
+ for sensitive actions, machine-readable output for scripts, and a stdio bridge
7
+ for MCP clients that cannot speak HTTP.
8
+
9
+ It is a thin client. Every capability comes from the same API the Tabbio apps
10
+ use, over the same authentication, so the CLI can never do more than you can do
11
+ in the app.
12
+
13
+ Version 1.2.8. Where this guide and the code disagree, the code is right.
14
+
15
+ - [Install](#install)
16
+ - [First run](#first-run)
17
+ - [Signing in](#signing-in)
18
+ - [Commands](#commands)
19
+ - [Output and exit codes](#output-and-exit-codes)
20
+ - [Profiles and files](#profiles-and-files)
21
+ - [Approvals](#approvals)
22
+ - [Limits](#limits)
23
+ - [Research, documents, pages and images](#research-documents-pages-and-images)
24
+ - [Using Tabbio from MCP clients](#using-tabbio-from-mcp-clients)
25
+ - [Security](#security)
26
+ - [Troubleshooting](#troubleshooting)
27
+ - [Screenshots](#screenshots)
28
+ - [Contributing](#contributing)
29
+
30
+ ## Install
31
+
32
+ Requires Node.js 20 or newer.
33
+
34
+ ```sh
35
+ # Run once without installing
36
+ npx @tabbio-technologies/cli
37
+
38
+ # Install the `tabbio` command globally
39
+ npm i -g @tabbio-technologies/cli
40
+ tabbio --version
41
+ ```
42
+
43
+ From source, inside the Tabbio monorepo:
44
+
45
+ ```sh
46
+ pnpm install
47
+ pnpm --filter @tabbio-technologies/cli build
48
+ node apps/cli/dist/cli.js --help
49
+
50
+ # or run the TypeScript sources directly
51
+ pnpm dev:cli -- --help
52
+ ```
53
+
54
+ ## First run
55
+
56
+ ```sh
57
+ tabbio login # opens your browser to approve this computer
58
+ tabbio status # who you are, which server, how you are signed in
59
+ tabbio # interactive home screen (in a terminal)
60
+ ```
61
+
62
+ In an interactive terminal, `tabbio` with no arguments opens the home screen.
63
+ It is built around the chat composer: type a message to start a chat, or `/`
64
+ for the command palette (browse tools, approvals, status). Recent tool runs and
65
+ key hints sit beside it on wide terminals and below it on narrow ones. When
66
+ stdout is not a terminal (a pipe, a script, CI) it prints help instead and
67
+ never draws the interactive UI.
68
+
69
+ ## Signing in
70
+
71
+ `tabbio login` picks a method in this order: an explicit flag, then the browser
72
+ hand-off when there is a terminal and a display, then email.
73
+
74
+ The browser hand-off and email both give the CLI an **app session**, the same
75
+ kind of session the Tabbio app itself uses. That one session is used for
76
+ everything: the tool catalog over MCP, chat, and approving actions from the
77
+ terminal. The CLI does not create or need a personal MCP token.
78
+
79
+ A personal MCP token (method 3) is the alternative for scripts and CI. It
80
+ reaches the tools only.
81
+
82
+ ### 1. Browser hand-off (default on a desktop)
83
+
84
+ ```sh
85
+ tabbio login
86
+ tabbio login --browser
87
+ ```
88
+
89
+ 1. The CLI starts a one-shot listener on `127.0.0.1` on a random port and opens
90
+ `https://app.tabbio.com/cli/connect?port=<port>&state=<nonce>&device=<hostname>`.
91
+ 2. Sign in to Tabbio in the browser if you are not already. The page shows the
92
+ account, the computer name, what you are granting, and the exact address
93
+ the one-time code will be sent to (`http://127.0.0.1:<port>/callback`).
94
+ 3. Choose **Approve and connect**. The browser hands a 60-second, single-use
95
+ code to the listener, and the CLI swaps it for its own session.
96
+ **Cancel** tells the listener you declined and the command exits.
97
+
98
+ The listener gives up after 5 minutes. Ctrl+C cancels at any time.
99
+
100
+ For editors and wrappers that want to open the page themselves:
101
+
102
+ ```sh
103
+ tabbio login --non-interactive
104
+ # {"url":"https://app.tabbio.com/cli/connect?port=…&state=…&device=…","state":"…","expiresAt":"…"}
105
+ ```
106
+
107
+ It prints that JSON on stdout, opens no browser, and waits for the same
108
+ loopback callback.
109
+
110
+ The browser has to run on the same computer as the CLI, because `127.0.0.1`
111
+ means "this machine". Over SSH, or on a machine without a browser, use email.
112
+
113
+ ### 2. Email code (headless, SSH, containers)
114
+
115
+ ```sh
116
+ tabbio login --email you@example.com
117
+ ```
118
+
119
+ Tabbio emails a 6-digit code. Type it at the prompt (3 attempts; the code is
120
+ valid for 10 minutes).
121
+
122
+ ### 3. Personal MCP token (tools only)
123
+
124
+ ```sh
125
+ # from stdin, which keeps the token out of your shell history and the process list
126
+ pbpaste | tabbio login --with-token
127
+ tabbio login --with-token < token.txt
128
+
129
+ # as an argument (visible in shell history and `ps` while it runs)
130
+ tabbio login --token tabbio_mcp_...
131
+
132
+ # or, without storing anything
133
+ export TABBIO_TOKEN=tabbio_mcp_...
134
+ ```
135
+
136
+ This uses a token you already have: create or copy it in the app under
137
+ **Settings › MCP Access**. It gives the CLI the tool catalog (`tools`, `run`,
138
+ `<group> <action>`, `mcp serve`) within the token's scope (personal, company or
139
+ both; read, or read and write). It is not an app session, so `chat`, `ask`,
140
+ `artifacts`, `approvals approve` and `approvals reject` need a full sign-in
141
+ (see [`ask`](#ask) for the one exception and why it does not work today).
142
+
143
+ Tabbio keeps **one active personal MCP token per account**: creating a new one
144
+ in Settings › MCP Access replaces the previous one. If you use the same token
145
+ in another MCP client (Claude Desktop, Cursor…), making a new token for either
146
+ one cuts the other off; run `tabbio login --with-token` again with the new
147
+ token. Browser and email sign-ins are not affected by this.
148
+
149
+ ### 4. CI and automation
150
+
151
+ Environment variables override the stored credentials and are never written to
152
+ disk:
153
+
154
+ | Variable | Meaning |
155
+ |---|---|
156
+ | `TABBIO_TOKEN` | Personal MCP token (`tabbio_mcp_…`). Enough for the tools and `mcp serve`. |
157
+ | `TABBIO_ACCESS_TOKEN` | App access token (JWT). Works for everything, including tools, chat and approvals. Expires after 24 hours and is not refreshed, so it suits short jobs only. |
158
+ | `TABBIO_PROFILE` | Profile to use when `--profile` is not given. |
159
+ | `TABBIO_API_URL`, `TABBIO_APP_URL`, `TABBIO_MCP_URL` | Point at another environment. |
160
+ | `CI` | Any value: never draw interactive UI, never prompt. |
161
+
162
+ ```sh
163
+ # GitHub Actions example
164
+ - run: npx -y @tabbio-technologies/cli run cv.list --json > cvs.json
165
+ env:
166
+ TABBIO_TOKEN: ${{ secrets.TABBIO_TOKEN }}
167
+ ```
168
+
169
+ ### What sign-in stores
170
+
171
+ After a browser or email sign-in the CLI keeps an app session: a 24-hour
172
+ access token, a refresh token that renews it, and your user id and email. The
173
+ session appears on the server under this computer's name (the hostname, or
174
+ `TABBIO_DEVICE_LABEL`). With `--token` / `--with-token` it stores the personal
175
+ token instead.
176
+
177
+ `tabbio status` says which one a profile uses, without showing secrets:
178
+ `app session` for a browser or email sign-in, or `personal token …a1b2` (the
179
+ last four characters) for a token.
180
+
181
+ ### Signing out
182
+
183
+ ```sh
184
+ tabbio logout # this profile: ends the app session and deletes the stored credentials
185
+ tabbio logout --all # every profile
186
+ ```
187
+
188
+ For a browser or email sign-in, `logout` ends the app session on the server
189
+ (the refresh token is revoked) and deletes the local credentials. For a
190
+ personal token, it only deletes the local copy: the token itself stays valid,
191
+ because other clients may use it. Revoke it in Settings › MCP Access if you
192
+ want it gone.
193
+
194
+ ## Commands
195
+
196
+ ```
197
+ tabbio TTY: interactive home. Non-TTY: help.
198
+ tabbio login [--browser | --email <addr> | --token <tabbio_mcp_…> | --with-token] [--non-interactive] [--profile p] [--api-url u] [--app-url u]
199
+ tabbio logout [--all]
200
+ tabbio status profile, API/MCP urls, user, plan, sign-in kind (app session | personal token …xxxx), pending approvals, catalog age
201
+ tabbio whoami [--json]
202
+ tabbio doctor node version, config perms, /api/health, MCP tools/list, JWT validity, clock skew
203
+ tabbio config list|get <k>|set <k> <v>|path ; tabbio config profile list|use <name>|add <name> --api-url … --app-url …
204
+ tabbio tools [query] [--group g] [--writes|--reads] [--json] [--refresh] TTY: browser; else list
205
+ tabbio tools describe <tool.id> [--json] schema as flags + example
206
+ tabbio run <tool.id> [--<flag> …] [--input '<json>' | --input-file f | -] [--wait] [--yes] [--json|--table|--plain] [--fields a,b]
207
+ tabbio <group> <action> [flags] generated for every catalog tool (same options as run)
208
+ tabbio workflows says that workflows are not exposed over MCP (they run inside chat)
209
+ tabbio approvals [list] [--json] ; approvals show <id> ; approvals approve <id> [--reason r] [--wait] ; approvals reject <id> [--reason r] ; approvals wait <id> [--timeout 10m]
210
+ tabbio artifacts [list] [--kind k] [--status s] ; artifacts get|open|versions|delete|wait <id> ; artifacts download <id> [--format f] [--out p] [--force] [--wait] ; artifacts restore <id> <versionId>
211
+ tabbio ask "<question>" [--mode m] [--via-mcp] [--json] one question through the chat stream (app session)
212
+ tabbio chat [message] [--mode seeker|employer] [--company <id>] [--thread <id>] [--model <id>] [--research auto|on|off] [--image auto|on|off] [--result auto|summary|document|slides|page|image] [--save] [--json]
213
+ tabbio mcp serve [--profile p] stdio ↔ remote MCP bridge for stdio-only clients
214
+ tabbio mcp url prints the MCP URL for `claude mcp add`
215
+ tabbio completion bash|zsh|fish
216
+ tabbio help exit-codes
217
+ tabbio --version | --help | --debug | --color | --no-color | --json
218
+ ```
219
+
220
+ Global flags work on every command:
221
+
222
+ | Flag | Effect |
223
+ |---|---|
224
+ | `--profile <name>` | Use a named profile (see [Profiles](#profiles-and-files)). |
225
+ | `--api-url <url>` | Override the API origin for this run. |
226
+ | `--json` | Machine-readable output (see [Output](#output-and-exit-codes)). |
227
+ | `--color`, `--no-color` | Force colour on or off. |
228
+ | `--debug` | Print method, URL, status, request id and timing for every request to stderr. Never prints bodies or secrets. |
229
+ | `--yes` | Approve your own approval-gated calls for this one invocation, when a full sign-in is present; otherwise exit 6. |
230
+ | `--quiet` | Only the result, no progress or hints. |
231
+
232
+ ### `login`, `logout`, `status`, `whoami`, `doctor`
233
+
234
+ ```sh
235
+ tabbio login --email you@example.com --profile staging --api-url https://staging-api.example.com --app-url https://staging-app.example.com
236
+ tabbio whoami --json | jq -r .email
237
+ tabbio doctor # run this first when something is off
238
+ ```
239
+
240
+ `doctor` checks the Node version, the permissions on the config directory and
241
+ credentials file, `/api/health`, an MCP `tools/list`, whether the access token
242
+ is still valid, and the clock skew between your machine and the server.
243
+
244
+ ### `config` and `config profile`
245
+
246
+ ```sh
247
+ tabbio config path # where config.json lives
248
+ tabbio config set updateCheck false # no daily npm version check
249
+ tabbio config profile list
250
+ tabbio config profile add staging --api-url https://staging-api.example.com --app-url https://staging-app.example.com
251
+ tabbio config profile use staging
252
+ ```
253
+
254
+ CLI profiles (environments and their credentials) live under `tabbio config
255
+ profile`. `tabbio profile …` is a different thing: it is generated from the
256
+ product's `profile.*` tools and edits your Tabbio profile, for example
257
+ `tabbio profile get` or `tabbio profile update --title "Product manager"`.
258
+
259
+ ### `tools`
260
+
261
+ ```sh
262
+ tabbio tools # interactive browser in a terminal, a list otherwise
263
+ tabbio tools cv --reads # read-only CV tools
264
+ tabbio tools --group job --json # machine-readable catalog slice
265
+ tabbio tools describe catalog.jobSearch
266
+ ```
267
+
268
+ The catalog comes from the MCP server's `tools/list` and is cached locally;
269
+ `--refresh` refetches it. Each tool has a canonical id (`cv.list`,
270
+ `catalog.jobSearch`, `careerHighlight.upsert`) and a read or write badge.
271
+ `describe` prints the input schema as command-line flags plus an example.
272
+
273
+ ### `run` and generated commands
274
+
275
+ Every tool id is also a command: the id is split on the dot and camelCase
276
+ becomes kebab-case.
277
+
278
+ | Tool id | Command |
279
+ |---|---|
280
+ | `cv.list` | `tabbio cv list` |
281
+ | `catalog.jobSearch` | `tabbio catalog job-search` |
282
+ | `careerHighlight.upsert` | `tabbio career-highlight upsert` |
283
+ | `publicProfile.builderGet` | `tabbio public-profile builder-get` |
284
+
285
+ ```sh
286
+ tabbio cv list
287
+ tabbio run cv.get --cv-id cv_123 --fields id,title,updatedAt
288
+ tabbio catalog job-search --query "product manager" --locations Dubai --work-modes hybrid --limit 10
289
+ tabbio run catalog.jobSearch --input '{"query":"data analyst","datePosted":"thisWeek"}' --json
290
+ echo '{"cvId":"cv_123"}' | tabbio run cv.get -
291
+ tabbio run cv.delete --cv-id cv_old # approval-gated, see Approvals
292
+ tabbio research web-search --query "UAE labour law changes 2026" --max-sources 3
293
+ tabbio artifact generate-image --prompt "Dubai skyline at dawn, flat illustration" --title "Skyline" --yes --wait
294
+ tabbio artifact create-page --input-file page.json --yes --wait # title, designPlan, html
295
+ tabbio site publish --artifact-id art_123 --name my-portfolio --yes
296
+ ```
297
+
298
+ `--wait` does two things: it waits for an approval instead of exiting 6, and
299
+ for the file tools (`artifact create-document`, `create-page`,
300
+ `generate-image`, `edit-image`, `update-document`, `update-page`) it waits
301
+ until the file has rendered (usually a few seconds; PDFs and images finish
302
+ after the tool returns) and prints it with its final status, followed by
303
+ `tabbio artifacts open <id>` / `download <id>` hints. With a personal token it
304
+ polls the `artifact.get` tool; with a full sign-in, `GET /api/artifacts/:id`.
305
+ The publishing tools, whose ids have no group (`publishArtifact`), are
306
+ `tabbio site publish` and `tabbio site unpublish`.
307
+
308
+ Input comes from flags, `--input '<json>'`, `--input-file path.json`, or `-`
309
+ (stdin). Flags are generated from the tool's JSON Schema: strings and numbers
310
+ take a value, booleans are switches, arrays repeat or take a comma list, and
311
+ nested objects go through `--input`. In a terminal, missing required fields
312
+ open a short form; without a terminal the command exits 2 and names them.
313
+
314
+ ### `workflows`
315
+
316
+ ```sh
317
+ tabbio workflows
318
+ # No workflows are exposed over MCP; multi-step flows run through tabbio chat
319
+ ```
320
+
321
+ The Tabbio MCP server exposes the audited tools only. Server workflows (tailor
322
+ a CV to a job, apply, outreach) are not published over MCP, because the
323
+ workflow engine takes the user id from its input rather than from the signed-in
324
+ caller. Ask for those flows in `tabbio chat`, where the server knows who you
325
+ are, or call the individual tools (`tabbio cv tailor`, `tabbio catalog
326
+ apply-prepare`, …).
327
+
328
+ ### `approvals`
329
+
330
+ ```sh
331
+ tabbio approvals # pending approvals
332
+ tabbio approvals show apr_123
333
+ tabbio approvals approve apr_123 --reason "cleaning up old drafts"
334
+ tabbio approvals approve apr_456 --wait # a file tool: waits for the render and prints the file
335
+ tabbio approvals reject apr_123
336
+ tabbio approvals wait apr_123 --timeout 10m
337
+ ```
338
+
339
+ See [Approvals](#approvals).
340
+
341
+ ### `ask`
342
+
343
+ ```sh
344
+ tabbio ask "Which of my saved jobs fit my main CV best?"
345
+ tabbio ask "Summarise my application pipeline" --json
346
+ ```
347
+
348
+ One question, one answer. With an app session (browser or email sign-in) the
349
+ question goes through the chat stream (`POST /api/agent/chat`), exactly like a
350
+ one-message `tabbio chat`: the answer streams, sources and files are listed,
351
+ and it is metered like any chat reply. It sends the profile's saved research,
352
+ image and result choice.
353
+
354
+ With a personal token, or with `--via-mcp`, it looks for the MCP ask tool
355
+ (`ask_tabbio`) instead. Today's server does not offer that tool (the MCP
356
+ endpoint exposes tools only), so that path exits 5 with "This Tabbio server
357
+ does not offer the ask_tabbio tool". Use a full sign-in for `ask`.
358
+
359
+ ### `chat`
360
+
361
+ ```sh
362
+ tabbio chat
363
+ tabbio chat "Tailor my CV for the Careem PM role" --thread thr_123
364
+ tabbio chat --mode employer --company cmp_456
365
+ ```
366
+
367
+ Streaming chat with the Tabbio agent, rendered as Markdown, with one-line
368
+ tool-call rows (`ctrl+o` expands them) and inline approval prompts. Inside
369
+ chat, `/new`, `/threads`, `/mode`, `/model`, `/research`, `/image`,
370
+ `/result`, `/help` and `/exit` are available. With `--json`, chat prints the
371
+ stream as NDJSON: one JSON event per line, exactly as the server sent it
372
+ (including event types this version does not know). Needs a full sign-in.
373
+
374
+ ```sh
375
+ tabbio chat --research on "What changed in UAE labour law this year? Two sources."
376
+ tabbio chat --result document "A one-page brief on my job search"
377
+ tabbio chat --result page --save # every chat on this profile asks for pages until changed
378
+ ```
379
+
380
+ See [Research, documents, pages and images](#research-documents-pages-and-images).
381
+
382
+ ### `artifacts`
383
+
384
+ ```sh
385
+ tabbio artifacts # your files, newest first
386
+ tabbio artifacts list --kind document --json
387
+ tabbio artifacts get art_123
388
+ tabbio artifacts open art_123 # prints a 15-minute link and opens it (on a terminal)
389
+ tabbio artifacts open art_123 --variant pdf --print
390
+ tabbio artifacts download art_123 # ./<title>.pdf (documents), .pptx (slides), .html (pages), the image
391
+ tabbio artifacts download art_123 --format html --out ~/Downloads --force
392
+ tabbio artifacts wait art_123 --timeout 2m # exit 0 ready, 1 failed, 7 still rendering
393
+ tabbio artifacts versions art_123
394
+ tabbio artifacts restore art_123 ver_456 # a copy of that version becomes the newest
395
+ tabbio artifacts delete art_123 --yes
396
+ ```
397
+
398
+ The documents, slide decks, pages and images Tabbio made for you. `download`
399
+ never overwrites a file unless you pass `--force`, writes through a temporary
400
+ file, and names the file after the title. It fetches a signed link (15
401
+ minutes) without sending your session to the storage host. `delete` asks
402
+ first unless `--yes` (and a published site of that file goes offline). Needs a
403
+ full sign-in; with a personal token, `tabbio artifact list|get|read` reach the
404
+ same files through the tools.
405
+
406
+ ### `mcp serve` and `mcp url`
407
+
408
+ ```sh
409
+ tabbio mcp url # https://server.tabbio.com/api/mcp
410
+ tabbio mcp serve # stdio MCP server that forwards to the remote one
411
+ ```
412
+
413
+ See [Using Tabbio from MCP clients](#using-tabbio-from-mcp-clients).
414
+
415
+ ### `completion`
416
+
417
+ ```sh
418
+ tabbio completion zsh > "${fpath[1]}/_tabbio"
419
+ tabbio completion bash > ~/.local/share/bash-completion/completions/tabbio
420
+ tabbio completion fish > ~/.config/fish/completions/tabbio.fish
421
+ ```
422
+
423
+ ## Output and exit codes
424
+
425
+ The output format is chosen in this order:
426
+
427
+ 1. a flag: `--json`, `--table` or `--plain`;
428
+ 2. the `TABBIO_OUTPUT` environment variable (`json`, `table` or `plain`);
429
+ 3. a terminal on stdout: human output (arrays of objects as tables, objects
430
+ as key/value panels, scalars as plain text);
431
+ 4. otherwise (piped or redirected): plain, tab-separated values, one record
432
+ per line, ready for `cut`, `awk` and `sort`.
433
+
434
+ | Flag | Output |
435
+ |---|---|
436
+ | `--json` | JSON. Pretty in a terminal, compact when piped. Carries `meta.schemaVersion` (currently `1`); within a schema version fields are only ever added, never renamed or removed. |
437
+ | `--table` | Force a table. |
438
+ | `--plain` | Tab-separated values, no colour. |
439
+ | `--fields a,b` | Only these fields (tables, plain and JSON). |
440
+
441
+ `tabbio chat --json` is the exception: it writes NDJSON, one stream event per
442
+ line.
443
+
444
+ Colour is decided in this order: `--color` / `--no-color`, then `FORCE_COLOR`,
445
+ then `NO_COLOR`, then `CLICOLOR_FORCE` / `CLICOLOR`, then `TERM=dumb` (no
446
+ colour), then whether stdout is a terminal. The accent colour adapts to light
447
+ and dark terminals; if it guesses wrong, set `TABBIO_THEME=light` or
448
+ `TABBIO_THEME=dark`. The CLI never paints background colours.
449
+
450
+ Errors print three parts: `✗ <title>`, a hint when there is one, and the
451
+ request id when the server returned one. Quote the request id when you report
452
+ a problem. Under `--json`, errors are JSON too, with `code`, `message`, `hint`,
453
+ `retry` and `requestId`.
454
+
455
+ | Code | Meaning |
456
+ |---|---|
457
+ | 0 | Success |
458
+ | 1 | Unexpected error |
459
+ | 2 | Usage error (unknown flag, missing required input, no terminal for an interactive command) |
460
+ | 3 | Not signed in, or the session could not be refreshed. Run `tabbio login`. |
461
+ | 4 | Forbidden (token scope, plan, out of credits, or a support session) |
462
+ | 5 | Not found |
463
+ | 6 | Approval pending (the action is waiting for a person) |
464
+ | 7 | Network error |
465
+ | 8 | Server error |
466
+ | 130 | Interrupted (Ctrl+C) |
467
+
468
+ `tabbio help exit-codes` prints this table.
469
+
470
+ ## Profiles and files
471
+
472
+ A profile is a named environment (API, app and MCP URLs) with its own
473
+ credentials. `default` points at production, and a built-in `local` profile
474
+ points at a development stack (`http://localhost:3001` for the API,
475
+ `http://localhost:8081` for the app):
476
+
477
+ | Setting | Production value |
478
+ |---|---|
479
+ | API | `https://server.tabbio.com` |
480
+ | App (sign-in page) | `https://app.tabbio.com` |
481
+ | MCP | `https://server.tabbio.com/api/mcp` |
482
+
483
+ Files live in `$TABBIO_CONFIG_DIR`, else `$XDG_CONFIG_HOME/tabbio`, else
484
+ `~/.config/tabbio`:
485
+
486
+ | File | Contents | Mode |
487
+ |---|---|---|
488
+ | `config.json` | Profiles, the active profile, preferences, each profile's saved research / image / result choice | 0600 |
489
+ | `credentials.json` | One entry per profile: the app session (access token and expiry, refresh token) or a personal MCP token, plus user id and email | 0600 (directory 0700) |
490
+
491
+ The tool catalog cache, update-check stamp and recent-runs history live in
492
+ `$TABBIO_CACHE_DIR`, else `$XDG_CACHE_HOME/tabbio`, else `~/.cache/tabbio`.
493
+
494
+ Other environment variables:
495
+
496
+ | Variable | Effect |
497
+ |---|---|
498
+ | `TABBIO_OUTPUT` | Default output format: `json`, `table` or `plain`. |
499
+ | `TABBIO_THEME` | `light` or `dark`, when the accent colour guesses the terminal background wrong. |
500
+ | `TABBIO_DEBUG=1` | Same as `--debug`. |
501
+ | `TABBIO_DEVICE_LABEL` | The name this computer shows on the sign-in page and in your sessions. Defaults to the hostname. |
502
+ | `TABBIO_NO_UPDATE_CHECK=1` | Skip the once-a-day check for a newer version on npm (printed on stderr). Also skipped under `CI`. |
503
+ | `TABBIO_ALLOW_INSECURE_HTTP=1` | Allow plain `http://` API URLs other than localhost. Development only. |
504
+ | `FORCE_HYPERLINK` | `1` to always print OSC 8 links (file previews, sources), `0` never. Default: detected from the terminal. |
505
+ | `NO_COLOR`, `FORCE_COLOR`, `CLICOLOR`, `CLICOLOR_FORCE`, `TERM` | Colour, see [Output](#output-and-exit-codes). |
506
+ | `DO_NOT_TRACK` | Honoured. The CLI sends no telemetry in any case; the only request that does not go to Tabbio is the update check, which `TABBIO_NO_UPDATE_CHECK` turns off. |
507
+
508
+ ## Approvals
509
+
510
+ Some tools change things that are hard to undo or that reach other people.
511
+ They never run straight from a tool call; they create an approval and wait for a
512
+ person. On a server without PR #512, 57 of the 162 tools work this way,
513
+ including:
514
+
515
+ - deleting anything (`cv.delete`, `experience.delete`, `memory.forget`, `conversation.delete`…)
516
+ - submitting or withdrawing applications (`catalog.applySubmit`, `application.submit`, `application.withdraw`)
517
+ - sending messages, email or Slack posts (`message.send`, `conversation.send`, `connector.sendEmail`, `connector.postSlackMessage`)
518
+ - sharing a CV or changing who can see it (`cv.shareLinkCreate`, `cv.accessGrantCreate`, `publicProfile.settingsUpdate`)
519
+ - publishing (`job.publish`, `skills.publish`) and starting automations (`nova.activate`, `nova.runNow`)
520
+
521
+ `tabbio tools --writes` lists write tools; `tabbio tools describe <id>` says
522
+ whether a tool needs approval.
523
+
524
+ **With a full sign-in, in a terminal**, the CLI shows the tool and its
525
+ arguments beside a yellow `◆` rail and offers three numbered choices:
526
+ **1 Approve** (`y`), **2 Reject** (`n`) and **3 Leave pending** (`l`, or
527
+ Esc). Approve confirms the action with your own session (the same thing the
528
+ Approve button in the app does) and prints the result. Reject cancels it.
529
+ Leave pending exits with code 6 and the approval id.
530
+
531
+ **Without a terminal**, or **with a personal token**, the CLI prints the
532
+ approval id with a hint to approve it in the app, or with `tabbio approvals
533
+ approve <id>` from a profile signed in with an app session (or to wait with
534
+ `tabbio approvals wait <id>`), and exits with code 6.
535
+
536
+ - `--wait` keeps the command alive until someone decides (polling every 3 s,
537
+ backing off to 10 s, up to `--timeout`), then prints the result.
538
+ - `--yes` approves the approvals created by that one command without asking,
539
+ and only when a full sign-in is present. It applies to a single invocation;
540
+ there is no setting that auto-approves for a whole session. Use it in scripts
541
+ you trust; it is the terminal equivalent of pressing Approve.
542
+ - Approvals created by any client (the CLI, Claude, Cursor…) also appear in the
543
+ app under Settings › MCP Access, where you can approve or reject them.
544
+
545
+ ## Limits
546
+
547
+ The CLI spends the same credits as the app, from the same daily pool. On the
548
+ Free plan that is **40 credits a day** (UTC day, refilled at 00:00 UTC), which
549
+ comes to roughly:
550
+
551
+ - **8 to 14 chat replies** (`tabbio chat`, `tabbio ask`; 4 if every reply is
552
+ tool-heavy): each reply costs 1 to 10 credits by its token use;
553
+ - **1 skill run** (40 credits, only as the first spend of the day);
554
+ - **1 CV tailoring from the CLI** (`tabbio cv tailor`, 30 credits).
555
+
556
+ Tool calls (`tabbio <group> <action>`, `tabbio run`) are direct MCP calls.
557
+ Most tools make no model call and cost nothing. The ones that do are metered
558
+ on the server:
559
+
560
+ | Tool | Cost | Plans |
561
+ |---|---|---|
562
+ | `cv.tailor` | 30 credits (priced like the browser extension's tailoring) | every plan |
563
+ | `cv.sectionPreview`, and `cv.updateSummary` without `--summary` | 12 credits | every plan |
564
+ | `message.draft` (employer) | 1 workspace AI action | every plan |
565
+ | Skills, Application Studio, automations, and #512 research, images and files | what the app charges; those services meter themselves | as in the app |
566
+
567
+ An approval-gated tool is charged when it is approved and runs, against the
568
+ balance at that moment. When a call does not fit, the server refuses it before
569
+ any model call with `SUBSCRIPTION_ENTITLEMENT_DENIED` and the time the pool
570
+ refills, and the CLI exits 4:
571
+
572
+ ```
573
+ ✗ Out of credits. Tailor CV to a job page needs 30 credits; you have 10 left. Your daily pool refills at 2026-09-26 00:00 UTC.
574
+ ```
575
+
576
+ Plus and Pro have larger pools (300 and 3,000 credits a day). The full table,
577
+ per surface and per plan, is in `docs/cli/limits-audit.md`. On a local
578
+ development API `TABBIO_DEV_BYPASS_PAYWALL=true` (the default in the
579
+ development `.env`) switches all of this off; deployed servers ignore it.
580
+
581
+ ## Research, documents, pages and images
582
+
583
+ When the server has them switched on (see `docs/cli/deployment-notes.md` §7),
584
+ the Tabbio agent can search the web, read pages, PDFs and repositories, and
585
+ make documents (HTML and PDF), slide decks (PPTX), web pages (HTML) and
586
+ images. Three controls decide what each chat message may do, like the
587
+ controls under the app's message box:
588
+
589
+ | Control | Values | Meaning |
590
+ |---|---|---|
591
+ | Research (`--research`, `/research`) | `auto` · `on` · `off` | Search the web when it helps, always first, or never. |
592
+ | Image (`--image`, `/image`) | `auto` · `on` · `off` | Images only when asked, on this message, or never. Uses image credits. |
593
+ | Result (`--result`, `/result`) | `auto` · `summary` · `document` · `slides` · `page` · `image` | What to make: let the message decide, an answer in the chat, or that file. |
594
+
595
+ They are sent with every message in seeker chats, together with your
596
+ timezone (`Intl` timezone, so "today" and the daily limits follow your day).
597
+ Employer chats do not send them; the server ignores them there. Flags apply to
598
+ one run; `/research on` in the chat and `tabbio chat … --save` remember the
599
+ choice for the profile (`profiles.<name>.capabilities` in `config.json`). The
600
+ status bar shows every control you changed from `auto`. If your account
601
+ cannot use a control you switched on (the server has it off, you are outside
602
+ the canary, or it needs a paid plan), the chat says why and Tabbio answers
603
+ without it.
604
+
605
+ What you see in the chat:
606
+
607
+ - **Research** as one activity row per call, e.g. `✓ Searched the web ·
608
+ "uae labour law" · 4 sources · 3.2s` (`ctrl+o` lists the queries and
609
+ sources), and a numbered **Sources** list after the answer. Where the
610
+ terminal supports OSC 8 links (iTerm2, WezTerm, kitty, Ghostty, VS Code,
611
+ Windows Terminal, recent GNOME Terminal; `FORCE_HYPERLINK=1` to force) the
612
+ titles are links; elsewhere the URL follows the title.
613
+ - **Files** as a card row: `▤ Q3 brief · document · ready · art_12…9xyz
614
+ tabbio artifacts open art_…` (`▦` slides, `◫` page, `▣` image). A file that
615
+ is still rendering shows a spinner and the writer's progress (`writing ·
616
+ 120 lines`) and turns ready by itself; its title then links to a preview.
617
+ - **Limits** (daily quota, plan tier, a switched-off feature) as a dim line
618
+ under the tool row with the reason.
619
+
620
+ `tabbio chat --json` passes every event through, including `artifact-draft`
621
+ (the streaming writer's progress). Research sources are in the
622
+ `tool-result` payloads of `webSearch`, `readUrl`, `readPdf`,
623
+ `readGithubRepo` and `readSkill` (`result.sources`); files are in the
624
+ `tool-result` payloads of `createDocument`, `createPage`, `generateImage`,
625
+ `updatePage`, `updateDocument` and `editImage` (`result.artifactId`,
626
+ `result.status`: `pending`, `ready` or `failed`).
627
+
628
+ Over MCP (`tabbio research …`, `tabbio artifact …`, `tabbio site …`), the
629
+ file tools and `site publish` always need your approval first, because they
630
+ spend credits or put something on the web: in a terminal `--yes` approves
631
+ them for that run, and `tabbio approvals approve <id> --wait` approves one
632
+ later and waits for the file.
633
+
634
+ ## Using Tabbio from MCP clients
635
+
636
+ Clients that support remote (HTTP) MCP servers should connect to Tabbio
637
+ directly:
638
+
639
+ ```sh
640
+ claude mcp add --transport http tabbio "$(tabbio mcp url)"
641
+ ```
642
+
643
+ For clients that only launch local stdio servers, `tabbio mcp serve` is a
644
+ bridge: it speaks MCP on stdin/stdout and forwards every request to the remote
645
+ server with the CLI's credentials (the app session, refreshed as needed, or a
646
+ personal token). Sign in once with `tabbio login` (or set `TABBIO_TOKEN`), then
647
+ point the client at it:
648
+
649
+ ```json
650
+ {
651
+ "mcpServers": {
652
+ "tabbio": {
653
+ "command": "npx",
654
+ "args": ["-y", "@tabbio-technologies/cli", "mcp", "serve"]
655
+ }
656
+ }
657
+ }
658
+ ```
659
+
660
+ Use `"args": ["-y", "@tabbio-technologies/cli", "mcp", "serve", "--profile", "staging"]` for
661
+ another profile. The bridge writes nothing but protocol messages to stdout; logs
662
+ go to stderr.
663
+
664
+ ## Security
665
+
666
+ - **Credentials** are stored in `credentials.json` with mode 0600 in a 0700
667
+ directory, written through a temporary file and an atomic rename. `tabbio
668
+ doctor` warns when the permissions are looser. The file is plain JSON: anyone
669
+ who can read your home directory as you can use it. OS keychain storage is a
670
+ planned follow-up.
671
+ - **Environment tokens** (`TABBIO_TOKEN`, `TABBIO_ACCESS_TOKEN`) are never
672
+ written to disk.
673
+ - **Redaction:** the CLI never prints tokens. `--debug` output and error
674
+ messages redact `Bearer …` values, `tabbio_mcp_…` tokens, JWTs, refresh
675
+ tokens, one-time codes, `state` values and session cookies.
676
+ - **Refresh tokens rotate** on every refresh, and reusing an old one revokes
677
+ the whole session family. The CLI saves the new one before using it, so a
678
+ crash between the two cannot lock you out.
679
+ - **The browser hand-off** only ever sends its one-time code to
680
+ `http://127.0.0.1:<port>/callback`, and only after you press Approve on a page
681
+ that shows that address. The code lives 60 seconds and works once. The CLI
682
+ rejects a callback whose `state` does not match the one it generated.
683
+ - **Support sessions** (a Tabbio admin viewing your account) cannot connect a
684
+ CLI, and their access tokens are refused by the MCP endpoint.
685
+ - **Revoking access:**
686
+ - on the computer: `tabbio logout`;
687
+ - a lost or compromised computer: change your password. That ends every app
688
+ session at once, including the CLI's tool access, which otherwise keeps
689
+ itself signed in by refreshing;
690
+ - a personal token: revoke it in Settings › MCP Access.
691
+
692
+ See `docs/cli/security-review.md` for the threat model.
693
+
694
+ ## Troubleshooting
695
+
696
+ | Symptom | Fix |
697
+ |---|---|
698
+ | `✗ Not signed in` / exit 3 / HTTP 401 | Run `tabbio login`. The refresh token was revoked (logout elsewhere, password change) or expired. |
699
+ | `This MCP token does not allow writes` (or `…is not scoped to that company workspace`) | You are using a personal token that is read-only or scoped to other data. Run `tabbio login` for a full app session, or create a broader token in Settings › MCP Access. |
700
+ | A personal token stopped working | Only one personal MCP token is active per account, so a newer one made in Settings replaced it. Run `tabbio login --with-token` with the new token, or switch to `tabbio login`. |
701
+ | `chat` or `approvals approve` says it needs a full sign-in | The profile uses a personal token. Run `tabbio login` (browser or `--email`). |
702
+ | Browser shows "This site can't be reached" at `127.0.0.1` | The CLI stopped waiting (5-minute timeout, Ctrl+C) or the browser is on a different computer. Run `tabbio login` again in the terminal, or use `--email` over SSH. |
703
+ | "This sign-in link is not valid" | The link was edited or truncated. Run `tabbio login` again. |
704
+ | `Access token has expired` right after login, or `doctor` reports clock skew | Your system clock is off. Enable automatic time sync and retry. |
705
+ | Nothing works behind a corporate proxy | Node's built-in `fetch` does not read `HTTPS_PROXY` by default. On Node versions that support it (24.5 and later), set `NODE_USE_ENV_PROXY=1` along with `HTTPS_PROXY` and `NO_PROXY`. Keep `127.0.0.1` out of the browser's proxy so the sign-in hand-off can reach the CLI. |
706
+ | Output has strange characters in CI logs | Pass `--no-color` or set `NO_COLOR=1`. |
707
+ | `✗ Cannot GET /api/artifacts` (exit 5) | This Tabbio server predates documents, pages and images (PR #512). |
708
+ | `Publishing is not available for this account yet.` / `… requires plus or higher.` (exit 4) | The server has that capability off for you (flag, canary or plan). The chat shows the same reason as a dim line. |
709
+ | `artifacts download` says the file is still being created | Add `--wait`, or `tabbio artifacts wait <id>` first. |
710
+ | `✗ Out of credits …` or `… requires plus or higher` (exit 4) | The daily pool is spent or the tool needs a paid plan. The message says when the pool refills. See [Limits](#limits). |
711
+ | `This Tabbio server does not offer the ask_tabbio tool` (exit 5) | `ask` with a personal token or `--via-mcp`. Sign in with `tabbio login` and ask without `--via-mcp`. |
712
+ | `tabbio workflows` lists nothing | Expected: workflows are not exposed over MCP. Use `tabbio chat`. |
713
+
714
+ `tabbio doctor` checks most of this for you. `tabbio --debug <command>` shows
715
+ every request (redacted) with its status and request id.
716
+
717
+ ## Screenshots
718
+
719
+ Captured from the real CLI against a local API, in the repository under
720
+ `qa-artifacts/cli-2026-09-25/`:
721
+
722
+ | File | What it shows |
723
+ |---|---|
724
+ | `01-web-cli-connect-consent.jpg`, `02-web-cli-connect-done.jpg` | The browser consent page and its done state |
725
+ | `10-status.png` to `14-tools-cv.png` | `status`, `doctor`, `tools describe`, `cv list` as a table, `tools cv` |
726
+ | `20-home.png`, `21-tools-browser.png`, `22-chat.png` | The interactive home screen, tool browser and chat |
727
+ | `30-out-of-credits.png` | A second `cv.tailor` refused on a free account (exit 4) |
728
+ | `40-artifacts-list-512.png`, `41-chat-research-512.png` | `artifacts list` and a researched chat answer against a PR #512 API |
729
+
730
+ ## Contributing
731
+
732
+ The CLI lives in `apps/cli` in the Tabbio monorepo.
733
+
734
+ ```sh
735
+ pnpm install
736
+ pnpm dev:cli -- status # run from source (tsx)
737
+ pnpm --filter @tabbio-technologies/cli test # vitest
738
+ pnpm --filter @tabbio-technologies/cli type-check
739
+ pnpm --filter @tabbio-technologies/cli lint
740
+ pnpm --filter @tabbio-technologies/cli build # esbuild (scripts/build.mjs) → dist/cli.js
741
+
742
+ # against a local API (port 3001) and app-web (port 8081)
743
+ node apps/cli/dist/cli.js --profile local login
744
+ ```
745
+
746
+ - `src/core` holds everything that talks to the network or the disk (config,
747
+ credentials, HTTP, auth, MCP, catalog, approvals, chat stream, errors,
748
+ output). Pure logic there needs a unit test.
749
+ - `src/commands` wires commander commands to `core`.
750
+ - `src/ui` is the Ink interface. It is only ever rendered in a terminal; every
751
+ command has a plain-text path for pipes and CI. Colours come only from
752
+ `src/ui/theme.ts`: no hex literals or background colours anywhere else.
753
+ - The browser half of `tabbio login` is the `/cli/connect` page in
754
+ `apps/mobile` (`src/app/cli/connect`, `src/components/cli`,
755
+ `src/lib/cli-connect.ts`).
756
+ - The server side the CLI depends on lives in `apps/api`: the app access
757
+ token on `/api/mcp` (`src/mastra/mcp/oauth.ts`), credit metering for direct
758
+ MCP calls (`src/mastra/tools/shared.ts`) and the tools-only MCP server
759
+ (`src/agent/mastra-agent.service.ts`). Raise any new server need before
760
+ building around it.
761
+
762
+ Release steps are in `docs/cli/release-checklist.md` and
763
+ `docs/cli/deployment-notes.md`.