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.
Files changed (146) hide show
  1. package/.env.example +161 -3
  2. package/CHANGELOG.md +83 -5
  3. package/README.md +240 -23
  4. package/README.th.md +87 -6
  5. package/dist/approval.js +6 -0
  6. package/dist/bin.js +3045 -210
  7. package/dist/brain-context.js +223 -0
  8. package/dist/brain-doctor.js +318 -0
  9. package/dist/brain-eval.js +186 -0
  10. package/dist/brain-final.js +371 -0
  11. package/dist/brain-review.js +382 -0
  12. package/dist/brain.js +12 -1
  13. package/dist/brand.js +1 -1
  14. package/dist/cli-args.js +152 -0
  15. package/dist/cli-option-values.js +16 -0
  16. package/dist/commands.js +172 -13
  17. package/dist/compaction.js +96 -11
  18. package/dist/config.js +118 -28
  19. package/dist/context-compression.js +191 -0
  20. package/dist/cost.js +49 -15
  21. package/dist/first-run.js +21 -0
  22. package/dist/gateway/auth.js +37 -8
  23. package/dist/gateway/bluebubbles.js +205 -0
  24. package/dist/gateway/config.js +929 -0
  25. package/dist/gateway/deliver.js +357 -0
  26. package/dist/gateway/discord.js +124 -0
  27. package/dist/gateway/email.js +472 -0
  28. package/dist/gateway/googlechat.js +207 -0
  29. package/dist/gateway/homeassistant.js +256 -0
  30. package/dist/gateway/ledger.js +18 -0
  31. package/dist/gateway/line.js +171 -0
  32. package/dist/gateway/lock.js +3 -1
  33. package/dist/gateway/matrix.js +366 -0
  34. package/dist/gateway/mattermost.js +322 -0
  35. package/dist/gateway/ntfy.js +218 -0
  36. package/dist/gateway/schedule.js +31 -4
  37. package/dist/gateway/serve.js +267 -7
  38. package/dist/gateway/server.js +253 -19
  39. package/dist/gateway/service.js +224 -0
  40. package/dist/gateway/session.js +343 -0
  41. package/dist/gateway/signal.js +351 -0
  42. package/dist/gateway/slack.js +124 -0
  43. package/dist/gateway/sms.js +169 -0
  44. package/dist/gateway/targets.js +576 -0
  45. package/dist/gateway/teams.js +106 -0
  46. package/dist/gateway/telegram.js +38 -15
  47. package/dist/gateway/webhooks.js +220 -0
  48. package/dist/gateway/whatsapp.js +230 -0
  49. package/dist/hooks.js +13 -2
  50. package/dist/insights-args.js +35 -0
  51. package/dist/insights.js +86 -0
  52. package/dist/loop.js +123 -24
  53. package/dist/lsp/index.js +23 -5
  54. package/dist/mcp-registry.js +350 -0
  55. package/dist/mcp-server.js +1 -1
  56. package/dist/mcp.js +44 -6
  57. package/dist/memory.js +100 -33
  58. package/dist/orchestrate.js +49 -19
  59. package/dist/personality.js +58 -0
  60. package/dist/providers/codex.js +86 -38
  61. package/dist/providers/keys.js +1 -1
  62. package/dist/providers/models.js +22 -6
  63. package/dist/providers/registry.js +38 -49
  64. package/dist/search/chunk.js +7 -8
  65. package/dist/search/cli.js +75 -0
  66. package/dist/search/embed-store.js +3 -0
  67. package/dist/search/indexer.js +44 -1
  68. package/dist/search/store.js +23 -1
  69. package/dist/session.js +93 -7
  70. package/dist/skill-install.js +29 -12
  71. package/dist/support-dump.js +175 -0
  72. package/dist/tools/edit.js +45 -15
  73. package/dist/tools/git.js +10 -5
  74. package/dist/tools/homeassistant.js +106 -0
  75. package/dist/tools/index.js +5 -0
  76. package/dist/tools/list.js +19 -6
  77. package/dist/tools/permission.js +923 -9
  78. package/dist/tools/read.js +16 -4
  79. package/dist/tools/schedule.js +19 -3
  80. package/dist/tools/search.js +217 -13
  81. package/dist/tools/task.js +18 -7
  82. package/dist/tools/timeout.js +21 -3
  83. package/dist/trust.js +11 -1
  84. package/dist/ui/app.js +57 -11
  85. package/dist/ui/brain-wizard.js +2 -2
  86. package/dist/ui/history.js +37 -5
  87. package/dist/ui/mentions.js +3 -2
  88. package/dist/ui/render.js +55 -15
  89. package/dist/ui/setup.js +107 -10
  90. package/dist/update.js +24 -11
  91. package/dist/worktree.js +175 -4
  92. package/package.json +4 -4
  93. package/second-brain/AGENTS.md +6 -4
  94. package/second-brain/CLAUDE.md +7 -1
  95. package/second-brain/Evals/_Index.md +10 -2
  96. package/second-brain/Evals/quality-ledger.md +9 -1
  97. package/second-brain/Evals/second-brain-benchmarks.md +62 -0
  98. package/second-brain/GEMINI.md +5 -4
  99. package/second-brain/Home.md +1 -1
  100. package/second-brain/Projects/_Index.md +3 -1
  101. package/second-brain/Projects/sanook-cli/_Index.md +26 -0
  102. package/second-brain/Projects/sanook-cli/second-brain-feature-roadmap.md +156 -0
  103. package/second-brain/README.md +1 -1
  104. package/second-brain/Research/2026-06-17-ai-second-brain-method-experiment.md +108 -0
  105. package/second-brain/Research/2026-06-18-ai-token-reduction-frameworks.md +55 -0
  106. package/second-brain/Research/2026-06-18-hermes-cli-second-brain-expansion-research.md +160 -0
  107. package/second-brain/Research/2026-06-18-sanook-mcp-ecosystem-and-ux-roadmap.md +181 -0
  108. package/second-brain/Research/_Index.md +6 -1
  109. package/second-brain/Reviews/2026-06-18-auto-improve-maintenance.md +54 -0
  110. package/second-brain/Reviews/_Index.md +1 -1
  111. package/second-brain/Runbooks/_Index.md +6 -1
  112. package/second-brain/Runbooks/ai-second-brain-operating-sequence.md +108 -0
  113. package/second-brain/SANOOK.md +45 -0
  114. package/second-brain/Sessions/2026-06-17-ai-framework-additional-zones.md +68 -0
  115. package/second-brain/Sessions/2026-06-17-ai-second-brain-sequence-experiment.md +63 -0
  116. package/second-brain/Sessions/2026-06-18-cli-args-release-readiness.md +59 -0
  117. package/second-brain/Sessions/2026-06-18-final-gate-template-final.md +192 -0
  118. package/second-brain/Sessions/2026-06-18-final-gate-template.md +71 -0
  119. package/second-brain/Sessions/2026-06-18-framework-dogfood-permission-and-memory.md +58 -0
  120. package/second-brain/Sessions/2026-06-18-hermes-second-brain-expansion-research.md +52 -0
  121. package/second-brain/Sessions/2026-06-18-mcp-ecosystem-and-sanook-ux-scan.md +81 -0
  122. package/second-brain/Sessions/2026-06-18-sanook-brain-cli-p0-implementation.md +86 -0
  123. package/second-brain/Sessions/2026-06-18-sanook-brain-final-cli-final.md +246 -0
  124. package/second-brain/Sessions/2026-06-18-sanook-brain-final-cli.md +78 -0
  125. package/second-brain/Sessions/2026-06-18-sanook-cli-second-brain-roadmap-correction.md +54 -0
  126. package/second-brain/Sessions/2026-06-18-token-reduction-framework-integration.md +69 -0
  127. package/second-brain/Sessions/_Index.md +15 -1
  128. package/second-brain/Shared/AI-Context-Index.md +22 -0
  129. package/second-brain/Shared/Context-Packs/_Index.md +9 -1
  130. package/second-brain/Shared/Context-Packs/coding-release.md +51 -0
  131. package/second-brain/Shared/Context-Packs/research-to-framework.md +51 -0
  132. package/second-brain/Shared/Context-Packs/second-brain-maintenance.md +41 -0
  133. package/second-brain/Shared/Operating-State/current-state.md +22 -3
  134. package/second-brain/Shared/Scripts/_Index.md +3 -1
  135. package/second-brain/Shared/Scripts/ai-second-brain-method-eval.mjs +198 -0
  136. package/second-brain/Shared/Tech-Standards/_Index.md +4 -1
  137. package/second-brain/Shared/Tech-Standards/mcp-integration-roadmap.md +86 -0
  138. package/second-brain/Shared/Tech-Standards/verification-standard.md +24 -0
  139. package/second-brain/Shared/User-Memory/_Index.md +4 -1
  140. package/second-brain/Shared/User-Memory/response-examples.md +98 -0
  141. package/second-brain/Shared/User-Memory/user-preferences.md +1 -0
  142. package/second-brain/Templates/_Index.md +9 -0
  143. package/second-brain/Templates/final-lite.md +111 -0
  144. package/second-brain/Templates/final.md +231 -0
  145. package/second-brain/Vault Structure Map.md +2 -1
  146. 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 · 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.
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](https://img.shields.io/badge/license-Apache--2.0-22c55e.svg)](LICENSE)
14
14
  [![Node](https://img.shields.io/badge/node-%E2%89%A5%2022-339933.svg?logo=node.js&logoColor=white)](https://nodejs.org)
15
15
  [![TypeScript](https://img.shields.io/badge/TypeScript-strict-3178c6.svg?logo=typescript&logoColor=white)](https://www.typescriptlang.org)
16
- [![Tests](https://img.shields.io/badge/tests-381%20passing-22c55e.svg)](#development)
16
+ [![Tests](https://img.shields.io/badge/tests-passing-22c55e.svg)](#development)
17
17
  [![CI](https://github.com/Sir-chawakorn/sanook-cli/actions/workflows/ci.yml/badge.svg)](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 | **12** | 1 | 1 | 1 |
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 + Telegram** | ✅ | ❌ | ❌ | ❌ |
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
- Set an API key (or run `sanook` with no task for the interactive setup wizard):
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`), and `--continue` resumes the latest run for the current project. |
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. Ask it in plain language and it schedules itself. |
104
- | **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. |
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, twelve providers. Switch with `-m <spec>` on the command line or `/model` in the REPL.
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 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.
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 serve --port 8787 # HTTP (127.0.0.1 only) + scheduler
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
- ### Telegram channel
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
- Set two environment variables before `sanook serve` and the gateway adds a Telegram adapter via long-polling (no public URL needed):
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
- sanook serve
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
- 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](#security).
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
- 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).
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 memory
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) · 12 providers · MCP · มี **"สมองที่สอง" (second brain)** ที่ทำให้ AI จำ context ข้าม session ได้ — สิ่งที่ Claude Code / Codex / Gemini CLI ลืมทุกครั้งที่ปิด terminal
7
+ ใส่ API key ของคุณเอง (BYOK) · 9 providers · MCP · มี **"สมองที่สอง" (second brain)** ที่ทำให้ AI จำ context ข้าม session ได้ — สิ่งที่ Claude Code / Codex / Gemini CLI ลืมทุกครั้งที่ปิด terminal
8
8
 
9
9
  [![npm](https://img.shields.io/npm/v/sanook-cli.svg?color=2563eb)](https://www.npmjs.com/package/sanook-cli)
10
10
  [![downloads](https://img.shields.io/npm/dm/sanook-cli.svg?color=2563eb)](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
- ตั้ง API key (หรือรัน `sanook` เฉย ๆ ครั้งแรกจะมี setup wizard ให้เลือก provider + วาง key):
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 + 12 providers** — Anthropic, Google, OpenAI, DeepSeek, xAI, Mistral, Groq, MiniMax, GLM, Ollama, LM Studio, Codex
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` รันเป็น service 24/7 + ตั้งงานล่วงหน้า + ต่อ Telegram
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 ได้ด้วย `SANOOK_DISABLE_PERSISTENCE=1`
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
  }