@tekmidian/pai 0.65.0 → 0.65.1

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 (66) hide show
  1. package/README.md +60 -1065
  2. package/dist/{chain-C8QO8gwj.mjs → chain-CLb6hbFS.mjs} +2 -2
  3. package/dist/{chain-C8QO8gwj.mjs.map → chain-CLb6hbFS.mjs.map} +1 -1
  4. package/dist/cli/index.mjs +6 -6
  5. package/dist/cli/program.mjs +6 -6
  6. package/dist/config-BbLFD7Uf.mjs.map +1 -1
  7. package/dist/daemon/index.mjs +3 -3
  8. package/dist/{daemon-CX9JomIJ.mjs → daemon-BjaPR39W.mjs} +3 -3
  9. package/dist/{daemon-D2r1AQqE.mjs → daemon-DqCB3fO-.mjs} +3 -3
  10. package/dist/{daemon-D2r1AQqE.mjs.map → daemon-DqCB3fO-.mjs.map} +1 -1
  11. package/dist/daemon-mcp/index.mjs +4 -4
  12. package/dist/daemon-mcp/index.mjs.map +1 -1
  13. package/dist/{fallback-CWDQYmJi.mjs → fallback-CupzGkuJ.mjs} +2 -2
  14. package/dist/{fallback-CWDQYmJi.mjs.map → fallback-CupzGkuJ.mjs.map} +1 -1
  15. package/dist/hooks/block-sleep-poll.mjs.map +1 -1
  16. package/dist/hooks/context-compression-hook.mjs.map +1 -1
  17. package/dist/hooks/load-project-context.mjs.map +2 -2
  18. package/dist/hooks/post-compact-inject.mjs.map +1 -1
  19. package/dist/hooks/route-agents-to-worker.mjs.map +1 -1
  20. package/dist/hooks/security-validator.mjs +2 -2
  21. package/dist/hooks/security-validator.mjs.map +1 -1
  22. package/dist/hooks/whisper-rules.mjs.map +1 -1
  23. package/dist/hooks/worker-guard.mjs.map +1 -1
  24. package/dist/hooks/worker-proxy.mjs.map +1 -1
  25. package/dist/hooks/worker-status-line.mjs.map +2 -2
  26. package/dist/hooks/worker-supervision.mjs.map +1 -1
  27. package/dist/{main-resolver-CDe7DCso.mjs → main-resolver-BeYWNzrt.mjs} +6 -6
  28. package/dist/{main-resolver-CDe7DCso.mjs.map → main-resolver-BeYWNzrt.mjs.map} +1 -1
  29. package/dist/{main-resolver-DI-A7lSO.mjs → main-resolver-kHW6FewU.mjs} +1 -1
  30. package/dist/{planner-8-shIa8t.mjs → planner-DAq4Yx-H.mjs} +3 -3
  31. package/dist/{planner-8-shIa8t.mjs.map → planner-DAq4Yx-H.mjs.map} +1 -1
  32. package/dist/{program-DiktbiWa.mjs → program-CWf9mT7Z.mjs} +45 -23
  33. package/dist/program-CWf9mT7Z.mjs.map +1 -0
  34. package/dist/{run-DUZRSnIT.mjs → run-uAkNItb6.mjs} +22 -4
  35. package/dist/run-uAkNItb6.mjs.map +1 -0
  36. package/dist/{session-keepalive-CZUwp5IQ.mjs → session-keepalive-BWEjcRrh.mjs} +2 -2
  37. package/dist/{session-keepalive-CZUwp5IQ.mjs.map → session-keepalive-BWEjcRrh.mjs.map} +1 -1
  38. package/dist/skills/Tasks/SKILL.md +1 -1
  39. package/docs/auto-compact.md +31 -0
  40. package/docs/budget-advisor.md +48 -0
  41. package/docs/command-reference.md +25 -0
  42. package/docs/companion-projects.md +9 -0
  43. package/docs/context-preservation.md +43 -0
  44. package/docs/how-it-works.md +25 -0
  45. package/docs/install-linux.md +32 -0
  46. package/docs/install.md +56 -0
  47. package/docs/memory.md +96 -0
  48. package/docs/observations.md +58 -0
  49. package/docs/release-history.md +42 -0
  50. package/docs/rules-and-privacy.md +37 -0
  51. package/docs/search.md +169 -0
  52. package/docs/session-management.md +153 -0
  53. package/docs/session-notes.md +64 -0
  54. package/docs/skills.md +45 -0
  55. package/docs/task-bus.md +1 -2
  56. package/docs/use-cases.md +194 -0
  57. package/docs/what-you-can-ask.md +78 -0
  58. package/docs/worker-providers.md +58 -0
  59. package/docs/zettelkasten.md +37 -0
  60. package/package.json +1 -1
  61. package/plugins/productivity/skills/Tasks/SKILL.md +1 -1
  62. package/src/hooks/ts/pre-tool-use/security-validator.test.ts +23 -0
  63. package/src/hooks/ts/pre-tool-use/security-validator.ts +1 -1
  64. package/src/hooks/ts/session-start/load-project-context.ts +1 -1
  65. package/dist/program-DiktbiWa.mjs.map +0 -1
  66. package/dist/run-DUZRSnIT.mjs.map +0 -1
package/README.md CHANGED
@@ -2,1143 +2,140 @@
2
2
 
3
3
  Claude Code has a memory problem. Every new session starts cold — no idea what you built yesterday, what decisions you made, or where you left off. PAI fixes this.
4
4
 
5
- Install PAI and Claude remembers. Ask it what you were working on. Ask it to find that conversation about the database schema. Ask it to pick up exactly where the last session ended. It knows.
5
+ Install PAI and Claude remembers. Ask it what you were working on, find that conversation about the database schema, or pick up exactly where the last session ended.
6
6
 
7
- ## Quick Start
7
+ - Automatic session notes, split by topic, written by a background daemon
8
+ - Federated keyword and semantic search across sessions, notes and vaults
9
+ - Workers on any provider, orchestrated from one Claude Code session
10
+ - Everything runs locally
8
11
 
9
- Tell Claude Code:
12
+ ## Install
10
13
 
11
- > Clone https://github.com/mnott/PAI and set it up for me
14
+ > **The easy way, on macOS and Linux:** open Claude Code and say
15
+ >
16
+ > **"Clone https://github.com/mnott/PAI and set it up for me"**
17
+ >
18
+ > Claude installs PAI, runs the setup wizard and checks the daemon.
12
19
 
13
- Or install with a single command:
20
+ **Prerequisites:** [Claude Code](https://claude.com/claude-code), Node.js 20 or newer, and Docker if you choose PostgreSQL.
14
21
 
15
- ```bash
16
- npx @tekmidian/pai install
17
- ```
18
-
19
- Or manually:
20
-
21
- ### 1. Install
22
-
23
- ```bash
24
- git clone https://github.com/mnott/PAI
25
- cd PAI
26
- bun install
27
- bun run build
28
- ```
29
-
30
- ### 2. Run the setup wizard
31
-
32
- ```bash
33
- pai setup # interactive
34
- pai setup --yes # unattended: every prompt takes its default
35
- ```
36
-
37
- The wizard walks you through: storage mode (SQLite or PostgreSQL), project directories, Obsidian vault path, MCP server registration, CLAUDE.md template, and daemon configuration. It's idempotent — safe to re-run anytime.
38
-
39
- #### Linux, from zero (Ubuntu, apt Node, no Docker)
40
-
41
- ```bash
42
- sudo apt install -y nodejs npm tmux
43
- npm i -g @anthropic-ai/claude-code && claude login
44
- npm i -g @tekmidian/pai # set `npm config set prefix ~/.npm-global` first to avoid sudo
45
- pai setup --yes --storage sqlite # skips macOS-only steps; installs the systemd user unit when systemd runs
46
- pai worker on # route subagents to `pai worker run`
47
- ```
48
-
49
- Run `loginctl enable-linger "$USER"` so the daemon survives logout. Inside tmux, `pai worker run` opens its follow pane as a tmux split; elsewhere use `pai worker follow <id>`. Where systemd is absent (containers), start the daemon with `pai daemon serve`.
50
-
51
- ### 3. Start the daemon
52
-
53
- ```bash
54
- pai daemon start
55
- ```
56
-
57
- The daemon runs in the background via launchd (macOS) or a systemd user unit (Linux), indexing your sessions and serving the MCP tools. It starts automatically on login.
58
-
59
- ### 4. Verify
22
+ By hand, the same on macOS and Linux:
60
23
 
61
24
  ```bash
62
- pai daemon status # should show "running"
63
- pai memory search "test" # should return results after indexing
25
+ npm i -g @tekmidian/pai
26
+ pai setup --yes --storage postgres # keyword + semantic search (pgvector in Docker); or: --storage sqlite
27
+ pai daemon status # should show "running"
64
28
  ```
65
29
 
66
- That's it. Claude Code now has persistent memory across all sessions.
30
+ `pai setup` without `--yes` asks every question interactively. It installs the daemon as a LaunchAgent on macOS and a systemd user service on Linux. From a source checkout: `git clone https://github.com/mnott/PAI && cd PAI && bun install && bun run build`.
67
31
 
68
- ---
32
+ → [docs/install.md](docs/install.md) · [docs/install-linux.md](docs/install-linux.md) (both storage paths, Docker, systemd)
69
33
 
70
34
  ## Command Reference
71
35
 
72
- Every `pai` command area has its own man page, **generated from the live CLI** so it never drifts from the actual commands. Read them three ways:
36
+ Every `pai` command area has a man page generated from the live CLI: `pai help`, `pai help memory`, `pai memory --help`.
73
37
 
74
- ```bash
75
- pai help # list all command areas (the index)
76
- pai help memory # the full man page for one area, in your terminal
77
- pai memory --help # terse Commander help for any command
78
- ```
79
-
80
- Browse the same pages on GitHub under [`docs/commands/`](docs/commands/README.md). Each page lists every subcommand, its arguments and options, and worked examples. The reference below in this README is the *guided tour*; `docs/commands/` is the *complete reference*.
81
-
82
- | Area | What it covers |
83
- |------|----------------|
84
- | [`pai memory`](docs/commands/memory.md) | Federated search, indexing, embeddings |
85
- | [`pai projects`](docs/commands/projects.md) | Project registry: add, cd, info, health, rebind |
86
- | [`pai kg`](docs/commands/kg.md) | Temporal knowledge graph |
87
- | [`pai zettel`](docs/commands/zettel.md) | Zettelkasten intelligence over your vault |
88
- | [`pai observation`](docs/commands/observation.md) | Automatic tool-call observation capture |
89
- | [`pai skill`](docs/commands/skill.md) | Skill telemetry (self-educating skill system) |
90
- | [`pai obsidian`](docs/commands/obsidian.md) | Obsidian vault sync |
91
- | [`pai daemon`](docs/commands/daemon.md) | Daemon lifecycle |
92
- | [`pai notify`](docs/commands/notify.md) | Notification configuration |
93
- | [`pai backup`](docs/commands/backup.md) · [`pai restore`](docs/commands/restore.md) | Data safety |
94
- | … | See [the full index](docs/commands/README.md) for all areas |
95
-
96
- ---
97
-
98
- ## Worker Providers — Run the Fleet Anywhere
99
-
100
- **Read the story: [Provider Independence — how I freed my stack from a single vendor in one day](docs/provider-independence.md).**
101
-
102
- Only the outer orchestrator session runs on Anthropic. Every worker PAI spawns — research, drafting, implementation, review, spotchecks — runs on a managed provider you choose. The same provider layer carries the daemon's background calls and the session picker, so the whole stack moves together.
103
-
104
- ### Why
105
-
106
- - **Vendor independence.** Any provider that speaks the Anthropic Messages protocol is a registry entry: models, key file, price tier. OpenAI-protocol providers work through a built-in translating proxy. Switching is configuration, not surgery.
107
- - **Cost control.** Parallel work is a commodity; it should not burn your premium seat. Workers bill against their own provider, and cheap classes resolve to the provider's fast model automatically.
108
- - **No lock-in to one orchestrator vendor.** Sessions run on the active provider too — the picker launches through it, and `pai worker fallback` extends that machine-wide.
109
- - **Survives orchestrator outages.** Workers carry their own provider credentials, so a quota freeze or outage on the vendor seat does not stop delegated work.
110
-
111
- ### How
112
-
113
- - **Managed providers.** `pai worker providers add` registers one, `pai worker providers use <name>` switches the fleet, `pai worker off` disables routing entirely (the Agent tool runs on Anthropic again), `pai worker on` re-enables it. The reserved name `anthropic` needs no `add` step — it's Claude Code's own login; `pai worker providers use anthropic` switches straight to it.
114
- - **Start the harness itself on any provider.** `pai launch` (numbered picker, or `--provider <name> [--model <model>]`) starts a fresh Claude Code session on any provider/model in `workers.yaml` — a running session can't switch providers (base URL and auth are fixed at start), so this always begins a new one. Claude Code's own `/model` only lists the current endpoint's models; `pai launch --list` (or the `/providers` skill, from inside a session) lists every provider configured here.
115
- - **Classes route work to the right model.** `--class` picks the provider and model for the job: `draft`, `plan`, `implement`, `review`, `research`, `spotcheck`, `simple`, `complex`, `image`. `pai worker classes` shows and edits the mapping; `--provider` / `--model` override for a single run.
116
- - **Every worker spawn stands alone.** The orchestrator's API key is stripped and the spawn gets the provider's base URL, token and model ids instead — proven live: a worker answers with the parent's credentials gone. No inherited billing, no fallback to the vendor login.
117
- - **The route is pinned, not inherited.** Claude Code's user settings outrank the process env, so a machine-wide proxy route (a `caveman` install, a `pai worker fallback`) would otherwise swallow a worker's base URL and send its provider token to the wrong endpoint. Every spawn repeats its route with `--settings`, which outranks user settings; native-Anthropic workers are pinned to `api.anthropic.com`, or launched as `caveman claude` when `workers.caveman: true` is set in `config.yaml`. Details: [docs/worker.md](docs/worker.md), "What a worker is".
118
- - **One file to configure it.** Providers, per-role model ids and class routing live in one hand-editable `workers.yaml` — adding a provider (Anthropic-compatible, OpenAI-compatible, or local) is a YAML edit, never code. Full reference: [docs/workers-config.md](docs/workers-config.md).
119
-
120
- ```yaml
121
- active: anthropic
122
- providers:
123
- anthropic:
124
- builtin: true # Claude Code's own login
125
- models: { default: claude-sonnet-5, fast: claude-haiku-4-5-20251001 }
126
- glm:
127
- url: https://api.z.ai/api/anthropic
128
- key: "<your-api-key>" # or key_file: <path to a 0600 file>
129
- tier: 3
130
- models: { default: glm-5.3[1m], fast: glm-5.3-flash }
131
- classes:
132
- implement: anthropic
133
- spotcheck: anthropic/fast # cheap classes default to the fast model
134
- ```
135
-
136
- ### What
137
-
138
- ```bash
139
- pai worker run -p '<task>' --class implement # one worker on a provider
140
- pai worker ps # this session's workers (--all: every one)
141
- pai worker follow <id> # live transcript of one worker
142
- pai worker pane # shared follow pane for the session
143
- pai worker replay <id> # transcript of a finished or running worker
144
- pai worker say <id> <text> # message a running worker mid-run
145
- pai worker handoff '<json>' # from inside a worker: report to the parent
146
- pai worker merge <id> # merge the worker's branch back, drop the worktree
147
- pai worker wait <id>... # block until workers finish (never sleep-loop)
148
- pai worker watch # ps refreshed every 2 seconds
149
- ```
150
-
151
- The rest of the surface — `discard`, `resume`, `controls`, `proxy`, `mcp`, `model`, `providers`, `classes` — is in `pai help worker` and [docs/commands/worker.md](docs/commands/worker.md).
152
-
153
- ![Workers in the statusline](docs/images/workers.png)
154
-
155
- Get started in three copy-paste steps: **[docs/provider-independence.md](docs/provider-independence.md)**. For the depth — provider registry, statusline instrumentation, seam patches, current limits — see **[docs/provider-abstraction.md](docs/provider-abstraction.md)**.
38
+ → [docs/command-reference.md](docs/command-reference.md) · [docs/commands/](docs/commands/README.md)
156
39
 
157
- ---
40
+ ## Worker Providers
158
41
 
159
- ## Automatic Session Notes — by Topic
42
+ Only the orchestrator session runs on Anthropic; every worker runs on a provider you choose, routed by class. Providers and classes live in one `workers.yaml`.
160
43
 
161
- PAI's headline feature: **every session is automatically documented.** No manual note-taking, no "pause session" commands, no forgetting to save what you did.
44
+ → [docs/worker-providers.md](docs/worker-providers.md) · [docs/worker.md](docs/worker.md) · [docs/workers-config.md](docs/workers-config.md) · [docs/provider-independence.md](docs/provider-independence.md)
162
45
 
163
- When you work, a background daemon watches your session **continuously**. Every time Claude's context compacts — which happens automatically as the conversation grows — the daemon reads the JSONL transcript, combines it with your git history, and spawns a headless Claude process to write a structured session note. Not just at session end. Midway through your work, while you're still coding. The notes build up in real time as you go — what was built, what decisions were made, what problems were hit, what's left to do.
164
-
165
- **When you change topics mid-session, PAI creates a new note.** If you start the day debugging audio, then pivot to a Flutter rewrite, you get two notes — not one giant file mixing unrelated work:
166
-
167
- ```
168
- Notes/2026/03/
169
- 0001 - 2026-03-23 - Phase 1 Research and Architecture.md
170
- 0002 - 2026-03-24 - Background Audio and iOS Conflicts.md
171
- 0003 - 2026-03-24 - Flutter Rewrite with Whisper.md ← auto-split, same day
172
- ```
173
-
174
- Topic detection uses Jaccard word similarity between the new summary's topic and the existing note's title. Below 30% overlap = new note.
175
-
176
- **Model tiering:** Opus for final session summaries (best quality, runs once). Sonnet for mid-session checkpoints (good quality, runs on compaction). All using your Max plan — no API charges.
46
+ ## Automatic Session Notes
177
47
 
178
- This is not a template or a skeleton. These are real notes with build error chronologies, architectural decisions with rationale, code snippets, and "what was tried and failed" sections. The kind of notes you'd write yourself if you had time.
48
+ A background daemon documents every session as it happens, from the transcript and git history, and starts a new note when the topic changes.
179
49
 
180
- ---
50
+ → [docs/session-notes.md](docs/session-notes.md)
181
51
 
182
52
  ## What You Can Ask Claude
183
53
 
184
- ### Searching Your Memory
185
-
186
- - "Search your memory for authentication" — finds past sessions about auth, even with different words
187
- - "What do you know about the Whazaa project?" — retrieves full project context instantly
188
- - "Find where we discussed the database migration" — semantic search finds it even if you phrase it differently
189
- - "Search your memory for that Chrome browser issue" — keyword and meaning-based search combined
190
-
191
- ### Managing Projects
192
-
193
- - "Show me all my projects" — lists everything PAI tracks with stats
194
- - "Which project am I in?" — auto-detects from your current directory
195
- - "What's the status of the PAI project?" — full project details, sessions, last activity
196
- - "How many sessions does Whazaa have?" — project-level session history
197
-
198
- ### Navigating Sessions
54
+ Search your memory, manage projects, navigate sessions, review your week, keep things safe, work with Obsidian and manage your budget, all in plain language.
199
55
 
200
- - "List my recent sessions" — shows what you've been working on across all projects
201
- - "What did we do in session 42?" — retrieves any specific session by number
202
- - "What were we working on last week?" — Claude knows, without you re-explaining
203
- - "Clean up my session notes" — auto-names unnamed sessions and organizes by date
204
-
205
- ### Reviewing Your Work
206
-
207
- - "Review my week" — synthesizes session notes, git commits, and completed tasks into a themed narrative
208
- - "What did I do today?" — daily review across all projects
209
- - "Journal this thought" — capture freeform reflections with timestamps
210
- - "Plan my week" — forward-looking priorities based on open TODOs and recent activity
211
- - "What themes are emerging in my work?" — spot patterns across sessions and projects
212
-
213
- ### Sharing Your Work
214
-
215
- - "Share on LinkedIn today" — generates a professional post about what you shipped, with real numbers and technical substance
216
- - "Tweet about the vault migration" — punchy X/Twitter post or thread, with option to post directly
217
- - "Share on Bluesky this week" — conversational technical post for the Bluesky audience
218
- - Platform-aware formatting: LinkedIn gets hashtags and narrative, X gets threads and hooks, Bluesky gets conversational tone
219
-
220
- ### Tracking Your Activity
221
-
222
- - "What changes did I make to the daemon today?" — automatic observation capture tracks every tool call
223
- - "Show me all decisions from the last session" — observations are classified: decision, bugfix, feature, refactor, discovery, change
224
- - "What files did I modify in the PAI project this week?" — searchable timeline of every edit, commit, and search
225
- - "Show observation stats" — totals, breakdowns by type and project, with visual bar charts
226
-
227
- ### Continuing Where You Left Off
228
-
229
- - "Go" — reads your TODO.md continuation prompt and picks up exactly where the last session stopped
230
- - "What was I working on?" — progressive context injection loads recent observations at session start
231
- - "Continue the daemon refactor" — session summaries give Claude full context without re-explaining
232
- - "/reconstruct" — retroactively creates session notes from JSONL transcripts and git history when automatic capture missed a session
233
-
234
- ### Keeping Things Safe
235
-
236
- - "Back up everything" — creates a timestamped backup of all your data
237
- - "How's the system doing?" — checks daemon health, index stats, embedding coverage
238
-
239
- ### Obsidian Integration
240
-
241
- - "Sync my Obsidian vault" — updates your linked vault with the latest notes
242
- - "Open my notes in Obsidian" — launches Obsidian with your full knowledge graph
243
-
244
- ### Zettelkasten Intelligence
245
-
246
- - "Explore notes linked to PAI" — follow trains of thought through wikilink chains
247
- - "Find surprising connections to this note" — discover semantically similar but graph-distant notes
248
- - "What themes are emerging in my vault?" — detect clusters of related notes forming new ideas
249
- - "How healthy is my vault?" — structural audit: dead links, orphans, disconnected clusters
250
- - "Suggest connections for this note" — proactive link suggestions using semantic + graph signals
251
- - "What does my vault say about knowledge management?" — use the vault as a thinking partner
252
-
253
- ### Budget Management
254
-
255
- - "How much budget do I have left?" — shows current weekly usage and advisor mode
256
- - "Go easy on the budget" — switches to conservative mode (prefer haiku subagents)
257
- - "Lock it down" — switches to critical mode (minimize all token usage)
258
- - "Go full power" — switches to normal mode (no constraints)
259
- - "Back to auto" — resets to auto mode (derives from weekly budget percentage)
260
-
261
- ---
56
+ → [docs/what-you-can-ask.md](docs/what-you-can-ask.md)
262
57
 
263
58
  ## Skills
264
59
 
265
- PAI ships 22 skills — slash commands that activate specialized workflows. Each responds to natural language triggers as well as the `/command` syntax.
266
-
267
- ### Productivity
268
-
269
- | Skill | Trigger | What it does |
270
- |-------|---------|-------------|
271
- | `/advisor` | "budget mode", "save budget", "go easy on the budget" | Manage budget-aware model tiering for subagents |
272
- | `/plan` | "plan my week", "what should I focus on", "priorities" | Plan tomorrow/week/month based on open tasks and calendar |
273
- | `/review` | "review my week", "what did I do", "recap" | Daily/weekly/monthly review of work accomplished |
274
- | `/journal` | "journal", "note to self", "capture this thought" | Create, read, or search personal journal entries |
275
- | `/share` | "share on LinkedIn", "tweet about", "post to Bluesky" | Generate social media posts about completed work |
276
-
277
- ### Session Management
278
-
279
- | Skill | Trigger | What it does |
280
- |-------|---------|-------------|
281
- | `/sessions` | "list sessions", "where was I working" | Navigate sessions, projects, switch working context |
282
- | `/route` | "what project is this", "tag this session" | Detect which PAI project the current session belongs to |
283
- | `/name` | "name this session", "rename session" | Name or rename the current session |
284
- | `/search-history` | "search history", "find past", "what did we do" | Search past sessions and previous work by keyword |
285
- | `/consolidate` | "consolidate notes", "clean up notes", "merge duplicates" | Merge duplicate session notes, fix titles, renumber |
286
- | `/reconstruct` | "reconstruct sessions", "backfill session notes" | Retroactively create notes from JSONL transcripts and git history |
287
-
288
- ### Obsidian Vault
289
-
290
- | Skill | Trigger | What it does |
291
- |-------|---------|-------------|
292
- | `/vault-context` | "morning briefing", "load vault context" | Load Obsidian vault context for a briefing |
293
- | `/vault-connect` | "connect X and Y", "how does X relate to Y" | Find connections between two topics in the vault |
294
- | `/vault-emerge` | "what's emerging", "find patterns", "themes in vault" | Surface emerging themes and clusters |
295
- | `/vault-orphans` | "find orphans", "unlinked notes" | Find and reconnect orphaned notes with zero inbound links |
296
- | `/vault-trace` | "trace idea", "how did X evolve", "idea history" | Trace the evolution of an idea across vault notes over time |
60
+ On-demand skills for productivity, session management, Obsidian vaults and system tools.
297
61
 
298
- ### Tools & System
299
-
300
- | Skill | Trigger | What it does |
301
- |-------|---------|-------------|
302
- | `/whisper` | "add whisper rule", "show whisper rules" | Manage persistent behavioral constraints injected on every prompt |
303
- | `/research` | "do research", "extract wisdom", "analyze content" | Web research, content extraction, and analysis via parallel agents |
304
- | `/art` | "create diagram", "flowchart", "visualize" | Create visual content, diagrams, flowcharts, and AI-generated images |
305
- | `/story` | "explain this as a story", "create story explanation" | Create numbered narrative story explanations of any content |
306
- | `/observability` | "start observability", "monitor agents" | Start, stop, or check the multi-agent observability dashboard |
307
- | `/createskill` | "create skill", "validate skill" | Create, validate, update, or canonicalize a PAI skill |
308
-
309
- ---
62
+ → [docs/skills.md](docs/skills.md)
310
63
 
311
64
  ## Budget-Aware Advisor Mode
312
65
 
313
- PAI tracks your weekly Claude usage and automatically adjusts subagent model selection to stay within budget. The statusline shows your current mode at a glance.
314
-
315
- ### How it works
316
-
317
- The statusline reads your OAuth usage from the Anthropic API (5-hour and 7-day windows) and writes the weekly budget percentage to `~/.claude/pai/advisor-mode.json`. A whisper-rules hook reads this file on every prompt and injects model-tiering guidance.
318
-
319
- ### Automatic thresholds
320
-
321
- | Budget Used | Mode | Subagent Model | Behavior |
322
- |-------------|------|----------------|----------|
323
- | < 60% | normal | Any | No constraints |
324
- | 60–80% | conservative | Haiku preferred | Escalate to sonnet only if haiku insufficient |
325
- | 80–92% | strict | Haiku only | Minimize spawning, no opus subagents |
326
- | > 92% | critical | Haiku or none | Essential work only, minimize all token usage |
327
-
328
- ### Statusline display
329
-
330
- The advisor mode label appears on the context line:
331
-
332
- ```
333
- 💎 Context: 12K / 1000K (68%) │ 5h: 3% → 13:18 │ 1d: 5% / 8% │ 7d: strict 91% → Fr. 08:00
334
- ```
335
-
336
- Manually forced modes show a 📌 prefix (e.g. `📌normal 91%`) so you always know whether the mode was auto-calculated or manually set.
337
-
338
- ### Switching modes
339
-
340
- Use `/budget` commands, `/Advisor` skill, or plain language:
66
+ Adapts how much work Claude delegates to cheaper models as your usage limits fill up, with thresholds and a statusline label.
341
67
 
342
- ```
343
- /budget auto — reset to auto (budget-driven)
344
- /budget mode normal — force normal mode
345
- /budget force haiku — force all subagents to haiku
346
-
347
- /Advisor auto — same, via skill (note: capital A)
348
- /Advisor mode strict — force strict mode
349
-
350
- "go full power" — normal mode (plain language)
351
- "be conservative" — conservative mode
352
- "lock it down" — critical mode
353
- "back to auto" — auto mode
354
- ```
355
-
356
- Changes take effect on the next prompt — no restart needed.
357
-
358
- > **Note:** `/advisor` (lowercase) conflicts with a Claude Code built-in command. Use `/budget` or `/Advisor` (capital A) instead.
359
-
360
- ---
68
+ → [docs/budget-advisor.md](docs/budget-advisor.md)
361
69
 
362
70
  ## Context Preservation
363
71
 
364
- When Claude's context window fills up, it compresses the conversation. Without PAI, everything from before that point is lost — Claude forgets what it was working on, what files it changed, and what you asked for.
365
-
366
- PAI intercepts this compression with a two-stage relay:
72
+ State is saved before compaction and injected afterwards, so a compaction, a restart or a crash does not cost you the thread.
367
73
 
368
- 1. **Before compression** — PAI extracts session state from the conversation transcript: your recent requests, work summaries, files modified, and current task context. This gets saved to a checkpoint.
369
-
370
- 2. **After compression** — PAI reads that checkpoint and injects it back into Claude's fresh context. Claude picks up exactly where it left off.
371
-
372
- This happens automatically. You don't need to do anything — just keep working, and PAI handles the continuity.
373
-
374
- ### What Gets Preserved
375
-
376
- - Your last 3 requests (so Claude knows what you were asking)
377
- - Work summaries and captured context
378
- - Files modified during the session
379
- - Current working directory and task state
380
- - Session note checkpoints (persistent — survive even full restarts)
381
-
382
- ### Surviving a Restart, and Surviving a Crash
383
-
384
- Compaction continuity above is one path. Closing the session and opening a new one is another, and it works differently:
385
-
386
- - **`## Continue` in the project's `TODO.md`** is the handover. `pai pause` writes a model-authored checkpoint there; the SessionStart hook reads it back and injects it. You do not have to say "go" — it arrives on its own.
387
- - **A rolling autosave keeps it fresh.** `pai session autosave` runs from the UserPromptSubmit and PostToolUse hooks (rate-limited, ~4 minutes) and records recent prompts plus the state of the working tree. The model is never invoked on `/exit` and never on Ctrl+C, so a checkpoint written *at* exit is impossible — it has to already exist. This is what makes an interrupted session survivable.
388
- - **Authored beats automatic.** The autosave writes in "auto" mode and will not overwrite a model-authored checkpoint for the same session. Preservation is keyed on the Claude session UUID rather than the session note's name, because the stop hook renames and renumbers that note before the handover runs.
389
-
390
- ### Session Lifecycle Hooks
391
-
392
- PAI runs hooks at every stage of a Claude Code session:
393
-
394
- | Event | What PAI Does |
395
- |-------|--------------|
396
- | **Session Start** | Loads project context, detects which project you're in, auto-registers new projects, creates a session note, injects recent observations, and **injects the previous session's `## Continue` checkpoint** so a restart resumes with full context |
397
- | **User Prompt** | Cleans up temp files, updates terminal tab titles, injects whisper rules and advisor mode guidance, refreshes the rolling autosave checkpoint |
398
- | **Pre-Compact** | Saves session state checkpoint, pushes `session-summary` work item to daemon, sends notification |
399
- | **Post-Compact** | Injects preserved state back into Claude's context |
400
- | **Tool Use** | Classifies tool calls into structured observations (decision/bugfix/feature/refactor/discovery/change), refreshes the rolling autosave checkpoint (rate-limited) |
401
- | **Session End** | Pushes `session-summary` work item to daemon for AI-powered note generation |
402
- | **Stop** | Pushes `session-summary` work item to daemon, sends notification |
403
-
404
- All hooks are TypeScript compiled to `.mjs` modules. They run as separate processes and communicate via stdin (JSON input from Claude Code) and stdout (context injection back into the conversation). Hooks are thin relays — they capture minimal data and immediately push work items to the daemon queue, which handles all heavy processing asynchronously.
405
-
406
- ---
74
+ → [docs/context-preservation.md](docs/context-preservation.md)
407
75
 
408
76
  ## Session Management
409
77
 
410
- PAI gives you a complete picture of every Claude Code session running on your machine — live tabs in iTerm2, paused snapshots on disk, and everything in between.
411
-
412
- ### The Core Idea: One Entry Point
413
-
414
- Two ways in, both forgiving:
415
-
416
- - **`pai`** (no args) — opens the **interactive picker**: type to search across projects *and* sessions, then act on the highlighted row with a single key.
417
- - **`pai <name>`** — the universal session command when you already know the name. It does the right thing based on session state:
418
- - **Live session** — switches the iTerm2 tab to front (no new Claude launched)
419
- - **Otherwise** — starts a fresh Claude in the project directory, on the configured route. If a resumable transcript exists it asks `Resume it? [y/N]` first (Enter keeps fresh); `--resume` or `pai resume <name>` resume without asking; `-y` skips the question.
420
- - **No match** — searches `~/.claude/history.jsonl`, shows a candidate picker
421
-
422
- ```bash
423
- pai # Interactive picker — search, then go / new / cd / finder / remove
424
- pai aibroker # Switch to the live AIBroker tab (iTerm comes to front)
425
- pai youdrill # Fresh youdrill session; offers to resume the last transcript
426
- pai mdf # Free-text search across your prompt history
427
- pai 0856d40b # Resume by UUID prefix
428
- pai --list # Static deduped table (the old no-args behaviour)
429
- ```
430
-
431
- ### Daily Commands
432
-
433
- ```bash
434
- pai # Interactive picker (projects + sessions; search then act)
435
- pai --list # Static deduped listing (one row per name)
436
- pai <name> # Switch / resume / fresh — universal
437
- pai pause # Save state checkpoint (write ## Continue to TODO.md)
438
- pai pause all # Pause every live Claude session at once
439
- pai end # Finalize: save state + mark session note Completed
440
- ```
441
-
442
- And inside Claude Code, the two slash commands that matter:
443
-
444
- ```
445
- /pause → write checkpoint to TODO.md, print handoff block, then type /exit
446
- /end → same as /pause, plus marks the session note Completed
447
- ```
448
-
449
- ### The Interactive Picker
450
-
451
- Run `pai` with no arguments to open a self-contained terminal selector (no `fzf` or other dependency) over a **unified, deduped list of both projects and sessions** — tagged so the two stay distinct. It's the one place to answer "where did I work on X, and take me there."
452
-
453
- ```
454
- pai — find a project or session
455
- search > samba
456
-
457
- live Chenarlier now …/Raspi/Chenarlier samba setup monster reverse proxy
458
- project Glidr 2d …/apps/glidr claude pai research
459
-
460
- ────────────────────────────────────────
461
- Chenarlier ~/…/Raspi/Chenarlier
462
- recent notes:
463
- 10 - Samba Setup/01 - Samba Server Setup.md 1mo
464
- 00 - Monster/00 - Monster.md 3mo
465
- ────────────────────────────────────────
466
- g go to tab · n new · c cd · f finder · d remove · s search · ↑↓ move · q quit
467
- ```
468
-
469
- **Two modes.** You start in *command mode* (single keys are actions). Press `s` (or `/`) to enter *search mode* (type a topic — it filters by name, path, **and folded-in note file/folder names**, so `samba` finds a project literally named "Chenarlier"); `Enter` or `esc` returns to command mode.
470
-
471
- **Command keys** act immediately on the highlighted row:
472
-
473
- | Key | Action |
474
- |-----|--------|
475
- | `g` | **Go to** the running iTerm2 tab (for live rows) |
476
- | `n` | **New** Claude session in that directory (current terminal) |
477
- | `c` | **cd** into the folder only — no Claude (your shell stays there) |
478
- | `f` | Open the folder in **Finder** / Explorer / `xdg-open` (keeps the picker open) |
479
- | `d` | **Remove** from PAI's list — archives the project (reversible, files untouched); asks `y/N` first |
480
- | `s` `/` | Enter **search** mode |
481
- | `↑↓` `j` `k` | Move the highlight |
482
- | `q` `esc` | Quit |
483
-
484
- `Enter` on a row takes the smart default: a live row → go to its tab, otherwise → new session.
485
-
486
- The `c` (cd) action needs PAI's shell integration to change your shell's directory — see [Finding the Claude Binary](#finding-the-claude-binary) / `pai shell-init`. On a non-interactive terminal (piped output), `pai` falls back to the static listing automatically.
487
-
488
- ### Static Listing
489
-
490
- `pai --list` shows a single deduped table — one row per session name, regardless of how many snapshots exist on disk:
491
-
492
- ```
493
- Sessions:
494
-
495
- # name status age project last prompt
496
- -- ---------- ---------- -------- ---------------------------- --------------------------
497
- 1 AIBroker live now — —
498
- 2 PAI resumable 2m ago /…dev/ai/PAI "refactor session listing…"
499
- 3 MDF transcript 3d ago /…MDF/Infrastruktur/Webseiten "ok so we recently had…"
500
- ```
501
-
502
- Status values: `live` (active iTerm tab), `resumable` (clean snapshot on disk), `transcript` (history available, not resumable), `stub` (empty or minimal).
503
-
504
- ### Finding Sessions by Topic
505
-
506
- `pai <topic>` first checks session names, then falls back to searching your prompt history:
507
-
508
- ```
509
- Sessions matching "mdf":
510
-
511
- # id when project last matching prompt
512
- - -------- ---------------- ----------------------------------- -------------------------
513
- 1 6269cf64 2026-05-21 08:20 /…MDF/Infrastruktur/20 - Webseiten "ok so we recently had an order…"
514
- 2 abe2d977 2026-02-23 08:40 /…MDF/Infrastruktur/20 - Webseiten "yes the session notes for Whazaa…"
515
-
516
- Enter # to launch (1-2), or press Enter to cancel:
517
- ```
518
-
519
- Use `pai <topic> --auto` (or `-y`) to auto-pick #1. Use `pai <topic> 2` to pick directly.
520
-
521
- ### Power User Access
522
-
523
- The full session management namespace is still available:
524
-
525
- ```bash
526
- pai sessions # Live + disk listing (with more columns)
527
- pai sessions --all # Include unnamed orphan sessions
528
- pai sessions --all-tabs # Include shell tabs in the live section
529
- pai sessions goto <name> # Named-session resolver (same as pai <name>)
530
- pai sessions list # Explicit listing (same as pai sessions)
531
- ```
532
-
533
- ### Pausing All Sessions at Once
534
-
535
- When you're done for the day and have multiple Claude windows open:
536
-
537
- ```bash
538
- pai pause all # send "pause session" to every live Claude pane
539
- pai pause all --dry-run # preview what would be sent
540
- pai pause all --exit # also send /exit after each session saves state
541
- ```
542
-
543
- AIBroker must be running for this to work. Shell tabs (bare zsh, SSH panes) are automatically skipped — only Claude Code panes receive the pause command. The count of skipped tabs is printed to stderr.
544
-
545
- ### /pause and /end Inside Claude Code
546
-
547
- Type `/pause` or `/end` from inside an active Claude Code session (not from a shell — these are Claude Code slash commands, not CLI commands):
548
-
549
- - `/pause` — Claude writes a `## Continue` block to the project's `TODO.md`, prints a handoff summary with the session ID, then tells you to type `/exit`. The next session starts by reading that TODO.md block and picking up exactly where you left off.
550
- - `/end` — Same as `/pause`, plus Claude marks the session note as Completed and writes a final summary. Use this when you're genuinely done with a topic, not just pausing mid-task.
551
-
552
- After either command, type `/exit` to exit Claude Code cleanly.
553
-
554
- ### Why /exit and Not Ctrl+C
555
-
556
- Ctrl+C or closing the terminal kills the Claude Code process abruptly. The session note generation hook never fires, the checkpoint is not written, and the session cannot be resumed with `claude --resume`.
557
-
558
- `/exit` sends a clean shutdown signal. Claude Code runs its Stop and Session End hooks, which trigger PAI to write the session note, push the final summary to the daemon, and save a resumable snapshot. The difference in recovery quality between a clean `/exit` and a Ctrl+C is significant for long sessions.
559
-
560
- If you do accidentally close a terminal, use `pai sessions --all` to find the orphaned transcript. The `/reconstruct` skill can retroactively generate a session note from it.
561
-
562
- ---
563
-
564
- ## Automatic Session Notes
565
-
566
- PAI automatically writes structured session notes after every session ends — no manual journaling required. The daemon spawns a headless Claude CLI process (using your Max plan, not the API) to summarize the JSONL conversation transcript combined with recent git history.
567
-
568
- ### What Gets Generated
569
-
570
- Each session note contains:
571
-
572
- - **Work Done** — concrete description of what was accomplished
573
- - **Key Decisions** — choices made and their rationale
574
- - **Known Issues** — bugs found, blockers, or open questions
575
- - **Next Steps** — where to pick up in the next session
576
-
577
- The summarizer uses tiered model selection based on the trigger:
578
-
579
- | Trigger | Model | Timeout | JSONL Limit |
580
- |---------|-------|---------|-------------|
581
- | Session end (Stop hook) | Opus | 5 minutes | 500K bytes |
582
- | Auto-compaction (PreCompact hook) | Sonnet | 2 minutes | 200K bytes |
583
-
584
- ### Topic-Based Note Splitting
585
-
586
- When a session covers multiple distinct topics, PAI creates separate notes rather than one long note for the whole session. The summarizer outputs a `TOPIC:` line describing the subject of the current work. PAI compares this against the existing note title using Jaccard word similarity — when similarity falls below 30%, a new note is created automatically.
587
-
588
- Notes within the same day are numbered sequentially: `0042 - 2026-03-24 - Session Name.md`, `0043 - 2026-03-24 - Different Topic.md`, and so on.
589
-
590
- ### One Note Per Session
591
-
592
- Each compaction within a session updates the existing note rather than creating a new one. The 30-minute cooldown between summaries prevents redundant updates. Stop hook triggers bypass the cooldown with a force flag to ensure the final state is always captured.
593
-
594
- ### Garbage Title Filter
595
-
596
- Session note titles are validated before creation. Over 20 patterns are rejected, including: task notification strings, `[object Object]`, hex hashes, bare numbers, and other non-descriptive artifacts that can appear in session transcripts. Titles must describe actual work done and are capped at 60 characters.
597
-
598
- ### Finding the Claude Binary
599
-
600
- The daemon runs under launchd with a minimal PATH that does not include `~/.local/bin/`. PAI resolves the Claude CLI binary by checking `~/.local/bin/claude` first, then falling back to PATH lookup, before spawning headless summarization processes.
601
-
602
- ### Stripping the API Key
603
-
604
- When spawning headless Claude CLI processes for summarization, the daemon strips `ANTHROPIC_API_KEY` from the subprocess environment. This forces the spawned process to authenticate via your Max plan (free) rather than using the API key (billable). Without this, every automatic session note would incur API charges.
78
+ One entry point, `pai <topic>`: an interactive picker over projects and sessions, topic search, pausing all sessions at once.
605
79
 
606
- ---
80
+ → [docs/session-management.md](docs/session-management.md)
607
81
 
608
- ## Progressive Memory Loading
82
+ ## Memory
609
83
 
610
- PAI loads context in layers at session start rather than all at once. This keeps early-session latency low while giving Claude everything it needs to be useful immediately.
84
+ Progressive memory loading in four layers, a temporal knowledge graph, and a three-tier hybrid store with graph-completion search and a relevance feedback loop.
611
85
 
612
- ### The Four Layers
613
-
614
- | Layer | What it loads | When |
615
- |-------|---------------|------|
616
- | **L0 — Identity** | Your identity file (`~/.pai/identity.txt`) — who you are, your working style, key preferences | Always, at every session start |
617
- | **L1 — Essential story** | Summaries from the most recent session notes — what you were doing, what decisions were made, where things stand | Always, at session start |
618
- | **L2 — Topic queries** | On-demand retrieval for the current topic — fetched when a specific question or task is identified | On demand, during the session |
619
- | **L3 — Deep search** | Full `memory_search` across all indexed content — for when L2 is not enough | On demand, when explicitly needed |
620
-
621
- L0 and L1 fire automatically via the `memory_wakeup` MCP tool, which is called by the `SessionStart` hook. L2 and L3 are invoked as needed — the model decides when to go deeper based on the question at hand.
622
-
623
- ### Configuring Your Identity File
624
-
625
- Create `~/.pai/identity.txt` with a short description of yourself and your working style. Claude will see this at every session start. Example:
626
-
627
- ```
628
- Principal engineer. Work across TypeScript, Dart, and shell scripting.
629
- Projects: PAI (AI infrastructure), RingsADay (Flutter app), Scribe (MCP server).
630
- Prefer concise explanations, hate unnecessary hedging.
631
- ```
632
-
633
- ---
634
-
635
- ## Advanced Memory Tools
636
-
637
- ### Temporal Knowledge Graph
638
-
639
- Facts change over time. The `kg_triples` table stores knowledge as subject-predicate-object triples with `valid_from` and `valid_to` timestamps, so facts can expire and contradict each other rather than accumulating in an undated blob.
640
-
641
- Four MCP tools cover the full lifecycle:
642
-
643
- - `kg_add` — Add a fact with a start date (and optional end date)
644
- - `kg_query` — Query the graph, filtered to facts valid at a given point in time
645
- - `kg_invalidate` — Mark a fact as no longer true (sets `valid_to`)
646
- - `kg_contradictions` — Surface facts that directly contradict each other, using predicate inversion rules
647
-
648
- Example: "the user prefers PostgreSQL" added in March; "the user prefers SQLite" added in April with the March fact invalidated. `kg_query` in April sees only the current fact; `kg_query` for March sees the historical one.
649
-
650
- ### Memory Taxonomy
651
-
652
- `memory_taxonomy` gives a shape-of-memory overview: projects, session counts, chunk counts, embedding coverage, and recent activity. Think of it as a dashboard for your knowledge base — useful both for the model (to understand what it knows) and for you (to audit what is indexed).
653
-
654
- ### Cross-Project Tunnels
655
-
656
- `memory_tunnels` detects concepts that appear across multiple projects. It works by comparing FTS vocabulary in SQLite mode or `ts_stat` output in PostgreSQL mode. When a concept — a library name, a design pattern, a person's name — shows up in three separate projects, PAI surfaces that connection as a tunnel.
657
-
658
- This reveals unexpected intellectual bridges: the same concurrency pattern used in PAI's daemon showing up in your Flutter app's state management, or a vendor name appearing in both your notes and your job applications.
659
-
660
- ---
661
-
662
- ## Memory Architecture
663
-
664
- PAI's memory system uses a three-tier hybrid store inspired by Cognee's approach to knowledge graphs and retrieval. Each tier has a distinct role, and they work together to answer queries that no single store could handle alone.
665
-
666
- ### Three-Tier Hybrid Store
667
-
668
- | Tier | Backend | What it stores |
669
- |------|---------|----------------|
670
- | **Chunks + entities** | SQLite (simple mode) or PostgreSQL (full mode) | Text chunks with embeddings; named entity records with content-address hashes |
671
- | **Knowledge graph** | PostgreSQL (`kg_triples`) | Subject-predicate-object triples with `valid_from`/`valid_to` timestamps |
672
- | **Vector embeddings** | pgvector (full mode) | 768-dimensional Snowflake Arctic embeddings on chunks and vault notes |
673
-
674
- ### Entity Deduplication via Content-Address Hashing
675
-
676
- Named entities (people, projects, libraries, concepts) extracted during indexing are stored in a `kg_entities` table and deduplicated using a content-address hash derived from the entity's canonical name. Two mentions of "PostgreSQL" in different session notes resolve to a single entity row — the hash acts as a stable identity, so the graph stays normalized even as new content is indexed.
677
-
678
- ### Graph-Completion Search Pipeline
679
-
680
- Standard vector search finds semantically similar chunks. Graph-completion search goes further:
681
-
682
- 1. **Vector seeds** — a semantic search returns the top-K most relevant chunks.
683
- 2. **Graph traversal** — the entities mentioned in those chunks are looked up in `kg_triples`; their immediate neighbors are fetched (one hop).
684
- 3. **Candidate expansion** — the neighbor entities' associated chunks are added to the result set.
685
- 4. **Re-rank** — the expanded candidate set is re-scored by the cross-encoder, which reads each (query, result) pair together. Results are sorted by this final relevance score.
686
-
687
- This means a query about "the PAI daemon" can surface a session note that mentions the daemon only indirectly — because a connected entity (the Unix socket, the launchd service) appears in both the graph and the note.
688
-
689
- ### Feedback Loop with Relevance Scoring
690
-
691
- Every search result that is subsequently retrieved via `memory_get` (i.e., actually read by the model) generates a positive feedback signal. These signals are stored and used to adjust future search weights using an exponential moving average (EMA):
692
-
693
- ```
694
- new_weight = alpha * signal + (1 - alpha) * old_weight
695
- ```
696
-
697
- The default alpha is 0.1, so recent positive signals gradually raise a chunk's effective score without overriding the semantic baseline. This creates a personalization loop: content you actually use rises in future rankings; content you skip does not.
698
-
699
- ### Access Timestamp Tracking
700
-
701
- Every chunk row carries a `last_accessed_at` timestamp updated on each `memory_get` call. This supports recency boost (content accessed recently scores higher) and enables future eviction policies for very large knowledge bases.
702
-
703
- ### Multi-Tenant Support
704
-
705
- PAI isolates memory by project. Every chunk, entity, and observation row carries a `project_id` foreign key. Searches default to the current project; the `all_projects: true` flag (or `--all` CLI option) lifts the filter. Knowledge-graph triples carry a `project_id` as well, so cross-project tunnels (`memory_tunnels`) are detected explicitly rather than accidentally.
706
-
707
- ---
86
+ → [docs/memory.md](docs/memory.md)
708
87
 
709
88
  ## Automatic Observation Capture
710
89
 
711
- PAI automatically classifies and stores every significant tool call during your sessions. When you edit a file, run a command, or make a decision, PAI captures it as a structured observation — building a searchable timeline of everything you've done across all projects.
712
-
713
- ### How it works
714
-
715
- A PostToolUse hook fires after every Claude Code tool call. A rule-based classifier (no AI needed, under 50ms) categorizes each action:
716
-
717
- | Type | What triggers it | Examples |
718
- |------|-----------------|----------|
719
- | **decision** | Git commits, config changes | `git commit`, writing to config files |
720
- | **bugfix** | Test runs, error investigation | `npm test`, debugging commands |
721
- | **feature** | New file creation, feature work | Creating components, adding endpoints |
722
- | **refactor** | Code restructuring | Renaming, moving files, reorganizing |
723
- | **discovery** | File reads, searches | Reading code, grep searches, glob patterns |
724
- | **change** | File edits | Editing source files, updating configs |
725
-
726
- Observations are stored with content-hash deduplication (30-second window) to prevent duplicates from rapid tool calls.
727
-
728
- ### Progressive context injection
729
-
730
- At session start, PAI injects recent observations as layered context:
731
-
732
- 1. **Compact index** (~100 tokens) — observation type counts and active projects
733
- 2. **Timeline** (~500 tokens) — recent observations with timestamps
734
- 3. **On-demand** — full details available via MCP tools
735
-
736
- This means Claude starts every session already knowing what you were working on, without you re-explaining anything.
737
-
738
- ### Searching observations
739
-
740
- Ask Claude naturally:
741
-
742
- ```
743
- "What changes did I make to the daemon today?"
744
- "Show me all decisions from the last session"
745
- "What files did I modify in the PAI project this week?"
746
- ```
747
-
748
- Or use the CLI:
749
-
750
- ```bash
751
- # List recent observations
752
- pai observation list
753
-
754
- # Filter by type
755
- pai observation list --type decision
756
-
757
- # Filter by project
758
- pai observation list --project pai
759
-
760
- # Show stats
761
- pai observation stats
762
- ```
763
-
764
- ### Session summaries
765
-
766
- When a session ends, PAI generates a structured summary capturing what was requested, investigated, learned, completed, and what the next steps are. These summaries feed into the progressive context system, giving future sessions a concise picture of past work.
767
-
768
- ---
769
-
770
- ## Whisper Rules
771
-
772
- PAI provides a hook that injects user-defined rules into every prompt via `UserPromptSubmit`. Rules survive compaction, `/clear`, and session restarts — they fire on every single turn, making them the most reliable way to enforce behavioral constraints.
773
-
774
- **PAI ships the mechanism. You provide the rules.** The file `~/.claude/pai/whisper-rules.md` does not exist by default. Use the `/whisper` skill to manage your rules:
775
-
776
- ```
777
- /whisper — show current rules
778
- /whisper add "NEVER send emails" — add a rule
779
- /whisper remove 3 — remove rule #3
780
- /whisper list — list with line numbers
781
- ```
782
-
783
- Or edit `~/.claude/pai/whisper-rules.md` directly — one rule per line, plain text.
784
-
785
- **Keep rules focused.** Every rule is injected on every prompt. Too many rules dilute effectiveness and waste tokens. Reserve whisper rules for truly critical constraints that keep getting violated despite being in CLAUDE.md.
786
-
787
- The pattern is inspired by [Letta's claude-subconscious](https://github.com/letta-ai/claude-subconscious) approach to persistent context injection.
788
-
789
- ---
790
-
791
- ## Privacy Tags
792
-
793
- Wrap any content in `<private>...</private>` tags to exclude it from PAI's memory index. Private content is stripped before chunking — it's never stored, never searched, never surfaced.
794
-
795
- ```markdown
796
- ## API Keys
797
- <private>
798
- STRIPE_KEY=sk_live_abc123
799
- DATABASE_URL=postgres://user:pass@host/db
800
- </private>
801
-
802
- ## Architecture Notes
803
- The payment system uses Stripe webhooks...
804
- ```
805
-
806
- The architecture notes get indexed. The API keys don't. Works in session notes, memory files, and any markdown PAI indexes.
807
-
808
- ---
809
-
810
- ## Token-Efficient Search (3-Layer Pattern)
811
-
812
- For budget-conscious usage, PAI supports a compact search format that returns ~10x fewer tokens per result. Instead of fetching full snippets upfront, get a compact index first, then drill into interesting results.
813
-
814
- ### The workflow
815
-
816
- ```
817
- 1. Search with format="compact" → IDs + paths + scores (~50 tokens/result)
818
- 2. Review the index, pick interesting results
819
- 3. Use memory_get to read full content for those specific files
820
- ```
821
-
822
- ### Example
823
-
824
- ```
825
- "Search for authentication with compact format"
826
- → Claude passes format: "compact" to memory_search
827
- → Gets a tight index: [1] pai — src/auth.ts L10-45 score=0.892
828
- → Then reads only the files that matter
829
- ```
830
-
831
- Via MCP, pass `format: "compact"` to the `memory_search` tool. Default is `"full"` (current behavior with snippets).
90
+ Tool calls are classified into structured observations and injected back as progressive context.
832
91
 
833
- ### Section-aware retrieval
92
+ → [docs/observations.md](docs/observations.md)
834
93
 
835
- Long notes are chunked at their headings, and every chunk carries its heading path as a first line, for example `[Decisions > Worker routing > Provider choice]`. A search for "routing" therefore finds the paragraph under that sub-section even when the paragraph never uses the word. Headings inside code fences are ignored.
94
+ ## Whisper Rules and Privacy Tags
836
95
 
837
- For long files, read by section instead of whole:
96
+ Rules injected into every prompt so they survive compaction, and `<private>` tags that keep content out of the index.
838
97
 
839
- ```
840
- 1. memory_outline(project, path) → heading tree with line ranges and token estimates
841
- ## Previous handovers L45-195 ~2361t
842
- ### Shipped (2026-09-29) L60-66 ~251t
843
- 2. memory_get(project, path, from=60, lines=7) → just that section
844
- ```
98
+ → [docs/rules-and-privacy.md](docs/rules-and-privacy.md)
845
99
 
846
- `memory_outline` returns structure only, never text, and takes an optional `max_depth`.
100
+ ## Search
847
101
 
848
- When the chunking logic changes, `CHUNKER_VERSION` in `src/memory/chunker.ts` is bumped. It is part of each file's change-detection hash, so the first index pass after an upgrade re-chunks and re-embeds every file once; later passes skip unchanged files as before. On a large index that pass takes hours of local CPU for embeddings, and semantic search misses files until they are re-embedded, so restart the daemon onto a new version at a quiet time.
102
+ Keyword, semantic and hybrid search with cross-encoder reranking, recency boost, a compact token-efficient format and section-aware retrieval.
849
103
 
850
- ---
104
+ → [docs/search.md](docs/search.md)
851
105
 
852
106
  ## Auto-Compact Context Window
853
107
 
854
- Claude Code can automatically compact your context window when it fills up, preventing session interruptions mid-task. PAI's statusline shows you at a glance whether auto-compact is active.
855
-
856
- ### Why the GUI setting doesn't work
857
-
858
- Claude Code has an `autoCompactEnabled` setting in `~/.claude.json`, but it gets overwritten on every restart. Do not use it — changes don't survive.
859
-
860
- ### The durable approach: environment variable
861
-
862
- Set `CLAUDE_AUTOCOMPACT_PCT_OVERRIDE` in your `~/.claude/settings.json` under the `env` block. This survives restarts, `/clear`, and Claude Code updates.
863
-
864
- ```json
865
- {
866
- "env": {
867
- "CLAUDE_AUTOCOMPACT_PCT_OVERRIDE": "80"
868
- }
869
- }
870
- ```
871
-
872
- The value is the context percentage at which compaction triggers. `80` means compact when the context window reaches 80% full. Restart Claude Code after saving.
873
-
874
- ### Statusline indicator
875
-
876
- PAI's statusline shows the remaining context until auto-compact triggers as a percentage on line 3, along with your 5-hour and 7-day usage limits, daily pace indicator, and advisor mode label.
877
-
878
- ### Set it up with one prompt
879
-
880
- Give Claude Code this prompt and it handles everything:
881
-
882
- > Add `CLAUDE_AUTOCOMPACT_PCT_OVERRIDE` set to `80` to the `env` block in `~/.claude/settings.json`. This enables durable auto-compact that survives restarts. Do not touch `~/.claude.json` — that file gets overwritten on startup. After saving, confirm the setting is in place and tell me to restart Claude Code.
883
-
884
- ---
885
-
886
- ## Storage Options
887
-
888
- PAI offers two modes, and the setup wizard asks which you prefer.
889
-
890
- **Simple mode (SQLite)** — Zero dependencies beyond Node. Keyword search only. Great for trying it out or for systems without Docker.
891
-
892
- **Full mode (PostgreSQL + pgvector)** — Adds semantic search and vector embeddings. Finds things by meaning, not just exact words. "How does the reconnection logic work?" finds the right session even if it never used those exact words. Requires Docker.
893
-
894
- ---
895
-
896
- ## Prerequisites
897
-
898
- - [Node.js](https://nodejs.org) 20 or newer (22 from apt works) — the installed `pai` runs on Node
899
- - [Bun](https://bun.sh) — only to build from a git checkout (development)
900
- - [Docker](https://docs.docker.com/get-docker/) — only for full mode
901
- - [Claude Code](https://claude.ai/code)
902
- - macOS or Linux (tmux for worker panes on Linux; iTerm2 on macOS)
903
-
904
- ---
905
-
906
- ## How It Works
907
-
908
- A background service runs quietly alongside your work. Every five minutes it indexes your Claude Code projects and session notes — chunking them, hashing them for change detection, and storing them in a local database. When you ask Claude something about past work, it searches this index by keyword, by meaning, or both, and surfaces the relevant context in seconds.
909
-
910
- Everything runs locally. No cloud. No API keys for the core system.
911
-
912
- For the technical deep-dive — architecture, database schema, CLI reference, and development setup — see [ARCHITECTURE.md](ARCHITECTURE.md).
913
-
914
- ---
915
-
916
- ## Search Intelligence
917
-
918
- PAI doesn't just store your notes — it understands them. Three search modes work together, with reranking and recency boost on by default. All search settings are configurable.
919
-
920
- ### Search Modes
921
-
922
- | Mode | How it works | Best for |
923
- |------|-------------|----------|
924
- | **Keyword** | Full-text search (BM25 via SQLite FTS5) | Exact terms, function names, error messages |
925
- | **Semantic** | Vector similarity (Snowflake Arctic embeddings) | Finding things by meaning, even with different words |
926
- | **Hybrid** | Keyword + semantic combined, scores normalized and blended | General use — the default |
927
-
928
- ### Cross-Encoder Reranking
929
-
930
- Every search automatically runs a second pass: a cross-encoder model reads each (query, result) pair together and re-scores them for relevance. This catches results that keyword or vector search ranked too low.
931
-
932
- ```bash
933
- # Search with reranking (default)
934
- pai memory search "how does session routing work"
935
-
936
- # Skip reranking for faster results
937
- pai memory search "how does session routing work" --no-rerank
938
- ```
939
-
940
- The reranker uses a small local model (~23 MB) that runs entirely on your machine. First use downloads it automatically. No API keys, no cloud calls.
941
-
942
- ### Recency Boost
943
-
944
- Recent content scores higher than older content — on by default with a 90-day half-life. A 3-month-old result retains 50% of its score, a 6-month-old retains 25%, and a year-old retains ~6%.
945
-
946
- ```bash
947
- # Search uses recency boost automatically (90-day half-life from config)
948
- pai memory search "notification system"
949
-
950
- # Override the half-life for this search
951
- pai memory search "notification system" --recency 30
952
-
953
- # Disable recency boost for this search
954
- pai memory search "notification system" --recency 0
955
- ```
956
-
957
- Via MCP, pass `recency_boost: 90` to the `memory_search` tool, or `recency_boost: 0` to disable.
958
-
959
- Recency boost is applied after cross-encoder reranking, so relevance is scored first, then time-weighted. Scores are normalized before decay so the math works correctly regardless of the underlying score scale.
960
-
961
- ### Search Settings
962
-
963
- All search defaults are configurable via `~/.claude/pai/config.json` and can be viewed or changed from the command line.
964
-
965
- ```bash
966
- # View all search settings
967
- pai memory settings
968
-
969
- # View a single setting
970
- pai memory settings recencyBoostDays
971
-
972
- # Change a setting
973
- pai memory settings recencyBoostDays 60
974
- pai memory settings mode hybrid
975
- pai memory settings rerank false
976
- ```
977
-
978
- | Setting | Default | Description |
979
- |---------|---------|-------------|
980
- | `mode` | `keyword` | Default search mode: `keyword`, `semantic`, or `hybrid` |
981
- | `rerank` | `true` | Cross-encoder reranking on by default |
982
- | `recencyBoostDays` | `90` | Recency half-life in days. `0` = off |
983
- | `defaultLimit` | `10` | Default number of results |
984
- | `snippetLength` | `200` | Max characters per snippet in MCP results |
985
-
986
- Settings live in the `search` section of `~/.claude/pai/config.json`. Per-call parameters (CLI flags or MCP tool arguments) always override config defaults.
987
-
988
- ### Using Search from Within Claude
989
-
990
- When PAI is configured as an MCP server, Claude uses the `memory_search` tool automatically. You don't need to call it yourself — just ask Claude naturally and it searches your memory behind the scenes.
991
-
992
- **Example prompts you can give Claude:**
993
-
994
- ```
995
- "Search your memory for authentication"
996
- "What do you know about the database migration?"
997
- "Find where we discussed the notification system"
998
- ```
999
-
1000
- Claude calls `memory_search` with the right parameters based on your config defaults. Reranking and recency boost are both active by default — you don't need to configure anything for good results.
1001
-
1002
- **Overriding defaults for a specific search:**
108
+ The durable way to make Claude Code compact automatically, via `CLAUDE_AUTOCOMPACT_PCT_OVERRIDE`.
1003
109
 
1004
- You can ask Claude to adjust search behavior per-query:
1005
-
1006
- ```
1007
- "Search for authentication using semantic mode"
1008
- → Claude passes mode: "semantic"
1009
-
1010
- "Search for the old logging discussion without recency boost"
1011
- → Claude passes recency_boost: 0
1012
-
1013
- "Search for database schema across all projects with no reranking"
1014
- → Claude passes all_projects: true, rerank: false
1015
- ```
1016
-
1017
- **The `memory_search` MCP tool accepts these parameters:**
1018
-
1019
- | Parameter | Type | Description |
1020
- |-----------|------|-------------|
1021
- | `query` | string | Free-text search query (required) |
1022
- | `project` | string | Scope to one project by slug |
1023
- | `all_projects` | boolean | Explicitly search all projects |
1024
- | `sources` | array | Restrict to `"memory"` or `"notes"` |
1025
- | `limit` | integer | Max results (1–100, default from config) |
1026
- | `mode` | string | `"keyword"`, `"semantic"`, or `"hybrid"` |
1027
- | `rerank` | boolean | Cross-encoder reranking (default: true from config) |
1028
- | `recency_boost` | integer | Recency half-life in days (0 = off, default from config) |
1029
-
1030
- All parameters except `query` are optional. Omitted values fall back to your `~/.claude/pai/config.json` defaults.
1031
-
1032
- **Changing defaults permanently:**
1033
-
1034
- Tell Claude to change your search settings:
1035
-
1036
- ```
1037
- "Set my default search mode to hybrid"
1038
- "Turn off reranking by default"
1039
- "Change the recency boost to 60 days"
1040
- ```
1041
-
1042
- Claude runs `pai memory settings <key> <value>` to update `~/.claude/pai/config.json`. Changes take effect on the next search — no restart needed.
1043
-
1044
- ---
110
+ → [docs/auto-compact.md](docs/auto-compact.md)
1045
111
 
1046
112
  ## Zettelkasten Intelligence
1047
113
 
1048
- PAI implements Niklas Luhmann's Zettelkasten principles as six computational operations on your Obsidian vault.
1049
-
1050
- ### How it works
1051
-
1052
- PAI indexes your entire vault — following symlinks, deduplicating by inode, parsing every link — and builds a graph database alongside semantic embeddings. Six tools then operate on this dual representation:
114
+ Graph operations over your Obsidian vault: connections, themes, god notes, communities, latent ideas.
1053
115
 
1054
- | Tool | What it does |
1055
- |------|-------------|
1056
- | `pai zettel explore` | Follow trains of thought through link chains (Folgezettel traversal) |
1057
- | `pai zettel surprise` | Find notes that are semantically close but far apart in the link graph |
1058
- | `pai zettel converse` | Ask questions and let the vault "talk back" with unexpected connections |
1059
- | `pai zettel themes` | Detect emerging clusters of related notes across folders |
1060
- | `pai zettel health` | Structural audit — dead links, orphans, disconnected clusters, health score |
1061
- | `pai zettel suggest` | Proactive connection suggestions combining semantic similarity, tags, and graph proximity |
116
+ → [docs/zettelkasten.md](docs/zettelkasten.md)
1062
117
 
1063
- All tools work as CLI commands (`pai zettel <command>`) and MCP tools (`zettel_*`) accessible through the daemon.
1064
-
1065
- ### Vault Indexing
1066
-
1067
- The vault indexer follows symlinks (critical for vaults built on symlinks), deduplicates files by inode to handle multiple paths to the same file, and builds a complete link graph with Obsidian-compatible shortest-match resolution.
118
+ ## How It Works
1068
119
 
1069
- All link types are parsed and resolved:
120
+ Storage options (SQLite or PostgreSQL + pgvector), prerequisites and the indexing loop. Deep dive: [ARCHITECTURE.md](ARCHITECTURE.md).
1070
121
 
1071
- | Syntax | Type | Example |
1072
- |--------|------|---------|
1073
- | `[[Note]]` | Wikilink | `[[Daily Note]]`, `[[Note\|alias]]`, `[[Note#heading]]` |
1074
- | `![[file]]` | Embed | `![[diagram.png]]`, `![[template]]` |
1075
- | `[text](path.md)` | Markdown link | `[see here](notes/idea.md)`, `[ref](note.md#section)` |
1076
- | `![alt](file)` | Markdown embed | `![photo](assets/img.jpg)` |
122
+ → [docs/how-it-works.md](docs/how-it-works.md)
1077
123
 
1078
- External URLs (`https://`, `mailto:`, etc.) are excluded — only relative paths are treated as vault connections. URL-encoded paths (e.g. `my%20note.md`) are decoded automatically.
124
+ ## Use Cases
1079
125
 
1080
- - Full index: ~10 seconds for ~1,000 files
1081
- - Incremental: ~2 seconds (hash-based change detection)
1082
- - Runs automatically via the daemon scheduler
126
+ Solo developer, team lead, researcher: what changes with persistent memory.
1083
127
 
1084
- ---
128
+ → [docs/use-cases.md](docs/use-cases.md)
1085
129
 
1086
130
  ## Release History
1087
131
 
1088
- 31 releases shipped from v0.7.2 to v0.10.0 (March 19 – May 21, 2026):
1089
-
1090
- | Version | Feature |
1091
- |---------|---------|
1092
- | v0.7.2 | Auto-registration, one-note-per-session, Reconstruct skill |
1093
- | v0.7.3 | Automatic AI-powered session notes via daemon |
1094
- | v0.7.4 | Auto-register on parent match |
1095
- | v0.7.5 | Tiered model selection (opus/sonnet/haiku) |
1096
- | v0.7.6 | Find claude binary in launchd |
1097
- | v0.7.7 | Whisper rules hook |
1098
- | v0.7.8 | Strip API key from daemon (prevent billing) |
1099
- | v0.8.0 | Topic-based note splitting |
1100
- | v0.8.1 | /whisper skill, remove hardcoded defaults |
1101
- | v0.8.2 | Reduce topic split sensitivity |
1102
- | v0.8.3 | /consolidate skill |
1103
- | v0.8.4 | Store TOPIC in HTML comment |
1104
- | v0.8.5 | God-note detection, confidence tagging, Louvain communities, query feedback |
1105
- | v0.9.0 | 4-layer wake-up, temporal KG, taxonomy, tunnels, mid-session auto-save |
1106
- | v0.9.1 | KG backfill CLI, shared kg-extraction module |
1107
- | v0.9.2 | Stop-hook first-run safeguard |
1108
- | v0.9.3 | Silence stop-hook diagnostics |
1109
- | v0.9.4 | Remove exit(2) noise |
1110
- | v0.9.5 | Budget-aware advisor mode |
1111
- | v0.9.6 | Statusline auto-writes budget to advisor |
1112
- | v0.9.7 | Advisor mode label in statusline, natural language mode switching |
1113
- | v0.9.8 | Privacy tags, compact search format, npx install |
1114
- | v0.9.9 | Fix advisor mode to delegate to haiku instead of hoarding in opus |
1115
- | v0.9.10 | Cognee-inspired three-tier memory: entity deduplication, graph-completion search, feedback EMA |
1116
- | v0.9.11 | Session-commands hook for truncation resilience |
1117
- | v0.9.12 | Dispatcher uses openFederation directly for kg_search/feedback |
1118
- | v0.9.13 | Emit chunk IDs in memory_search output |
1119
- | v0.9.14 | AIBroker live-session integration: `pai sessions` shows live iTerm2 panes |
1120
- | v0.9.15 | `pai pause all`: pause every live Claude session at once via AIBroker |
1121
- | v0.9.16 | createHash import fix, registry scan clc fallback map |
1122
- | v0.9.17 | Switch live-session listing to `sessions` IPC (metadata-only, faster); `--all-tabs` flag |
1123
- | v0.9.18 | `pai projects`: moved-project auto-detect, rebind command, active-only default listing |
1124
- | v0.10.0 | Topic-first redesign: `pai <topic>` universal resolver, history search, sticky tab titles |
1125
- | v0.10.1 | `pai sessions clear-names` recovery command |
1126
- | v0.11.0 | Deduped session listing + universal `pai <name>` (switch / resume / fresh) |
1127
- | v0.12.0 | Interactive picker: `pai` opens a modal search-and-act selector over projects + sessions (g go · n new · c cd · f finder · d remove); note-keyword filtering; quoted exit-dir path |
1128
-
1129
- ---
132
+ → [docs/release-history.md](docs/release-history.md) · [CHANGELOG.md](CHANGELOG.md)
1130
133
 
1131
134
  ## Companion Projects
1132
135
 
1133
- PAI works great alongside these tools (also by the same author):
136
+ AIBroker, Whazaa, Telex, Coogle and DEVONthink MCP.
1134
137
 
1135
- - **[AIBroker](https://github.com/mnott/AIBroker)** — Unified message bridge for Claude Code (WhatsApp, Telegram, PAILot — text and voice routing)
1136
- - **[Whazaa](https://github.com/mnott/Whazaa)** — WhatsApp bridge for Claude Code (voice notes, screenshots, session routing)
1137
- - **[Telex](https://github.com/mnott/Telex)** — Telegram bridge for Claude Code (text and voice messaging)
1138
- - **[Coogle](https://github.com/mnott/Coogle)** — Google Workspace MCP daemon (Gmail, Calendar, Drive multiplexing)
1139
- - **[DEVONthink MCP](https://github.com/mnott/devonthink-mcp)** — DEVONthink integration for document search and archival
1140
-
1141
- ---
138
+ → [docs/companion-projects.md](docs/companion-projects.md)
1142
139
 
1143
140
  ## Acknowledgments
1144
141
 
@@ -1150,8 +147,6 @@ The three-store hybrid memory architecture — combining SQLite/PostgreSQL chunk
1150
147
 
1151
148
  Section-aware retrieval (heading paths on chunks, `memory_outline`) borrows from [PageIndex](https://github.com/VectifyAI/PageIndex) by [VectifyAI](https://github.com/VectifyAI), which retrieves from long documents by navigating a heading tree rather than by similarity alone. PAI keeps its keyword, vector and graph search and adds the tree as structure the model can navigate, without an LLM call per query.
1152
149
 
1153
- ---
1154
-
1155
150
  ## License
1156
151
 
1157
152
  MIT