sanook-cli 0.5.0 → 0.5.2
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/.env.example +161 -3
- package/CHANGELOG.md +83 -5
- package/README.md +240 -23
- package/README.th.md +87 -6
- package/dist/approval.js +6 -0
- package/dist/bin.js +3045 -210
- package/dist/brain-context.js +223 -0
- package/dist/brain-doctor.js +318 -0
- package/dist/brain-eval.js +186 -0
- package/dist/brain-final.js +371 -0
- package/dist/brain-review.js +382 -0
- package/dist/brain.js +12 -1
- package/dist/brand.js +1 -1
- package/dist/cli-args.js +152 -0
- package/dist/cli-option-values.js +16 -0
- package/dist/commands.js +172 -13
- package/dist/compaction.js +96 -11
- package/dist/config.js +118 -28
- package/dist/context-compression.js +191 -0
- package/dist/cost.js +49 -15
- package/dist/first-run.js +21 -0
- package/dist/gateway/auth.js +37 -8
- package/dist/gateway/bluebubbles.js +205 -0
- package/dist/gateway/config.js +929 -0
- package/dist/gateway/deliver.js +357 -0
- package/dist/gateway/discord.js +124 -0
- package/dist/gateway/email.js +472 -0
- package/dist/gateway/googlechat.js +207 -0
- package/dist/gateway/homeassistant.js +256 -0
- package/dist/gateway/ledger.js +18 -0
- package/dist/gateway/line.js +171 -0
- package/dist/gateway/lock.js +3 -1
- package/dist/gateway/matrix.js +366 -0
- package/dist/gateway/mattermost.js +322 -0
- package/dist/gateway/ntfy.js +218 -0
- package/dist/gateway/schedule.js +31 -4
- package/dist/gateway/serve.js +267 -7
- package/dist/gateway/server.js +253 -19
- package/dist/gateway/service.js +224 -0
- package/dist/gateway/session.js +343 -0
- package/dist/gateway/signal.js +351 -0
- package/dist/gateway/slack.js +124 -0
- package/dist/gateway/sms.js +169 -0
- package/dist/gateway/targets.js +576 -0
- package/dist/gateway/teams.js +106 -0
- package/dist/gateway/telegram.js +38 -15
- package/dist/gateway/webhooks.js +220 -0
- package/dist/gateway/whatsapp.js +230 -0
- package/dist/hooks.js +13 -2
- package/dist/insights-args.js +35 -0
- package/dist/insights.js +86 -0
- package/dist/loop.js +123 -24
- package/dist/lsp/index.js +23 -5
- package/dist/mcp-registry.js +350 -0
- package/dist/mcp-server.js +1 -1
- package/dist/mcp.js +44 -6
- package/dist/memory.js +100 -33
- package/dist/orchestrate.js +49 -19
- package/dist/personality.js +58 -0
- package/dist/providers/codex.js +86 -38
- package/dist/providers/keys.js +1 -1
- package/dist/providers/models.js +22 -6
- package/dist/providers/registry.js +38 -49
- package/dist/search/chunk.js +7 -8
- package/dist/search/cli.js +75 -0
- package/dist/search/embed-store.js +3 -0
- package/dist/search/indexer.js +44 -1
- package/dist/search/store.js +23 -1
- package/dist/session.js +93 -7
- package/dist/skill-install.js +29 -12
- package/dist/support-dump.js +175 -0
- package/dist/tools/edit.js +45 -15
- package/dist/tools/git.js +10 -5
- package/dist/tools/homeassistant.js +106 -0
- package/dist/tools/index.js +5 -0
- package/dist/tools/list.js +19 -6
- package/dist/tools/permission.js +923 -9
- package/dist/tools/read.js +16 -4
- package/dist/tools/schedule.js +19 -3
- package/dist/tools/search.js +217 -13
- package/dist/tools/task.js +18 -7
- package/dist/tools/timeout.js +21 -3
- package/dist/trust.js +11 -1
- package/dist/ui/app.js +57 -11
- package/dist/ui/brain-wizard.js +2 -2
- package/dist/ui/history.js +37 -5
- package/dist/ui/mentions.js +3 -2
- package/dist/ui/render.js +55 -15
- package/dist/ui/setup.js +107 -10
- package/dist/update.js +24 -11
- package/dist/worktree.js +175 -4
- package/package.json +4 -4
- package/second-brain/AGENTS.md +6 -4
- package/second-brain/CLAUDE.md +7 -1
- package/second-brain/Evals/_Index.md +10 -2
- package/second-brain/Evals/quality-ledger.md +9 -1
- package/second-brain/Evals/second-brain-benchmarks.md +62 -0
- package/second-brain/GEMINI.md +5 -4
- package/second-brain/Home.md +1 -1
- package/second-brain/Projects/_Index.md +3 -1
- package/second-brain/Projects/sanook-cli/_Index.md +26 -0
- package/second-brain/Projects/sanook-cli/second-brain-feature-roadmap.md +156 -0
- package/second-brain/README.md +1 -1
- package/second-brain/Research/2026-06-17-ai-second-brain-method-experiment.md +108 -0
- package/second-brain/Research/2026-06-18-ai-token-reduction-frameworks.md +55 -0
- package/second-brain/Research/2026-06-18-hermes-cli-second-brain-expansion-research.md +160 -0
- package/second-brain/Research/2026-06-18-sanook-mcp-ecosystem-and-ux-roadmap.md +181 -0
- package/second-brain/Research/_Index.md +6 -1
- package/second-brain/Reviews/2026-06-18-auto-improve-maintenance.md +54 -0
- package/second-brain/Reviews/_Index.md +1 -1
- package/second-brain/Runbooks/_Index.md +6 -1
- package/second-brain/Runbooks/ai-second-brain-operating-sequence.md +108 -0
- package/second-brain/SANOOK.md +45 -0
- package/second-brain/Sessions/2026-06-17-ai-framework-additional-zones.md +68 -0
- package/second-brain/Sessions/2026-06-17-ai-second-brain-sequence-experiment.md +63 -0
- package/second-brain/Sessions/2026-06-18-cli-args-release-readiness.md +59 -0
- package/second-brain/Sessions/2026-06-18-final-gate-template-final.md +192 -0
- package/second-brain/Sessions/2026-06-18-final-gate-template.md +71 -0
- package/second-brain/Sessions/2026-06-18-framework-dogfood-permission-and-memory.md +58 -0
- package/second-brain/Sessions/2026-06-18-hermes-second-brain-expansion-research.md +52 -0
- package/second-brain/Sessions/2026-06-18-mcp-ecosystem-and-sanook-ux-scan.md +81 -0
- package/second-brain/Sessions/2026-06-18-sanook-brain-cli-p0-implementation.md +86 -0
- package/second-brain/Sessions/2026-06-18-sanook-brain-final-cli-final.md +246 -0
- package/second-brain/Sessions/2026-06-18-sanook-brain-final-cli.md +78 -0
- package/second-brain/Sessions/2026-06-18-sanook-cli-second-brain-roadmap-correction.md +54 -0
- package/second-brain/Sessions/2026-06-18-token-reduction-framework-integration.md +69 -0
- package/second-brain/Sessions/_Index.md +15 -1
- package/second-brain/Shared/AI-Context-Index.md +22 -0
- package/second-brain/Shared/Context-Packs/_Index.md +9 -1
- package/second-brain/Shared/Context-Packs/coding-release.md +51 -0
- package/second-brain/Shared/Context-Packs/research-to-framework.md +51 -0
- package/second-brain/Shared/Context-Packs/second-brain-maintenance.md +41 -0
- package/second-brain/Shared/Operating-State/current-state.md +22 -3
- package/second-brain/Shared/Scripts/_Index.md +3 -1
- package/second-brain/Shared/Scripts/ai-second-brain-method-eval.mjs +198 -0
- package/second-brain/Shared/Tech-Standards/_Index.md +4 -1
- package/second-brain/Shared/Tech-Standards/mcp-integration-roadmap.md +86 -0
- package/second-brain/Shared/Tech-Standards/verification-standard.md +24 -0
- package/second-brain/Shared/User-Memory/_Index.md +4 -1
- package/second-brain/Shared/User-Memory/response-examples.md +98 -0
- package/second-brain/Shared/User-Memory/user-preferences.md +1 -0
- package/second-brain/Templates/_Index.md +9 -0
- package/second-brain/Templates/final-lite.md +111 -0
- package/second-brain/Templates/final.md +231 -0
- package/second-brain/Vault Structure Map.md +2 -1
- package/skills/structured-output-llm/SKILL.md +1 -1
package/README.md
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
**The open-source terminal AI coding agent that remembers across sessions.**
|
|
6
6
|
|
|
7
|
-
Bring your own key ·
|
|
7
|
+
Bring your own key · 9 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.
|
|
8
8
|
|
|
9
9
|
🇹🇭 [อ่านภาษาไทย](README.th.md)
|
|
10
10
|
|
|
@@ -13,7 +13,7 @@ Bring your own key · 12 providers · MCP · a built-in **"second brain"** that
|
|
|
13
13
|
[](LICENSE)
|
|
14
14
|
[](https://nodejs.org)
|
|
15
15
|
[](https://www.typescriptlang.org)
|
|
16
|
-
[](#development)
|
|
17
17
|
[](https://github.com/Sir-chawakorn/sanook-cli/actions/workflows/ci.yml)
|
|
18
18
|
|
|
19
19
|
[Quickstart](#quickstart) · [Providers](#providers) · [Usage](#usage) · [Gateway](#gateway--scheduling) · [Skills](#skills) · [MCP](#mcp) · [Security](#security)
|
|
@@ -45,7 +45,7 @@ The agent loop, BYOK, and MCP are table stakes now. What Sanook has that the big
|
|
|
45
45
|
|---|:---:|:---:|:---:|:---:|
|
|
46
46
|
| Open-source | ✅ | ❌ | ✅ | ✅ |
|
|
47
47
|
| Bring your own key | ✅ | — | ✅ | ✅ |
|
|
48
|
-
| Providers | **
|
|
48
|
+
| Providers | **9** | 1 | 1 | 1 |
|
|
49
49
|
| Local models (Ollama / LM Studio) | ✅ | ❌ | ❌ | ❌ |
|
|
50
50
|
| MCP (stdio **+ remote HTTP**) | ✅ | ✅ | ✅ | ✅ |
|
|
51
51
|
| OS sandbox (Seatbelt / bubblewrap) | ✅ | ✅ | ✅ | ✅ |
|
|
@@ -53,7 +53,7 @@ The agent loop, BYOK, and MCP are table stakes now. What Sanook has that the big
|
|
|
53
53
|
| Image / vision input | ✅ | ✅ | ✅ | ✅ |
|
|
54
54
|
| Prompt caching | ✅ | ✅ | ✅ | ✅ |
|
|
55
55
|
| **Durable cross-session memory** | ✅ | ❌ | ❌ | ❌ |
|
|
56
|
-
| **Local gateway + cron +
|
|
56
|
+
| **Local gateway + cron + messaging** | ✅ | ❌ | ❌ | ❌ |
|
|
57
57
|
|
|
58
58
|
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.
|
|
59
59
|
|
|
@@ -68,9 +68,13 @@ npm install -g sanook-cli
|
|
|
68
68
|
> ⚠️ **`'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 the `sanook` command isn't found. Fix: reinstall with `npm install -g sanook-cli`, or just run it via **`npx sanook`** (uses the local copy you already installed).
|
|
69
69
|
> Run **`npx sanook doctor`** to auto-diagnose Node version / PATH / install state and print the exact fix for your OS (incl. a safe Windows PATH one-liner).
|
|
70
70
|
|
|
71
|
-
|
|
71
|
+
Run the setup wizard or set an API key manually:
|
|
72
72
|
|
|
73
73
|
```bash
|
|
74
|
+
sanook setup # provider + model wizard; offers to create a second brain
|
|
75
|
+
sanook model # re-run provider/model setup later
|
|
76
|
+
sanook auth add anthropic --api-key sk-ant-... --use
|
|
77
|
+
|
|
74
78
|
export ANTHROPIC_API_KEY=sk-ant-... # macOS / Linux
|
|
75
79
|
setx ANTHROPIC_API_KEY "sk-ant-..." # Windows (export won't work in cmd) — then open a NEW terminal
|
|
76
80
|
|
|
@@ -82,7 +86,13 @@ Run `sanook` with no task to drop into an interactive REPL. On the very first ru
|
|
|
82
86
|
```bash
|
|
83
87
|
sanook # interactive REPL
|
|
84
88
|
sanook "fix the failing test" # one-shot, headless
|
|
89
|
+
sanook chat -q "fix the failing test" --provider anthropic
|
|
90
|
+
sanook -z "summarise the diff" # one-shot, final output only
|
|
85
91
|
sanook --json "..." # JSONL output for CI / scripts
|
|
92
|
+
sanook status # redacted provider/key/brain/gateway status
|
|
93
|
+
sanook sessions # list saved sessions for this project
|
|
94
|
+
sanook --resume <session_id> "continue here"
|
|
95
|
+
sanook dump # support snapshot; raw secrets are never printed
|
|
86
96
|
```
|
|
87
97
|
|
|
88
98
|
## Features
|
|
@@ -95,13 +105,14 @@ sanook --json "..." # JSONL output for CI / scripts
|
|
|
95
105
|
| **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. |
|
|
96
106
|
| **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). |
|
|
97
107
|
| **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). |
|
|
98
|
-
| **Memory** | The agent writes its own notes (`remember`), recalls them across past sessions (`recall`),
|
|
108
|
+
| **Memory** | The agent writes its own notes (`remember`), recalls them across past sessions (`recall`), `--continue` resumes the latest run for the current project, `--resume <id>` resumes a specific run, and `sanook sessions` audits/exports/renames/prunes saved conversations. |
|
|
109
|
+
| **Familiar CLI surfaces** | `sanook setup`, `sanook model`, `sanook auth`, `sanook chat -q`, `sanook gateway`, `sanook status`, `sanook sessions`, `sanook dump`, `sanook tools`, and `sanook send` provide familiar management entry points, all Sanook-branded. |
|
|
99
110
|
| **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. |
|
|
100
111
|
| **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. |
|
|
101
|
-
| **Custom commands** | Drop a `.sanook/commands/<name>.md` prompt template and call it as `/<name>` (project commands require trust). |
|
|
112
|
+
| **Custom commands** | Drop a `.sanook/commands/<name>.md` prompt template and call it as `/<name>` (project commands require trust). Arguments replace `$ARGUMENTS` or `{{ args }}`; without a placeholder they are appended. |
|
|
102
113
|
| **Subagents** | A `task` tool spawns a fresh-context sub-agent for scoped exploration without bloating the main context — read-only by default, depth-guarded. |
|
|
103
|
-
| **Gateway + cron** | `sanook serve` runs a long-lived daemon: a loopback OpenAI-compatible HTTP endpoint plus a cron scheduler.
|
|
104
|
-
| **Channels** |
|
|
114
|
+
| **Gateway + cron** | `sanook gateway run` (alias: `sanook serve`) runs a long-lived daemon: a loopback OpenAI-compatible HTTP endpoint plus a cron scheduler. Scheduled tasks can use `--to` to deliver results back through the messaging gateway. |
|
|
115
|
+
| **Channels** | `sanook gateway setup telegram|discord|slack|mattermost|homeassistant|email|line|sms|ntfy|signal|whatsapp|matrix|googlechat|bluebubbles|teams|webhooks` stores messaging adapter config, and `sanook gateway run` starts Telegram long-polling, lightweight Discord Gateway / Slack Socket Mode / Mattermost REST+WebSocket adapters, Home Assistant state-change WebSocket filters, Email IMAP polling, LINE webhooks, Twilio SMS webhooks, ntfy topic streams, Signal via `signal-cli` HTTP/SSE, WhatsApp Cloud webhooks, Matrix Client-Server sync, and generic event webhooks when configured. Chat/event history is persisted per platform target, and final responses of `[SILENT]`, `SILENT`, `NO_REPLY`, or `NO REPLY` are stored but not delivered. `sanook send --to telegram|discord|slack|mattermost|homeassistant|email|line|sms|ntfy|signal|whatsapp|matrix|googlechat|bluebubbles|teams`, `sanook webhook subscribe`, and `sanook cron add --to ...` use the same outbound delivery rules. |
|
|
105
116
|
| **MCP** | Connect any Model Context Protocol server over **stdio or remote Streamable-HTTP** (filesystem, GitHub, Postgres, hosted servers, …) via `~/.sanook/mcp.json`. |
|
|
106
117
|
| **Git** | Branch, uncommitted changes, and recent commits are injected automatically, with `git_status` / `git_diff` / `git_log` / `git_commit` tools. |
|
|
107
118
|
| **Hooks** | Run your own command before/after any tool. A non-zero `PreToolUse` exit blocks the tool — enforce lint, format, or policy. |
|
|
@@ -111,19 +122,16 @@ sanook --json "..." # JSONL output for CI / scripts
|
|
|
111
122
|
|
|
112
123
|
## Providers
|
|
113
124
|
|
|
114
|
-
One model spec,
|
|
125
|
+
One model spec, nine providers. Switch with `-m <spec>` on the command line or `/model` in the REPL.
|
|
115
126
|
|
|
116
127
|
| Provider | Spec example | Key |
|
|
117
128
|
|---|---|---|
|
|
118
129
|
| Anthropic (Claude) | `-m sonnet`, `-m opus`, `-m haiku` | `ANTHROPIC_API_KEY` |
|
|
119
130
|
| Google (Gemini) | `-m gemini`, `-m google:gemini-2.5-flash` | `GOOGLE_GENERATIVE_AI_API_KEY` |
|
|
120
131
|
| OpenAI | `-m gpt`, `-m openai:gpt-5.5` | `OPENAI_API_KEY` |
|
|
121
|
-
| DeepSeek | `-m deepseek` | `DEEPSEEK_API_KEY` |
|
|
122
132
|
| xAI (Grok) | `-m grok` | `XAI_API_KEY` |
|
|
123
133
|
| Mistral | `-m mistral` | `MISTRAL_API_KEY` |
|
|
124
134
|
| Groq | `-m groq:fast` | `GROQ_API_KEY` |
|
|
125
|
-
| MiniMax | `-m minimax` | `MINIMAX_API_KEY` |
|
|
126
|
-
| GLM (Zhipu) | `-m glm` | `ZHIPU_API_KEY` |
|
|
127
135
|
| Ollama | `-m ollama` | — (local) |
|
|
128
136
|
| LM Studio | `-m lmstudio` | — (local) |
|
|
129
137
|
| OpenAI Codex | `-m codex` | via the official Codex CLI |
|
|
@@ -133,27 +141,47 @@ A spec is an alias (`sonnet`), a `provider:model-id` pair (`openai:gpt-5.5`), or
|
|
|
133
141
|
```bash
|
|
134
142
|
sanook models # list all providers
|
|
135
143
|
sanook models anthropic # curated ids (+ live verification if a key is set)
|
|
144
|
+
sanook auth list # redacted key status for every provider
|
|
145
|
+
sanook auth status openai # env/store/console details
|
|
136
146
|
```
|
|
137
147
|
|
|
138
148
|
## Usage
|
|
139
149
|
|
|
140
150
|
```
|
|
141
151
|
sanook "<task>" run one task (headless)
|
|
152
|
+
sanook -z "<task>" one-shot final output (script-friendly)
|
|
153
|
+
sanook chat -q "<query>" direct one-shot query
|
|
142
154
|
sanook interactive REPL
|
|
155
|
+
sanook setup [section] setup model/gateway/tools/agent/brain
|
|
156
|
+
sanook model choose provider + model
|
|
157
|
+
sanook status redacted install/config status
|
|
158
|
+
sanook auth list redacted provider key status
|
|
159
|
+
sanook auth add openai --api-key <key> [--use]
|
|
160
|
+
sanook sessions list saved sessions for this project
|
|
161
|
+
sanook sessions show <id>
|
|
162
|
+
sanook sessions export <id> [--format json|markdown] [--output path]
|
|
163
|
+
sanook sessions rename <id> <title>
|
|
164
|
+
sanook sessions stats [--all]
|
|
165
|
+
sanook sessions prune --keep N [--all] [--yes]
|
|
166
|
+
sanook sessions rm <id>
|
|
167
|
+
sanook dump [--show-keys] support dump (keys are still redacted)
|
|
143
168
|
sanook -c "<task>" resume the latest session for this project
|
|
169
|
+
sanook --resume <id> resume a specific saved session
|
|
144
170
|
sanook --continue-any resume the newest session across all projects
|
|
145
171
|
sanook --plan "<task>" plan mode (read-only)
|
|
146
172
|
sanook --json "<task>" JSONL output for scripts / CI
|
|
147
173
|
sanook update update the CLI to the latest npm release
|
|
148
174
|
|
|
149
175
|
-m, --model <spec> model or provider:model-id
|
|
176
|
+
--provider <id> provider shortcut for `sanook chat`
|
|
150
177
|
-b, --budget <usd> stop when estimated cost exceeds this
|
|
151
178
|
-y, --yes auto-approve tool calls (skip ask-mode)
|
|
179
|
+
--yolo alias for --yes
|
|
152
180
|
-v, --version print version
|
|
153
181
|
-h, --help show help
|
|
154
182
|
```
|
|
155
183
|
|
|
156
|
-
**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).
|
|
184
|
+
**REPL slash commands:** `/new` · `/reset` · `/status` · `/model` · `/personality` · `/platforms` · `/tools` · `/skills` · `/cost` · `/usage` · `/insights` · `/diff` · `/retry` · `/stop` · `/undo` · `/rewind` · `/clear` · `/compact` · `/compress` · `/help` · `/quit` — plus your own `.sanook/commands/*.md`. Input supports `↑`/`↓` history, `@file` mentions (text or image), and multiline (trailing `\` or Alt+Enter).
|
|
157
185
|
|
|
158
186
|
## Updating
|
|
159
187
|
|
|
@@ -170,11 +198,19 @@ When you launch the interactive TUI with plain `sanook`, the CLI checks for upda
|
|
|
170
198
|
|
|
171
199
|
## Gateway & scheduling
|
|
172
200
|
|
|
173
|
-
`sanook
|
|
201
|
+
`sanook gateway run` starts a single long-lived foreground process that hosts an HTTP API, a cron scheduler, and optional chat channels — all driving the same agent core. `sanook gateway start` runs the same gateway in the background and records its pid/log path under `~/.sanook/gateway/`. `sanook serve` remains as a compatibility alias.
|
|
174
202
|
|
|
175
203
|
```bash
|
|
176
|
-
sanook
|
|
204
|
+
sanook gateway status # redacted gateway config + token path
|
|
205
|
+
sanook gateway run --port 8787 # HTTP (127.0.0.1 only) + scheduler
|
|
206
|
+
sanook gateway start --port 8787 # background process + pid/log tracking
|
|
207
|
+
sanook gateway stop
|
|
208
|
+
sanook gateway restart
|
|
209
|
+
sanook gateway install # write launchd/systemd helper file
|
|
210
|
+
sanook serve --port 8787 # compatibility alias
|
|
177
211
|
sanook cron add "every 30m" "check the CI" # also "09:00", an ISO time, or "now"
|
|
212
|
+
sanook cron add "every 30m" "check the CI" --to slack:C01ABCDEF
|
|
213
|
+
sanook cron add "09:00" "summarise calendar" --to email:owner@example.com --model openai:gpt-5.1
|
|
178
214
|
sanook cron list
|
|
179
215
|
sanook cron rm <id>
|
|
180
216
|
```
|
|
@@ -194,17 +230,174 @@ curl http://127.0.0.1:8787/v1/chat/completions \
|
|
|
194
230
|
| `POST` | `/v1/chat/completions` | run the agent (OpenAI-compatible) |
|
|
195
231
|
| `GET` / `POST` | `/tasks` | list / enqueue scheduled tasks |
|
|
196
232
|
|
|
197
|
-
###
|
|
233
|
+
### Messaging channels
|
|
234
|
+
|
|
235
|
+
Use the setup command, or set environment variables before `sanook gateway run`. Telegram uses long-polling (no public URL needed), Discord uses the Gateway websocket, Slack uses Socket Mode, Mattermost uses REST API v4 plus websocket events, Home Assistant uses `/api/websocket` for watched `state_changed` events plus REST `persistent_notification.create` for replies, Email uses IMAP polling plus SMTP threaded replies, LINE uses the official Messaging API webhook + Reply/Push endpoints, SMS uses Twilio Programmable Messaging with `X-Twilio-Signature` validation, ntfy uses the HTTP JSON stream + publish API, Signal uses `signal-cli daemon --http` with JSON-RPC + Server-Sent Events, WhatsApp Cloud uses Meta's official webhook + Graph Messages API, Matrix uses the Matrix Client-Server sync/send API, Google Chat uses incoming webhooks or service-account Chat REST API sends with Pub/Sub config saved for future inbound, BlueBubbles/iMessage uses the BlueBubbles REST API for outbound text with webhook settings saved for inbound parity, Microsoft Teams supports Incoming Webhook delivery and Graph chat/channel delivery, and generic Webhooks accept GitHub/GitLab/Jira/Stripe-style events with HMAC validation.
|
|
236
|
+
|
|
237
|
+
```bash
|
|
238
|
+
sanook gateway setup # platform menu
|
|
239
|
+
sanook gateway setup telegram --bot-token 123:abc --allowed-chats 5222385839
|
|
240
|
+
sanook gateway setup discord --bot-token "$DISCORD_BOT_TOKEN" --channel 123456789012345678
|
|
241
|
+
sanook gateway setup slack --bot-token "$SLACK_BOT_TOKEN" --app-token "$SLACK_APP_TOKEN" --channel C01ABCDEF
|
|
242
|
+
sanook gateway setup mattermost --url https://mm.example.com --token "$MATTERMOST_TOKEN" \
|
|
243
|
+
--allowed-users user_id_1 --home-channel chan_home_id --thread-replies
|
|
244
|
+
sanook gateway setup homeassistant --url http://homeassistant.local:8123 --token "$HASS_TOKEN" \
|
|
245
|
+
--home-channel sanook_agent --watch-domains light,binary_sensor,climate
|
|
246
|
+
sanook gateway setup email --address bot@example.com --password "$EMAIL_PASSWORD" \
|
|
247
|
+
--imap-host imap.example.com --smtp-host smtp.example.com --home-address owner@example.com
|
|
248
|
+
sanook gateway setup line --channel-access-token "$LINE_CHANNEL_ACCESS_TOKEN" \
|
|
249
|
+
--channel-secret "$LINE_CHANNEL_SECRET" --home-channel U1234567890abcdef
|
|
250
|
+
sanook gateway setup sms --account-sid "$TWILIO_ACCOUNT_SID" --auth-token "$TWILIO_AUTH_TOKEN" \
|
|
251
|
+
--phone-number "$TWILIO_PHONE_NUMBER" --home-channel +15551234567 \
|
|
252
|
+
--webhook-url https://your-tunnel.example.com/sms/webhook
|
|
253
|
+
sanook gateway setup ntfy --topic sanook-yourname-2026 --token "$NTFY_TOKEN" --markdown
|
|
254
|
+
sanook gateway setup signal --account +15550000000 --home-channel +15551234567 \
|
|
255
|
+
--http-url http://127.0.0.1:8080
|
|
256
|
+
sanook gateway setup whatsapp --phone-number-id "$WHATSAPP_CLOUD_PHONE_NUMBER_ID" \
|
|
257
|
+
--access-token "$WHATSAPP_CLOUD_ACCESS_TOKEN" --app-secret "$WHATSAPP_CLOUD_APP_SECRET" \
|
|
258
|
+
--home-channel 15551234567 --public-url https://your-tunnel.example.com
|
|
259
|
+
sanook gateway setup matrix --homeserver https://matrix.example.org \
|
|
260
|
+
--access-token "$MATRIX_ACCESS_TOKEN" --allowed-users @alice:matrix.org \
|
|
261
|
+
--home-room '!abc123:matrix.example.org'
|
|
262
|
+
sanook gateway setup googlechat --service-account-json "$GOOGLE_CHAT_SERVICE_ACCOUNT_JSON" \
|
|
263
|
+
--home-channel spaces/AAAA --allowed-spaces spaces/AAAA
|
|
264
|
+
sanook gateway setup googlechat --incoming-webhook-url "$GOOGLE_CHAT_INCOMING_WEBHOOK_URL"
|
|
265
|
+
sanook gateway setup bluebubbles --server-url http://localhost:1234 --password "$BLUEBUBBLES_PASSWORD" \
|
|
266
|
+
--home-channel user@example.com --allowed-users user@example.com,+15551234567
|
|
267
|
+
sanook gateway setup teams --incoming-webhook-url "$TEAMS_INCOMING_WEBHOOK_URL"
|
|
268
|
+
sanook gateway setup teams --delivery-mode graph --graph-access-token "$TEAMS_GRAPH_ACCESS_TOKEN" \
|
|
269
|
+
--chat-id '19:chatid@thread.v2'
|
|
270
|
+
sanook gateway setup webhooks --secret "$WEBHOOK_SECRET" --public-url https://your-tunnel.example.com
|
|
271
|
+
sanook webhook subscribe github-issues --events issues \
|
|
272
|
+
--prompt "New issue #{issue.number}: {issue.title}\n{issue.html_url}" --to slack:C01ABCDEF
|
|
273
|
+
sanook webhook subscribe deploy-notify --events push --deliver-only \
|
|
274
|
+
--prompt "Push to {repository.full_name}: {head_commit.message}" --to sms
|
|
275
|
+
sanook gateway run
|
|
276
|
+
sanook send --to telegram "deploy finished"
|
|
277
|
+
sanook send --to discord "deploy finished"
|
|
278
|
+
sanook send --to slack:C01ABCDEF "deploy finished"
|
|
279
|
+
sanook send --to mattermost:chan_home_id "deploy finished"
|
|
280
|
+
sanook send --to homeassistant:doorbell "deploy finished"
|
|
281
|
+
sanook send --to email:owner@example.com --subject "[CI]" "deploy finished"
|
|
282
|
+
sanook send --to line "deploy finished"
|
|
283
|
+
sanook send --to sms "deploy finished"
|
|
284
|
+
sanook send --to ntfy "deploy finished"
|
|
285
|
+
sanook send --to signal "deploy finished"
|
|
286
|
+
sanook send --to whatsapp "deploy finished"
|
|
287
|
+
sanook send --to matrix "deploy finished"
|
|
288
|
+
sanook send --to matrix:'!ops:matrix.example.org' "deploy finished"
|
|
289
|
+
sanook send --to googlechat "deploy finished"
|
|
290
|
+
sanook send --to googlechat:spaces/AAAA/threads/thread-1 "threaded update"
|
|
291
|
+
sanook send --to bluebubbles "deploy finished"
|
|
292
|
+
sanook send --to bluebubbles:'iMessage;-;user@example.com' "deploy finished"
|
|
293
|
+
sanook send --to teams "deploy finished"
|
|
294
|
+
sanook send --to teams:'19:chatid@thread.v2' "deploy finished"
|
|
295
|
+
sanook cron add "every 30m" "check the CI" --to line
|
|
296
|
+
sanook cron add "09:00" "daily check-in" --to sms
|
|
297
|
+
sanook cron add "09:00" "daily check-in" --to ntfy
|
|
298
|
+
sanook cron add "09:00" "daily check-in" --to mattermost
|
|
299
|
+
sanook cron add "09:00" "daily check-in" --to homeassistant
|
|
300
|
+
sanook cron add "09:00" "daily check-in" --to signal
|
|
301
|
+
sanook cron add "09:00" "daily check-in" --to whatsapp
|
|
302
|
+
sanook cron add "09:00" "daily check-in" --to matrix
|
|
303
|
+
sanook cron add "09:00" "daily check-in" --to googlechat
|
|
304
|
+
sanook cron add "09:00" "daily check-in" --to bluebubbles
|
|
305
|
+
sanook cron add "09:00" "daily check-in" --to teams
|
|
306
|
+
sanook send --to telegram --subject "[CI]" --file build.log
|
|
307
|
+
echo "RAM 92%" | sanook send --to telegram --quiet
|
|
308
|
+
sanook send --to telegram:5222385839:17585 "threaded reply"
|
|
309
|
+
sanook webhook list
|
|
310
|
+
sanook webhook test github-issues --payload '{"event_type":"issues","issue":{"number":42,"title":"Test"}}'
|
|
311
|
+
sanook send --list --json
|
|
312
|
+
```
|
|
198
313
|
|
|
199
|
-
|
|
314
|
+
Environment overrides still work:
|
|
200
315
|
|
|
201
316
|
```bash
|
|
202
317
|
export TELEGRAM_BOT_TOKEN=123:abc
|
|
203
318
|
export TELEGRAM_ALLOWED_CHATS=5222385839 # required — comma-separated chat ids
|
|
204
|
-
|
|
319
|
+
export LINE_CHANNEL_ACCESS_TOKEN=xxx
|
|
320
|
+
export LINE_HOME_CHANNEL=U1234567890abcdef
|
|
321
|
+
export TWILIO_ACCOUNT_SID=ACxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
|
322
|
+
export TWILIO_AUTH_TOKEN=xxx
|
|
323
|
+
export TWILIO_PHONE_NUMBER=+15550000000
|
|
324
|
+
export SMS_HOME_CHANNEL=+15551234567
|
|
325
|
+
export SMS_WEBHOOK_URL=https://your-tunnel.example.com/sms/webhook
|
|
326
|
+
export NTFY_TOPIC=sanook-yourname-2026
|
|
327
|
+
export NTFY_ALLOWED_USERS=sanook-yourname-2026
|
|
328
|
+
export NTFY_HOME_CHANNEL=sanook-yourname-2026
|
|
329
|
+
export MATTERMOST_URL=https://mm.example.com
|
|
330
|
+
export MATTERMOST_TOKEN=xxx
|
|
331
|
+
export MATTERMOST_HOME_CHANNEL=chan_home_id
|
|
332
|
+
export MATTERMOST_ALLOWED_USERS=user_id_1,user_id_2
|
|
333
|
+
export MATTERMOST_ALLOWED_CHANNELS=chan_home_id,chan_ops_id
|
|
334
|
+
export MATTERMOST_REQUIRE_MENTION=true
|
|
335
|
+
export MATTERMOST_REPLY_MODE=thread
|
|
336
|
+
export HASS_URL=http://homeassistant.local:8123
|
|
337
|
+
export HASS_TOKEN=xxx
|
|
338
|
+
export HASS_HOME_CHANNEL=sanook_agent
|
|
339
|
+
export HASS_WATCH_DOMAINS=light,binary_sensor,climate
|
|
340
|
+
export HASS_WATCH_ENTITIES=sensor.temp,alarm_control_panel.home
|
|
341
|
+
export HASS_COOLDOWN_SECONDS=30
|
|
342
|
+
export SIGNAL_HTTP_URL=http://127.0.0.1:8080
|
|
343
|
+
export SIGNAL_ACCOUNT=+15550000000
|
|
344
|
+
export SIGNAL_HOME_CHANNEL=+15551234567
|
|
345
|
+
export SIGNAL_ALLOWED_USERS=+15551234567
|
|
346
|
+
export SIGNAL_GROUP_ALLOWED_USERS=groupIdBase64
|
|
347
|
+
export WHATSAPP_CLOUD_PHONE_NUMBER_ID=123456789012345
|
|
348
|
+
export WHATSAPP_CLOUD_ACCESS_TOKEN=EAA...
|
|
349
|
+
export WHATSAPP_CLOUD_APP_SECRET=xxx
|
|
350
|
+
export WHATSAPP_CLOUD_VERIFY_TOKEN=choose-a-long-random-token
|
|
351
|
+
export WHATSAPP_CLOUD_HOME_CHANNEL=15551234567
|
|
352
|
+
export WHATSAPP_CLOUD_ALLOWED_USERS=15551234567,15557654321
|
|
353
|
+
export WHATSAPP_CLOUD_PUBLIC_URL=https://your-tunnel.example.com
|
|
354
|
+
export WHATSAPP_CLOUD_API_VERSION=v20.0
|
|
355
|
+
export MATRIX_HOMESERVER=https://matrix.example.org
|
|
356
|
+
export MATRIX_ACCESS_TOKEN=syt_...
|
|
357
|
+
export MATRIX_USER_ID=@sanook:matrix.example.org
|
|
358
|
+
export MATRIX_HOME_ROOM='!abc123:matrix.example.org'
|
|
359
|
+
export MATRIX_ALLOWED_USERS=@alice:matrix.org,@bob:matrix.org
|
|
360
|
+
export MATRIX_ALLOWED_ROOMS='!abc123:matrix.example.org,!ops:matrix.example.org'
|
|
361
|
+
export MATRIX_REQUIRE_MENTION=true
|
|
362
|
+
export MATRIX_FREE_RESPONSE_ROOMS='!free:matrix.example.org'
|
|
363
|
+
export TEAMS_DELIVERY_MODE=incoming_webhook
|
|
364
|
+
export TEAMS_INCOMING_WEBHOOK_URL=https://...
|
|
365
|
+
export TEAMS_GRAPH_ACCESS_TOKEN=xxx
|
|
366
|
+
export TEAMS_CHAT_ID='19:chatid@thread.v2'
|
|
367
|
+
export TEAMS_HOME_CHANNEL='19:chatid@thread.v2'
|
|
368
|
+
export WEBHOOK_ENABLED=true
|
|
369
|
+
export WEBHOOK_SECRET=xxx
|
|
370
|
+
export WEBHOOK_PUBLIC_URL=https://your-tunnel.example.com
|
|
371
|
+
sanook gateway run
|
|
205
372
|
```
|
|
206
373
|
|
|
207
|
-
|
|
374
|
+
Messaging channels are **fail-closed** by default: configure a home target or allowlist before accepting remote users, and internal errors are redacted before they reach chat surfaces. See [Security](#security).
|
|
375
|
+
|
|
376
|
+
Inside Telegram/Discord/Slack/Mattermost/Email/LINE/SMS/ntfy/Signal/WhatsApp/Matrix conversations, Hermes-style commands are handled without calling the model: `/new`, `/reset`, `/model`, `/personality`, `/retry`, `/undo`, `/compress`, `/usage`, `/insights`, `/stop`, `/status`, `/sethome`, and `/help`. Matrix and Mattermost also accept `!new`, `!reset`, `!status`, and `!help` aliases for clients that reserve `/`.
|
|
377
|
+
|
|
378
|
+
For ntfy, the topic is the identity and trust boundary: use a long random topic, a private/reserved topic with `NTFY_TOKEN`, or a self-hosted ntfy server with ACLs. Sanook authorizes inbound ntfy messages by topic, not by the user-controlled notification title.
|
|
379
|
+
|
|
380
|
+
For Mattermost, use a dedicated bot account/token, set `MATTERMOST_ALLOWED_USERS` to Mattermost user IDs, and optionally restrict shared channels with `MATTERMOST_ALLOWED_CHANNELS`. DMs respond without a mention; public/private channels require `@botname` unless `MATTERMOST_REQUIRE_MENTION=false` or the channel is listed in `MATTERMOST_FREE_RESPONSE_CHANNELS`. Cron/send uses `MATTERMOST_HOME_CHANNEL`, `mattermost:channel_id`, or `mattermost:channel_id:root_post_id` for a threaded reply.
|
|
381
|
+
|
|
382
|
+
For Home Assistant, create a Long-Lived Access Token, keep `HASS_WATCH_DOMAINS`/`HASS_WATCH_ENTITIES` narrow, and use `HASS_IGNORE_ENTITIES` plus `HASS_COOLDOWN_SECONDS` for noisy sensors. No state events are forwarded unless a watch filter or `HASS_WATCH_ALL=true` is configured. Conversation tools can read entities/states/services, while `ha_call_service` is approval-gated and blocks unsafe domains such as `shell_command`, `command_line`, `python_script`, `pyscript`, `hassio`, and `rest_command`.
|
|
383
|
+
|
|
384
|
+
For Signal, run `signal-cli daemon --http 127.0.0.1:8080` locally, set `SIGNAL_ACCOUNT`, and keep `SIGNAL_ALLOWED_USERS` or `SIGNAL_HOME_CHANNEL` set so inbound DMs fail closed. Groups are disabled unless explicitly listed in `SIGNAL_GROUP_ALLOWED_USERS` or set to `*`; group send targets use `signal:group:<groupId>`.
|
|
385
|
+
|
|
386
|
+
For WhatsApp Cloud inbound messages, expose the gateway through a tunnel and set the Meta webhook callback URL to `https://<your-tunnel>/whatsapp/webhook`. Use the generated verify token for Meta's GET challenge, keep `WHATSAPP_CLOUD_APP_SECRET` set so Sanook can validate `X-Hub-Signature-256`, and check `GET /whatsapp/webhook/health` first. Send targets use country-code digits without `+` (for example `whatsapp:15551234567`), and normal WhatsApp 24-hour customer-service window limits still apply.
|
|
387
|
+
|
|
388
|
+
For Matrix, create a bot account on your homeserver, copy an access token from Element (or use `MATRIX_USER_ID` + `MATRIX_PASSWORD`), invite the bot to rooms, and keep `MATRIX_ALLOWED_USERS` set so inbound users fail closed. DMs respond without a mention; shared rooms require a bot mention unless `MATRIX_REQUIRE_MENTION=false` or the room is listed in `MATRIX_FREE_RESPONSE_ROOMS`. Cron/send uses `MATRIX_HOME_ROOM` or an explicit target like `matrix:!abc123:matrix.example.org`.
|
|
389
|
+
|
|
390
|
+
For Google Chat, use `GOOGLE_CHAT_INCOMING_WEBHOOK_URL` for the fastest proactive send path, or configure `GOOGLE_CHAT_SERVICE_ACCOUNT_JSON` plus `GOOGLE_CHAT_HOME_CHANNEL` (`spaces/...`) for Chat REST API delivery. Pub/Sub fields (`GOOGLE_CHAT_PROJECT_ID`, `GOOGLE_CHAT_SUBSCRIPTION_NAME`, `GOOGLE_CHAT_ALLOWED_USERS`) are saved now for inbound parity work. Cron/send uses `googlechat`, `googlechat:spaces/...`, or `googlechat:spaces/.../threads/...`.
|
|
391
|
+
|
|
392
|
+
For BlueBubbles/iMessage, run a BlueBubbles Server and configure `BLUEBUBBLES_SERVER_URL`, `BLUEBUBBLES_PASSWORD`, and `BLUEBUBBLES_HOME_CHANNEL` (chat GUID, email, or `+E.164` phone). Sanook resolves email/phone targets through `/api/v1/chat/query`, sends text via `/api/v1/message/text`, and keeps webhook fields (`BLUEBUBBLES_WEBHOOK_HOST`, `BLUEBUBBLES_WEBHOOK_PORT`, `BLUEBUBBLES_WEBHOOK_PATH`, mention gating) ready for inbound parity work.
|
|
393
|
+
|
|
394
|
+
For Microsoft Teams, use `TEAMS_DELIVERY_MODE=incoming_webhook` with a channel Incoming Webhook for simple proactive send/cron delivery, or `TEAMS_DELIVERY_MODE=graph` with `TEAMS_GRAPH_ACCESS_TOKEN` plus `TEAMS_CHAT_ID` or `TEAMS_TEAM_ID` + `TEAMS_CHANNEL_ID`. Teams chat IDs can contain colons, so quote explicit targets such as `teams:'19:chatid@thread.v2'` in shells.
|
|
395
|
+
|
|
396
|
+
For LINE inbound messages, expose the gateway through a tunnel and set the LINE Developers Console webhook URL to `https://<your-tunnel>/line/webhook`. Check the tunnel with `GET /line/webhook/health` first.
|
|
397
|
+
|
|
398
|
+
For SMS inbound messages, expose the gateway through a tunnel and set the Twilio Messaging webhook URL to `https://<your-tunnel>/sms/webhook`. Set `SMS_WEBHOOK_URL` to that exact URL so Sanook can validate `X-Twilio-Signature`; check `GET /sms/webhook/health` first.
|
|
399
|
+
|
|
400
|
+
For generic webhooks, create routes with `sanook webhook subscribe <route>` and point external services at `https://<your-tunnel>/webhooks/<route>`. Sanook accepts GitHub `X-Hub-Signature-256`, GitLab `X-Gitlab-Token`, or generic `X-Webhook-Signature`; check `GET /webhooks/health` first.
|
|
208
401
|
|
|
209
402
|
## Skills
|
|
210
403
|
|
|
@@ -229,7 +422,7 @@ sanook brain init # interactive — asks where + a few identity
|
|
|
229
422
|
sanook brain init ~/notes/brain # non-interactive (with --yes)
|
|
230
423
|
```
|
|
231
424
|
|
|
232
|
-
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.
|
|
425
|
+
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` / `SANOOK.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.
|
|
233
426
|
|
|
234
427
|
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.
|
|
235
428
|
|
|
@@ -263,7 +456,18 @@ Connect Model Context Protocol servers over **stdio or remote Streamable-HTTP**
|
|
|
263
456
|
}
|
|
264
457
|
```
|
|
265
458
|
|
|
266
|
-
|
|
459
|
+
Discover and install servers from the official MCP registry:
|
|
460
|
+
|
|
461
|
+
```bash
|
|
462
|
+
sanook mcp search gitlab
|
|
463
|
+
sanook mcp info com.gitlab/mcp
|
|
464
|
+
sanook mcp install com.gitlab/mcp --name gitlab
|
|
465
|
+
sanook mcp preset dev
|
|
466
|
+
sanook mcp test gitlab
|
|
467
|
+
sanook mcp doctor
|
|
468
|
+
```
|
|
469
|
+
|
|
470
|
+
Use `--env KEY=value` or `--header KEY=value` when a registry entry requires secrets, and `--project` to write to a trusted project `.sanook/mcp.json`. Some hosted MCP endpoints may return `401 Unauthorized` until you pass an auth header, even when the registry entry does not declare it yet. You can still add servers manually: `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).
|
|
267
471
|
|
|
268
472
|
Their tools are merged into the agent's toolset automatically. `/tools` in the REPL lists everything currently available.
|
|
269
473
|
|
|
@@ -308,9 +512,12 @@ Quality-neutral knobs in `~/.sanook/config.json` (or the matching `SANOOK_*` env
|
|
|
308
512
|
| `config set …` | env | effect |
|
|
309
513
|
|---|---|---|
|
|
310
514
|
| `cacheTtl 1h` | `SANOOK_CACHE_TTL=1h` | keep the cached system preamble alive for 1h (default `5m`) — cheaper to resume after a pause |
|
|
515
|
+
| `contextCompression selective` | `SANOOK_CONTEXT_COMPRESSION=selective` | zero-LLM, query-aware selective compression for stale, very large tool outputs before each model step (default `selective`; set `off` to disable) |
|
|
516
|
+
| `contextCompression headroom` | `SANOOK_CONTEXT_COMPRESSION=headroom` | wrap the Vercel AI SDK model with `headroom-ai` when you run a Headroom proxy/cloud setup (`SANOOK_HEADROOM_BASE_URL` / `SANOOK_HEADROOM_API_KEY`) |
|
|
311
517
|
| `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) |
|
|
312
518
|
| — | `SANOOK_SUBAGENT_MODEL=haiku` | run all sub-agent work (exploration/search) on a cheaper model while the main agent keeps the strong one |
|
|
313
519
|
| `summaryModel <spec>` | `SANOOK_SUMMARY_MODEL=<spec>` | model used for summarize-compaction (default: the fast sibling of your main model) |
|
|
520
|
+
| `embeddingModel <spec>` | `SANOOK_EMBEDDING_MODEL=<spec>` | model used for semantic search embeddings (for example `openai:text-embedding-3-small`) |
|
|
314
521
|
| `thinking 4000` | `SANOOK_THINKING=4000` | opt-in Anthropic extended thinking on the main agent with a `budgetTokens` cap (default off) |
|
|
315
522
|
|
|
316
523
|
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.
|
|
@@ -322,7 +529,7 @@ SANOOK_MODEL=sonnet # default model alias or provider:model
|
|
|
322
529
|
SANOOK_ALLOW_OUTSIDE_WORKSPACE=1 # allow file tools outside cwd/brain
|
|
323
530
|
SANOOK_GATEWAY_ALLOW_WRITE=1 # let sanook serve run mutating tools unattended
|
|
324
531
|
SANOOK_HOOKS_INHERIT_ENV=1 # pass full env to hooks instead of a minimal safe env
|
|
325
|
-
SANOOK_DISABLE_PERSISTENCE=1 # do not save sessions or
|
|
532
|
+
SANOOK_DISABLE_PERSISTENCE=1 # do not save sessions, memory, prompt history, or worklogs
|
|
326
533
|
SANOOK_DISABLE_UPDATE_CHECK=1 # do not show interactive update prompts
|
|
327
534
|
SANOOK_DISABLE_WORKLOG=1 # do not append second-brain worklogs
|
|
328
535
|
SANOOK_TRUST_PROJECT=1 # temporary trust override for project .sanook extensions
|
|
@@ -340,6 +547,16 @@ Sanook runs shell commands and edits files, so safety is built into the core rat
|
|
|
340
547
|
- **Safe fallback** — provider fallback does not retry after a mutating tool call has already happened, avoiding duplicate side effects.
|
|
341
548
|
- **Gateway** — HTTP binds to `127.0.0.1` only and requires a bearer token on every non-health endpoint.
|
|
342
549
|
- **Telegram** — fail-closed: a required allowlist, private-chat-only, per-chat rate-limiting, and generic error replies that never reveal internal paths.
|
|
550
|
+
- **Email** — use a dedicated mailbox and app password; store only app passwords, require an allowlist/home address by default, and keep SMTP/IMAP credentials in `~/.sanook/gateway/config.json` (chmod 600).
|
|
551
|
+
- **LINE** — use a long-lived Messaging API channel access token, keep a home/allowed target list by default, and store the token/secret in `~/.sanook/gateway/config.json` (chmod 600).
|
|
552
|
+
- **ntfy** — treat the topic as a shared secret unless you protect it with ntfy auth/ACLs; Sanook requires `NTFY_ALLOWED_USERS`/home topic or `NTFY_ALLOW_ALL_USERS` before subscribing.
|
|
553
|
+
- **Mattermost** — use a dedicated bot token, require `MATTERMOST_ALLOWED_USERS` by default, optionally restrict channels with `MATTERMOST_ALLOWED_CHANNELS`, and keep public/private channels on mention-only mode unless you deliberately list free-response channels.
|
|
554
|
+
- **Home Assistant** — use a dedicated Long-Lived Access Token, keep watch filters narrow, leave `HASS_WATCH_ALL` off by default, and require approval for device-control calls through `ha_call_service`.
|
|
555
|
+
- **Signal** — keep `signal-cli` HTTP bound to loopback, require DM allowlists by default, and enable groups only with `SIGNAL_GROUP_ALLOWED_USERS` (or `*` deliberately).
|
|
556
|
+
- **WhatsApp Cloud** — use a dedicated Meta app/access token, keep `WHATSAPP_CLOUD_APP_SECRET` and a long verify token configured, require home/allowed wa_ids by default, and verify every inbound POST with `X-Hub-Signature-256`.
|
|
557
|
+
- **Matrix** — use a dedicated bot account/access token, require `MATRIX_ALLOWED_USERS` by default, optionally restrict shared rooms with `MATRIX_ALLOWED_ROOMS`, and treat password login as a convenience fallback rather than the preferred production mode.
|
|
558
|
+
- **Google Chat** — keep service account JSON files chmod 600, do not paste private keys into shell history, keep incoming webhook URLs out of logs/support dumps, and restrict proactive sends with `GOOGLE_CHAT_HOME_CHANNEL` or `GOOGLE_CHAT_ALLOWED_SPACES`.
|
|
559
|
+
- **Microsoft Teams** — prefer narrowly scoped Graph permissions or a dedicated channel Incoming Webhook, keep tokens out of logs/support dumps, and treat `TEAMS_CLIENT_SECRET` as future inbound bot credential material.
|
|
343
560
|
|
|
344
561
|
Hardened across several adversarial security reviews covering command injection, prompt injection, concurrency, and credential leakage.
|
|
345
562
|
|
package/README.th.md
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
**AI coding agent ใน terminal ที่ "จำงานข้ามวันได้" — open-source**
|
|
6
6
|
|
|
7
|
-
ใส่ API key ของคุณเอง (BYOK) ·
|
|
7
|
+
ใส่ API key ของคุณเอง (BYOK) · 9 providers · MCP · มี **"สมองที่สอง" (second brain)** ที่ทำให้ AI จำ context ข้าม session ได้ — สิ่งที่ Claude Code / Codex / Gemini CLI ลืมทุกครั้งที่ปิด terminal
|
|
8
8
|
|
|
9
9
|
[](https://www.npmjs.com/package/sanook-cli)
|
|
10
10
|
[](https://www.npmjs.com/package/sanook-cli)
|
|
@@ -39,9 +39,13 @@ npm install -g sanook-cli
|
|
|
39
39
|
> แก้: ลงใหม่ด้วย `npm install -g sanook-cli` · หรือเรียกผ่าน **`npx sanook`** (ใช้ตัวที่ลง local ไปแล้วได้เลย)
|
|
40
40
|
> หรือรัน **`npx sanook doctor`** — ตรวจ Node/PATH/สถานะการติดตั้งให้ แล้วบอกคำสั่งแก้ที่ตรงกับ OS (มีบรรทัดแก้ PATH บน Windows แบบปลอดภัยให้ก็อปด้วย)
|
|
41
41
|
|
|
42
|
-
|
|
42
|
+
เริ่มด้วย setup wizard แบบเป็นทางการ หรือจะตั้ง API key เองก็ได้:
|
|
43
43
|
|
|
44
44
|
```bash
|
|
45
|
+
sanook setup # เลือก provider + model และเสนอสร้าง second brain
|
|
46
|
+
sanook model # กลับมาเปลี่ยน provider/model ภายหลัง
|
|
47
|
+
sanook auth add anthropic --api-key sk-ant-... --use
|
|
48
|
+
|
|
45
49
|
# macOS / Linux
|
|
46
50
|
export ANTHROPIC_API_KEY=sk-ant-...
|
|
47
51
|
|
|
@@ -54,16 +58,84 @@ setx ANTHROPIC_API_KEY "sk-ant-..."
|
|
|
54
58
|
```bash
|
|
55
59
|
sanook # REPL (ครั้งแรก = setup wizard)
|
|
56
60
|
sanook "อ่าน package.json แล้วบอกว่ามี dependencies อะไรบ้าง"
|
|
61
|
+
sanook chat -q "อ่าน package.json แล้วสรุป dependencies" --provider anthropic
|
|
62
|
+
sanook -z "สรุป diff นี้" # one-shot เฉพาะคำตอบสุดท้าย เหมาะกับ script
|
|
63
|
+
sanook status # ดู provider/key/brain/gateway แบบ redact secret
|
|
64
|
+
sanook sessions # ดู saved sessions ของ project นี้
|
|
65
|
+
sanook --resume <session_id> "ทำต่อจาก session นี้"
|
|
66
|
+
sanook dump # diagnostic/support snapshot โดยไม่โชว์ raw secret
|
|
57
67
|
sanook -c "ทำต่อจาก session ล่าสุดของ project นี้"
|
|
58
68
|
sanook --continue-any "ทำต่อจาก session ล่าสุดข้าม project"
|
|
59
69
|
```
|
|
60
70
|
|
|
71
|
+
ตัวอย่างตั้งค่า messaging:
|
|
72
|
+
|
|
73
|
+
```bash
|
|
74
|
+
sanook gateway setup line --channel-access-token "$LINE_CHANNEL_ACCESS_TOKEN" \
|
|
75
|
+
--channel-secret "$LINE_CHANNEL_SECRET" --home-channel U1234567890abcdef
|
|
76
|
+
sanook gateway setup sms --account-sid "$TWILIO_ACCOUNT_SID" --auth-token "$TWILIO_AUTH_TOKEN" \
|
|
77
|
+
--phone-number "$TWILIO_PHONE_NUMBER" --home-channel +15551234567 \
|
|
78
|
+
--webhook-url https://your-tunnel.example.com/sms/webhook
|
|
79
|
+
sanook gateway setup ntfy --topic sanook-yourname-2026 --token "$NTFY_TOKEN" --markdown
|
|
80
|
+
sanook gateway setup mattermost --url https://mm.example.com --token "$MATTERMOST_TOKEN" \
|
|
81
|
+
--allowed-users user_id_1 --home-channel chan_home_id --thread-replies
|
|
82
|
+
sanook gateway setup homeassistant --url http://homeassistant.local:8123 --token "$HASS_TOKEN" \
|
|
83
|
+
--home-channel sanook_agent --watch-domains light,binary_sensor,climate
|
|
84
|
+
sanook gateway setup signal --account +15550000000 --home-channel +15551234567 \
|
|
85
|
+
--http-url http://127.0.0.1:8080
|
|
86
|
+
sanook gateway setup whatsapp --phone-number-id "$WHATSAPP_CLOUD_PHONE_NUMBER_ID" \
|
|
87
|
+
--access-token "$WHATSAPP_CLOUD_ACCESS_TOKEN" --app-secret "$WHATSAPP_CLOUD_APP_SECRET" \
|
|
88
|
+
--home-channel 15551234567 --public-url https://your-tunnel.example.com
|
|
89
|
+
sanook gateway setup matrix --homeserver https://matrix.example.org \
|
|
90
|
+
--access-token "$MATRIX_ACCESS_TOKEN" --allowed-users @alice:matrix.org \
|
|
91
|
+
--home-room '!abc123:matrix.example.org'
|
|
92
|
+
sanook gateway setup googlechat --service-account-json "$GOOGLE_CHAT_SERVICE_ACCOUNT_JSON" \
|
|
93
|
+
--home-channel spaces/AAAA --allowed-spaces spaces/AAAA
|
|
94
|
+
sanook gateway setup googlechat --incoming-webhook-url "$GOOGLE_CHAT_INCOMING_WEBHOOK_URL"
|
|
95
|
+
sanook gateway setup bluebubbles --server-url http://localhost:1234 --password "$BLUEBUBBLES_PASSWORD" \
|
|
96
|
+
--home-channel user@example.com --allowed-users user@example.com,+15551234567
|
|
97
|
+
sanook gateway setup teams --incoming-webhook-url "$TEAMS_INCOMING_WEBHOOK_URL"
|
|
98
|
+
sanook gateway setup webhooks --secret "$WEBHOOK_SECRET" --public-url https://your-tunnel.example.com
|
|
99
|
+
sanook webhook subscribe github-issues --events issues \
|
|
100
|
+
--prompt "Issue #{issue.number}: {issue.title}" --to slack:C01ABCDEF
|
|
101
|
+
sanook send --to sms "deploy finished"
|
|
102
|
+
sanook send --to ntfy "deploy finished"
|
|
103
|
+
sanook send --to mattermost "deploy finished"
|
|
104
|
+
sanook send --to homeassistant "deploy finished"
|
|
105
|
+
sanook send --to signal "deploy finished"
|
|
106
|
+
sanook send --to whatsapp "deploy finished"
|
|
107
|
+
sanook send --to matrix "deploy finished"
|
|
108
|
+
sanook send --to googlechat "deploy finished"
|
|
109
|
+
sanook send --to bluebubbles "deploy finished"
|
|
110
|
+
sanook send --to teams "deploy finished"
|
|
111
|
+
sanook cron add "09:00" "สรุปงานเช้านี้" --to ntfy
|
|
112
|
+
sanook cron add "09:00" "สรุปงานเช้านี้" --to mattermost
|
|
113
|
+
sanook cron add "09:00" "สรุปงานเช้านี้" --to homeassistant
|
|
114
|
+
sanook cron add "09:00" "สรุปงานเช้านี้" --to whatsapp
|
|
115
|
+
sanook cron add "09:00" "สรุปงานเช้านี้" --to matrix
|
|
116
|
+
sanook cron add "09:00" "สรุปงานเช้านี้" --to googlechat
|
|
117
|
+
sanook cron add "09:00" "สรุปงานเช้านี้" --to bluebubbles
|
|
118
|
+
sanook cron add "09:00" "สรุปงานเช้านี้" --to teams
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
ใน Telegram/Discord/Slack/Mattermost/Email/LINE/SMS/ntfy/Signal/WhatsApp/Matrix ใช้คำสั่งสไตล์ Hermes ได้โดยไม่เรียก model: `/new`, `/reset`, `/model`, `/personality`, `/retry`, `/undo`, `/compress`, `/usage`, `/insights`, `/stop`, `/status`, `/sethome`, และ `/help`; Matrix/Mattermost ใช้ `!new`, `!reset`, `!status`, `!help` ได้ด้วยสำหรับ client ที่กันคำสั่ง `/`
|
|
122
|
+
|
|
123
|
+
Home Assistant ใช้ Long-Lived Access Token, รับเฉพาะ `state_changed` ที่ตรง `--watch-domains`, `--watch-entities` หรือ `--watch-all`, และตอบกลับผ่าน persistent notification (`homeassistant[:notification_id]`). Tools อ่านสถานะ/บริการได้ ส่วน `ha_call_service` ต้องผ่าน approval และ block domain เสี่ยงเช่น `shell_command`, `command_line`, `python_script`, `pyscript`, `hassio`, `rest_command`
|
|
124
|
+
|
|
125
|
+
Google Chat ตอนนี้รองรับ proactive delivery/cron ผ่าน incoming webhook (`googlechat`) หรือ Service Account + Chat REST API (`googlechat:spaces/...`). ค่าของ Pub/Sub (`GOOGLE_CHAT_PROJECT_ID`, `GOOGLE_CHAT_SUBSCRIPTION_NAME`, `GOOGLE_CHAT_ALLOWED_USERS`) บันทึกไว้เพื่อทำ inbound parity ต่อ
|
|
126
|
+
|
|
127
|
+
BlueBubbles/iMessage ตอนนี้รองรับ proactive delivery/cron ผ่าน BlueBubbles REST API (`bluebubbles`, `imessage:user@example.com`, หรือ raw chat GUID). ใช้ `sanook gateway setup bluebubbles --server-url ... --password ... --home-channel ...`; ค่า webhook/mention (`BLUEBUBBLES_WEBHOOK_*`, `BLUEBUBBLES_REQUIRE_MENTION`) ถูกบันทึกไว้เพื่อทำ inbound parity ต่อ
|
|
128
|
+
|
|
129
|
+
Microsoft Teams ตอนนี้รองรับ proactive delivery/cron ผ่าน Incoming Webhook (`teams`) หรือ Graph mode (`teams:'19:chatid@thread.v2'`). ใช้ `sanook gateway setup teams --incoming-webhook-url ...` สำหรับเริ่มง่ายที่สุด
|
|
130
|
+
|
|
61
131
|
## ทำอะไรได้บ้าง
|
|
62
132
|
|
|
63
|
-
- **BYOK +
|
|
133
|
+
- **BYOK + 9 providers** — Anthropic, Google, OpenAI, xAI, Mistral, Groq, Ollama, LM Studio, Codex
|
|
134
|
+
- **Familiar CLI** — `sanook setup`, `sanook model`, `sanook auth`, `sanook chat -q`, `sanook gateway`, `sanook status`, `sanook sessions`, `sanook dump`, `sanook tools`, `sanook send`
|
|
64
135
|
- **Second brain** — `sanook brain init` สร้าง workspace Obsidian ให้ AI จำงานข้ามวัน
|
|
65
136
|
- **Tools** — อ่าน/เขียน/แก้ไฟล์ · รัน bash · git · grep/glob พร้อม permission gate
|
|
66
|
-
- **Gateway + cron** — `sanook serve`
|
|
137
|
+
- **Gateway + cron** — `sanook gateway run` (alias: `sanook serve`) รัน 24/7 + ตั้งงานล่วงหน้า + ต่อ Telegram/Discord/Slack/Mattermost/Home Assistant/Email/LINE/SMS/ntfy/Signal/WhatsApp/Matrix/Google Chat/BlueBubbles/Teams/Webhooks; task ใช้ `--to` เพื่อส่งผลลัพธ์กลับไปยัง messaging target ได้
|
|
138
|
+
- **Messaging setup/send** — `sanook gateway setup telegram|discord|slack|mattermost|homeassistant|email|line|sms|ntfy|signal|whatsapp|matrix|googlechat|bluebubbles|teams|webhooks` บันทึก token/allowlist หรือ SMTP/IMAP/LINE/Twilio/ntfy/Mattermost/Home Assistant/Signal/WhatsApp/Matrix/Google Chat/BlueBubbles/Teams/Webhook config; `sanook gateway run` เริ่ม Telegram long-polling, Discord Gateway, Slack Socket Mode, Mattermost REST/WebSocket, Home Assistant state-change WebSocket, Email IMAP polling + SMTP threaded replies, LINE webhook, Twilio SMS webhook, ntfy topic stream, Signal ผ่าน `signal-cli` HTTP/SSE, WhatsApp Cloud webhook + Graph Messages API, Matrix Client-Server sync/send, Google Chat outbound ผ่าน incoming webhook/Chat REST API, BlueBubbles outbound ผ่าน REST API, Teams Incoming Webhook/Graph delivery และ generic webhooks เมื่อ config พร้อม; history ถูกเก็บต่อ platform/target และถ้าคำตอบสุดท้ายเป็น `[SILENT]`, `SILENT`, `NO_REPLY`, หรือ `NO REPLY` จะบันทึกไว้แต่ไม่ส่งกลับ; `sanook send --to telegram|discord|slack|mattermost|homeassistant|email|line|sms|ntfy|signal|whatsapp|matrix|googlechat|bluebubbles|teams "..."`, `sanook webhook subscribe` และ `sanook cron add --to ...` ใช้กฎส่งออกชุดเดียวกัน
|
|
67
139
|
- **MCP + Skills** — ต่อ MCP server ได้ + มี built-in skills และติดตั้งเพิ่มได้
|
|
68
140
|
- **Update ง่าย** — ใช้ `sanook update` เพื่ออัปเดต CLI เป็นเวอร์ชันล่าสุดจาก npm
|
|
69
141
|
|
|
@@ -72,8 +144,17 @@ sanook --continue-any "ทำต่อจาก session ล่าสุดข้
|
|
|
72
144
|
```bash
|
|
73
145
|
sanook -m sonnet "..." # Claude
|
|
74
146
|
sanook -m gemini "..." # Gemini
|
|
75
|
-
sanook -m glm:smart "..." # GLM (z.ai Coding Plan)
|
|
76
147
|
sanook -m ollama "..." # local ไม่ต้องมี key
|
|
148
|
+
sanook auth list # ดู key/provider status แบบ redact secret
|
|
149
|
+
sanook auth status openai # ดู env/store/console ของ provider
|
|
150
|
+
sanook sessions # ดู session ที่บันทึกไว้ของ project นี้
|
|
151
|
+
sanook sessions show <id> # ดูรายละเอียด session แบบย่อ
|
|
152
|
+
sanook sessions export <id> --format markdown --output session.md
|
|
153
|
+
sanook sessions rename <id> "ชื่อ session"
|
|
154
|
+
sanook sessions stats --all
|
|
155
|
+
sanook sessions prune --keep 20 --yes
|
|
156
|
+
sanook sessions rm <id> # ลบ session
|
|
157
|
+
sanook dump [--show-keys] # support dump; key ยังถูก redact
|
|
77
158
|
```
|
|
78
159
|
|
|
79
160
|
ตั้งค่า default model ได้ด้วย:
|
|
@@ -114,7 +195,7 @@ sanook trust remove
|
|
|
114
195
|
```
|
|
115
196
|
|
|
116
197
|
- gateway bind ที่ `127.0.0.1` และต้องใช้ bearer token ยกเว้น `/health`; mutating tools ใน `sanook serve` เป็น `ask` โดย default และ opt-in unattended write ได้ด้วย `sanook config set permissionMode auto` หรือ `SANOOK_GATEWAY_ALLOW_WRITE=1`
|
|
117
|
-
- session/memory/worklog redact API keys ก่อนบันทึก และปิด persistence
|
|
198
|
+
- session/memory/prompt history/worklog redact API keys ก่อนบันทึก และปิด persistence ทั้งหมดได้ด้วย `SANOOK_DISABLE_PERSISTENCE=1`
|
|
118
199
|
|
|
119
200
|
## พัฒนา
|
|
120
201
|
|
package/dist/approval.js
CHANGED
|
@@ -11,6 +11,7 @@ export const MUTATE_TOOLS = new Set([
|
|
|
11
11
|
'cancel_scheduled',
|
|
12
12
|
'remember', // เขียน auto-memory ถาวร
|
|
13
13
|
'create_skill', // เขียน skill ถาวร
|
|
14
|
+
'ha_call_service', // ควบคุมอุปกรณ์ Home Assistant จริง
|
|
14
15
|
]);
|
|
15
16
|
// capability-based gate: tool ที่ "อ่านอย่างเดียว" เท่านั้นที่ผ่านโดยไม่ขออนุมัติ
|
|
16
17
|
// อย่างอื่น (รวม MCP tools ที่ไม่รู้จัก เช่น fs write / postgres DELETE) = treat as mutating → gate ใน ask-mode
|
|
@@ -26,6 +27,9 @@ const READ_ONLY_TOOLS = new Set([
|
|
|
26
27
|
'git_diff',
|
|
27
28
|
'git_log',
|
|
28
29
|
'list_scheduled',
|
|
30
|
+
'ha_list_entities',
|
|
31
|
+
'ha_get_state',
|
|
32
|
+
'ha_list_services',
|
|
29
33
|
]);
|
|
30
34
|
export function isReadOnlyTool(tool) {
|
|
31
35
|
return READ_ONLY_TOOLS.has(tool);
|
|
@@ -53,6 +57,8 @@ export function summarizeToolCall(tool, input) {
|
|
|
53
57
|
return `จำ: ${String(i.fact ?? '').slice(0, 50)}`;
|
|
54
58
|
case 'create_skill':
|
|
55
59
|
return `สร้าง skill ${String(i.name ?? '')}`;
|
|
60
|
+
case 'ha_call_service':
|
|
61
|
+
return `Home Assistant ${String(i.domain ?? '')}.${String(i.service ?? '')}${i.entity_id ? ` ${String(i.entity_id)}` : ''}`;
|
|
56
62
|
default:
|
|
57
63
|
return tool;
|
|
58
64
|
}
|