
Security News
GitHub Actions Checkout Now Blocks Risky pull_request_target Checkouts
GitHub Actions checkout now blocks risky pull_request_target checkouts by default to help prevent pwn request supply chain attacks.
sanook-cli
Advanced tools
A terminal AI coding agent — BYOK, 12 providers, MCP, cron gateway, skills, and git awareness. Built from scratch in TypeScript.
The open-source terminal AI coding agent that remembers across sessions.
Bring your own key · 12 providers · MCP · a built-in "second brain" that gives the AI durable memory across sessions — the thing Claude Code, Codex, and Gemini CLI lose at the session boundary.
🇹🇭 อ่านภาษาไทย
Quickstart · Providers · Usage · Gateway · Skills · MCP · Security
Sanook is a small, transparent coding agent for your terminal. At its heart is a single loop —
prompt → LLM → tool call → result → loop → answer
— wrapped with everything that makes it usable for real work: a permission gate, a memory the agent writes itself, a long-running gateway with cron and chat channels, on-demand skills, MCP servers, and first-class git awareness.
It is BYOK (bring your own key) by design. Every provider connects with a direct API key from that provider's own console — Sanook never reuses OAuth or subscription credentials, because that violates provider terms and gets accounts banned.
The agent loop, BYOK, and MCP are table stakes now. What Sanook has that the big vendor CLIs don't is memory that survives the session — a structured Obsidian "second brain" the agent reads at the start of every run.
| Sanook | Claude Code | Codex CLI | Gemini CLI | |
|---|---|---|---|---|
| Open-source | ✅ | ❌ | ✅ | ✅ |
| Bring your own key | ✅ | — | ✅ | ✅ |
| Providers | 12 | 1 | 1 | 1 |
| Local models (Ollama / LM Studio) | ✅ | ❌ | ❌ | ❌ |
| MCP (stdio + remote HTTP) | ✅ | ✅ | ✅ | ✅ |
| OS sandbox (Seatbelt / bubblewrap) | ✅ | ✅ | ✅ | ✅ |
| Checkpoint / rewind | ✅ | ✅ | ✅ | ✅ |
| Image / vision input | ✅ | ✅ | ✅ | ✅ |
| Prompt caching | ✅ | ✅ | ✅ | ✅ |
| Durable cross-session memory | ✅ | ❌ | ❌ | ❌ |
| Local gateway + cron + Telegram | ✅ | ❌ | ❌ | ❌ |
On raw benchmark scores the frontier vendors win — Sanook's bet is portability + persistent memory, not beating Opus on SWE-bench. Use whatever fits; this one remembers.
Install globally — the -g is required (needs Node ≥ 22; check with node -v):
npm install -g sanook-cli
⚠️
'sanook' is not recognized/ command not found? You installed it locally —npm i sanook-cli(without-g) drops it into the current folder, not on your PATH, so thesanookcommand isn't found. Fix: reinstall withnpm install -g sanook-cli, or just run it vianpx sanook(uses the local copy you already installed). Runnpx sanook doctorto auto-diagnose Node version / PATH / install state and print the exact fix for your OS (incl. a safe Windows PATH one-liner).
Set an API key (or run sanook with no task for the interactive setup wizard):
export ANTHROPIC_API_KEY=sk-ant-... # macOS / Linux
setx ANTHROPIC_API_KEY "sk-ant-..." # Windows (export won't work in cmd) — then open a NEW terminal
sanook "read package.json and list the dependencies"
Run sanook with no task to drop into an interactive REPL. On the very first run with no key configured, a setup wizard walks you through picking a provider, pasting a key, and choosing a model.
sanook # interactive REPL
sanook "fix the failing test" # one-shot, headless
sanook --json "..." # JSONL output for CI / scripts
| Area | What you get |
|---|---|
| Agent loop | Built on the Vercel AI SDK 6 (streamText + stopWhen + fullStream), with streamed output, a cost meter, a budget cap, Anthropic prompt caching on the static preamble, and rate-limit-aware retry/backoff (distinct from auth failures) with model fallback. |
| Tools | read_file · write_file · edit_file (multi-tier matcher) · list_dir · glob · grep · run_bash, plus git tools — gated by a permission layer that denies destructive commands, protected paths, and paths outside the workspace/brain by default. Non-bash tools are timeout-guarded so a runaway read/grep can't hang the loop. |
| Sandbox | run_bash is confined by an OS sandbox — Seatbelt on macOS, bubblewrap on Linux — so shell writes stay inside the workspace/brain/tmp (reads + network unaffected). Opt out with SANOOK_NO_SANDBOX=1. |
| Approval | ask mode is the default and prompts y/n before any file write or shell command. --yes for auto-approve; headless ask-mode safely denies mutations when no approval UI exists. |
| Input | Multiline editing, ↑/↓ persisted prompt history, readline keys (Ctrl-A/E/U/K/W), and @file mentions that inline a file's contents (or attach an image for vision-capable models). |
| Checkpoint | A shadow-git snapshot is taken before each turn; /rewind restores the files and truncates the conversation — recoverable (it stashes the current state first). |
| Memory | The agent writes its own notes (remember), recalls them across past sessions (recall), and --continue resumes the latest run for the current project. |
| Repo map | A lightweight symbol map of the repo (zero-dep, git-aware) is injected at session start so the agent picks the right files without blind grepping. |
| Skills | Built-in skills + install your own from a GitHub repo, URL, or local path. The agent can also author new skills after a repeatable task. |
| Custom commands | Drop a .sanook/commands/<name>.md prompt template and call it as /<name> (project commands require trust). |
| Subagents | A task tool spawns a fresh-context sub-agent for scoped exploration without bloating the main context — read-only by default, depth-guarded. |
| Gateway + cron | sanook serve runs a long-lived daemon: a loopback OpenAI-compatible HTTP endpoint plus a cron scheduler. Ask it in plain language and it schedules itself. |
| Channels | A Telegram adapter (long-polling, no public URL) lets you drive the agent from your phone — locked down with a required allowlist and private-chat-only policy. |
| MCP | Connect any Model Context Protocol server over stdio or remote Streamable-HTTP (filesystem, GitHub, Postgres, hosted servers, …) via ~/.sanook/mcp.json. |
| Git | Branch, uncommitted changes, and recent commits are injected automatically, with git_status / git_diff / git_log / git_commit tools. |
| Hooks | Run your own command before/after any tool. A non-zero PreToolUse exit blocks the tool — enforce lint, format, or policy. |
| Plan mode | --plan restricts the agent to read-only tools and asks it to produce a plan before touching anything. |
| Auto-compaction | A token-aware sliding window keeps long sessions under the context limit with zero extra LLM cost. |
| Second brain | sanook brain init scaffolds a structured Obsidian "second-brain" workspace (folders + _Index + a portable AI operating constitution) for organising work and giving the agent durable, cross-session memory. |
One model spec, twelve providers. Switch with -m <spec> on the command line or /model in the REPL.
| Provider | Spec example | Key |
|---|---|---|
| Anthropic (Claude) | -m sonnet, -m opus, -m haiku | ANTHROPIC_API_KEY |
| Google (Gemini) | -m gemini, -m google:gemini-2.5-flash | GOOGLE_GENERATIVE_AI_API_KEY |
| OpenAI | -m gpt, -m openai:gpt-5.5 | OPENAI_API_KEY |
| DeepSeek | -m deepseek | DEEPSEEK_API_KEY |
| xAI (Grok) | -m grok | XAI_API_KEY |
| Mistral | -m mistral | MISTRAL_API_KEY |
| Groq | -m groq:fast | GROQ_API_KEY |
| MiniMax | -m minimax | MINIMAX_API_KEY |
| GLM (Zhipu) | -m glm | ZHIPU_API_KEY |
| Ollama | -m ollama | — (local) |
| LM Studio | -m lmstudio | — (local) |
| OpenAI Codex | -m codex | via the official Codex CLI |
A spec is an alias (sonnet), a provider:model-id pair (openai:gpt-5.5), or a bare model id. sanook models <provider> lists the curated ids and, when a key is set, verifies them against the provider's live /models endpoint.
sanook models # list all providers
sanook models anthropic # curated ids (+ live verification if a key is set)
sanook "<task>" run one task (headless)
sanook interactive REPL
sanook -c "<task>" resume the latest session for this project
sanook --continue-any resume the newest session across all projects
sanook --plan "<task>" plan mode (read-only)
sanook --json "<task>" JSONL output for scripts / CI
sanook update update the CLI to the latest npm release
-m, --model <spec> model or provider:model-id
-b, --budget <usd> stop when estimated cost exceeds this
-y, --yes auto-approve tool calls (skip ask-mode)
-v, --version print version
-h, --help show help
REPL slash commands: /model · /tools · /skills · /cost · /diff · /undo · /rewind · /clear · /compact · /help · /quit — plus your own .sanook/commands/*.md. Input supports ↑/↓ history, @file mentions (text or image), and multiline (trailing \ or Alt+Enter).
Use the built-in updater whenever a new CLI version is available:
sanook update
sanook update --check # check only
It checks the npm latest release for sanook-cli and, when newer than your installed version, runs npm install -g sanook-cli@latest.
When you launch the interactive TUI with plain sanook, the CLI checks for updates at most once per day. If a newer version exists, it asks Yes/No before running the same updater. Set SANOOK_DISABLE_UPDATE_CHECK=1 to silence the prompt.
sanook serve starts a single long-lived process that hosts an HTTP API, a cron scheduler, and optional chat channels — all driving the same agent core.
sanook serve --port 8787 # HTTP (127.0.0.1 only) + scheduler
sanook cron add "every 30m" "check the CI" # also "09:00", an ISO time, or "now"
sanook cron list
sanook cron rm <id>
The HTTP server binds to loopback only and authenticates every endpoint (except /health) with a bearer token stored at ~/.sanook/gateway/token (chmod 600). It runs mutating tools in ask mode by default; opt into unattended writes with sanook config set permissionMode auto or SANOOK_GATEWAY_ALLOW_WRITE=1. It speaks the OpenAI chat-completions shape, so existing clients work unchanged:
curl http://127.0.0.1:8787/v1/chat/completions \
-H "Authorization: Bearer $(cat ~/.sanook/gateway/token)" \
-H 'content-type: application/json' \
-d '{"messages":[{"role":"user","content":"summarise today's commits"}]}'
| Method | Endpoint | Purpose |
|---|---|---|
GET | /health | liveness (public) |
POST | /v1/chat/completions | run the agent (OpenAI-compatible) |
GET / POST | /tasks | list / enqueue scheduled tasks |
Set two environment variables before sanook serve and the gateway adds a Telegram adapter via long-polling (no public URL needed):
export TELEGRAM_BOT_TOKEN=123:abc
export TELEGRAM_ALLOWED_CHATS=5222385839 # required — comma-separated chat ids
sanook serve
The channel is fail-closed: with no allowlist it refuses to start, it accepts private chats only, and it never leaks internal errors back to the sender. See Security.
A skill is a SKILL.md file (front-matter + instructions) the agent loads on demand. Sanook ships with built-in skills and can install more.
sanook skill list # browse all skills
sanook skill add anthropics/skills # from a GitHub repo
sanook skill add https://…/SKILL.md # from a URL
sanook skill add ./my-skill # from a local path
sanook skill remove my-skill
⚠️ A skill is an instruction the agent will follow. Install only from sources you trust.
Scaffold a structured Obsidian workspace for organising your work and giving the agent a durable, cross-session memory:
sanook brain init # interactive — asks where + a few identity questions
sanook brain init ~/notes/brain # non-interactive (with --yes)
It creates a full folder taxonomy (Projects/, Sessions/, Shared/ memory layer, Goals/, Research/, Skills/, …), an _Index.md in every folder, seed memory files, and a portable AI operating constitution (CLAUDE.md / GEMINI.md / AGENTS.md) so any AI agent works with the vault consistently. It ships with research-backed operating rules — context-assembly (anti context-rot), an intake quarantine + injection-scan gate, bi-temporal fact validity, provenance tracking, a verification-gated Skills/ library, and sleep-time consolidation. The first-run setup wizard also offers to create one.
Everything is create-if-missing — re-running never overwrites your notes. Point an Obsidian or filesystem MCP server at the workspace to let the agent read and write it.
Ranked search over the vault and the agent's memory, past sessions, and skills — one surface, no native binaries:
sanook index # incremental index of vault + memory + sessions + skills (O(delta))
sanook search "vercel edge deploy" # ranked hits with snippets
sanook search "race condition" --mode hybrid --source vault,memory --limit 5
Intl.Segmenter word breaks for Thai). No SQLite, no Bun, no native binary, no API key, no network.--mode hybrid|semantic embeds through your existing provider key (OpenAI / Mistral / Google / …), stores compact Float32 vectors locally, and fuses with BM25 via Reciprocal Rank Fusion. Activates only when a key resolves; degrades silently to BM25 otherwise. Configure with sanook config set embeddingModel openai:text-embedding-3-small (or SANOOK_EMBEDDING_MODEL).The agent's recall tool uses the same engine, so remembered facts and vault notes are searchable the moment they exist.
Connect Model Context Protocol servers over stdio or remote Streamable-HTTP with the same config shape you already use elsewhere:
// ~/.sanook/mcp.json
{
"mcpServers": {
"filesystem": { "command": "npx", "args": ["-y", "@modelcontextprotocol/server-filesystem", "/path"] },
"remote": { "url": "https://example.com/mcp", "headers": { "Authorization": "Bearer <token>" } }
}
}
Add servers from the CLI too: sanook mcp add fs npx -y @modelcontextprotocol/server-filesystem /path (stdio) or sanook mcp add remote https://example.com/mcp (a URL is detected as remote HTTP).
Their tools are merged into the agent's toolset automatically. /tools in the REPL lists everything currently available.
sanook is also an MCP server: sanook mcp serve exposes your brain (sanook_search / sanook_recall / sanook_remember / sanook_index / sanook_stats) over stdio, so Claude Desktop, Cursor, or any MCP host can query it:
// in another host's MCP config
{ "mcpServers": { "sanook-brain": { "command": "sanook", "args": ["mcp", "serve"] } } }
Project-local .sanook/mcp.json, .sanook/hooks.json, .sanook/skills/, and .sanook/commands/ are ignored until the project is trusted:
sanook trust status
sanook trust add # allow this project's .sanook mcp/hooks/skills/commands
sanook trust remove
Everything lives under ~/.sanook/ (with per-project .sanook/ overrides where relevant):
~/.sanook/auth.json API keys (chmod 600)
~/.sanook/memory/ auto-memory the agent writes
~/.sanook/search/ brain-search index + optional embedding vectors (regenerable via `sanook index`)
~/.sanook/sessions/ saved conversations (for --continue)
~/.sanook/skills/<name>/ installed SKILL.md files
~/.sanook/mcp.json MCP servers { "mcpServers": { … } }
~/.sanook/hooks.json PreToolUse / PostToolUse hooks
~/.sanook/gateway/ gateway token + task ledger
~/.sanook/trusted-projects.json project roots allowed to load project .sanook extensions
SANOOK.md project memory (hierarchical, like a system prompt)
Untrusted project config can set ordinary project defaults, but it cannot lower permissionMode to auto; trust the project first if you want project-local config to control mutation approval.
Quality-neutral knobs in ~/.sanook/config.json (or the matching SANOOK_* env var) to cut tokens/cost:
config set … | env | effect |
|---|---|---|
cacheTtl 1h | SANOOK_CACHE_TTL=1h | keep the cached system preamble alive for 1h (default 5m) — cheaper to resume after a pause |
compaction summarize | SANOOK_COMPACTION=summarize | when context gets long, condense it with a cheap model instead of truncating — better recall at the same budget (default truncate, zero-LLM) |
| — | SANOOK_SUBAGENT_MODEL=haiku | run all sub-agent work (exploration/search) on a cheaper model while the main agent keeps the strong one |
summaryModel <spec> | SANOOK_SUMMARY_MODEL=<spec> | model used for summarize-compaction (default: the fast sibling of your main model) |
thinking 4000 | SANOOK_THINKING=4000 | opt-in Anthropic extended thinking on the main agent with a budgetTokens cap (default off) |
Read-side savings are automatic: the agent reads file ranges (read_file with offset/limit) and edits with minimal old_string / replace_all rather than rewriting whole files.
Useful environment flags:
SANOOK_MODEL=sonnet # default model alias or provider:model
SANOOK_ALLOW_OUTSIDE_WORKSPACE=1 # allow file tools outside cwd/brain
SANOOK_GATEWAY_ALLOW_WRITE=1 # let sanook serve run mutating tools unattended
SANOOK_HOOKS_INHERIT_ENV=1 # pass full env to hooks instead of a minimal safe env
SANOOK_DISABLE_PERSISTENCE=1 # do not save sessions or memory
SANOOK_DISABLE_UPDATE_CHECK=1 # do not show interactive update prompts
SANOOK_DISABLE_WORKLOG=1 # do not append second-brain worklogs
SANOOK_TRUST_PROJECT=1 # temporary trust override for project .sanook extensions
Sanook runs shell commands and edits files, so safety is built into the core rather than bolted on:
ya29., Bearer, sk-ant-oat…). This keeps you within every provider's terms of service.rm -rf, git reset --hard, push --force, fork bombs, …), protected paths (.env, .git, node_modules, credential folders), and paths outside the workspace/brain are denied unless explicitly opted in.run_bash runs under Seatbelt (macOS) / bubblewrap (Linux) when available, confining shell writes to the workspace/brain/tmp — defense in depth beyond the regex blocklist (SANOOK_NO_SANDBOX=1 to disable)..sanook/mcp.json, .sanook/hooks.json, .sanook/skills/, and .sanook/commands/ can execute or steer the agent, so they are ignored until sanook trust add.127.0.0.1 only and requires a bearer token on every non-health endpoint.Hardened across several adversarial security reviews covering command injection, prompt injection, concurrency, and credential leakage.
npm install
npm run build # → dist/
npm test # vitest
npm run typecheck # tsc --noEmit (strict)
npm run dev -- "…" # run from source without building
CI runs the suite across macOS / Linux / Windows on Node 22 and 24. Requires Node ≥ 22.
Built by Sanook AI — AI tools & education 🇹🇭
Built from scratch in TypeScript on the Vercel AI SDK — no framework, no magic.
FAQs
A terminal AI coding agent — BYOK, 9 providers, MCP, cron gateway, skills, and git awareness. Built from scratch in TypeScript.
The npm package sanook-cli receives a total of 1,485 weekly downloads. As such, sanook-cli popularity was classified as popular.
We found that sanook-cli demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Security News
GitHub Actions checkout now blocks risky pull_request_target checkouts by default to help prevent pwn request supply chain attacks.

Product
Socket now supports Custom Roles and Repository Access Permissions so organizations can control who can access specific repositories and actions.

Product
Socket MCP now lets AI assistants review org alerts, investigate threats using the Socket threat feed, and inspect package files in addition to dependency scoring.