sanook-cli 0.5.7 → 0.5.9

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/CHANGELOG.md CHANGED
@@ -1,5 +1,47 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.5.9
4
+
5
+ ### Codex (ChatGPT plan) + install
6
+
7
+ - **Codex models** — setup, `/model` picker, and config migration now only offer ChatGPT-plan-safe models (`gpt-5.5`, `gpt-5.4`, `gpt-5.4-mini`); legacy `gpt-5-codex` / `*-codex` ids auto-migrate instead of failing at runtime.
8
+ - **Codex errors** — surface JSONL API errors from `codex exec` (not just opaque exit codes).
9
+ - **Install** — README install section, GitHub Pages deploy script, npm publish guard (`scripts/publish-npm.sh`).
10
+
11
+ ## 0.5.8
12
+
13
+ ### Self-maintaining memory + reliability & security hardening
14
+
15
+ **New: automatic memory maintenance** (default on; `sanook config set autoMaintain off` / `SANOOK_DISABLE_AUTO_MAINTAIN=1` to disable)
16
+
17
+ - **Auto-consolidate** — on REPL startup (at most once a week) the second brain consolidates itself: dedup memory, archive stale notes by importance decay (reversible — never deletes), refresh the index. Background, non-blocking.
18
+ - **Auto-distill** — on session exit (and each headless turn) durable facts from the conversation are distilled into the compounding memory store so the self-retrieving brain surfaces them next time (previously opt-in via `SANOOK_AUTO_DISTILL`).
19
+ - Status shown in `sanook config`.
20
+
21
+ **Vault data-integrity fixes** (second brain)
22
+
23
+ - Worklog/transcript/index writers no longer truncate history when pasted content contains an `up::` line — the footer regex now matches only the trailing footer.
24
+ - `$`-sequences in prompts/answers/titles/paths no longer corrupt vault notes (String.replace replacement-pattern injection) — fixed across every note/index writer.
25
+ - Worklog writes are serialized (lost-update under back-to-back turns); chat-transcript headings use the real per-turn time (were frozen to session start, and mis-filed past midnight).
26
+
27
+ **Persona** (`sanook persona`)
28
+
29
+ - `sanook persona <bad-arg>` errors with an unknown-subcommand message instead of falling through to a paid LLM call.
30
+ - Re-running with identical answers no longer claims facts were newly saved; Esc-back no longer overwrites a prior answer (including a custom "อื่นๆ" value); warns when the vault profile note can't be written.
31
+
32
+ **REPL / terminal**
33
+
34
+ - Detailed live activity: the busy status line shows the friendly action ("📖 อ่านไฟล์ …", "`$ npm test`") instead of the raw tool name; expanded tool-trail height is bounded so big diffs can't push the prompt off-screen; scrollback renders past turns compact.
35
+
36
+ **Dashboard**
37
+
38
+ - Security: fixed directory traversal in the file API (path confinement now uses a real path boundary, not a string prefix).
39
+ - Web terminal: the agent run is cancelled when the browser disconnects; the raw-shell websocket is guarded against uncaught-error crashes.
40
+
41
+ **Installer**
42
+
43
+ - `install.ps1` checks the install exit code — no more false "Sanook CLI installed" banner when `npm install -g` fails.
44
+
3
45
  ## 0.5.7
4
46
 
5
47
  ### Local token usage ledger (ccusage-style)
package/README.md CHANGED
@@ -1,41 +1,199 @@
1
- <div align="center">
1
+ <p align="center">
2
+ <br />
3
+ <strong>Sanook CLI</strong>
4
+ <br />
5
+ <br />
6
+ <em>The terminal AI coding agent with a memory that outlives the session.</em>
7
+ <br />
8
+ <br />
9
+ <sub>Bring your own key · 9 providers · MCP · Obsidian second brain · gateway & cron</sub>
10
+ <br />
11
+ <br />
12
+ 🇹🇭 <a href="README.th.md">อ่านภาษาไทย</a>
13
+ </p>
14
+
15
+ <p align="center">
16
+ <a href="https://www.npmjs.com/package/sanook-cli"><img src="https://img.shields.io/npm/v/sanook-cli.svg?style=flat-square&color=111827&labelColor=1f2937" alt="npm version" /></a>
17
+ <a href="https://www.npmjs.com/package/sanook-cli"><img src="https://img.shields.io/npm/dm/sanook-cli.svg?style=flat-square&color=111827&labelColor=1f2937" alt="downloads" /></a>
18
+ <a href="LICENSE"><img src="https://img.shields.io/badge/license-Apache--2.0-22c55e?style=flat-square&labelColor=1f2937" alt="license" /></a>
19
+ <a href="https://nodejs.org"><img src="https://img.shields.io/badge/node-%E2%89%A5%2022-339933?style=flat-square&labelColor=1f2937&logo=node.js&logoColor=white" alt="node" /></a>
20
+ <a href="#development"><img src="https://img.shields.io/badge/tests-passing-22c55e?style=flat-square&labelColor=1f2937" alt="tests" /></a>
21
+ <a href="https://github.com/Sir-chawakorn/sanook-cli/actions/workflows/ci.yml"><img src="https://img.shields.io/github/actions/workflow/status/Sir-chawakorn/sanook-cli/ci.yml?style=flat-square&labelColor=1f2937" alt="CI" /></a>
22
+ </p>
2
23
 
3
- # Sanook CLI
24
+ ---
4
25
 
5
- **The open-source terminal AI coding agent that remembers across sessions.**
26
+ <h2 align="center" id="install">Install Sanook CLI</h2>
6
27
 
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.
28
+ <p align="center">
29
+ <strong>Pick one command below — all roads lead to <code>sanook</code>.</strong><br/>
30
+ <sub>Requires <strong>Node.js ≥ 22</strong> &nbsp;·&nbsp; <code>node -v</code> to check &nbsp;·&nbsp; <code>npx sanook doctor</code> auto-fixes PATH / Node issues</sub>
31
+ </p>
8
32
 
9
- 🇹🇭 [อ่านภาษาไทย](README.th.md)
33
+ <p align="center">
34
+ <img src="https://img.shields.io/badge/npm-✅_Ready-22c55e?style=for-the-badge&labelColor=14532d" alt="npm ready" />
35
+ &nbsp;
36
+ <img src="https://img.shields.io/badge/curl_|_bash-✅_Ready-22c55e?style=for-the-badge&labelColor=14532d" alt="curl ready" />
37
+ &nbsp;
38
+ <img src="https://img.shields.io/badge/Homebrew-✅_Ready-22c55e?style=for-the-badge&labelColor=14532d" alt="homebrew ready" />
39
+ &nbsp;
40
+ <img src="https://img.shields.io/badge/GitHub_Pages-✅_Ready-22c55e?style=for-the-badge&labelColor=14532d" alt="pages ready" />
41
+ &nbsp;
42
+ <img src="https://img.shields.io/badge/WinGet-⏳_PR_pending-f59e0b?style=for-the-badge&labelColor=78350f" alt="winget pending" />
43
+ &nbsp;
44
+ <img src="https://img.shields.io/badge/sanook.ai-⏳_DNS_pending-94a3b8?style=for-the-badge&labelColor=334155" alt="sanook.ai pending" />
45
+ </p>
10
46
 
11
- [![npm](https://img.shields.io/npm/v/sanook-cli.svg?color=2563eb)](https://www.npmjs.com/package/sanook-cli)
12
- [![downloads](https://img.shields.io/npm/dm/sanook-cli.svg?color=2563eb)](https://www.npmjs.com/package/sanook-cli)
13
- [![License](https://img.shields.io/badge/license-Apache--2.0-22c55e.svg)](LICENSE)
14
- [![Node](https://img.shields.io/badge/node-%E2%89%A5%2022-339933.svg?logo=node.js&logoColor=white)](https://nodejs.org)
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-passing-22c55e.svg)](#development)
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)
47
+ <br />
18
48
 
19
- [Quickstart](#quickstart) · [Providers](#providers) · [Usage](#usage) · [Gateway](#gateway--scheduling) · [Skills](#skills) · [MCP](#mcp) · [Security](#security)
49
+ <table width="100%">
50
+ <tr>
51
+ <td width="50%" valign="top">
20
52
 
21
- <!-- 📹 DEMO GIF record the close-session → reopen → "it remembered" loop (asciinema + agg), save to docs/demo.gif, then uncomment: -->
22
- <!-- ![sanook-cli demo](docs/demo.gif) -->
53
+ ### 🍎 macOS · 🐧 Linux · WSL
54
+
55
+ **Recommended — npm**
56
+
57
+ ```bash
58
+ npm install -g sanook-cli
59
+ # or run once without installing:
60
+ npx sanook-cli
61
+ ```
62
+
63
+ **One-liner install script** *(checks Node, then installs via npm)*
64
+
65
+ ```bash
66
+ # GitHub raw (default)
67
+ curl -fsSL https://raw.githubusercontent.com/Sir-chawakorn/sanook-cli/main/scripts/install.sh | bash
68
+
69
+ # GitHub Pages mirror
70
+ curl -fsSL https://sir-chawakorn.github.io/sanook-cli/install.sh | bash
71
+
72
+ # jsDelivr CDN
73
+ curl -fsSL https://cdn.jsdelivr.net/gh/Sir-chawakorn/sanook-cli@main/scripts/install.sh | bash
74
+ ```
75
+
76
+ **Homebrew**
77
+
78
+ ```bash
79
+ brew trust Sir-chawakorn/tap # once on newer Homebrew
80
+ brew tap Sir-chawakorn/tap
81
+ brew install sanook-cli
82
+ ```
83
+
84
+ </td>
85
+ <td width="50%" valign="top">
86
+
87
+ ### 🪟 Windows
88
+
89
+ **Recommended — npm** *(PowerShell or cmd)*
90
+
91
+ ```powershell
92
+ npm install -g sanook-cli
93
+ # or:
94
+ npx sanook-cli
95
+ ```
96
+
97
+ **One-liner install script**
98
+
99
+ ```powershell
100
+ # GitHub raw (default)
101
+ irm https://raw.githubusercontent.com/Sir-chawakorn/sanook-cli/main/scripts/install.ps1 | iex
102
+
103
+ # GitHub Pages mirror
104
+ irm https://sir-chawakorn.github.io/sanook-cli/install.ps1 | iex
105
+ ```
106
+
107
+ **WinGet** *(after [PR #391114](https://github.com/microsoft/winget-pkgs/pull/391114) merges)*
108
+
109
+ ```powershell
110
+ winget install Sanook.SanookCLI
111
+ ```
112
+
113
+ Portable zip (no WinGet yet): [sanook-cli-win-x64.zip](https://github.com/Sir-chawakorn/sanook-cli/releases/download/v0.5.7/sanook-cli-win-x64.zip)
114
+
115
+ </td>
116
+ </tr>
117
+ </table>
23
118
 
24
- </div>
119
+ <br />
120
+
121
+ <details open>
122
+ <summary><strong>📋 All install methods — status &amp; links</strong></summary>
123
+
124
+ | Method | Command | Status |
125
+ |--------|---------|--------|
126
+ | **npm / npx** | `npm install -g sanook-cli` | ✅ [npm](https://www.npmjs.com/package/sanook-cli) · latest **0.5.7** |
127
+ | **curl \| bash** | `curl -fsSL …/install.sh \| bash` | ✅ [raw](https://raw.githubusercontent.com/Sir-chawakorn/sanook-cli/main/scripts/install.sh) · [Pages](https://sir-chawakorn.github.io/sanook-cli/install.sh) · [jsDelivr](https://cdn.jsdelivr.net/gh/Sir-chawakorn/sanook-cli@main/scripts/install.sh) |
128
+ | **irm \| iex** | `irm …/install.ps1 \| iex` | ✅ [raw](https://raw.githubusercontent.com/Sir-chawakorn/sanook-cli/main/scripts/install.ps1) · [Pages](https://sir-chawakorn.github.io/sanook-cli/install.ps1) |
129
+ | **Homebrew** | `brew tap Sir-chawakorn/tap && brew install sanook-cli` | ✅ [homebrew-tap](https://github.com/Sir-chawakorn/homebrew-tap) |
130
+ | **GitHub Pages** | `curl -fsSL https://sir-chawakorn.github.io/sanook-cli/install.sh \| bash` | ✅ Live |
131
+ | **WinGet** | `winget install Sanook.SanookCLI` | ⏳ [PR #391114](https://github.com/microsoft/winget-pkgs/pull/391114) · CLA signed · [release zip](https://github.com/Sir-chawakorn/sanook-cli/releases/tag/v0.5.7) ready |
132
+ | **sanook.ai** *(optional short URL)* | `curl -fsSL https://sanook.ai/install.sh \| bash` | ⏳ DNS at GoDaddy → run `bash scripts/configure-sanook-ai-dns.sh` |
133
+
134
+ Full maintainer guide: **[docs/INSTALL_INFRA.md](docs/INSTALL_INFRA.md)**
135
+
136
+ </details>
137
+
138
+ <br />
139
+
140
+ > **Troubleshooting**
141
+ >
142
+ > | Symptom | Fix |
143
+ > |---------|-----|
144
+ > | `'sanook' is not recognized` | You ran `npm i sanook-cli` without `-g` — reinstall with `npm install -g sanook-cli`, or use `npx sanook` |
145
+ > | Node too old | Install [Node ≥ 22](https://nodejs.org) · scripts refuse older versions |
146
+ > | Homebrew refuses tap | Run `brew trust Sir-chawakorn/tap` once, then retry |
147
+ > | Not sure what's wrong | `npx sanook doctor` — prints OS-specific fixes (incl. Windows PATH one-liner) |
148
+
149
+ <br />
150
+
151
+ <p align="center">
152
+ <a href="#quickstart"><strong>First run → setup wizard &amp; API key</strong></a>
153
+ </p>
25
154
 
26
155
  ---
27
156
 
157
+ <p align="center">
158
+ <a href="#install"><strong>Install</strong></a>
159
+ &nbsp;·&nbsp;
160
+ <a href="#quickstart"><strong>Quickstart</strong></a>
161
+ &nbsp;·&nbsp;
162
+ <a href="#memory--second-brain"><strong>Memory</strong></a>
163
+ &nbsp;·&nbsp;
164
+ <a href="#persona"><strong>Persona</strong></a>
165
+ &nbsp;·&nbsp;
166
+ <a href="#dashboard"><strong>Dashboard</strong></a>
167
+ &nbsp;·&nbsp;
168
+ <a href="#providers"><strong>Providers</strong></a>
169
+ &nbsp;·&nbsp;
170
+ <a href="#usage"><strong>Usage</strong></a>
171
+ &nbsp;·&nbsp;
172
+ <a href="#gateway--scheduling"><strong>Gateway</strong></a>
173
+ &nbsp;·&nbsp;
174
+ <a href="#mcp"><strong>MCP</strong></a>
175
+ &nbsp;·&nbsp;
176
+ <a href="#security"><strong>Security</strong></a>
177
+ </p>
178
+
179
+ <!-- 📹 DEMO GIF — record the close-session → reopen → "it remembered" loop (asciinema + agg), save to docs/demo.gif, then uncomment: -->
180
+ <!-- <p align="center"><img src="docs/demo.gif" alt="sanook-cli demo" width="720" /></p> -->
181
+
182
+ <br />
183
+
28
184
  ## Overview
29
185
 
30
- Sanook is a small, transparent coding agent for your terminal. At its heart is a single loop —
186
+ > **Close the terminal. Come back tomorrow. Sanook still knows what you decided.**
31
187
 
32
- ```
188
+ Sanook is a transparent coding agent for your terminal — one loop, no magic:
189
+
190
+ ```text
33
191
  prompt → LLM → tool call → result → loop → answer
34
192
  ```
35
193
 
36
- wrapped with everything that makes it usable for real work: a permission gate, a memory the agent writes itself, a long-running gateway with cron and chat channels, on-demand skills, MCP servers, and first-class git awareness.
194
+ Wrapped in the things real work needs: a permission gate, **structured memory across sessions**, a long-running gateway with cron and chat channels, on-demand skills, MCP servers, and first-class git awareness.
37
195
 
38
- It is **BYOK (bring your own key)** by design. Every provider connects with a **direct API key from that provider's own console** — Sanook never reuses OAuth or subscription credentials, because that violates provider terms and gets accounts banned.
196
+ **BYOK by design.** Every provider uses a **direct API key from that provider's console** — Sanook never reuses OAuth or subscription credentials, because that violates provider terms and gets accounts banned.
39
197
 
40
198
  ## How it compares
41
199
 
@@ -57,22 +215,155 @@ The agent loop, BYOK, and MCP are table stakes now. What Sanook has that the big
57
215
 
58
216
  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
217
 
60
- ## Quickstart
218
+ ## Memory & second brain
219
+
220
+ Sanook does **not** dump everything into one folder. Memory is layered — some lives in your Obsidian vault, some in `~/.sanook/` for speed and resume. Both are wired together at runtime.
221
+
222
+ ```mermaid
223
+ flowchart LR
224
+ START([Start<br/>sanook / gateway / cron / resume]):::start
225
+ CFG["Load config<br/>~/.sanook/config.json"]:::local
226
+ MODE{"brainPath is set<br/>and vault is reachable?"}:::gate
227
+ LOCALONLY([Fallback end<br/>answer works with local session + usage only]):::warn
228
+
229
+ subgraph read["1. Read path · gather memory before the turn"]
230
+ direction TB
231
+ HIER["Hierarchical SANOOK.md<br/>global -> repo -> cwd instructions"]:::inject
232
+ AM["Auto-memory<br/>~/.sanook/memory/memory.json"]:::local
233
+ RESUME["Resume context<br/>~/.sanook/sessions/*.json"]:::local
234
+ HOT["Vault hot files<br/>AI-Context-Index + current-state + inbox"]:::vault
235
+ PROJECT["Project hot context<br/>Projects/&lt;slug&gt;/ matched from cwd"]:::vault
236
+ PACK["Context pack<br/>Shared/Context-Packs/*.md selected by task"]:::vault
237
+ SEARCH["Per-turn retrieval<br/>search/index.json over vault + memory + sessions + skills"]:::local
238
+ end
239
+
240
+ subgraph inject["2. Injection · build the model input"]
241
+ direction TB
242
+ STATIC["Static brain block<br/>stable context injected at session start"]:::inject
243
+ RECALLED["Recalled context block<br/>fresh matches for this prompt"]:::inject
244
+ SYS["System prompt<br/>policy + tools + memory + repo state"]:::inject
245
+ USER["User prompt<br/>or incoming gateway message"]:::process
246
+ end
247
+
248
+ subgraph loop["3. Agent loop · act, observe, answer"]
249
+ direction TB
250
+ LLM["LLM reasoning step"]:::process
251
+ NEED{"Need tools?"}:::gate
252
+ TOOLS["Tool calls<br/>files, shell, git, MCP, skills"]:::process
253
+ RESULT["Tool results<br/>fed back into context"]:::process
254
+ ANSWER["Final answer<br/>terminal or gateway reply"]:::finish
255
+ end
256
+
257
+ subgraph write["4. Write-back · make the next session smarter"]
258
+ direction TB
259
+ REMEMBER["remember tool<br/>redact -> merge -> rank"]:::write
260
+ MEMJSON["Persist auto-memory<br/>memory.json + MEMORY.md mirror"]:::write
261
+ INBOX["Append candidate fact<br/>Shared/Memory-Inbox/memory-inbox.md"]:::write
262
+ WORKLOG["Append daily worklog<br/>Sessions/YYYY-MM-DD-worklog.md"]:::write
263
+ CHAT["Append full transcript<br/>Sessions/*-chat.md when enabled"]:::write
264
+ SESSION["Save session JSON<br/>~/.sanook/sessions/*.json"]:::write
265
+ USAGE["Record usage<br/>~/.sanook/usage/events.jsonl"]:::write
266
+ INDEX["Re-index changed sources<br/>sanook index -> search/index.json"]:::write
267
+ END([End<br/>answer returned + memory ready for resume/retrieval]):::finish
268
+ end
269
+
270
+ START -->|entrypoint starts| CFG
271
+ CFG --> MODE
272
+ MODE -->|yes| HOT
273
+ MODE -->|no vault path| LOCALONLY
274
+ CFG --> AM
275
+ CFG --> RESUME
276
+ CFG --> SEARCH
277
+ HIER --> STATIC
278
+ AM --> STATIC
279
+ HOT --> STATIC
280
+ PROJECT --> STATIC
281
+ PACK --> RECALLED
282
+ RESUME --> RECALLED
283
+ SEARCH --> RECALLED
284
+ STATIC --> SYS
285
+ RECALLED --> SYS
286
+ USER --> LLM
287
+ SYS -->|injected every turn| LLM
288
+ LLM --> NEED
289
+ NEED -->|yes| TOOLS
290
+ TOOLS --> RESULT
291
+ RESULT --> LLM
292
+ NEED -->|no| ANSWER
293
+ LLM -->|durable fact found| REMEMBER
294
+ REMEMBER --> MEMJSON
295
+ REMEMBER --> INBOX
296
+ ANSWER --> WORKLOG
297
+ ANSWER --> CHAT
298
+ ANSWER --> SESSION
299
+ ANSWER --> USAGE
300
+ MEMJSON --> INDEX
301
+ INBOX --> INDEX
302
+ WORKLOG --> INDEX
303
+ CHAT --> INDEX
304
+ SESSION --> INDEX
305
+ ANSWER --> END
306
+
307
+ classDef start fill:#064e3b,stroke:#34d399,color:#ffffff,stroke-width:3px
308
+ classDef finish fill:#0f766e,stroke:#5eead4,color:#ffffff,stroke-width:3px
309
+ classDef gate fill:#7c2d12,stroke:#fdba74,color:#ffffff,stroke-width:2px
310
+ classDef local fill:#172554,stroke:#60a5fa,color:#ffffff
311
+ classDef vault fill:#312e81,stroke:#a78bfa,color:#ffffff
312
+ classDef inject fill:#164e63,stroke:#22d3ee,color:#ffffff
313
+ classDef process fill:#1f2937,stroke:#94a3b8,color:#ffffff
314
+ classDef write fill:#78350f,stroke:#fbbf24,color:#ffffff
315
+ classDef warn fill:#7f1d1d,stroke:#fca5a5,color:#ffffff,stroke-width:2px
316
+ ```
61
317
 
62
- Install **globally** the `-g` is required (needs **Node 22**; check with `node -v`):
318
+ **How to read the flow:** green nodes mark start/end, orange diamonds are decisions, blue nodes are local runtime state, purple nodes live inside the Obsidian-style vault, cyan nodes are injected into the system prompt, dark nodes are the active agent loop, amber nodes write memory back after/during the turn, and the red node is the safe fallback when no vault is configured.
319
+
320
+ ### What goes where
321
+
322
+ | Data | Stored at | When | Purpose |
323
+ |---|---|---|---|
324
+ | **Worklog** | `{brainPath}/Sessions/YYYY-MM-DD-worklog.md` | After every agent turn (REPL + headless) | Daily trace of prompts & cost summary |
325
+ | **Full transcript** *(opt-in)* | `{brainPath}/Sessions/YYYY-MM-DD-<id>-chat.md` | After every turn, when `brainTranscript` is on | The actual conversation — your prompt **and** the AI's reply |
326
+ | **Session note** | `{brainPath}/Sessions/YYYY-MM-DD-<id>-session.md` | On REPL exit (`/quit` or Ctrl+C at empty prompt) | AI/heuristic summary + key facts |
327
+ | **Memory inbox** | `{brainPath}/Shared/Memory-Inbox/memory-inbox.md` | When the agent calls `remember` | Candidate facts for vault curation |
328
+ | **Project workspace** | `{brainPath}/Projects/<slug>/` | Setup wizard / `sanook brain init` links your repo | Project-scoped notes & hot context |
329
+ | **Persona profile** | `{brainPath}/Shared/User-Persona/persona.md` | `sanook persona` or `/persona` in REPL | Who you are + how you want the agent to work |
330
+ | **Auto-memory** | `~/.sanook/memory/memory.json` | When the agent calls `remember`, or `sanook persona` (protected) | Structured facts (merge, rank, inject) |
331
+ | **Session JSON** | `~/.sanook/sessions/*.json` | Every turn | `--continue` / `--resume` transcript |
332
+ | **Search index** | `~/.sanook/search/` | `sanook index` (incremental) | BM25 / hybrid retrieval |
333
+ | **Usage ledger** | `~/.sanook/usage/events.jsonl` | Every turn | Token/cost tracking — **not** semantic memory |
334
+
335
+ **Read at session start:** hierarchical `SANOOK.md` (global → project root → cwd), auto-memory block, vault hot files (`AI-Context-Index`, `current-state`, inbox, matched `Projects/<slug>/`), plus per-turn retrieval over vault + memory + past sessions.
336
+
337
+ **Setup links your repo to the vault:** the first-run wizard (or `sanook brain init`) saves `brainPath` in `~/.sanook/config.json`, scaffolds `Projects/<slug>/` inside the vault, and creates `SANOOK.md` in your repo if missing.
63
338
 
64
339
  ```bash
65
- npm install -g sanook-cli
340
+ sanook brain init # pick vault folder + identity
341
+ sanook brain context # inspect what gets injected from cwd
342
+ sanook brain projects list # vault projects ↔ repo paths
343
+ sanook memory stats # auto-memory store overview
344
+ sanook usage daily # token/cost ledger (ccusage-style)
66
345
  ```
67
346
 
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
- > 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).
347
+ **Want the entire conversation in your vault?** Turn on full transcriptsevery prompt and reply is appended to `Sessions/*-chat.md` per session:
348
+
349
+ ```bash
350
+ sanook config set brainTranscript on # or env: SANOOK_BRAIN_TRANSCRIPT=1
351
+ ```
352
+
353
+ > It is **opt-in** because verbatim transcripts of long coding sessions grow a vault fast. Worklog (always on) keeps a lighter daily trace; the full transcript is the complete record.
354
+
355
+ Disable persistence: `SANOOK_DISABLE_PERSISTENCE=1` · worklog only: `SANOOK_DISABLE_WORKLOG=1` · usage ledger: `SANOOK_DISABLE_USAGE=1`
356
+
357
+ ## Quickstart
358
+
359
+ Already installed? Jump straight to setup — see **[Install](#install)** if you haven't yet.
70
360
 
71
361
  Run the setup wizard or set an API key manually:
72
362
 
73
363
  ```bash
74
364
  sanook setup # provider + model wizard; offers to create a second brain
75
365
  sanook model # re-run provider/model setup later
366
+ sanook persona # tell the agent who you are + how you like to work
76
367
  sanook auth add anthropic --api-key sk-ant-... --use
77
368
 
78
369
  export ANTHROPIC_API_KEY=sk-ant-... # macOS / Linux
@@ -106,7 +397,7 @@ sanook dump # support snapshot; raw secrets are never printe
106
397
  | **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. |
107
398
  | **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). |
108
399
  | **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). |
109
- | **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. |
400
+ | **Memory** | Layered memory: `remember` / `recall`, hierarchical `SANOOK.md`, Obsidian vault injection, per-turn retrieval, `--continue` / `--resume`, session notes on exit, daily worklogs, and `sanook memory` / `sanook usage` inspect commands. |
110
401
  | **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. |
111
402
  | **Startup cockpit** | The interactive REPL opens with a Sanook-branded wordmark, service routes (Code, Brain, Connect, Ship), and live readiness signals for second-brain, MCP servers, installed skills, and the current git branch. |
112
403
  | **Web grounding** | `sanook web status` separates local brain search from true internet search, detects configured MCP web/search/fetch candidates, and prints Sanook's citation + prompt-injection policy for current external facts. |
@@ -124,6 +415,46 @@ sanook dump # support snapshot; raw secrets are never printe
124
415
  | **Prompt budget inspectability** | `sanook prompt-size [--json]` reports the offline size of Sanook's system prompt, personality overlay, auto-memory, skills index, second-brain context, project memory, repo map, git context, and built-in tool schemas. |
125
416
  | **Polyglot runtime surface** | `sanook runtimes [--json]` shows optional Python/Rust readiness. The agent gets `run_python` for data/document/ML-style helper scripts and `run_rust` for small performance/safety-critical helpers, both approval-gated and no-shell. |
126
417
  | **Second brain** | `sanook brain init` scaffolds a structured Obsidian "second-brain" workspace (folders + `_Index` + a portable AI operating constitution) for organising work and giving the agent durable, cross-session memory. |
418
+ | **Self-improvement** | Sanook watches for repeated tasks and, past a threshold, **auto-authors a skill** for the pattern — announced in the terminal and surfaced on the Dashboard. Tune with `SANOOK_SELF_IMPROVE_THRESHOLD`; disable with `SANOOK_DISABLE_SELF_IMPROVE=1`. |
419
+ | **Persona** | `sanook persona` runs a short questionnaire (who you are, language, tone, autonomy, stack, preferences) and stores the answers as **protected memory** plus a vault profile so every session starts in context. |
420
+
421
+ ## Persona
422
+
423
+ Teach the agent who you are once, and it carries that context into every session — name, language, tone, autonomy, your stack, and what you like (or don't like) it to do.
424
+
425
+ ```bash
426
+ sanook persona # short questionnaire (A/B/C/D + free-text)
427
+ # or /persona inside the REPL — pre-fills from existing profile
428
+ ```
429
+
430
+ A mix of multiple-choice and free-text questions. Answers are saved in two places, wired into the agent automatically:
431
+
432
+ - **Auto-memory** (`~/.sanook/memory/memory.json`) as **protected, owner-trust facts** — injected at the start of every run, so the agent immediately knows how to address you and how you want it to work.
433
+ - **Second brain** (`{brainPath}/Shared/User-Persona/persona.md`) as a readable profile note you can edit by hand — written only when a vault exists.
434
+
435
+ Re-run any time to update; existing answers are **pre-filled** from `persona.md` and protected memory. Blanks are skipped, and the vault profile is rewritten in place. The brain wizard (`sanook brain init`) already seeds a lighter identity (name + AI name + autonomy); `sanook persona` is the deeper, standalone pass.
436
+
437
+ ## Dashboard
438
+
439
+ A local, Hermes-style admin panel for everything the CLI knows — open it in a browser and drive Sanook without leaving the page.
440
+
441
+ ```bash
442
+ sanook dashboard # http://127.0.0.1:9119
443
+ sanook dashboard --port 8080
444
+ ```
445
+
446
+ | Page | What it shows |
447
+ |---|---|
448
+ | **Terminal** | A real web terminal — an **Agent console** (the Sanook REPL, streamed over SSE with live tool activity + color-coded diffs) and an optional **Raw shell** (a system PTY via `xterm.js`, enabled when the `node-pty` + `ws` optional deps are installed). |
449
+ | **Skills** | Built-in and installed skills, including the ones Sanook auto-authored from repeated tasks. |
450
+ | **Memory** | Your structured auto-memory facts (incl. persona) with tier/trust. |
451
+ | **Persona** | Your saved persona profile (`sanook persona` / `/persona`) — view answers and profile path. |
452
+ | **Usage** | Token/cost ledger, daily/weekly/monthly. |
453
+ | **Self-improve** | The task ledger — what's repeating and which skills were created. |
454
+ | **Install** | The multi-platform install commands (see [Quickstart](#quickstart)), with copy buttons. |
455
+ | **Sessions · Models · Files · Logs · Cron · Channels · Config · MCP · Brain** | Inspect and manage the same surfaces as the CLI. |
456
+
457
+ It binds to **loopback only** and reads the same `~/.sanook/` state as the CLI, so the Dashboard and terminal always agree.
127
458
 
128
459
  ## Providers
129
460
 
@@ -159,6 +490,8 @@ sanook chat -q "<query>" direct one-shot query
159
490
  sanook interactive REPL
160
491
  sanook setup [section] setup model/gateway/tools/agent/brain
161
492
  sanook model choose provider + model
493
+ sanook persona questionnaire → durable persona (memory + second brain)
494
+ sanook dashboard [--port] local web admin UI (terminal, skills, memory, usage, install)
162
495
  sanook status redacted install/config status
163
496
  sanook auth list redacted provider key status
164
497
  sanook auth add openai --api-key <key> [--use]
@@ -170,6 +503,7 @@ sanook sessions stats [--all]
170
503
  sanook sessions prune --keep N [--all] [--yes]
171
504
  sanook sessions rm <id>
172
505
  sanook dump [--show-keys] support dump (keys are still redacted)
506
+ sanook usage [daily|weekly|monthly|session] [--days N] [--json]
173
507
  sanook prompt-size [--json] inspect system/brain/skill/tool context budget
174
508
  sanook runtimes [--json] inspect optional Python/Rust runtime surface
175
509
  sanook web status [--json] inspect true web-search/fetch readiness
@@ -424,16 +758,20 @@ sanook skill remove my-skill
424
758
 
425
759
  ## Second brain
426
760
 
427
- Scaffold a structured [Obsidian](https://obsidian.md) workspace for organising your work and giving the agent a durable, cross-session memory:
761
+ Scaffold a structured [Obsidian](https://obsidian.md) workspace the durable layer Sanook reads and writes alongside `~/.sanook/`:
428
762
 
429
763
  ```bash
430
764
  sanook brain init # interactive — asks where + a few identity questions
431
765
  sanook brain init ~/notes/brain # non-interactive (with --yes)
432
766
  ```
433
767
 
434
- 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.
768
+ The wizard 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`). 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.
769
+
770
+ **Every folder documents its own job.** Each folder gets a generated `_Index.md` stating its role, what goes there, what doesn't, and an AI routing contract — and a top-level `Vault Structure Map.md` lists the whole taxonomy in one place. So both you and the agent always know where a note belongs. Identity lives in `Shared/User-Persona/` (see [Persona](#persona)); what the agent learns over time lives in `Shared/User-Memory/`.
435
771
 
436
- 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.
772
+ **Create-if-missing** — re-running never overwrites your notes. On init, Sanook also links your current repo (`Projects/<slug>/` + `SANOOK.md`) and can wire a filesystem MCP server so the agent reads and writes the vault directly.
773
+
774
+ See [Memory & second brain](#memory--second-brain) for the exact routing table (worklog, session notes, inbox, auto-memory, sessions).
437
775
 
438
776
  ### Brain search
439
777
 
@@ -503,16 +841,19 @@ sanook trust remove
503
841
  Everything lives under `~/.sanook/` (with per-project `.sanook/` overrides where relevant):
504
842
 
505
843
  ```
844
+ ~/.sanook/config.json brainPath, model, tuning knobs
506
845
  ~/.sanook/auth.json API keys (chmod 600)
507
- ~/.sanook/memory/ auto-memory the agent writes
508
- ~/.sanook/search/ brain-search index + optional embedding vectors (regenerable via `sanook index`)
846
+ ~/.sanook/memory/ auto-memory store (memory.json + MEMORY.md view)
847
+ ~/.sanook/usage/ token/cost ledger (events.jsonl)
848
+ ~/.sanook/search/ brain-search index + optional embedding vectors
509
849
  ~/.sanook/sessions/ saved conversations (for --continue)
510
850
  ~/.sanook/skills/<name>/ installed SKILL.md files
511
851
  ~/.sanook/mcp.json MCP servers { "mcpServers": { … } }
512
852
  ~/.sanook/hooks.json PreToolUse / PostToolUse hooks
513
853
  ~/.sanook/gateway/ gateway token + task ledger
514
- ~/.sanook/trusted-projects.json project roots allowed to load project .sanook extensions
515
- SANOOK.md project memory (hierarchical, like a system prompt)
854
+ ~/.sanook/trusted-projects.json
855
+ SANOOK.md project memory (hierarchical, cwd project root → global)
856
+ {brainPath}/ your Obsidian vault — worklogs, session notes, Projects/, Shared/
516
857
  ```
517
858
 
518
859
  Untrusted project config can set ordinary project defaults, but it cannot lower `permissionMode` to `auto`; trust the project first if you want project-local config to control mutation approval.
@@ -530,6 +871,7 @@ Quality-neutral knobs in `~/.sanook/config.json` (or the matching `SANOOK_*` env
530
871
  | — | `SANOOK_SUBAGENT_MODEL=haiku` | run all sub-agent work (exploration/search) on a cheaper model while the main agent keeps the strong one |
531
872
  | `summaryModel <spec>` | `SANOOK_SUMMARY_MODEL=<spec>` | model used for summarize-compaction (default: the fast sibling of your main model) |
532
873
  | `embeddingModel <spec>` | `SANOOK_EMBEDDING_MODEL=<spec>` | model used for semantic search embeddings (for example `openai:text-embedding-3-small`) |
874
+ | `brainTranscript on` | `SANOOK_BRAIN_TRANSCRIPT=1` | append the **full conversation** (prompt + reply, every turn) to `{brainPath}/Sessions/*-chat.md` (default off) |
533
875
  | `thinking on` / `thinking 4000` | `SANOOK_THINKING=on` / `4000` | opt-in Anthropic extended thinking on the main agent; use `on`, `true`, or `yes` for the default budget, `off`, `false`, or `no` to disable, or a positive integer for `budgetTokens` |
534
876
 
535
877
  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.
@@ -544,6 +886,7 @@ SANOOK_HOOKS_INHERIT_ENV=1 # pass full env to hooks instead of a minima
544
886
  SANOOK_DISABLE_PERSISTENCE=1 # do not save sessions, memory, prompt history, or worklogs
545
887
  SANOOK_DISABLE_UPDATE_CHECK=1 # do not show interactive update prompts
546
888
  SANOOK_DISABLE_WORKLOG=1 # do not append second-brain worklogs
889
+ SANOOK_DISABLE_USAGE=1 # do not append token/cost usage events
547
890
  SANOOK_TRUST_PROJECT=1 # temporary trust override for project .sanook extensions
548
891
  ```
549
892
 
@@ -590,12 +933,19 @@ CI runs the suite across macOS / Linux / Windows on Node 22 and 24. Requires **N
590
933
 
591
934
  ---
592
935
 
593
- <div align="center">
594
-
595
- **Built by [Sanook AI](https://www.facebook.com/sanookai)** AI tools & education 🇹🇭
596
-
597
- [Facebook](https://www.facebook.com/sanookai) · [X / Twitter](https://x.com/sanook_ai)
598
-
599
- <sub>Built from scratch in TypeScript on the Vercel AI SDK — no framework, no magic.</sub>
600
-
601
- </div>
936
+ <p align="center">
937
+ <br />
938
+ <strong>Built by <a href="https://www.facebook.com/sanookai">Sanook AI</a></strong>
939
+ <br />
940
+ <sub>AI tools & education · 🇹🇭</sub>
941
+ <br />
942
+ <br />
943
+ <a href="https://www.facebook.com/sanookai">Facebook</a>
944
+ &nbsp;·&nbsp;
945
+ <a href="https://x.com/sanook_ai">X / Twitter</a>
946
+ <br />
947
+ <br />
948
+ <sub>TypeScript · Vercel AI SDK · no framework, no magic</sub>
949
+ <br />
950
+ <br />
951
+ </p>