vs Official CLI
The official Tabstack CLI is Mozilla-Ocho/tabstack-cli, written in Go. This version is a TypeScript/Bun reimplementation with full feature parity — plus three things that didn’t make it into the original.
Feature matrix
| Feature | Official (Go) | This (Bun/TS) |
|---|---|---|
extract markdown | ✓ | ✓ |
extract json with --schema | ✓ | ✓ |
generate json | ✓ | ✓ |
research (streaming SSE) | ✓ | ✓ |
automate (streaming SSE) | ✓ | ✓ |
agent input / tabstack input | ✓ | ✓ |
login / logout / status | ✓ | ✓ |
--geo, --effort, --nocache | ✓ | ✓ |
--max-iterations | ✓ | ✓ |
--schema from @file, -, inline | ✓ | ✓ |
| NDJSON in piped mode | ✓ | ✓ |
| Safe-by-default automate guardrail | — | ✓ |
login opens browser + verifies key | — | ✓ |
--interactive actually works | — | ✓ |
recipes cookbook command | — | ✓ |
skill install for coding agents | — | ✓ |
usage credit tracking | — | ✓ |
The three extras
1. Safe-by-default automate
automate is read-only by default. The CLI injects a guardrail unless you explicitly pass --allow-actions. The reasoning: most automation tasks are read operations (find, extract, summarize). Making destructive actions opt-in means the default path is safe for agents running unsupervised.
# Safe by default — read-only guardrail active
tabstack automate "find the top 3 trending repos" --url https://github.com/trending
# Explicit opt-in for actions
tabstack automate "fill and submit the contact form"
--url https://example.com/contact
--allow-actions 2. Login that works
The official CLI stores keys but doesn’t verify them before saving. This version:
- Opens the Tabstack console in your browser (API Keys → Create New Key)
- Prompts you to paste the key
- Makes one cheap verification call before storing it
- Stores at
~/.config/tabstack/config.jsonwith mode0600
A stored key that doesn’t work is worse than no stored key. The verification catches typos and expired keys at the moment you set them up, not three steps into a pipeline.
tabstack login # opens browser, prompts, verifies, stores
tabstack login --with-key ts_xxx # non-interactive (CI)
echo "$KEY" | tabstack login --no-verify # skip verification (e.g. you just created it) 3. Interactive automation that actually fires
The official CLI has an agent input command for answering paused automation tasks, but the --interactive flag that enables the API’s input-request events was never wired through to the request body. So agent input was unreachable in practice.
We found this while dogfooding, filed Mozilla-Ocho/tabstack-cli#15, and fixed it in this version:
# Start an automation that can pause and ask for input
tabstack automate "book the flight but confirm before payment"
--url https://example.com/flights
--interactive
# When it pauses — the CLI prints the request-id and instructions
tabstack input <request-id> --data '{"fields":[{"ref":"confirm","value":"yes"}]}'
tabstack input <request-id> --data '{"cancelled":true}' # cancel the pause The API supports this. The --interactive flag sends "interactive": true in the request body, which enables interactive:form_data:request events in the SSE stream. Without that flag, no events fire and tabstack input has nothing to respond to.
Why Bun/TypeScript vs Go?
Go produces a smaller, faster binary. Bun is already in most JS/TS developer toolchains. The Tabstack API is already the slow part — a few milliseconds of runtime overhead doesn’t matter when each request takes 2–10 seconds.
TypeScript gave one concrete advantage during the stream: the API response types could be expressed inline as the schema, and the arg parser could be written incrementally without a build step. That matters when you’re writing code live on camera.
Zero runtime dependencies. The binary is a single bun build artifact.