@tekmidian/pai 0.64.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.
- package/README.md +60 -1051
- package/dist/{aibroker-client-BpfuGPe5.mjs → aibroker-client-B8c42Lh8.mjs} +1 -1
- package/dist/{aibroker-client-DRld7g6z.mjs → aibroker-client-C5Fw7DNz.mjs} +10 -4
- package/dist/{aibroker-client-DRld7g6z.mjs.map → aibroker-client-C5Fw7DNz.mjs.map} +1 -1
- package/dist/{async-CY_cd_8j.mjs → async-CNn36gm4.mjs} +2 -2
- package/dist/{async-CY_cd_8j.mjs.map → async-CNn36gm4.mjs.map} +1 -1
- package/dist/{auto-route-CPlam4iv.mjs → auto-route-sLMU-NnM.mjs} +2 -2
- package/dist/{auto-route-CPlam4iv.mjs.map → auto-route-sLMU-NnM.mjs.map} +1 -1
- package/dist/{chain-o-g8AgE3.mjs → chain-CLb6hbFS.mjs} +4 -4
- package/dist/{chain-o-g8AgE3.mjs.map → chain-CLb6hbFS.mjs.map} +1 -1
- package/dist/cli/index.mjs +19 -19
- package/dist/cli/program.d.mts.map +1 -1
- package/dist/cli/program.mjs +19 -19
- package/dist/{clusters-DsMf20PP.mjs → clusters-PgIUYT_v.mjs} +1 -1
- package/dist/{clusters-DsMf20PP.mjs.map → clusters-PgIUYT_v.mjs.map} +1 -1
- package/dist/{config-2wkz744W.mjs → config-BbLFD7Uf.mjs} +3 -3
- package/dist/config-BbLFD7Uf.mjs.map +1 -0
- package/dist/{config-CUTg6VDq.mjs → config-YinjgXEJ.mjs} +1 -1
- package/dist/{context-handover-cache-BOpjLsKe.mjs → context-handover-cache-mGxq2-8f.mjs} +11 -29
- package/dist/context-handover-cache-mGxq2-8f.mjs.map +1 -0
- package/dist/daemon/index.mjs +16 -16
- package/dist/daemon-BjaPR39W.mjs +19 -0
- package/dist/{daemon-BYieXduQ.mjs → daemon-DqCB3fO-.mjs} +30 -30
- package/dist/{daemon-BYieXduQ.mjs.map → daemon-DqCB3fO-.mjs.map} +1 -1
- package/dist/daemon-mcp/index.mjs +18 -18
- package/dist/daemon-mcp/index.mjs.map +1 -1
- package/dist/detector-C3Q7mxQU.mjs +3 -0
- package/dist/{detector-BAlmrLQ0.mjs → detector-CIHEXKsV.mjs} +1 -1
- package/dist/{detector-BAlmrLQ0.mjs.map → detector-CIHEXKsV.mjs.map} +1 -1
- package/dist/{embeddings-DK9XfQic.mjs → embeddings-BbNVXa_0.mjs} +1 -1
- package/dist/{embeddings-DK9XfQic.mjs.map → embeddings-BbNVXa_0.mjs.map} +1 -1
- package/dist/{embeddings-Xg8XLf2K.mjs → embeddings-CDfM63uC.mjs} +1 -1
- package/dist/{factory-BMK0tC1b.mjs → factory-CaswxuJ0.mjs} +1 -1
- package/dist/{factory-C4We3xR_.mjs → factory-y36qGegI.mjs} +13 -13
- package/dist/{factory-C4We3xR_.mjs.map → factory-y36qGegI.mjs.map} +1 -1
- package/dist/{fallback-ECiqCuh6.mjs → fallback-CupzGkuJ.mjs} +1205 -1204
- package/dist/fallback-CupzGkuJ.mjs.map +1 -0
- package/dist/{federation-db-CUgy0WYs.mjs → federation-db-BTyoufBh.mjs} +2 -2
- package/dist/{federation-db-CUgy0WYs.mjs.map → federation-db-BTyoufBh.mjs.map} +1 -1
- package/dist/federation-db-HfIFc7FG.mjs +3 -0
- package/dist/hooks/block-sleep-poll.mjs +36 -11
- package/dist/hooks/block-sleep-poll.mjs.map +2 -2
- package/dist/hooks/capture-all-events.mjs +3 -17
- package/dist/hooks/capture-all-events.mjs.map +3 -3
- package/dist/hooks/capture-session-summary.mjs +3 -17
- package/dist/hooks/capture-session-summary.mjs.map +3 -3
- package/dist/hooks/capture-tool-output.mjs +3 -17
- package/dist/hooks/capture-tool-output.mjs.map +3 -3
- package/dist/hooks/cleanup-session-files.mjs +3 -17
- package/dist/hooks/cleanup-session-files.mjs.map +2 -2
- package/dist/hooks/context-compression-hook.mjs +3 -17
- package/dist/hooks/context-compression-hook.mjs.map +3 -3
- package/dist/hooks/initialize-session.mjs +3 -17
- package/dist/hooks/initialize-session.mjs.map +2 -2
- package/dist/hooks/inject-observations.mjs +3 -17
- package/dist/hooks/inject-observations.mjs.map +2 -2
- package/dist/hooks/load-core-context.mjs +4 -22
- package/dist/hooks/load-core-context.mjs.map +2 -2
- package/dist/hooks/load-project-context.mjs +3 -17
- package/dist/hooks/load-project-context.mjs.map +3 -3
- package/dist/hooks/mcp-deferred-gate.mjs +3 -17
- package/dist/hooks/mcp-deferred-gate.mjs.map +2 -2
- package/dist/hooks/observe.mjs +3 -17
- package/dist/hooks/observe.mjs.map +2 -2
- package/dist/hooks/post-compact-inject.mjs.map +1 -1
- package/dist/hooks/route-agents-to-worker.mjs.map +1 -1
- package/dist/hooks/security-validator.mjs +5 -19
- package/dist/hooks/security-validator.mjs.map +3 -3
- package/dist/hooks/stop-hook.mjs +3 -17
- package/dist/hooks/stop-hook.mjs.map +3 -3
- package/dist/hooks/sync-todo-to-md.mjs +3 -17
- package/dist/hooks/sync-todo-to-md.mjs.map +2 -2
- package/dist/hooks/whisper-rules.mjs.map +1 -1
- package/dist/hooks/worker-guard.mjs.map +2 -2
- package/dist/hooks/worker-proxy.mjs.map +1 -1
- package/dist/hooks/worker-status-line.mjs +4 -4
- package/dist/hooks/worker-status-line.mjs.map +2 -2
- package/dist/hooks/worker-supervision.mjs.map +1 -1
- package/dist/{indexer-backend-CJ0RGgMz.mjs → indexer-backend-Cnc7Tf5C.mjs} +2 -2
- package/dist/{ipc-client-EhWY8XL0.mjs → ipc-client-D16Xw6Uo.mjs} +2 -2
- package/dist/{ipc-client-EhWY8XL0.mjs.map → ipc-client-D16Xw6Uo.mjs.map} +1 -1
- package/dist/{kg-entity-1uqCnk4u.mjs → kg-entity-COTUj1ZC.mjs} +1 -1
- package/dist/{kg-entity-1uqCnk4u.mjs.map → kg-entity-COTUj1ZC.mjs.map} +1 -1
- package/dist/{latent-ideas-CSuKfiq3.mjs → latent-ideas-ByvMjVcb.mjs} +3 -3
- package/dist/{latent-ideas-CSuKfiq3.mjs.map → latent-ideas-ByvMjVcb.mjs.map} +1 -1
- package/dist/{link-boost-BtjzfE3c.mjs → link-boost-UiE-uooT.mjs} +1 -1
- package/dist/{link-boost-BtjzfE3c.mjs.map → link-boost-UiE-uooT.mjs.map} +1 -1
- package/dist/{main-resolver-DyOrwNYw.mjs → main-resolver-BeYWNzrt.mjs} +11 -11
- package/dist/{main-resolver-DyOrwNYw.mjs.map → main-resolver-BeYWNzrt.mjs.map} +1 -1
- package/dist/main-resolver-kHW6FewU.mjs +7 -0
- package/dist/merge-2gqRPFu2.mjs +3 -0
- package/dist/{merge-D58n_-LZ.mjs → merge-DgU9OgZy.mjs} +1 -1
- package/dist/{merge-D58n_-LZ.mjs.map → merge-DgU9OgZy.mjs.map} +1 -1
- package/dist/module-paths-DdRzbkUI.mjs +44 -0
- package/dist/module-paths-DdRzbkUI.mjs.map +1 -0
- package/dist/{neighborhood-DNuRelRB.mjs → neighborhood-CvRHlqdR.mjs} +2 -2
- package/dist/{neighborhood-DNuRelRB.mjs.map → neighborhood-CvRHlqdR.mjs.map} +1 -1
- package/dist/{note-context-D9JZ4-7o.mjs → note-context-BrbfUIoP.mjs} +1 -1
- package/dist/{note-context-D9JZ4-7o.mjs.map → note-context-BrbfUIoP.mjs.map} +1 -1
- package/dist/{pai-home-UncxWxlX.mjs → pai-home-Cm9rcJgX.mjs} +1 -1
- package/dist/{pai-home-UncxWxlX.mjs.map → pai-home-Cm9rcJgX.mjs.map} +1 -1
- package/dist/{planner-DgC3oSvb.mjs → planner-DAq4Yx-H.mjs} +7 -7
- package/dist/{planner-DgC3oSvb.mjs.map → planner-DAq4Yx-H.mjs.map} +1 -1
- package/dist/{postgres-CcsRKir-.mjs → postgres-DYtZg7J7.mjs} +5 -13
- package/dist/{postgres-CcsRKir-.mjs.map → postgres-DYtZg7J7.mjs.map} +1 -1
- package/dist/{program-JhF2GgJY.mjs → program-CWf9mT7Z.mjs} +262 -260
- package/dist/program-CWf9mT7Z.mjs.map +1 -0
- package/dist/{query-feedback-BPa0dISE.mjs → query-feedback-BIaZTTFO.mjs} +2 -2
- package/dist/{query-feedback-BPa0dISE.mjs.map → query-feedback-BIaZTTFO.mjs.map} +1 -1
- package/dist/query-feedback-B_iigYj-.mjs +3 -0
- package/dist/{registry-db-DCzdI4sC.mjs → registry-db-C7voqML9.mjs} +2 -2
- package/dist/{registry-db-DCzdI4sC.mjs.map → registry-db-C7voqML9.mjs.map} +1 -1
- package/dist/registry-db-JHPhA8vF.mjs +3 -0
- package/dist/{registry-postgres-BUnkHKYs.mjs → registry-postgres-DSrkxqfF.mjs} +2 -2
- package/dist/{registry-postgres-BUnkHKYs.mjs.map → registry-postgres-DSrkxqfF.mjs.map} +1 -1
- package/dist/{registry-sqlite-CKYNwkUv.mjs → registry-sqlite-B2436JgX.mjs} +2 -2
- package/dist/{registry-sqlite-CKYNwkUv.mjs.map → registry-sqlite-B2436JgX.mjs.map} +1 -1
- package/dist/router-S6C5BxzZ.mjs +3 -0
- package/dist/{router-CGZATlvm.mjs → router-aqLMvNMg.mjs} +1 -1
- package/dist/{router-CGZATlvm.mjs.map → router-aqLMvNMg.mjs.map} +1 -1
- package/dist/{run-env-Br4Bc7Vz.mjs → run-env-BHWnXqle.mjs} +3 -3
- package/dist/{run-env-Br4Bc7Vz.mjs.map → run-env-BHWnXqle.mjs.map} +1 -1
- package/dist/{run-W2rV_9j0.mjs → run-uAkNItb6.mjs} +140 -44
- package/dist/run-uAkNItb6.mjs.map +1 -0
- package/dist/{runtime-paths-QGQJAekd.mjs → runtime-paths-CHTg3ywb.mjs} +1 -1
- package/dist/{runtime-paths-QGQJAekd.mjs.map → runtime-paths-CHTg3ywb.mjs.map} +1 -1
- package/dist/{server-B71rem4q.mjs → server-DlL1QI2k.mjs} +4 -5
- package/dist/server-DlL1QI2k.mjs.map +1 -0
- package/dist/{session-keepalive-Dgil9hjw.mjs → session-keepalive-BWEjcRrh.mjs} +7 -7
- package/dist/{session-keepalive-Dgil9hjw.mjs.map → session-keepalive-BWEjcRrh.mjs.map} +1 -1
- package/dist/skills/Art/SKILL.md +1 -1
- package/dist/skills/Observability/SKILL.md +4 -4
- package/dist/skills/Research/SKILL.md +1 -1
- package/dist/skills/Tasks/SKILL.md +1 -1
- package/dist/{sources-LcGptLA-.mjs → sources-DX4ElmrE.mjs} +1 -1
- package/dist/{sources-LcGptLA-.mjs.map → sources-DX4ElmrE.mjs.map} +1 -1
- package/dist/{sqlite-CAJcw2zL.mjs → sqlite-BrEu3avy.mjs} +3 -3
- package/dist/{sqlite-CAJcw2zL.mjs.map → sqlite-BrEu3avy.mjs.map} +1 -1
- package/dist/{state-S9wlKarB.mjs → state-DW8zdweW.mjs} +1 -1
- package/dist/{state-CHltNjXI.mjs → state-HyjqTihC.mjs} +1 -1
- package/dist/{state-CHltNjXI.mjs.map → state-HyjqTihC.mjs.map} +1 -1
- package/dist/{themes-D1FQFthd.mjs → themes-BgqahYVM.mjs} +2 -2
- package/dist/{themes-D1FQFthd.mjs.map → themes-BgqahYVM.mjs.map} +1 -1
- package/dist/{tools-BW7OXf-N.mjs → tools-BbqQIHPe.mjs} +4 -4
- package/dist/{tools-BFC-113F.mjs → tools-gMGDIpJ9.mjs} +18 -18
- package/dist/{tools-BFC-113F.mjs.map → tools-gMGDIpJ9.mjs.map} +1 -1
- package/dist/{trace-IDKK1VFs.mjs → trace-CmAB7iJZ.mjs} +1 -1
- package/dist/{trace-IDKK1VFs.mjs.map → trace-CmAB7iJZ.mjs.map} +1 -1
- package/dist/{vault-indexer-y6YC2-mh.mjs → vault-indexer-Ddq51X20.mjs} +1 -1
- package/dist/{vault-indexer-y6YC2-mh.mjs.map → vault-indexer-Ddq51X20.mjs.map} +1 -1
- package/dist/{wakeup-CNZQZzsY.mjs → wakeup-CZw88uXf.mjs} +3 -3
- package/dist/{wakeup-CNZQZzsY.mjs.map → wakeup-CZw88uXf.mjs.map} +1 -1
- package/dist/{work-queue-worker-Dy5FT2ak.mjs → work-queue-worker-DCzfH0d1.mjs} +4 -4
- package/dist/{work-queue-worker-Dy5FT2ak.mjs.map → work-queue-worker-DCzfH0d1.mjs.map} +1 -1
- package/dist/work-queue-worker-Taba_vcA.mjs +11 -0
- package/dist/{zettelkasten-Dx-63BEk.mjs → zettelkasten-Dwj67e4p.mjs} +4 -4
- package/dist/{zettelkasten-Dx-63BEk.mjs.map → zettelkasten-Dwj67e4p.mjs.map} +1 -1
- package/docker/docker-compose.yml +39 -0
- package/docs/auto-compact.md +31 -0
- package/docs/budget-advisor.md +48 -0
- package/docs/command-reference.md +25 -0
- package/docs/commands/README.md +3 -3
- package/docs/commands/config.md +3 -3
- package/docs/commands/setup.md +9 -2
- package/docs/commands/worker.md +2 -2
- package/docs/companion-projects.md +9 -0
- package/docs/context-preservation.md +43 -0
- package/docs/how-it-works.md +25 -0
- package/docs/install-linux.md +32 -0
- package/docs/install.md +56 -0
- package/docs/memory.md +96 -0
- package/docs/observations.md +58 -0
- package/docs/release-history.md +42 -0
- package/docs/rules-and-privacy.md +37 -0
- package/docs/search.md +169 -0
- package/docs/session-management.md +153 -0
- package/docs/session-notes.md +64 -0
- package/docs/skills.md +45 -0
- package/docs/task-bus.md +1 -2
- package/docs/use-cases.md +194 -0
- package/docs/what-you-can-ask.md +78 -0
- package/docs/worker-providers.md +58 -0
- package/docs/zettelkasten.md +37 -0
- package/package.json +3 -2
- package/plugins/productivity/skills/Tasks/SKILL.md +1 -1
- package/scripts/build-hooks.mjs +6 -6
- package/src/hooks/ts/lib/pai-paths-case.test.ts +12 -0
- package/src/hooks/ts/lib/pai-paths-import.test.ts +25 -0
- package/src/hooks/ts/lib/pai-paths.ts +5 -28
- package/src/hooks/ts/lib/sleep-poll-gate.test.ts +17 -1
- package/src/hooks/ts/lib/sleep-poll-gate.ts +21 -9
- package/src/hooks/ts/pre-tool-use/security-validator.test.ts +23 -0
- package/src/hooks/ts/pre-tool-use/security-validator.ts +1 -1
- package/src/hooks/ts/session-start/load-core-context.ts +2 -6
- package/src/hooks/ts/session-start/load-project-context.ts +1 -1
- package/src/hooks/ts/session-start/session-start-worker-guard.test.ts +24 -1
- package/dist/config-2wkz744W.mjs.map +0 -1
- package/dist/context-handover-cache-BOpjLsKe.mjs.map +0 -1
- package/dist/daemon-q3xjHwa4.mjs +0 -19
- package/dist/detector-C-YmZsOi.mjs +0 -3
- package/dist/fallback-ECiqCuh6.mjs.map +0 -1
- package/dist/federation-db-BZ8PyxFe.mjs +0 -3
- package/dist/main-resolver-vN09bkXv.mjs +0 -7
- package/dist/merge-CXGz5wXz.mjs +0 -3
- package/dist/program-JhF2GgJY.mjs.map +0 -1
- package/dist/query-feedback-BPHFFSu1.mjs +0 -3
- package/dist/registry-db-Hphlj3H4.mjs +0 -3
- package/dist/router-CoA8Uy1m.mjs +0 -3
- package/dist/run-W2rV_9j0.mjs.map +0 -1
- package/dist/server-B71rem4q.mjs.map +0 -1
- package/dist/work-queue-worker-CkShUa0z.mjs +0 -11
- /package/dist/{indexer-backend-DotpxHJd.mjs → indexer-backend-isSLg6yE.mjs} +0 -0
package/docs/commands/setup.md
CHANGED
|
@@ -2,16 +2,23 @@
|
|
|
2
2
|
|
|
3
3
|
# pai setup
|
|
4
4
|
|
|
5
|
-
>
|
|
5
|
+
> Setup wizard — configure storage, embeddings, agent config, and indexing (--yes for unattended)
|
|
6
6
|
|
|
7
7
|
**Aliases:** `install`
|
|
8
8
|
|
|
9
9
|
## Synopsis
|
|
10
10
|
|
|
11
11
|
```
|
|
12
|
-
pai setup
|
|
12
|
+
pai setup [options]
|
|
13
13
|
```
|
|
14
14
|
|
|
15
|
+
## Options
|
|
16
|
+
|
|
17
|
+
| Option | Description | Default |
|
|
18
|
+
|--------|-------------|---------|
|
|
19
|
+
| `-y, --yes` | Unattended: take every default, read no input | |
|
|
20
|
+
| `--storage <backend>` | Storage backend: sqlite \| postgres (default under --yes: sqlite unless local Postgres answers) | |
|
|
21
|
+
|
|
15
22
|
## See also
|
|
16
23
|
|
|
17
24
|
[`pai audit`](audit.md) · [`pai backup`](backup.md) · [`pai clear-names`](clear-names.md) · [`pai config`](config.md) · [`pai daemon`](daemon.md) · [`pai db`](db.md) · [`pai end`](end.md) · [`pai help`](help.md) · [`pai hooks-db`](hooks-db.md) · [`pai identity`](identity.md) · [`pai kg`](kg.md) · [`pai launch`](launch.md) · [`pai mcp`](mcp.md) · [`pai memory`](memory.md) · [`pai notify`](notify.md) · [`pai observation`](observation.md) · [`pai obsidian`](obsidian.md) · [`pai pause`](pause.md) · [`pai project`](project.md) · [`pai projects`](projects.md) · [`pai registry`](registry.md) · [`pai restore`](restore.md) · [`pai session`](session.md) · [`pai sessions`](sessions.md) · [`pai shell-init`](shell-init.md) · [`pai skill`](skill.md) · [`pai task`](task.md) · [`pai topic`](topic.md) · [`pai update`](update.md) · [`pai worker`](worker.md) · [`pai zettel`](zettel.md)
|
package/docs/commands/worker.md
CHANGED
|
@@ -24,7 +24,7 @@ pai worker <subcommand> [options]
|
|
|
24
24
|
| [`pai worker follow [id]`](#pai-worker-follow-id) | Live transcript of one worker, or of this session's running workers |
|
|
25
25
|
| [`pai worker replay <id>`](#pai-worker-replay-id) | Print the transcript of one finished or running worker |
|
|
26
26
|
| [`pai worker watch`](#pai-worker-watch) | ps refreshed every 2 seconds (plain `watch`, colors kept) |
|
|
27
|
-
| [`pai worker pane [id]`](#pai-worker-pane-id) | Open the follow pane for a worker (
|
|
27
|
+
| [`pai worker pane [id]`](#pai-worker-pane-id) | Open the follow pane for a worker (tmux split when $TMUX is set, else iTerm2 on macOS, else prints the follow command) |
|
|
28
28
|
| [`pai worker log [what]`](#pai-worker-log-what) | all = ledger, tail = last ledger lines, <id> = raw event stream, none = list |
|
|
29
29
|
| [`pai worker say <id> <text>`](#pai-worker-say-id-text) | Send one message to a running worker (forwarded to its open stdin) |
|
|
30
30
|
| [`pai worker goal <id> <text>`](#pai-worker-goal-id-text) | Relabel a running worker (its ps / pane goal) without sending it a message |
|
|
@@ -164,7 +164,7 @@ ps refreshed every 2 seconds (plain `watch`, colors kept)
|
|
|
164
164
|
|
|
165
165
|
### pai worker pane [id]
|
|
166
166
|
|
|
167
|
-
Open the follow pane for a worker (
|
|
167
|
+
Open the follow pane for a worker (tmux split when $TMUX is set, else iTerm2 on macOS, else prints the follow command)
|
|
168
168
|
|
|
169
169
|
**Arguments**
|
|
170
170
|
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
# Companion Projects
|
|
2
|
+
|
|
3
|
+
PAI works great alongside these tools (also by the same author):
|
|
4
|
+
|
|
5
|
+
- **[AIBroker](https://github.com/mnott/AIBroker)** — Unified message bridge for Claude Code (WhatsApp, Telegram, PAILot — text and voice routing)
|
|
6
|
+
- **[Whazaa](https://github.com/mnott/Whazaa)** — WhatsApp bridge for Claude Code (voice notes, screenshots, session routing)
|
|
7
|
+
- **[Telex](https://github.com/mnott/Telex)** — Telegram bridge for Claude Code (text and voice messaging)
|
|
8
|
+
- **[Coogle](https://github.com/mnott/Coogle)** — Google Workspace MCP daemon (Gmail, Calendar, Drive multiplexing)
|
|
9
|
+
- **[DEVONthink MCP](https://github.com/mnott/devonthink-mcp)** — DEVONthink integration for document search and archival
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# Context Preservation
|
|
2
|
+
|
|
3
|
+
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.
|
|
4
|
+
|
|
5
|
+
PAI intercepts this compression with a two-stage relay:
|
|
6
|
+
|
|
7
|
+
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.
|
|
8
|
+
|
|
9
|
+
2. **After compression** — PAI reads that checkpoint and injects it back into Claude's fresh context. Claude picks up exactly where it left off.
|
|
10
|
+
|
|
11
|
+
This happens automatically. You don't need to do anything — just keep working, and PAI handles the continuity.
|
|
12
|
+
|
|
13
|
+
## What Gets Preserved
|
|
14
|
+
|
|
15
|
+
- Your last 3 requests (so Claude knows what you were asking)
|
|
16
|
+
- Work summaries and captured context
|
|
17
|
+
- Files modified during the session
|
|
18
|
+
- Current working directory and task state
|
|
19
|
+
- Session note checkpoints (persistent — survive even full restarts)
|
|
20
|
+
|
|
21
|
+
## Surviving a Restart, and Surviving a Crash
|
|
22
|
+
|
|
23
|
+
Compaction continuity above is one path. Closing the session and opening a new one is another, and it works differently:
|
|
24
|
+
|
|
25
|
+
- **`## 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.
|
|
26
|
+
- **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.
|
|
27
|
+
- **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.
|
|
28
|
+
|
|
29
|
+
## Session Lifecycle Hooks
|
|
30
|
+
|
|
31
|
+
PAI runs hooks at every stage of a Claude Code session:
|
|
32
|
+
|
|
33
|
+
| Event | What PAI Does |
|
|
34
|
+
|-------|--------------|
|
|
35
|
+
| **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 |
|
|
36
|
+
| **User Prompt** | Cleans up temp files, updates terminal tab titles, injects whisper rules and advisor mode guidance, refreshes the rolling autosave checkpoint |
|
|
37
|
+
| **Pre-Compact** | Saves session state checkpoint, pushes `session-summary` work item to daemon, sends notification |
|
|
38
|
+
| **Post-Compact** | Injects preserved state back into Claude's context |
|
|
39
|
+
| **Tool Use** | Classifies tool calls into structured observations (decision/bugfix/feature/refactor/discovery/change), refreshes the rolling autosave checkpoint (rate-limited) |
|
|
40
|
+
| **Session End** | Pushes `session-summary` work item to daemon for AI-powered note generation |
|
|
41
|
+
| **Stop** | Pushes `session-summary` work item to daemon, sends notification |
|
|
42
|
+
|
|
43
|
+
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.
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# How It Works
|
|
2
|
+
|
|
3
|
+
## How It Works
|
|
4
|
+
|
|
5
|
+
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.
|
|
6
|
+
|
|
7
|
+
Everything runs locally. No cloud. No API keys for the core system.
|
|
8
|
+
|
|
9
|
+
For the technical deep-dive — architecture, database schema, CLI reference, and development setup — see [ARCHITECTURE.md](../ARCHITECTURE.md).
|
|
10
|
+
|
|
11
|
+
## Storage Options
|
|
12
|
+
|
|
13
|
+
PAI offers two modes, and the setup wizard asks which you prefer.
|
|
14
|
+
|
|
15
|
+
**Simple mode (SQLite)** — Zero dependencies beyond Node. Keyword search only. Great for trying it out or for systems without Docker.
|
|
16
|
+
|
|
17
|
+
**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.
|
|
18
|
+
|
|
19
|
+
## Prerequisites
|
|
20
|
+
|
|
21
|
+
- [Node.js](https://nodejs.org) 20 or newer (22 from apt works) — the installed `pai` runs on Node
|
|
22
|
+
- [Bun](https://bun.sh) — only to build from a git checkout (development)
|
|
23
|
+
- [Docker](https://docs.docker.com/get-docker/) — only for full mode
|
|
24
|
+
- [Claude Code](https://claude.ai/code)
|
|
25
|
+
- macOS or Linux (tmux for worker panes on Linux; iTerm2 on macOS)
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# Linux, from zero (Ubuntu)
|
|
2
|
+
|
|
3
|
+
Both paths below were run end to end on a fresh Ubuntu 26.04 (arm64) install: setup, daemon, statusline in Claude Code, and a real `pai worker run`.
|
|
4
|
+
|
|
5
|
+
Prerequisite: Claude Code installed.
|
|
6
|
+
|
|
7
|
+
Common start:
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
sudo apt install -y nodejs npm tmux
|
|
11
|
+
npm config set prefix ~/.npm-global && export PATH="$HOME/.npm-global/bin:$PATH" # global npm installs without sudo
|
|
12
|
+
npm i -g @tekmidian/pai
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
**Keyword search only (SQLite, no Docker):**
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
pai setup --yes --storage sqlite
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
**Keyword and semantic search (PostgreSQL + pgvector in Docker):**
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
sudo apt install -y docker.io docker-compose-v2
|
|
25
|
+
sudo usermod -aG docker "$USER" # then log out and in, or prefix the next command with: sg docker -c "…"
|
|
26
|
+
export PAI_PG_SHARED_BUFFERS=256MB # only on small machines; the default 1GB must fit in RAM
|
|
27
|
+
pai setup --yes --storage postgres
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
Setup starts the `pai-pgvector` container itself (`pgvector/pgvector:pg17`, bound to 127.0.0.1:5432, data in `~/.pai/pgdata`). The daemon waits for the database, so the first start of the container can take its time.
|
|
31
|
+
|
|
32
|
+
Either way, setup skips macOS-only steps, installs the daemon as a systemd user unit, and turns workers on with the built-in `anthropic` provider. Inside tmux, `pai worker run` opens its follow pane as a tmux split; elsewhere use `pai worker follow <id>`. Setup also enables systemd linger itself so the daemon survives logout, and prints the `sudo loginctl enable-linger` command if the system does not allow it. Where systemd is absent (containers), run the daemon with `pai daemon serve`.
|
package/docs/install.md
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# Install
|
|
2
|
+
|
|
3
|
+
## Quick Start
|
|
4
|
+
|
|
5
|
+
Tell Claude Code:
|
|
6
|
+
|
|
7
|
+
> Clone https://github.com/mnott/PAI and set it up for me
|
|
8
|
+
|
|
9
|
+
Or install with a single command:
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
npx @tekmidian/pai install
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
Or manually:
|
|
16
|
+
|
|
17
|
+
### 1. Install
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
git clone https://github.com/mnott/PAI
|
|
21
|
+
cd PAI
|
|
22
|
+
bun install
|
|
23
|
+
bun run build
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
### 2. Run the setup wizard
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
pai setup # interactive
|
|
30
|
+
pai setup --yes # unattended: every prompt takes its default
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
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.
|
|
34
|
+
|
|
35
|
+
On Linux, follow [Linux, from zero (Ubuntu)](install-linux.md): it covers the native Claude installer, both storage paths (SQLite, PostgreSQL + pgvector in Docker) and the systemd daemon.
|
|
36
|
+
|
|
37
|
+
### 3. The daemon
|
|
38
|
+
|
|
39
|
+
Setup installs and starts it. To manage it:
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
pai daemon status # running? which storage?
|
|
43
|
+
pai daemon restart
|
|
44
|
+
pai daemon install # re-create the launchd (macOS) or systemd (Linux) service
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
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.
|
|
48
|
+
|
|
49
|
+
### 4. Verify
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
pai daemon status # should show "running"
|
|
53
|
+
pai memory search "test" # should return results after indexing
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
That's it. Claude Code now has persistent memory across all sessions.
|
package/docs/memory.md
ADDED
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
# Memory
|
|
2
|
+
|
|
3
|
+
## Progressive Memory Loading
|
|
4
|
+
|
|
5
|
+
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.
|
|
6
|
+
|
|
7
|
+
### The Four Layers
|
|
8
|
+
|
|
9
|
+
| Layer | What it loads | When |
|
|
10
|
+
|-------|---------------|------|
|
|
11
|
+
| **L0 — Identity** | Your identity file (`~/.pai/identity.txt`) — who you are, your working style, key preferences | Always, at every session start |
|
|
12
|
+
| **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 |
|
|
13
|
+
| **L2 — Topic queries** | On-demand retrieval for the current topic — fetched when a specific question or task is identified | On demand, during the session |
|
|
14
|
+
| **L3 — Deep search** | Full `memory_search` across all indexed content — for when L2 is not enough | On demand, when explicitly needed |
|
|
15
|
+
|
|
16
|
+
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.
|
|
17
|
+
|
|
18
|
+
### Configuring Your Identity File
|
|
19
|
+
|
|
20
|
+
Create `~/.pai/identity.txt` with a short description of yourself and your working style. Claude will see this at every session start. Example:
|
|
21
|
+
|
|
22
|
+
```
|
|
23
|
+
Principal engineer. Work across TypeScript, Dart, and shell scripting.
|
|
24
|
+
Projects: PAI (AI infrastructure), RingsADay (Flutter app), Scribe (MCP server).
|
|
25
|
+
Prefer concise explanations, hate unnecessary hedging.
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## Advanced Memory Tools
|
|
29
|
+
|
|
30
|
+
### Temporal Knowledge Graph
|
|
31
|
+
|
|
32
|
+
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.
|
|
33
|
+
|
|
34
|
+
Four MCP tools cover the full lifecycle:
|
|
35
|
+
|
|
36
|
+
- `kg_add` — Add a fact with a start date (and optional end date)
|
|
37
|
+
- `kg_query` — Query the graph, filtered to facts valid at a given point in time
|
|
38
|
+
- `kg_invalidate` — Mark a fact as no longer true (sets `valid_to`)
|
|
39
|
+
- `kg_contradictions` — Surface facts that directly contradict each other, using predicate inversion rules
|
|
40
|
+
|
|
41
|
+
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.
|
|
42
|
+
|
|
43
|
+
### Memory Taxonomy
|
|
44
|
+
|
|
45
|
+
`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).
|
|
46
|
+
|
|
47
|
+
### Cross-Project Tunnels
|
|
48
|
+
|
|
49
|
+
`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.
|
|
50
|
+
|
|
51
|
+
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.
|
|
52
|
+
|
|
53
|
+
## Memory Architecture
|
|
54
|
+
|
|
55
|
+
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.
|
|
56
|
+
|
|
57
|
+
### Three-Tier Hybrid Store
|
|
58
|
+
|
|
59
|
+
| Tier | Backend | What it stores |
|
|
60
|
+
|------|---------|----------------|
|
|
61
|
+
| **Chunks + entities** | SQLite (simple mode) or PostgreSQL (full mode) | Text chunks with embeddings; named entity records with content-address hashes |
|
|
62
|
+
| **Knowledge graph** | PostgreSQL (`kg_triples`) | Subject-predicate-object triples with `valid_from`/`valid_to` timestamps |
|
|
63
|
+
| **Vector embeddings** | pgvector (full mode) | 768-dimensional Snowflake Arctic embeddings on chunks and vault notes |
|
|
64
|
+
|
|
65
|
+
### Entity Deduplication via Content-Address Hashing
|
|
66
|
+
|
|
67
|
+
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.
|
|
68
|
+
|
|
69
|
+
### Graph-Completion Search Pipeline
|
|
70
|
+
|
|
71
|
+
Standard vector search finds semantically similar chunks. Graph-completion search goes further:
|
|
72
|
+
|
|
73
|
+
1. **Vector seeds** — a semantic search returns the top-K most relevant chunks.
|
|
74
|
+
2. **Graph traversal** — the entities mentioned in those chunks are looked up in `kg_triples`; their immediate neighbors are fetched (one hop).
|
|
75
|
+
3. **Candidate expansion** — the neighbor entities' associated chunks are added to the result set.
|
|
76
|
+
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.
|
|
77
|
+
|
|
78
|
+
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.
|
|
79
|
+
|
|
80
|
+
### Feedback Loop with Relevance Scoring
|
|
81
|
+
|
|
82
|
+
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):
|
|
83
|
+
|
|
84
|
+
```
|
|
85
|
+
new_weight = alpha * signal + (1 - alpha) * old_weight
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
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.
|
|
89
|
+
|
|
90
|
+
### Access Timestamp Tracking
|
|
91
|
+
|
|
92
|
+
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.
|
|
93
|
+
|
|
94
|
+
### Multi-Tenant Support
|
|
95
|
+
|
|
96
|
+
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.
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
# Automatic Observation Capture
|
|
2
|
+
|
|
3
|
+
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.
|
|
4
|
+
|
|
5
|
+
## How it works
|
|
6
|
+
|
|
7
|
+
A PostToolUse hook fires after every Claude Code tool call. A rule-based classifier (no AI needed, under 50ms) categorizes each action:
|
|
8
|
+
|
|
9
|
+
| Type | What triggers it | Examples |
|
|
10
|
+
|------|-----------------|----------|
|
|
11
|
+
| **decision** | Git commits, config changes | `git commit`, writing to config files |
|
|
12
|
+
| **bugfix** | Test runs, error investigation | `npm test`, debugging commands |
|
|
13
|
+
| **feature** | New file creation, feature work | Creating components, adding endpoints |
|
|
14
|
+
| **refactor** | Code restructuring | Renaming, moving files, reorganizing |
|
|
15
|
+
| **discovery** | File reads, searches | Reading code, grep searches, glob patterns |
|
|
16
|
+
| **change** | File edits | Editing source files, updating configs |
|
|
17
|
+
|
|
18
|
+
Observations are stored with content-hash deduplication (30-second window) to prevent duplicates from rapid tool calls.
|
|
19
|
+
|
|
20
|
+
## Progressive context injection
|
|
21
|
+
|
|
22
|
+
At session start, PAI injects recent observations as layered context:
|
|
23
|
+
|
|
24
|
+
1. **Compact index** (~100 tokens) — observation type counts and active projects
|
|
25
|
+
2. **Timeline** (~500 tokens) — recent observations with timestamps
|
|
26
|
+
3. **On-demand** — full details available via MCP tools
|
|
27
|
+
|
|
28
|
+
This means Claude starts every session already knowing what you were working on, without you re-explaining anything.
|
|
29
|
+
|
|
30
|
+
## Searching observations
|
|
31
|
+
|
|
32
|
+
Ask Claude naturally:
|
|
33
|
+
|
|
34
|
+
```
|
|
35
|
+
"What changes did I make to the daemon today?"
|
|
36
|
+
"Show me all decisions from the last session"
|
|
37
|
+
"What files did I modify in the PAI project this week?"
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
Or use the CLI:
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
# List recent observations
|
|
44
|
+
pai observation list
|
|
45
|
+
|
|
46
|
+
# Filter by type
|
|
47
|
+
pai observation list --type decision
|
|
48
|
+
|
|
49
|
+
# Filter by project
|
|
50
|
+
pai observation list --project pai
|
|
51
|
+
|
|
52
|
+
# Show stats
|
|
53
|
+
pai observation stats
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## Session summaries
|
|
57
|
+
|
|
58
|
+
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.
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# Release History
|
|
2
|
+
|
|
3
|
+
31 releases shipped from v0.7.2 to v0.10.0 (March 19 – May 21, 2026):
|
|
4
|
+
|
|
5
|
+
| Version | Feature |
|
|
6
|
+
|---------|---------|
|
|
7
|
+
| v0.7.2 | Auto-registration, one-note-per-session, Reconstruct skill |
|
|
8
|
+
| v0.7.3 | Automatic AI-powered session notes via daemon |
|
|
9
|
+
| v0.7.4 | Auto-register on parent match |
|
|
10
|
+
| v0.7.5 | Tiered model selection (opus/sonnet/haiku) |
|
|
11
|
+
| v0.7.6 | Find claude binary in launchd |
|
|
12
|
+
| v0.7.7 | Whisper rules hook |
|
|
13
|
+
| v0.7.8 | Strip API key from daemon (prevent billing) |
|
|
14
|
+
| v0.8.0 | Topic-based note splitting |
|
|
15
|
+
| v0.8.1 | /whisper skill, remove hardcoded defaults |
|
|
16
|
+
| v0.8.2 | Reduce topic split sensitivity |
|
|
17
|
+
| v0.8.3 | /consolidate skill |
|
|
18
|
+
| v0.8.4 | Store TOPIC in HTML comment |
|
|
19
|
+
| v0.8.5 | God-note detection, confidence tagging, Louvain communities, query feedback |
|
|
20
|
+
| v0.9.0 | 4-layer wake-up, temporal KG, taxonomy, tunnels, mid-session auto-save |
|
|
21
|
+
| v0.9.1 | KG backfill CLI, shared kg-extraction module |
|
|
22
|
+
| v0.9.2 | Stop-hook first-run safeguard |
|
|
23
|
+
| v0.9.3 | Silence stop-hook diagnostics |
|
|
24
|
+
| v0.9.4 | Remove exit(2) noise |
|
|
25
|
+
| v0.9.5 | Budget-aware advisor mode |
|
|
26
|
+
| v0.9.6 | Statusline auto-writes budget to advisor |
|
|
27
|
+
| v0.9.7 | Advisor mode label in statusline, natural language mode switching |
|
|
28
|
+
| v0.9.8 | Privacy tags, compact search format, npx install |
|
|
29
|
+
| v0.9.9 | Fix advisor mode to delegate to haiku instead of hoarding in opus |
|
|
30
|
+
| v0.9.10 | Cognee-inspired three-tier memory: entity deduplication, graph-completion search, feedback EMA |
|
|
31
|
+
| v0.9.11 | Session-commands hook for truncation resilience |
|
|
32
|
+
| v0.9.12 | Dispatcher uses openFederation directly for kg_search/feedback |
|
|
33
|
+
| v0.9.13 | Emit chunk IDs in memory_search output |
|
|
34
|
+
| v0.9.14 | AIBroker live-session integration: `pai sessions` shows live iTerm2 panes |
|
|
35
|
+
| v0.9.15 | `pai pause all`: pause every live Claude session at once via AIBroker |
|
|
36
|
+
| v0.9.16 | createHash import fix, registry scan clc fallback map |
|
|
37
|
+
| v0.9.17 | Switch live-session listing to `sessions` IPC (metadata-only, faster); `--all-tabs` flag |
|
|
38
|
+
| v0.9.18 | `pai projects`: moved-project auto-detect, rebind command, active-only default listing |
|
|
39
|
+
| v0.10.0 | Topic-first redesign: `pai <topic>` universal resolver, history search, sticky tab titles |
|
|
40
|
+
| v0.10.1 | `pai sessions clear-names` recovery command |
|
|
41
|
+
| v0.11.0 | Deduped session listing + universal `pai <name>` (switch / resume / fresh) |
|
|
42
|
+
| 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 |
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# Whisper Rules and Privacy Tags
|
|
2
|
+
|
|
3
|
+
## Whisper Rules
|
|
4
|
+
|
|
5
|
+
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.
|
|
6
|
+
|
|
7
|
+
**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:
|
|
8
|
+
|
|
9
|
+
```
|
|
10
|
+
/whisper — show current rules
|
|
11
|
+
/whisper add "NEVER send emails" — add a rule
|
|
12
|
+
/whisper remove 3 — remove rule #3
|
|
13
|
+
/whisper list — list with line numbers
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
Or edit `~/.claude/pai/whisper-rules.md` directly — one rule per line, plain text.
|
|
17
|
+
|
|
18
|
+
**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.
|
|
19
|
+
|
|
20
|
+
The pattern is inspired by [Letta's claude-subconscious](https://github.com/letta-ai/claude-subconscious) approach to persistent context injection.
|
|
21
|
+
|
|
22
|
+
## Privacy Tags
|
|
23
|
+
|
|
24
|
+
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.
|
|
25
|
+
|
|
26
|
+
```markdown
|
|
27
|
+
## API Keys
|
|
28
|
+
<private>
|
|
29
|
+
STRIPE_KEY=sk_live_abc123
|
|
30
|
+
DATABASE_URL=postgres://user:pass@host/db
|
|
31
|
+
</private>
|
|
32
|
+
|
|
33
|
+
## Architecture Notes
|
|
34
|
+
The payment system uses Stripe webhooks...
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
The architecture notes get indexed. The API keys don't. Works in session notes, memory files, and any markdown PAI indexes.
|
package/docs/search.md
ADDED
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
# Search
|
|
2
|
+
|
|
3
|
+
## Token-Efficient Search (3-Layer Pattern)
|
|
4
|
+
|
|
5
|
+
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.
|
|
6
|
+
|
|
7
|
+
### The workflow
|
|
8
|
+
|
|
9
|
+
```
|
|
10
|
+
1. Search with format="compact" → IDs + paths + scores (~50 tokens/result)
|
|
11
|
+
2. Review the index, pick interesting results
|
|
12
|
+
3. Use memory_get to read full content for those specific files
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
### Example
|
|
16
|
+
|
|
17
|
+
```
|
|
18
|
+
"Search for authentication with compact format"
|
|
19
|
+
→ Claude passes format: "compact" to memory_search
|
|
20
|
+
→ Gets a tight index: [1] pai — src/auth.ts L10-45 score=0.892
|
|
21
|
+
→ Then reads only the files that matter
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
Via MCP, pass `format: "compact"` to the `memory_search` tool. Default is `"full"` (current behavior with snippets).
|
|
25
|
+
|
|
26
|
+
### Section-aware retrieval
|
|
27
|
+
|
|
28
|
+
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.
|
|
29
|
+
|
|
30
|
+
For long files, read by section instead of whole:
|
|
31
|
+
|
|
32
|
+
```
|
|
33
|
+
1. memory_outline(project, path) → heading tree with line ranges and token estimates
|
|
34
|
+
## Previous handovers L45-195 ~2361t
|
|
35
|
+
### Shipped (2026-09-29) L60-66 ~251t
|
|
36
|
+
2. memory_get(project, path, from=60, lines=7) → just that section
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
`memory_outline` returns structure only, never text, and takes an optional `max_depth`.
|
|
40
|
+
|
|
41
|
+
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.
|
|
42
|
+
|
|
43
|
+
## Search Intelligence
|
|
44
|
+
|
|
45
|
+
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.
|
|
46
|
+
|
|
47
|
+
### Search Modes
|
|
48
|
+
|
|
49
|
+
| Mode | How it works | Best for |
|
|
50
|
+
|------|-------------|----------|
|
|
51
|
+
| **Keyword** | Full-text search (BM25 via SQLite FTS5) | Exact terms, function names, error messages |
|
|
52
|
+
| **Semantic** | Vector similarity (Snowflake Arctic embeddings) | Finding things by meaning, even with different words |
|
|
53
|
+
| **Hybrid** | Keyword + semantic combined, scores normalized and blended | General use — the default |
|
|
54
|
+
|
|
55
|
+
### Cross-Encoder Reranking
|
|
56
|
+
|
|
57
|
+
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.
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
# Search with reranking (default)
|
|
61
|
+
pai memory search "how does session routing work"
|
|
62
|
+
|
|
63
|
+
# Skip reranking for faster results
|
|
64
|
+
pai memory search "how does session routing work" --no-rerank
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
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.
|
|
68
|
+
|
|
69
|
+
### Recency Boost
|
|
70
|
+
|
|
71
|
+
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%.
|
|
72
|
+
|
|
73
|
+
```bash
|
|
74
|
+
# Search uses recency boost automatically (90-day half-life from config)
|
|
75
|
+
pai memory search "notification system"
|
|
76
|
+
|
|
77
|
+
# Override the half-life for this search
|
|
78
|
+
pai memory search "notification system" --recency 30
|
|
79
|
+
|
|
80
|
+
# Disable recency boost for this search
|
|
81
|
+
pai memory search "notification system" --recency 0
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
Via MCP, pass `recency_boost: 90` to the `memory_search` tool, or `recency_boost: 0` to disable.
|
|
85
|
+
|
|
86
|
+
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.
|
|
87
|
+
|
|
88
|
+
### Search Settings
|
|
89
|
+
|
|
90
|
+
All search defaults are configurable via `~/.claude/pai/config.json` and can be viewed or changed from the command line.
|
|
91
|
+
|
|
92
|
+
```bash
|
|
93
|
+
# View all search settings
|
|
94
|
+
pai memory settings
|
|
95
|
+
|
|
96
|
+
# View a single setting
|
|
97
|
+
pai memory settings recencyBoostDays
|
|
98
|
+
|
|
99
|
+
# Change a setting
|
|
100
|
+
pai memory settings recencyBoostDays 60
|
|
101
|
+
pai memory settings mode hybrid
|
|
102
|
+
pai memory settings rerank false
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
| Setting | Default | Description |
|
|
106
|
+
|---------|---------|-------------|
|
|
107
|
+
| `mode` | `keyword` | Default search mode: `keyword`, `semantic`, or `hybrid` |
|
|
108
|
+
| `rerank` | `true` | Cross-encoder reranking on by default |
|
|
109
|
+
| `recencyBoostDays` | `90` | Recency half-life in days. `0` = off |
|
|
110
|
+
| `defaultLimit` | `10` | Default number of results |
|
|
111
|
+
| `snippetLength` | `200` | Max characters per snippet in MCP results |
|
|
112
|
+
|
|
113
|
+
Settings live in the `search` section of `~/.claude/pai/config.json`. Per-call parameters (CLI flags or MCP tool arguments) always override config defaults.
|
|
114
|
+
|
|
115
|
+
### Using Search from Within Claude
|
|
116
|
+
|
|
117
|
+
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.
|
|
118
|
+
|
|
119
|
+
**Example prompts you can give Claude:**
|
|
120
|
+
|
|
121
|
+
```
|
|
122
|
+
"Search your memory for authentication"
|
|
123
|
+
"What do you know about the database migration?"
|
|
124
|
+
"Find where we discussed the notification system"
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
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.
|
|
128
|
+
|
|
129
|
+
**Overriding defaults for a specific search:**
|
|
130
|
+
|
|
131
|
+
You can ask Claude to adjust search behavior per-query:
|
|
132
|
+
|
|
133
|
+
```
|
|
134
|
+
"Search for authentication using semantic mode"
|
|
135
|
+
→ Claude passes mode: "semantic"
|
|
136
|
+
|
|
137
|
+
"Search for the old logging discussion without recency boost"
|
|
138
|
+
→ Claude passes recency_boost: 0
|
|
139
|
+
|
|
140
|
+
"Search for database schema across all projects with no reranking"
|
|
141
|
+
→ Claude passes all_projects: true, rerank: false
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
**The `memory_search` MCP tool accepts these parameters:**
|
|
145
|
+
|
|
146
|
+
| Parameter | Type | Description |
|
|
147
|
+
|-----------|------|-------------|
|
|
148
|
+
| `query` | string | Free-text search query (required) |
|
|
149
|
+
| `project` | string | Scope to one project by slug |
|
|
150
|
+
| `all_projects` | boolean | Explicitly search all projects |
|
|
151
|
+
| `sources` | array | Restrict to `"memory"` or `"notes"` |
|
|
152
|
+
| `limit` | integer | Max results (1–100, default from config) |
|
|
153
|
+
| `mode` | string | `"keyword"`, `"semantic"`, or `"hybrid"` |
|
|
154
|
+
| `rerank` | boolean | Cross-encoder reranking (default: true from config) |
|
|
155
|
+
| `recency_boost` | integer | Recency half-life in days (0 = off, default from config) |
|
|
156
|
+
|
|
157
|
+
All parameters except `query` are optional. Omitted values fall back to your `~/.claude/pai/config.json` defaults.
|
|
158
|
+
|
|
159
|
+
**Changing defaults permanently:**
|
|
160
|
+
|
|
161
|
+
Tell Claude to change your search settings:
|
|
162
|
+
|
|
163
|
+
```
|
|
164
|
+
"Set my default search mode to hybrid"
|
|
165
|
+
"Turn off reranking by default"
|
|
166
|
+
"Change the recency boost to 60 days"
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
Claude runs `pai memory settings <key> <value>` to update `~/.claude/pai/config.json`. Changes take effect on the next search — no restart needed.
|