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 +42 -0
- package/README.md +392 -42
- package/README.th.md +15 -8
- package/dist/auto-maintain.js +113 -0
- package/dist/bin.js +63 -15
- package/dist/brain-final.js +8 -4
- package/dist/brain-new.js +9 -5
- package/dist/brain-repair.js +7 -4
- package/dist/brand.js +17 -0
- package/dist/commands.js +17 -6
- package/dist/config.js +11 -0
- package/dist/dashboard/api-helpers.js +112 -3
- package/dist/dashboard/server.js +85 -1
- package/dist/dashboard/static/app.js +381 -0
- package/dist/dashboard/static/styles.css +36 -0
- package/dist/dashboard/terminal.js +214 -0
- package/dist/diff.js +22 -8
- package/dist/i18n/en.js +1 -0
- package/dist/i18n/th.js +1 -0
- package/dist/install-info.js +91 -0
- package/dist/loop.js +10 -1
- package/dist/memory.js +236 -16
- package/dist/model-picker.js +4 -1
- package/dist/persona.js +300 -0
- package/dist/project-scaffold.js +4 -2
- package/dist/providers/codex.js +75 -2
- package/dist/providers/models.js +17 -2
- package/dist/providers/registry.js +6 -13
- package/dist/self-improve-synth.js +86 -0
- package/dist/self-improve.js +203 -0
- package/dist/session-brain.js +10 -1
- package/dist/slash-completion.js +1 -0
- package/dist/ui/app.js +118 -27
- package/dist/ui/input-view.js +104 -0
- package/dist/ui/persona-wizard.js +89 -0
- package/dist/ui/render.js +78 -5
- package/dist/ui/setup.js +3 -4
- package/dist/ui/tool-activity.js +118 -0
- package/dist/ui/tool-trail.js +15 -3
- package/package.json +9 -1
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
|
-
<
|
|
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
|
-
|
|
24
|
+
---
|
|
4
25
|
|
|
5
|
-
|
|
26
|
+
<h2 align="center" id="install">Install Sanook CLI</h2>
|
|
6
27
|
|
|
7
|
-
|
|
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> · <code>node -v</code> to check · <code>npx sanook doctor</code> auto-fixes PATH / Node issues</sub>
|
|
31
|
+
</p>
|
|
8
32
|
|
|
9
|
-
|
|
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
|
+
|
|
36
|
+
<img src="https://img.shields.io/badge/curl_|_bash-✅_Ready-22c55e?style=for-the-badge&labelColor=14532d" alt="curl ready" />
|
|
37
|
+
|
|
38
|
+
<img src="https://img.shields.io/badge/Homebrew-✅_Ready-22c55e?style=for-the-badge&labelColor=14532d" alt="homebrew ready" />
|
|
39
|
+
|
|
40
|
+
<img src="https://img.shields.io/badge/GitHub_Pages-✅_Ready-22c55e?style=for-the-badge&labelColor=14532d" alt="pages ready" />
|
|
41
|
+
|
|
42
|
+
<img src="https://img.shields.io/badge/WinGet-⏳_PR_pending-f59e0b?style=for-the-badge&labelColor=78350f" alt="winget pending" />
|
|
43
|
+
|
|
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
|
-
|
|
12
|
-
[](https://www.npmjs.com/package/sanook-cli)
|
|
13
|
-
[](LICENSE)
|
|
14
|
-
[](https://nodejs.org)
|
|
15
|
-
[](https://www.typescriptlang.org)
|
|
16
|
-
[](#development)
|
|
17
|
-
[](https://github.com/Sir-chawakorn/sanook-cli/actions/workflows/ci.yml)
|
|
47
|
+
<br />
|
|
18
48
|
|
|
19
|
-
|
|
49
|
+
<table width="100%">
|
|
50
|
+
<tr>
|
|
51
|
+
<td width="50%" valign="top">
|
|
20
52
|
|
|
21
|
-
|
|
22
|
-
|
|
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
|
-
|
|
119
|
+
<br />
|
|
120
|
+
|
|
121
|
+
<details open>
|
|
122
|
+
<summary><strong>📋 All install methods — status & 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 & 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
|
+
·
|
|
160
|
+
<a href="#quickstart"><strong>Quickstart</strong></a>
|
|
161
|
+
·
|
|
162
|
+
<a href="#memory--second-brain"><strong>Memory</strong></a>
|
|
163
|
+
·
|
|
164
|
+
<a href="#persona"><strong>Persona</strong></a>
|
|
165
|
+
·
|
|
166
|
+
<a href="#dashboard"><strong>Dashboard</strong></a>
|
|
167
|
+
·
|
|
168
|
+
<a href="#providers"><strong>Providers</strong></a>
|
|
169
|
+
·
|
|
170
|
+
<a href="#usage"><strong>Usage</strong></a>
|
|
171
|
+
·
|
|
172
|
+
<a href="#gateway--scheduling"><strong>Gateway</strong></a>
|
|
173
|
+
·
|
|
174
|
+
<a href="#mcp"><strong>MCP</strong></a>
|
|
175
|
+
·
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
##
|
|
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/<slug>/ 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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
69
|
-
|
|
347
|
+
**Want the entire conversation in your vault?** Turn on full transcripts — every 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** |
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
508
|
-
~/.sanook/
|
|
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
|
|
515
|
-
SANOOK.md project memory (hierarchical,
|
|
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
|
-
<
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
<
|
|
600
|
-
|
|
601
|
-
|
|
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
|
+
·
|
|
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>
|