sable-cli
v0.17.0
Published
A terminal coding agent that runs on rotur (sable.rotur.dev).
Maintainers
Readme
sable-cli
A terminal coding agent that runs on sable. It's a full-screen TUI: chat with sable, and she can run commands and read/write/edit files on your machine to actually do the work.
The agent loop lives on the server — sable runs the model and decides what to do. This app is the client: the TUI, the local tools she calls, and the approval prompts. See SABLE.md for how sable works and its WebSocket API.
Install
For normal use, install the published CLI globally:
npm install --global sable-cli
sableOr run the current checkout locally:
npm install
npm startThe CLI requires Node.js 22 or newer. On first run it opens a Rotur device-link login; approve the link
in your browser. The token is saved to ~/.config/sable/config.json and used only from there (or
ROTUR_TOKEN). It never reads any other tool's saved token.
Development
npm install
npm run typecheck
npm run format:check
npm test
npm run buildnpm run dev starts TypeScript in watch mode. npm run build writes the distributable JavaScript to
dist/. npm test compiles first and then runs the compiled unit tests.
What sable can do to your machine
| tool | what it does | approval |
| -------------- | ------------------------------------------------------------------------------------------------------------------------ | -------- |
| run_command | run a shell command in a worker thread (cwd = where you launched), with an agent-selected timeout (default 30s, max 90s) | asks |
| local_write | create / overwrite a file | asks |
| local_edit | exact-match replace in a file | asks |
| local_read | read a regular text file (optionally a line range; max 4 MiB) | silent |
| local_list | list a directory tree (skips node_modules/.git) | silent |
| local_search | ripgrep/grep the project for text, with an agent-selected timeout (default 10s, max 90s) | silent |
(The local_* prefix is deliberate: sable already has built-in read_file/edit_file/… for her
server workspace, and a client tool with a clashing name gets dropped.)
At an approval prompt: y = once, a = allow that tool for the rest of the session, anything else = no.
Everything runs with your permissions — only approve what you'd run yourself. run_command can execute arbitrary
shell commands, and /yolo disables tool confirmations for the session. Do not enable it unless you trust the
request and the server.
The CLI only ever uses temporary server chats — nothing is saved to your account and it never opens
your existing chats. Local transcripts are saved as JSONL under ~/.sable/<escaped-cwd>/ for /resume.
Project instructions and skills
Drop an AGENTS.md at the root of your repo (or anywhere up the tree from where
you launch sable) and its contents are sent to sable as project context on the first message of each
new chat — build commands, test steps, code-style rules, files to avoid, anything you'd tell a new
teammate.
Sable keeps her backend skill tool and personal skill library unchanged. The CLI additionally provides a
read-only local_skill tool backed by .agents/skills/<name>/SKILL.md. The first message includes a compact
local skill index; Sable can use local_skill with action: "read" to fetch a local skill, or action: "list"
to list local skills. Skill names are normalized to the backend's lowercase_underscore format. Local skills
are capped at 20,000 characters, matching the backend limit.
- In a monorepo, nest
AGENTS.mdper package; the nearest file to your cwd takes precedence and ancestor files are merged in below it. - The legacy
AGENT.mdis read as a fallback whenAGENTS.mdisn't present at a given level. - Empty files are skipped. Nothing is sent when no file is found.
.agents/skillsdirectories are optional; missing or unreadable skills are ignored.
Commands
Type / inside sable for the autocomplete menu (Tab completes, Enter runs). /help prints the same list.
/new start a fresh chat (saves the current one)
/clear start a fresh chat and clear the terminal
/resume [id] resume a saved chat
/models [id] model picker · type to search · tab to sort
/persona [id] personality picker · switching starts a new chat
/effort low|medium|high|off reasoning effort for new turns
/todos add|done|stuck|clear [..] manage the todo list
/attach <path>|clear queue a file or image for your next message
/compact [0-100] fold older conversation (optional aggressiveness)
/export [path] export the session transcript as JSONL
/memory forget|edit|clear|reset [..] what sable remembers about you
/usage weekly and monthly allowance, resets, extra credits
/billing manage your rotur subscription in the browser
/key set|clear|toggle <provider> [key] your own provider key (no allowance used)
/rotur grant <perm..>|revoke rotur account permissions
/profile open your rotur profile in the browser
/yolo toggle auto-approve for tool calls (no prompts)
/stop cancel the running turn (same as esc)
/help show this list
/logout forget the saved token and exit
/quit exitKeys: Enter sends, Shift-Enter inserts a newline (Ctrl-J is the fallback in terminals that do not distinguish Shift-Enter), Tab completes a command, Ctrl-V pastes an image from the clipboard (macOS). Esc or Ctrl-C stops the running turn; Ctrl-C at an idle prompt quits.
Type ahead while a turn runs to queue messages; they send when it finishes. /new saves the current
conversation as JSONL under ~/.sable/<escaped-working-directory>/ and starts a fresh chat while keeping
the terminal scrollback; /clear does the same and wipes the screen. Use /resume to pick a saved chat or
/resume <id> to restore one. Switching personality with /persona also starts a new chat. The status
bar and multiline input stay pinned at the bottom.
sable --help lists the launch flags (--version, --update).
Layout
src/
chatStore.ts per-directory JSONL persistence under ~/.sable/<escaped-cwd>/
client.ts SableClient: one WebSocket, frames in/out (isolated mode)
auth.ts rotur device-link login
config.ts token + prefs at ~/.config/sable/config.json
ansi.ts ANSI helpers for the pre-TUI login prints
types.ts shared domain types
diff.ts line diff + patch model for edit/write previews
pretty.ts friendly names for tool calls
tools/ tool schemas sable registers + local dispatch/approval gate
index.ts exec.ts files.ts search.ts todo.ts types.ts
tui/
App.tsx the Ink app: state, server-event wiring, input, commands
markdown.tsx terminal markdown renderer
toolCategory.ts models.ts input.ts theme.ts constants.ts platform.ts
components/
transcript.tsx scrollback + turn rows (Line, LiveRow, Diff)
chrome.tsx status bar, activity line, input echo, confirms, todos
Picker.tsx model / personality pickernpm test runs the unit tests. Before publishing, run npm run release:check to build, test, check formatting,
inspect the npm package contents, and audit production dependencies.
