@tekmidian/pai 0.5.6 → 0.6.0
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/ARCHITECTURE.md +72 -1
- package/README.md +107 -3
- package/dist/{auto-route-BG6I_4B1.mjs → auto-route-C-DrW6BL.mjs} +3 -3
- package/dist/{auto-route-BG6I_4B1.mjs.map → auto-route-C-DrW6BL.mjs.map} +1 -1
- package/dist/cli/index.mjs +1897 -1569
- package/dist/cli/index.mjs.map +1 -1
- package/dist/clusters-JIDQW65f.mjs +201 -0
- package/dist/clusters-JIDQW65f.mjs.map +1 -0
- package/dist/{config-Cf92lGX_.mjs → config-BuhHWyOK.mjs} +21 -6
- package/dist/config-BuhHWyOK.mjs.map +1 -0
- package/dist/daemon/index.mjs +12 -9
- package/dist/daemon/index.mjs.map +1 -1
- package/dist/{daemon-D9evGlgR.mjs → daemon-D3hYb5_C.mjs} +670 -219
- package/dist/daemon-D3hYb5_C.mjs.map +1 -0
- package/dist/daemon-mcp/index.mjs +4597 -4
- package/dist/daemon-mcp/index.mjs.map +1 -1
- package/dist/{db-4lSqLFb8.mjs → db-BtuN768f.mjs} +9 -2
- package/dist/db-BtuN768f.mjs.map +1 -0
- package/dist/db-DdUperSl.mjs +110 -0
- package/dist/db-DdUperSl.mjs.map +1 -0
- package/dist/{detect-BU3Nx_2L.mjs → detect-CdaA48EI.mjs} +1 -1
- package/dist/{detect-BU3Nx_2L.mjs.map → detect-CdaA48EI.mjs.map} +1 -1
- package/dist/{detector-Bp-2SM3x.mjs → detector-jGBuYQJM.mjs} +2 -2
- package/dist/{detector-Bp-2SM3x.mjs.map → detector-jGBuYQJM.mjs.map} +1 -1
- package/dist/{factory-Bzcy70G9.mjs → factory-Ygqe_bVZ.mjs} +7 -5
- package/dist/{factory-Bzcy70G9.mjs.map → factory-Ygqe_bVZ.mjs.map} +1 -1
- package/dist/helpers-BEST-4Gx.mjs +420 -0
- package/dist/helpers-BEST-4Gx.mjs.map +1 -0
- package/dist/hooks/capture-all-events.mjs +19 -4
- package/dist/hooks/capture-all-events.mjs.map +4 -4
- package/dist/hooks/capture-session-summary.mjs +38 -0
- package/dist/hooks/capture-session-summary.mjs.map +3 -3
- package/dist/hooks/cleanup-session-files.mjs +6 -12
- package/dist/hooks/cleanup-session-files.mjs.map +4 -4
- package/dist/hooks/context-compression-hook.mjs +105 -111
- package/dist/hooks/context-compression-hook.mjs.map +4 -4
- package/dist/hooks/initialize-session.mjs +26 -17
- package/dist/hooks/initialize-session.mjs.map +4 -4
- package/dist/hooks/inject-observations.mjs +220 -0
- package/dist/hooks/inject-observations.mjs.map +7 -0
- package/dist/hooks/load-core-context.mjs +18 -2
- package/dist/hooks/load-core-context.mjs.map +4 -4
- package/dist/hooks/load-project-context.mjs +102 -97
- package/dist/hooks/load-project-context.mjs.map +4 -4
- package/dist/hooks/observe.mjs +354 -0
- package/dist/hooks/observe.mjs.map +7 -0
- package/dist/hooks/stop-hook.mjs +174 -90
- package/dist/hooks/stop-hook.mjs.map +4 -4
- package/dist/hooks/sync-todo-to-md.mjs +31 -33
- package/dist/hooks/sync-todo-to-md.mjs.map +4 -4
- package/dist/index.d.mts +32 -9
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +6 -9
- package/dist/indexer-D53l5d1U.mjs +1 -0
- package/dist/{indexer-backend-CIMXedqk.mjs → indexer-backend-jcJFsmB4.mjs} +37 -127
- package/dist/indexer-backend-jcJFsmB4.mjs.map +1 -0
- package/dist/{ipc-client-Bjg_a1dc.mjs → ipc-client-CoyUHPod.mjs} +2 -7
- package/dist/{ipc-client-Bjg_a1dc.mjs.map → ipc-client-CoyUHPod.mjs.map} +1 -1
- package/dist/latent-ideas-bTJo6Omd.mjs +191 -0
- package/dist/latent-ideas-bTJo6Omd.mjs.map +1 -0
- package/dist/neighborhood-BYYbEkUJ.mjs +135 -0
- package/dist/neighborhood-BYYbEkUJ.mjs.map +1 -0
- package/dist/note-context-BK24bX8Y.mjs +126 -0
- package/dist/note-context-BK24bX8Y.mjs.map +1 -0
- package/dist/postgres-CKf-EDtS.mjs +846 -0
- package/dist/postgres-CKf-EDtS.mjs.map +1 -0
- package/dist/{reranker-D7bRAHi6.mjs → reranker-CMNZcfVx.mjs} +1 -1
- package/dist/{reranker-D7bRAHi6.mjs.map → reranker-CMNZcfVx.mjs.map} +1 -1
- package/dist/{search-_oHfguA5.mjs → search-DC1qhkKn.mjs} +2 -58
- package/dist/search-DC1qhkKn.mjs.map +1 -0
- package/dist/{sqlite-WWBq7_2C.mjs → sqlite-l-s9xPjY.mjs} +160 -3
- package/dist/sqlite-l-s9xPjY.mjs.map +1 -0
- package/dist/state-C6_vqz7w.mjs +102 -0
- package/dist/state-C6_vqz7w.mjs.map +1 -0
- package/dist/stop-words-BaMEGVeY.mjs +326 -0
- package/dist/stop-words-BaMEGVeY.mjs.map +1 -0
- package/dist/{indexer-CMPOiY1r.mjs → sync-BOsnEj2-.mjs} +14 -216
- package/dist/sync-BOsnEj2-.mjs.map +1 -0
- package/dist/themes-BvYF0W8T.mjs +148 -0
- package/dist/themes-BvYF0W8T.mjs.map +1 -0
- package/dist/{tools-DV_lsiCc.mjs → tools-DcaJlYDN.mjs} +162 -273
- package/dist/tools-DcaJlYDN.mjs.map +1 -0
- package/dist/trace-CRx9lPuc.mjs +137 -0
- package/dist/trace-CRx9lPuc.mjs.map +1 -0
- package/dist/{vault-indexer-DXWs9pDn.mjs → vault-indexer-Bi2cRmn7.mjs} +174 -138
- package/dist/vault-indexer-Bi2cRmn7.mjs.map +1 -0
- package/dist/zettelkasten-cdajbnPr.mjs +708 -0
- package/dist/zettelkasten-cdajbnPr.mjs.map +1 -0
- package/package.json +1 -2
- package/src/hooks/ts/capture-all-events.ts +6 -0
- package/src/hooks/ts/lib/project-utils/index.ts +50 -0
- package/src/hooks/ts/lib/project-utils/notify.ts +75 -0
- package/src/hooks/ts/lib/project-utils/paths.ts +218 -0
- package/src/hooks/ts/lib/project-utils/session-notes.ts +363 -0
- package/src/hooks/ts/lib/project-utils/todo.ts +178 -0
- package/src/hooks/ts/lib/project-utils/tokens.ts +39 -0
- package/src/hooks/ts/lib/project-utils.ts +40 -999
- package/src/hooks/ts/post-tool-use/observe.ts +327 -0
- package/src/hooks/ts/pre-compact/context-compression-hook.ts +6 -0
- package/src/hooks/ts/session-end/capture-session-summary.ts +41 -0
- package/src/hooks/ts/session-start/initialize-session.ts +7 -1
- package/src/hooks/ts/session-start/inject-observations.ts +254 -0
- package/src/hooks/ts/session-start/load-core-context.ts +7 -0
- package/src/hooks/ts/session-start/load-project-context.ts +8 -1
- package/src/hooks/ts/stop/stop-hook.ts +28 -0
- package/templates/claude-md.template.md +7 -74
- package/templates/skills/user/.gitkeep +0 -0
- package/dist/chunker-CbnBe0s0.mjs +0 -191
- package/dist/chunker-CbnBe0s0.mjs.map +0 -1
- package/dist/config-Cf92lGX_.mjs.map +0 -1
- package/dist/daemon-D9evGlgR.mjs.map +0 -1
- package/dist/db-4lSqLFb8.mjs.map +0 -1
- package/dist/db-Dp8VXIMR.mjs +0 -212
- package/dist/db-Dp8VXIMR.mjs.map +0 -1
- package/dist/indexer-CMPOiY1r.mjs.map +0 -1
- package/dist/indexer-backend-CIMXedqk.mjs.map +0 -1
- package/dist/mcp/index.d.mts +0 -1
- package/dist/mcp/index.mjs +0 -500
- package/dist/mcp/index.mjs.map +0 -1
- package/dist/postgres-FXrHDPcE.mjs +0 -358
- package/dist/postgres-FXrHDPcE.mjs.map +0 -1
- package/dist/schemas-BFIgGntb.mjs +0 -3405
- package/dist/schemas-BFIgGntb.mjs.map +0 -1
- package/dist/search-_oHfguA5.mjs.map +0 -1
- package/dist/sqlite-WWBq7_2C.mjs.map +0 -1
- package/dist/tools-DV_lsiCc.mjs.map +0 -1
- package/dist/vault-indexer-DXWs9pDn.mjs.map +0 -1
- package/dist/zettelkasten-e-a4rW_6.mjs +0 -901
- package/dist/zettelkasten-e-a4rW_6.mjs.map +0 -1
- package/templates/README.md +0 -181
- package/templates/skills/createskill-skill.template.md +0 -78
- package/templates/skills/history-system.template.md +0 -371
- package/templates/skills/hook-system.template.md +0 -913
- package/templates/skills/sessions-skill.template.md +0 -102
- package/templates/skills/skill-system.template.md +0 -214
- package/templates/skills/terminal-tabs.template.md +0 -120
- package/templates/templates.md +0 -20
package/ARCHITECTURE.md
CHANGED
|
@@ -21,6 +21,8 @@ Claude Code Session
|
|
|
21
21
|
│ ↓
|
|
22
22
|
│ PostgreSQL + pgvector
|
|
23
23
|
│ (chunks, embeddings, files, FTS)
|
|
24
|
+
│ ├── Observation Store (PostgreSQL)
|
|
25
|
+
│ │ classify → store → query → inject
|
|
24
26
|
│
|
|
25
27
|
├── Registry (SQLite)
|
|
26
28
|
│ ~/.pai/registry.db
|
|
@@ -28,7 +30,8 @@ Claude Code Session
|
|
|
28
30
|
│
|
|
29
31
|
└── CLI (pai)
|
|
30
32
|
project, session, registry, memory,
|
|
31
|
-
daemon, obsidian, zettel,
|
|
33
|
+
daemon, obsidian, zettel, observation,
|
|
34
|
+
backup, restore, setup
|
|
32
35
|
```
|
|
33
36
|
|
|
34
37
|
### Key Components
|
|
@@ -161,6 +164,8 @@ Claude Code (stdio)
|
|
|
161
164
|
| `session_list` | List session notes, optionally filtered by project |
|
|
162
165
|
| `registry_search` | Search project metadata (names, paths, tags) |
|
|
163
166
|
| `project_detect` | Identify which project a given path belongs to |
|
|
167
|
+
| `observation_search` | Search classified observations by project, type, or session |
|
|
168
|
+
| `observation_timeline` | Recent observation timeline with progressive context layers |
|
|
164
169
|
| `zettel_explore` | BFS traversal of wikilink graph from a seed note |
|
|
165
170
|
| `zettel_surprise` | Find semantically distant but graph-close notes |
|
|
166
171
|
| `zettel_converse` | Hybrid search with graph expansion and cross-domain connections |
|
|
@@ -184,6 +189,10 @@ Claude Code (stdio)
|
|
|
184
189
|
|
|
185
190
|
**`project_detect(path?)`** — Given a filesystem path (defaults to CWD), returns the matching project.
|
|
186
191
|
|
|
192
|
+
**`observation_search(project?, type?, session_id?, limit?)`** — Search the observation store. Filter by project slug, observation type (`decision`, `bugfix`, `feature`, `refactor`, `discovery`, `change`), or session ID. Returns observations ordered by creation time descending.
|
|
193
|
+
|
|
194
|
+
**`observation_timeline(project?, limit?)`** — Returns a layered timeline: compact index (~100 tokens with type counts and active projects), recent timeline (~500 tokens with timestamped observations), and on-demand detail access via `observation_search`.
|
|
195
|
+
|
|
187
196
|
**`zettel_explore(note, depth?, direction?)`** — BFS walk from a seed note across `vault_links`. Returns a subgraph of neighboring notes with each edge classified as `sequential` or `associative`. `direction`: `outbound` (default), `inbound`, or `both`.
|
|
188
197
|
|
|
189
198
|
**`zettel_surprise(note, limit?)`** — Returns notes that are semantically dissimilar to `note` but reachable within a short graph distance. Scored as `cosine_similarity × log2(graph_distance + 1)`. Useful for lateral discovery.
|
|
@@ -389,6 +398,21 @@ pai zettel health
|
|
|
389
398
|
pai zettel suggest "My Seed Note" --limit 5
|
|
390
399
|
```
|
|
391
400
|
|
|
401
|
+
### Observation Management
|
|
402
|
+
|
|
403
|
+
| Subcommand | Description |
|
|
404
|
+
|------------|-------------|
|
|
405
|
+
| `observation list` | List recent observations with optional filters |
|
|
406
|
+
| `observation search <query>` | Search observations by title or narrative text |
|
|
407
|
+
| `observation stats` | Show totals, breakdowns by type and project |
|
|
408
|
+
|
|
409
|
+
```bash
|
|
410
|
+
pai observation list --type decision --limit 10
|
|
411
|
+
pai observation list --project my-app
|
|
412
|
+
pai observation search "database migration"
|
|
413
|
+
pai observation stats
|
|
414
|
+
```
|
|
415
|
+
|
|
392
416
|
### Other Commands
|
|
393
417
|
|
|
394
418
|
```bash
|
|
@@ -531,6 +555,8 @@ Claude Code Event
|
|
|
531
555
|
| `post-compact-inject.mjs` | SessionStart (compact) | Reads saved state and injects into post-compaction context |
|
|
532
556
|
| `security-validator.mjs` | PreToolUse (Bash) | Validates shell commands against security rules |
|
|
533
557
|
| `capture-all-events.mjs` | All events | Observability — logs every hook event to session timeline |
|
|
558
|
+
| `observe.mjs` | PostToolUse | Classifies tool calls into typed observations (decision/bugfix/feature/refactor/discovery/change) |
|
|
559
|
+
| `inject-observations.mjs` | SessionStart | Injects recent observation context (compact index + timeline) |
|
|
534
560
|
| `context-compression-hook.mjs` | PreCompact | Extracts session state, saves checkpoint, writes temp file for relay |
|
|
535
561
|
| `capture-tool-output.mjs` | PostToolUse | Records tool inputs/outputs for observability dashboard |
|
|
536
562
|
| `update-tab-on-action.mjs` | PostToolUse | Updates terminal tab title based on current activity |
|
|
@@ -704,6 +730,47 @@ These tables are populated by `src/memory/vault-indexer.ts` and queried by all s
|
|
|
704
730
|
| `detail` | TEXT | Human-readable description |
|
|
705
731
|
| `checked_at` | BIGINT | Timestamp of the audit run |
|
|
706
732
|
|
|
733
|
+
### Observation Tables (PostgreSQL)
|
|
734
|
+
|
|
735
|
+
These tables are populated by the PostToolUse hook classifier and queried by the CLI and MCP tools.
|
|
736
|
+
|
|
737
|
+
**`pai_observations`** — Classified tool call events:
|
|
738
|
+
|
|
739
|
+
| Column | Type | Description |
|
|
740
|
+
|--------|------|-------------|
|
|
741
|
+
| `id` | SERIAL | Primary key |
|
|
742
|
+
| `session_id` | TEXT | Claude Code session identifier |
|
|
743
|
+
| `project_id` | INTEGER | Owning project (nullable) |
|
|
744
|
+
| `project_slug` | TEXT | Project slug for display |
|
|
745
|
+
| `type` | TEXT | Classification: decision, bugfix, feature, refactor, discovery, change |
|
|
746
|
+
| `title` | TEXT | Human-readable observation title |
|
|
747
|
+
| `narrative` | TEXT | Extended description (nullable) |
|
|
748
|
+
| `tool_name` | TEXT | Claude Code tool that triggered the observation |
|
|
749
|
+
| `tool_input_summary` | TEXT | Abbreviated tool input |
|
|
750
|
+
| `files_read` | JSONB | Array of file paths read |
|
|
751
|
+
| `files_modified` | JSONB | Array of file paths modified |
|
|
752
|
+
| `concepts` | JSONB | Extracted concept tags |
|
|
753
|
+
| `content_hash` | TEXT | SHA-256 hash for 30-second deduplication window |
|
|
754
|
+
| `created_at` | TIMESTAMPTZ | Observation timestamp |
|
|
755
|
+
|
|
756
|
+
**`pai_session_summaries`** — Structured end-of-session summaries:
|
|
757
|
+
|
|
758
|
+
| Column | Type | Description |
|
|
759
|
+
|--------|------|-------------|
|
|
760
|
+
| `id` | SERIAL | Primary key |
|
|
761
|
+
| `session_id` | TEXT | Claude Code session identifier (unique) |
|
|
762
|
+
| `project_id` | INTEGER | Owning project (nullable) |
|
|
763
|
+
| `project_slug` | TEXT | Project slug for display |
|
|
764
|
+
| `request` | TEXT | What was requested |
|
|
765
|
+
| `investigated` | TEXT | What was investigated |
|
|
766
|
+
| `learned` | TEXT | What was learned |
|
|
767
|
+
| `completed` | TEXT | What was completed |
|
|
768
|
+
| `next_steps` | TEXT | Recommended next steps |
|
|
769
|
+
| `observation_count` | INTEGER | Number of observations in the session |
|
|
770
|
+
| `created_at` | TIMESTAMPTZ | Summary timestamp |
|
|
771
|
+
|
|
772
|
+
**Indexes:** B-tree on project_id, session_id, type, created_at DESC, content_hash.
|
|
773
|
+
|
|
707
774
|
**Content Tiers:**
|
|
708
775
|
|
|
709
776
|
| Tier | Description | Example |
|
|
@@ -770,6 +837,10 @@ src/
|
|
|
770
837
|
├── memory/ # Indexer, chunker, embeddings, search, reranker
|
|
771
838
|
│ ├── reranker.ts # Cross-encoder reranking (Xenova/ms-marco-MiniLM-L-6-v2)
|
|
772
839
|
│ └── vault-indexer.ts # Obsidian vault indexing into v3 vault tables
|
|
840
|
+
├── observations/ # Automatic observation capture
|
|
841
|
+
│ ├── classifier.ts # Rule-based tool call classifier (decision/bugfix/feature/refactor/discovery/change)
|
|
842
|
+
│ ├── store.ts # PostgreSQL persistence with content-hash deduplication
|
|
843
|
+
│ └── schema.sql # Observation + session summary table DDL
|
|
773
844
|
├── obsidian/ # Obsidian vault bridge
|
|
774
845
|
│ └── vault-fixer.ts # Repairs broken wikilinks and orphaned entries
|
|
775
846
|
├── registry/ # Registry migrations and queries
|
package/README.md
CHANGED
|
@@ -29,6 +29,34 @@ Install PAI and Claude remembers. Ask it what you were working on. Ask it to fin
|
|
|
29
29
|
- "What were we working on last week?" — Claude knows, without you re-explaining
|
|
30
30
|
- "Clean up my session notes" — auto-names unnamed sessions and organizes by date
|
|
31
31
|
|
|
32
|
+
### Reviewing Your Work
|
|
33
|
+
|
|
34
|
+
- "Review my week" — synthesizes session notes, git commits, and completed tasks into a themed narrative
|
|
35
|
+
- "What did I do today?" — daily review across all projects
|
|
36
|
+
- "Journal this thought" — capture freeform reflections with timestamps
|
|
37
|
+
- "Plan my week" — forward-looking priorities based on open TODOs and recent activity
|
|
38
|
+
- "What themes are emerging in my work?" — spot patterns across sessions and projects
|
|
39
|
+
|
|
40
|
+
### Sharing Your Work
|
|
41
|
+
|
|
42
|
+
- "Share on LinkedIn today" — generates a professional post about what you shipped, with real numbers and technical substance
|
|
43
|
+
- "Tweet about the vault migration" — punchy X/Twitter post or thread, with option to post directly
|
|
44
|
+
- "Share on Bluesky this week" — conversational technical post for the Bluesky audience
|
|
45
|
+
- Platform-aware formatting: LinkedIn gets hashtags and narrative, X gets threads and hooks, Bluesky gets conversational tone
|
|
46
|
+
|
|
47
|
+
### Tracking Your Activity
|
|
48
|
+
|
|
49
|
+
- "What changes did I make to the daemon today?" — automatic observation capture tracks every tool call
|
|
50
|
+
- "Show me all decisions from the last session" — observations are classified: decision, bugfix, feature, refactor, discovery, change
|
|
51
|
+
- "What files did I modify in the PAI project this week?" — searchable timeline of every edit, commit, and search
|
|
52
|
+
- "Show observation stats" — totals, breakdowns by type and project, with visual bar charts
|
|
53
|
+
|
|
54
|
+
### Continuing Where You Left Off
|
|
55
|
+
|
|
56
|
+
- "Go" — reads your TODO.md continuation prompt and picks up exactly where the last session stopped
|
|
57
|
+
- "What was I working on?" — progressive context injection loads recent observations at session start
|
|
58
|
+
- "Continue the daemon refactor" — session summaries give Claude full context without re-explaining
|
|
59
|
+
|
|
32
60
|
### Keeping Things Safe
|
|
33
61
|
|
|
34
62
|
- "Back up everything" — creates a timestamped backup of all your data
|
|
@@ -90,7 +118,7 @@ PAI runs hooks at every stage of a Claude Code session:
|
|
|
90
118
|
| **User Prompt** | Cleans up temp files, updates terminal tab titles |
|
|
91
119
|
| **Pre-Compact** | Saves session state checkpoint, sends notification |
|
|
92
120
|
| **Post-Compact** | Injects preserved state back into Claude's context |
|
|
93
|
-
| **Tool Use** |
|
|
121
|
+
| **Tool Use** | Classifies tool calls into structured observations (decision/bugfix/feature/refactor/discovery/change) |
|
|
94
122
|
| **Session End** | Summarizes work done, finalizes session note |
|
|
95
123
|
| **Stop** | Writes work items to session note, sends notification |
|
|
96
124
|
|
|
@@ -98,6 +126,67 @@ All hooks are TypeScript compiled to `.mjs` modules. They run as separate proces
|
|
|
98
126
|
|
|
99
127
|
---
|
|
100
128
|
|
|
129
|
+
## Automatic Observation Capture
|
|
130
|
+
|
|
131
|
+
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.
|
|
132
|
+
|
|
133
|
+
### How it works
|
|
134
|
+
|
|
135
|
+
A PostToolUse hook fires after every Claude Code tool call. A rule-based classifier (no AI needed, under 50ms) categorizes each action:
|
|
136
|
+
|
|
137
|
+
| Type | What triggers it | Examples |
|
|
138
|
+
|------|-----------------|----------|
|
|
139
|
+
| **decision** | Git commits, config changes | `git commit`, writing to config files |
|
|
140
|
+
| **bugfix** | Test runs, error investigation | `npm test`, debugging commands |
|
|
141
|
+
| **feature** | New file creation, feature work | Creating components, adding endpoints |
|
|
142
|
+
| **refactor** | Code restructuring | Renaming, moving files, reorganizing |
|
|
143
|
+
| **discovery** | File reads, searches | Reading code, grep searches, glob patterns |
|
|
144
|
+
| **change** | File edits | Editing source files, updating configs |
|
|
145
|
+
|
|
146
|
+
Observations are stored in PostgreSQL with content-hash deduplication (30-second window) to prevent duplicates from rapid tool calls.
|
|
147
|
+
|
|
148
|
+
### Progressive context injection
|
|
149
|
+
|
|
150
|
+
At session start, PAI injects recent observations as layered context:
|
|
151
|
+
|
|
152
|
+
1. **Compact index** (~100 tokens) — observation type counts and active projects
|
|
153
|
+
2. **Timeline** (~500 tokens) — recent observations with timestamps
|
|
154
|
+
3. **On-demand** — full details available via MCP tools
|
|
155
|
+
|
|
156
|
+
This means Claude starts every session already knowing what you were working on, without you re-explaining anything.
|
|
157
|
+
|
|
158
|
+
### Searching observations
|
|
159
|
+
|
|
160
|
+
Ask Claude naturally:
|
|
161
|
+
|
|
162
|
+
```
|
|
163
|
+
"What changes did I make to the daemon today?"
|
|
164
|
+
"Show me all decisions from the last session"
|
|
165
|
+
"What files did I modify in the PAI project this week?"
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
Or use the CLI:
|
|
169
|
+
|
|
170
|
+
```bash
|
|
171
|
+
# List recent observations
|
|
172
|
+
pai observation list
|
|
173
|
+
|
|
174
|
+
# Filter by type
|
|
175
|
+
pai observation list --type decision
|
|
176
|
+
|
|
177
|
+
# Filter by project
|
|
178
|
+
pai observation list --project pai
|
|
179
|
+
|
|
180
|
+
# Show stats
|
|
181
|
+
pai observation stats
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
### Session summaries
|
|
185
|
+
|
|
186
|
+
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.
|
|
187
|
+
|
|
188
|
+
---
|
|
189
|
+
|
|
101
190
|
## Auto-Compact Context Window
|
|
102
191
|
|
|
103
192
|
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.
|
|
@@ -297,7 +386,7 @@ PAI implements Niklas Luhmann's Zettelkasten principles as six computational ope
|
|
|
297
386
|
|
|
298
387
|
### How it works
|
|
299
388
|
|
|
300
|
-
PAI indexes your entire vault — following symlinks, deduplicating by inode, parsing every
|
|
389
|
+
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:
|
|
301
390
|
|
|
302
391
|
| Tool | What it does |
|
|
303
392
|
|------|-------------|
|
|
@@ -312,7 +401,18 @@ All tools work as CLI commands (`pai zettel <command>`) and MCP tools (`zettel_*
|
|
|
312
401
|
|
|
313
402
|
### Vault Indexing
|
|
314
403
|
|
|
315
|
-
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
|
|
404
|
+
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.
|
|
405
|
+
|
|
406
|
+
All link types are parsed and resolved:
|
|
407
|
+
|
|
408
|
+
| Syntax | Type | Example |
|
|
409
|
+
|--------|------|---------|
|
|
410
|
+
| `[[Note]]` | Wikilink | `[[Daily Note]]`, `[[Note\|alias]]`, `[[Note#heading]]` |
|
|
411
|
+
| `![[file]]` | Embed | `![[diagram.png]]`, `![[template]]` |
|
|
412
|
+
| `[text](path.md)` | Markdown link | `[see here](notes/idea.md)`, `[ref](note.md#section)` |
|
|
413
|
+
| `` | Markdown embed | `` |
|
|
414
|
+
|
|
415
|
+
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.
|
|
316
416
|
|
|
317
417
|
- Full index: ~10 seconds for ~1,000 files
|
|
318
418
|
- Incremental: ~2 seconds (hash-based change detection)
|
|
@@ -324,7 +424,9 @@ The vault indexer follows symlinks (critical for vaults built on symlinks), dedu
|
|
|
324
424
|
|
|
325
425
|
PAI works great alongside these tools (also by the same author):
|
|
326
426
|
|
|
427
|
+
- **[AIBroker](https://github.com/mnott/AIBroker)** — Unified message bridge for Claude Code (WhatsApp, Telegram, PAILot — text and voice routing)
|
|
327
428
|
- **[Whazaa](https://github.com/mnott/Whazaa)** — WhatsApp bridge for Claude Code (voice notes, screenshots, session routing)
|
|
429
|
+
- **[Telex](https://github.com/mnott/Telex)** — Telegram bridge for Claude Code (text and voice messaging)
|
|
328
430
|
- **[Coogle](https://github.com/mnott/Coogle)** — Google Workspace MCP daemon (Gmail, Calendar, Drive multiplexing)
|
|
329
431
|
- **[DEVONthink MCP](https://github.com/mnott/devonthink-mcp)** — DEVONthink integration for document search and archival
|
|
330
432
|
|
|
@@ -334,6 +436,8 @@ PAI works great alongside these tools (also by the same author):
|
|
|
334
436
|
|
|
335
437
|
PAI Knowledge OS is inspired by [Daniel Miessler](https://github.com/danielmiessler)'s concept of Personal AI Infrastructure and his [Fabric](https://github.com/danielmiessler/fabric) project — a Python CLI for augmenting human capabilities with reusable AI prompt patterns. Fabric is excellent and solves a different problem; PAI takes the same philosophy in a different direction: persistent memory, session continuity, and deep Claude Code integration. See [FEATURE.md](FEATURE.md) for a detailed comparison.
|
|
336
438
|
|
|
439
|
+
The automatic observation capture system — classifying tool calls into structured observations with progressive context injection — is inspired by [claude-mem](https://github.com/thedotmack/claude-mem) by [thedotmack](https://github.com/thedotmack). claude-mem demonstrated that automatic memory capture during Claude Code sessions dramatically improves continuity. PAI adapts this concept with a rule-based classifier, PostgreSQL storage, and three-layer progressive disclosure.
|
|
440
|
+
|
|
337
441
|
---
|
|
338
442
|
|
|
339
443
|
## License
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { r as readPaiMarker } from "./pai-marker-CXQPX2P6.mjs";
|
|
2
|
-
import { t as detectProject } from "./detect-
|
|
2
|
+
import { t as detectProject } from "./detect-CdaA48EI.mjs";
|
|
3
3
|
import { existsSync } from "node:fs";
|
|
4
4
|
import { dirname, resolve } from "node:path";
|
|
5
5
|
|
|
@@ -26,7 +26,7 @@ async function autoRoute(registryDb, federation, cwd, context) {
|
|
|
26
26
|
const markerResult = findMarkerUpward(registryDb, target);
|
|
27
27
|
if (markerResult) return markerResult;
|
|
28
28
|
if (context && context.trim().length > 0) {
|
|
29
|
-
const { detectTopicShift } = await import("./detector-
|
|
29
|
+
const { detectTopicShift } = await import("./detector-jGBuYQJM.mjs").then((n) => n.n);
|
|
30
30
|
const topicResult = await detectTopicShift(registryDb, federation, {
|
|
31
31
|
context,
|
|
32
32
|
threshold: .5
|
|
@@ -83,4 +83,4 @@ function formatAutoRouteJson(result) {
|
|
|
83
83
|
|
|
84
84
|
//#endregion
|
|
85
85
|
export { autoRoute, formatAutoRouteJson };
|
|
86
|
-
//# sourceMappingURL=auto-route-
|
|
86
|
+
//# sourceMappingURL=auto-route-C-DrW6BL.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"auto-route-
|
|
1
|
+
{"version":3,"file":"auto-route-C-DrW6BL.mjs","names":[],"sources":["../src/session/auto-route.ts"],"sourcesContent":["/**\n * Auto-route: automatic project routing suggestion on session start.\n *\n * Given a working directory (and optional conversation context), determine\n * which registered project the session belongs to.\n *\n * Strategy (in priority order):\n * 1. Path match — exact or parent-directory match in the project registry\n * 2. Marker walk — walk up from cwd looking for Notes/PAI.md, resolve slug\n * 3. Topic match — BM25 keyword search against memory (requires context text)\n *\n * The function is stateless and works with direct DB access (no daemon\n * required), making it fast and safe to call during session startup.\n */\n\nimport type { Database } from \"better-sqlite3\";\nimport type { StorageBackend } from \"../storage/interface.js\";\nimport { resolve, dirname } from \"node:path\";\nimport { existsSync } from \"node:fs\";\nimport { readPaiMarker } from \"../registry/pai-marker.js\";\nimport { detectProject } from \"../cli/commands/detect.js\";\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\nexport type AutoRouteMethod = \"path\" | \"marker\" | \"topic\";\n\nexport interface AutoRouteResult {\n /** Project slug */\n slug: string;\n /** Human-readable project name */\n display_name: string;\n /** Absolute path to the project root */\n root_path: string;\n /** How the project was detected */\n method: AutoRouteMethod;\n /** Confidence [0,1]: 1.0 for path/marker matches, BM25 fraction for topic */\n confidence: number;\n}\n\n// ---------------------------------------------------------------------------\n// Core function\n// ---------------------------------------------------------------------------\n\n/**\n * Determine which project a session should be routed to.\n *\n * @param registryDb Open PAI registry database\n * @param federation Memory storage backend (needed only for topic fallback)\n * @param cwd Working directory to detect from (defaults to process.cwd())\n * @param context Optional conversation text for topic-based fallback\n * @returns Best project match, or null if nothing matched\n */\nexport async function autoRoute(\n registryDb: Database,\n federation: Database | StorageBackend,\n cwd?: string,\n context?: string\n): Promise<AutoRouteResult | null> {\n const target = resolve(cwd ?? process.cwd());\n\n // -------------------------------------------------------------------------\n // Strategy 1: Path match via registry\n // -------------------------------------------------------------------------\n\n const pathMatch = detectProject(registryDb, target);\n\n if (pathMatch) {\n return {\n slug: pathMatch.slug,\n display_name: pathMatch.display_name,\n root_path: pathMatch.root_path,\n method: \"path\",\n confidence: 1.0,\n };\n }\n\n // -------------------------------------------------------------------------\n // Strategy 2: PAI.md marker file walk\n //\n // Walk up from cwd, checking <dir>/Notes/PAI.md at each level.\n // Once found, resolve the slug against the registry to get full project info.\n // -------------------------------------------------------------------------\n\n const markerResult = findMarkerUpward(registryDb, target);\n if (markerResult) {\n return markerResult;\n }\n\n // -------------------------------------------------------------------------\n // Strategy 3: Topic detection (requires context text)\n // -------------------------------------------------------------------------\n\n if (context && context.trim().length > 0) {\n // Lazy import to avoid bundler pulling in daemon/index.mjs at module load time\n const { detectTopicShift } = await import(\"../topics/detector.js\");\n const topicResult = await detectTopicShift(registryDb, federation, {\n context,\n threshold: 0.5, // Lower threshold for initial routing (vs shift detection)\n });\n\n if (topicResult.suggestedProject && topicResult.confidence > 0) {\n // Look up the full project info from the registry\n const projectRow = registryDb\n .prepare(\n \"SELECT slug, display_name, root_path FROM projects WHERE slug = ? AND status != 'archived'\"\n )\n .get(topicResult.suggestedProject) as\n | { slug: string; display_name: string; root_path: string }\n | undefined;\n\n if (projectRow) {\n return {\n slug: projectRow.slug,\n display_name: projectRow.display_name,\n root_path: projectRow.root_path,\n method: \"topic\",\n confidence: topicResult.confidence,\n };\n }\n }\n }\n\n return null;\n}\n\n// ---------------------------------------------------------------------------\n// Marker walk helper\n// ---------------------------------------------------------------------------\n\n/**\n * Walk up the directory tree from `startDir`, checking each level for a\n * `Notes/PAI.md` file. If found, read the slug and look up the project.\n *\n * Stops at the filesystem root or after 20 levels (safety guard).\n */\nfunction findMarkerUpward(\n registryDb: Database,\n startDir: string\n): AutoRouteResult | null {\n let current = startDir;\n let depth = 0;\n\n while (depth < 20) {\n const markerPath = `${current}/Notes/PAI.md`;\n\n if (existsSync(markerPath)) {\n const marker = readPaiMarker(current);\n\n if (marker && marker.status !== \"archived\") {\n // Resolve slug to full project info in the registry\n const projectRow = registryDb\n .prepare(\n \"SELECT slug, display_name, root_path FROM projects WHERE slug = ? AND status != 'archived'\"\n )\n .get(marker.slug) as\n | { slug: string; display_name: string; root_path: string }\n | undefined;\n\n if (projectRow) {\n return {\n slug: projectRow.slug,\n display_name: projectRow.display_name,\n root_path: projectRow.root_path,\n method: \"marker\",\n confidence: 1.0,\n };\n }\n }\n }\n\n const parent = dirname(current);\n if (parent === current) break; // Reached filesystem root\n current = parent;\n depth++;\n }\n\n return null;\n}\n\n// ---------------------------------------------------------------------------\n// Format helpers\n// ---------------------------------------------------------------------------\n\n/**\n * Format an AutoRouteResult as a human-readable string for CLI output.\n */\nexport function formatAutoRoute(result: AutoRouteResult): string {\n const lines: string[] = [\n `slug: ${result.slug}`,\n `display_name: ${result.display_name}`,\n `root_path: ${result.root_path}`,\n `method: ${result.method}`,\n `confidence: ${(result.confidence * 100).toFixed(0)}%`,\n ];\n return lines.join(\"\\n\");\n}\n\n/**\n * Format an AutoRouteResult as JSON for machine consumption.\n */\nexport function formatAutoRouteJson(result: AutoRouteResult): string {\n return JSON.stringify(result, null, 2);\n}\n"],"mappings":";;;;;;;;;;;;;;;AAsDA,eAAsB,UACpB,YACA,YACA,KACA,SACiC;CACjC,MAAM,SAAS,QAAQ,OAAO,QAAQ,KAAK,CAAC;CAM5C,MAAM,YAAY,cAAc,YAAY,OAAO;AAEnD,KAAI,UACF,QAAO;EACL,MAAM,UAAU;EAChB,cAAc,UAAU;EACxB,WAAW,UAAU;EACrB,QAAQ;EACR,YAAY;EACb;CAUH,MAAM,eAAe,iBAAiB,YAAY,OAAO;AACzD,KAAI,aACF,QAAO;AAOT,KAAI,WAAW,QAAQ,MAAM,CAAC,SAAS,GAAG;EAExC,MAAM,EAAE,qBAAqB,MAAM,OAAO;EAC1C,MAAM,cAAc,MAAM,iBAAiB,YAAY,YAAY;GACjE;GACA,WAAW;GACZ,CAAC;AAEF,MAAI,YAAY,oBAAoB,YAAY,aAAa,GAAG;GAE9D,MAAM,aAAa,WAChB,QACC,6FACD,CACA,IAAI,YAAY,iBAAiB;AAIpC,OAAI,WACF,QAAO;IACL,MAAM,WAAW;IACjB,cAAc,WAAW;IACzB,WAAW,WAAW;IACtB,QAAQ;IACR,YAAY,YAAY;IACzB;;;AAKP,QAAO;;;;;;;;AAaT,SAAS,iBACP,YACA,UACwB;CACxB,IAAI,UAAU;CACd,IAAI,QAAQ;AAEZ,QAAO,QAAQ,IAAI;AAGjB,MAAI,WAFe,GAAG,QAAQ,eAEJ,EAAE;GAC1B,MAAM,SAAS,cAAc,QAAQ;AAErC,OAAI,UAAU,OAAO,WAAW,YAAY;IAE1C,MAAM,aAAa,WAChB,QACC,6FACD,CACA,IAAI,OAAO,KAAK;AAInB,QAAI,WACF,QAAO;KACL,MAAM,WAAW;KACjB,cAAc,WAAW;KACzB,WAAW,WAAW;KACtB,QAAQ;KACR,YAAY;KACb;;;EAKP,MAAM,SAAS,QAAQ,QAAQ;AAC/B,MAAI,WAAW,QAAS;AACxB,YAAU;AACV;;AAGF,QAAO;;;;;AAwBT,SAAgB,oBAAoB,QAAiC;AACnE,QAAO,KAAK,UAAU,QAAQ,MAAM,EAAE"}
|