@gi4nks/ph 1.5.0 → 1.7.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.
Files changed (37) hide show
  1. package/CHANGELOG.md +9 -2
  2. package/LICENSE +1 -1
  3. package/README.md +155 -145
  4. package/dist/cli.js +2279 -1052
  5. package/dist/cli.js.map +1 -1
  6. package/docs/evals/context-retrieval-golden.json +26 -0
  7. package/docs/evals/context-retrieval.md +27 -0
  8. package/docs/hooks.md +13 -7
  9. package/docs/ph-analysis.html +145 -0
  10. package/docs/ph-manual.md +375 -373
  11. package/docs/specs/SPEC-001-architecture-cli.md +82 -0
  12. package/docs/specs/SPEC-002-database-layer.md +105 -0
  13. package/docs/specs/SPEC-003-capture-modes.md +110 -0
  14. package/docs/specs/SPEC-004-filter-metadata.md +82 -0
  15. package/docs/specs/SPEC-005-search.md +102 -0
  16. package/docs/specs/SPEC-006-analysis-pipeline.md +98 -0
  17. package/docs/specs/SPEC-007-memory-summaries.md +96 -0
  18. package/docs/specs/SPEC-008-embeddings.md +90 -0
  19. package/docs/specs/SPEC-009-retention-archive.md +91 -0
  20. package/docs/specs/SPEC-010-remote-sync.md +106 -0
  21. package/docs/specs/SPEC-011-mcp-server.md +94 -0
  22. package/docs/specs/SPEC-012-tui-browser.md +98 -0
  23. package/docs/specs/SPEC-013-importers.md +109 -0
  24. package/docs/specs/SPEC-014-analytics-commands.md +109 -0
  25. package/docs/specs/SPEC-015-config-env.md +85 -0
  26. package/docs/specs/SPEC-INDEX.md +35 -0
  27. package/docs/specs/SPEC-ISSUES.md +122 -0
  28. package/docs/specs/_TEMPLATE.md +65 -0
  29. package/docs/superpowers/plans/2026-06-12-ph-evolution-phase1.md +466 -0
  30. package/docs/superpowers/plans/2026-06-12-ph-evolution-phase2.md +351 -0
  31. package/docs/superpowers/specs/2026-06-12-ph-evolution-design.md +173 -0
  32. package/hooks/claude/README.md +1 -1
  33. package/hooks/codex/README.md +54 -0
  34. package/hooks/codex/ph-hook.sh +14 -0
  35. package/hooks/gemini/README.md +1 -1
  36. package/hooks/opencode/ph-plugin.ts +60 -57
  37. package/package.json +18 -12
package/docs/ph-manual.md CHANGED
@@ -1,518 +1,520 @@
1
- # ph — Prompt History CLI
1
+ # ph — Prompt History and Project Memory
2
2
 
3
- **Architecture, Hook System & Usage Guide**
3
+ **Zero-friction capture, semantic search, project memory, and MCP-based knowledge retrieval for AI CLI tools.**
4
4
 
5
5
  ---
6
6
 
7
7
  ## 1. Overview
8
8
 
9
- ph is a transparent capture layer for AI CLI tools such as Claude Code and Gemini CLI. Every prompt you type — and the AI response that follows — is automatically saved to a local SQLite database with full-text and semantic search, Git context, and optional background analysis.
9
+ ph is a transparent observability and knowledge layer for AI CLI tools (Claude Code, Codex CLI, Gemini CLI, OpenCode, etc.). It automatically records every prompt+response into a local SQLite database with full-text search, semantic vector search, LLM-based analysis, Git context snapshots, session grouping, and an interactive TUI browser.
10
10
 
11
- The core design principle is zero friction: ph never interrupts your workflow. Capture happens silently in the background. Your AI sessions remain unchanged.
11
+ **Core principle:** ph captures conversations without changing the normal tool workflow. Optional analysis turns captured history into project summaries and memories that can be searched locally or requested by an MCP client. Capture and full-text search work without an LLM provider; analysis, embeddings, and semantic search require the configured provider.
12
12
 
13
- ### Key Features
14
-
15
- - **Automatic Capture** — saves prompts, responses, and metadata without any manual action
16
- - **Git Context** — records current branch, modified files, and diff at capture time
17
- - **Full-text & Semantic Search** — FTS5 text search and vector-based semantic search (via Ollama embeddings)
18
- - **Background Analysis** — automatic role/tag/relevance classification via Ollama or Gemini
19
- - **Interactive TUI** — browse, filter, edit, re-run, and export your history with `ph browse`
20
- - **Privacy First** — all data stays local; no data ever leaves your machine
21
-
22
- ---
23
-
24
- ## 2. Architecture
25
-
26
- ph uses a two-tier storage model: a SQLite database with FTS5 full-text indexing for fast retrieval, and a JSON config file for runtime settings. Both live in your home directory by default.
27
-
28
- ### Storage Layout
13
+ In the TUI, `p` runs the selected prompt through one of the configured Wise analysis providers (same provider/model/URL settings shown by `ph config show`) and saves the response to history. `r` reruns the prompt with its original CLI tool.
29
14
 
30
- | Item | Default Path | Description |
31
- |------|-------------|-------------|
32
- | Database | `~/.prompt_history.db` | SQLite with FTS5 + vector embeddings |
33
- | Config | `~/.ph_config.json` | JSON config file (0o600 permissions) |
15
+ ### Key Features
34
16
 
35
- The database uses WAL (Write-Ahead Logging) mode, enabling concurrent reads and writes. This is essential for the background analysis system, which processes prompts asynchronously without blocking your terminal session.
17
+ - **Automatic capture** via hooks (Claude Code, Codex CLI, Gemini CLI, OpenCode plugin) or wrapper mode
18
+ - **Full-text search** (FTS5) and **semantic vector search** (Ollama embeddings, 768-dim via sqlite-vec)
19
+ - **LLM analysis** — role/tag/relevance classification, summary extraction, key insights, technical decisions
20
+ - **Project memory** — per-project accumulated knowledge with deduped insights and decisions
21
+ - **MCP server** — tools for agents to search memories, check project knowledge, get context
22
+ - **Interactive TUI** — browse, filter, edit, star, re-run, export prompts
23
+ - **Session grouping** — automatic conversation grouping with cohesion scoring
24
+ - **Git context** — records branch, modified files, and diff at capture time
25
+ - **Background analysis** — async LLM processing after each capture (optional)
26
+ - **Retention & archiving** — configurable auto-archive of old/low-relevance prompts
27
+ - **Remote sync** — push/pull prompt history across machines via HTTP server
28
+ - **Local-first storage** — the database stays on the configured machine unless optional remote sync is enabled; no telemetry is sent
36
29
 
37
30
  ---
38
31
 
39
- ## 3. The Hook System
40
-
41
- The hook system is ph's most powerful integration mechanism. Rather than requiring you to manually invoke ph for each session, hooks let the AI CLI tools themselves notify ph after every interaction — automatically, silently, and without any impact on response latency.
42
-
43
- > **Key insight:** Hooks are post-action handlers registered inside the AI tool's own config. ph never wraps or intercepts the AI process. The AI runs normally; the hook fires after the session ends.
44
-
45
- ### How Hooks Work
32
+ ## 2. Installation
46
33
 
47
- Each supported AI CLI tool exposes a native hook mechanism:
34
+ ```bash
35
+ # Via npm
36
+ npm install -g @gi4nks/ph
48
37
 
49
- - **Claude Code** — provides a `Stop` hook, triggered after each agent session completes
50
- - **Gemini CLI** — provides an `AfterAgent` hook, triggered after each agent turn
38
+ # From source
39
+ git clone git@github.com:gi4nks/ph.git
40
+ cd ph
41
+ npm install
42
+ npm run build
43
+ npm link
44
+ ```
51
45
 
52
- When the hook fires, the AI tool passes a JSON payload on stdin to your registered script. The script reads that payload, extracts the prompt and response, and pipes the data to `ph log` — which persists everything to the local SQLite database.
46
+ ### Quick config
53
47
 
54
- The entire operation runs in the background using shell job control (`& + disown`), so it never adds latency to your terminal session and never blocks the AI tool from exiting.
48
+ ```bash
49
+ ph config set background-analysis true # auto-analyze after each capture
50
+ ph config set analyze-provider ollama # ollama (default), gemini, openrouter, or mlx-serve
51
+ ph config set ollama-model llama3.1:latest
52
+ ```
55
53
 
56
54
  ---
57
55
 
58
- ### Claude Code Hook
56
+ ## 3. Capture Modes
59
57
 
60
- #### How Claude Code delivers data
58
+ ### 3a. Hook mode (recommended)
61
59
 
62
- When the `Stop` hook fires, Claude Code sends a JSON object on stdin:
60
+ AI CLI tools invoke `ph log` automatically after each interaction.
63
61
 
64
- ```json
65
- {
66
- "session_id": "abc123...",
67
- "transcript_path": "/path/to/session.jsonl"
68
- }
62
+ **Claude Code** — `hooks/claude/ph-hook.sh`:
63
+ ```bash
64
+ ln -sf $(pwd)/hooks/claude/ph-hook.sh ~/.claude/ph-hook.sh
65
+ # Add to ~/.claude/settings.json:
66
+ # "hooks": { "Stop": [{ "matcher": ".*", "hooks": [{ "type": "command", "command": "~/.claude/ph-hook.sh", "async": true }] }] }
69
67
  ```
70
68
 
71
- The transcript is a JSONL file — one JSON object per line — containing the full session history. Each line is one of:
72
-
73
- | Turn type | Identifier |
74
- |-----------|-----------|
75
- | Human turn | Has `promptId` key; `message.content` is a plain string |
76
- | Tool result | Has `toolUseResult` key; `message.content` is an array |
77
- | Assistant turn | `message.role == "assistant"`; content is an array of typed blocks |
78
-
79
- #### What the hook script does
80
-
81
- 1. Reads the hook input from stdin to obtain the transcript path
82
- 2. Uses `jq` with slurp mode to parse the entire JSONL in one pass
83
- 3. Filters for genuine human turns: must have `promptId`, string content, and no `toolUseResult` key
84
- 4. Extracts the last human turn as the prompt
85
- 5. Scans assistant turns for the last `text`-type block as the response
86
- 6. Builds a JSON payload with `tool`, `prompt`, `response`, and `workdir` fields
87
- 7. Pipes the payload to `ph log` running in the background (`& + disown`)
88
- 8. Exits `0` unconditionally — Claude Code is never blocked
89
-
90
- #### Hook installation — Claude Code
91
-
69
+ **Gemini CLI** — `hooks/gemini/ph-hook.sh`:
92
70
  ```bash
93
- # Step 1: link the hook script
94
- ln -sf /path/to/ph/hooks/claude/ph-hook.sh ~/.claude/ph-hook.sh
95
-
96
- # Step 2: register in ~/.claude/settings.json
97
- {
98
- "hooks": {
99
- "Stop": [
100
- {
101
- "matcher": ".*",
102
- "hooks": [
103
- {
104
- "type": "command",
105
- "command": "~/.claude/ph-hook.sh",
106
- "async": true
107
- }
108
- ]
109
- }
110
- ]
111
- }
112
- }
71
+ ln -sf $(pwd)/hooks/gemini/ph-hook.sh ~/.gemini/ph-hook.sh
72
+ # Add to ~/.gemini/settings.json:
73
+ # "hooks": { "AfterAgent": [{ "hooks": [{ "type": "command", "command": "~/.gemini/ph-hook.sh" }] }] }
113
74
  ```
114
75
 
115
- ---
116
-
117
- ### Gemini CLI Hook
76
+ **OpenCode** — plugin at `hooks/opencode/ph-plugin.ts`:
77
+ ```bash
78
+ ./hooks/opencode/install.sh # global install
79
+ ```
118
80
 
119
- #### How Gemini CLI delivers data
81
+ **Codex CLI** — see [the Codex hook setup](../hooks/codex/README.md). The Stop
82
+ hook imports the active rollout transcript. To import existing sessions, run
83
+ `ph import codex --dry-run` and then `ph import codex`.
120
84
 
121
- Gemini CLI's `AfterAgent` hook is simpler: it delivers the prompt and response directly in the stdin payload, with no transcript file to parse:
85
+ ### 3b. Wrapper mode
122
86
 
123
- ```json
124
- {
125
- "session_id": "...",
126
- "transcript_path": "...",
127
- "cwd": "/path/to/workdir",
128
- "hook_event_name": "AfterAgent",
129
- "timestamp": "...",
130
- "prompt": "the user's prompt text",
131
- "prompt_response": "the assistant's full response text"
132
- }
87
+ ```bash
88
+ ph claude "explain goroutines"
89
+ ph codex exec "explain goroutines"
90
+ ph gemini "refactor this code"
91
+ ph --ph-role debug --ph-tag auth claude "fix JWT expiration"
133
92
  ```
134
93
 
135
- #### What the hook script does
136
-
137
- 1. Reads the JSON payload from stdin
138
- 2. Extracts `prompt`, `prompt_response`, and `cwd` directly via `jq`
139
- 3. Builds a JSON payload with `tool`, `prompt`, `response`, and `workdir` fields
140
- 4. Pipes to `ph log` in the background
141
- 5. Exits `0` unconditionally
142
-
143
- #### Hook installation — Gemini CLI
94
+ ### 3c. Direct log
144
95
 
145
96
  ```bash
146
- # Step 1: link the hook script
147
- ln -sf /path/to/ph/hooks/gemini/ph-hook.sh ~/.gemini/ph-hook.sh
148
-
149
- # Step 2: register in ~/.gemini/settings.json
150
- {
151
- "hooks": {
152
- "AfterAgent": [
153
- {
154
- "hooks": [
155
- {
156
- "type": "command",
157
- "command": "~/.gemini/ph-hook.sh"
158
- }
159
- ]
160
- }
161
- ]
162
- }
163
- }
97
+ ph log --tool claude --prompt "your prompt" --response "response text"
98
+ echo '{"tool":"claude","prompt":"hi","response":"hello"}' | ph log --stdin
164
99
  ```
165
100
 
166
101
  ---
167
102
 
168
- ### OpenCode Hook
169
-
170
- OpenCode uses a JavaScript/TypeScript **plugin** system (rather than shell scripts). The `ph` integration is a plugin that hooks into OpenCode's message lifecycle to capture prompts and responses.
171
-
172
- #### How the plugin captures data
173
-
174
- The plugin registers two hooks inside OpenCode's runtime:
175
-
176
- | Hook | Purpose |
177
- |------|---------|
178
- | `chat.message` | Intercepts every message in the conversation. User messages become prompts; assistant messages become response snapshots. |
179
- | `experimental.text.complete` | Fires after streaming completes. Replaces the snapshot with the full, final response text. |
180
-
181
- **Data flow:**
103
+ ## 4. CLI Commands
104
+
105
+ | Command | Description |
106
+ |---------|-------------|
107
+ | `ph` (no args) | Open interactive TUI browser |
108
+ | `ph <tool> [args...]` | Wrapper mode — run tool + capture |
109
+ | `ph search [query]` | Full-text search prompts |
110
+ | `ph search --semantic <query>` | Semantic (vector) search |
111
+ | `ph search --archive` | Search archived prompts |
112
+ | `ph search -i <query>` | Open results in interactive TUI |
113
+ | `ph last [n]` | Show last N prompts |
114
+ | `ph context [query]` | Get RAG context for current project |
115
+ | `ph sessions` | Group prompts into work sessions |
116
+ | `ph timeline <project>` | Full chronological project history |
117
+ | `ph stats` | History statistics |
118
+ | `ph cluster -k 5` | K-means clustering on embeddings |
119
+ | `ph analyze` | LLM analysis of untagged prompts |
120
+ | `ph analyze-reusability` | Reusability scoring |
121
+ | `ph cleanup` | Remove useless prompts (length/duplicates) |
122
+ | `ph cleanup --retention` | Archive old/unqualified prompts per retention policy |
123
+ | `ph cleanup-reusability` | Cleanup by reusability score |
124
+ | `ph star <id>` | Toggle bookmark |
125
+ | `ph export <id>` | Export prompt (txt/json/md) |
126
+ | `ph import gemini|claude|opencode|codex` | Import from AI CLI history |
127
+ | `ph log --tool <name> ...` | Direct log (hook target) |
128
+ | `ph embed-all` | Generate embeddings for all prompts |
129
+ | `ph config get|set <key> <value>` | View/edit config |
130
+ | `ph vacuum` | Compact SQLite database |
131
+ | `ph memory-migrate` | Merge existing memories into project_summaries |
132
+ | `ph mcp` | Start MCP stdio server |
133
+ | `ph server --port 3001` | Start HTTP REST server |
134
+ | `ph remote push|pull|status` | Sync with remote ph server |
135
+ | `ph chat <tool> <prompt>` | Run tool with project context injected |
136
+ | `ph ollama-models` | List available Ollama models |
137
+
138
+ ### Search options
182
139
 
183
140
  ```
184
- User types prompt
185
- → chat.message fires (role: user)
186
- → plugin stores the prompt text + metadata (agent, model, workdir)
187
-
188
- Assistant streams response
189
- → experimental.text.complete fires for each text part
190
- → plugin accumulates the complete response text
191
-
192
- Next user message or session end
193
- → plugin pairs prompt + accumulated response
194
- → pipes {"tool":"opencode","prompt":"...","response":"..."} to ph log
195
- → runs in background — never blocks OpenCode
141
+ -i / --interactive Open in TUI browser
142
+ --tool <name> Filter by tool
143
+ --project <name> Filter by project
144
+ --language <lang> Filter by language
145
+ --role <role> Filter by role
146
+ --tag <tag> Filter by tag
147
+ --starred Show only starred
148
+ --semantic Use semantic (vector) search
149
+ --archive Search archived prompts
150
+ --since YYYY-MM-DD Start date
151
+ --until YYYY-MM-DD End date
152
+ --limit <n> Max results (default 50)
153
+ --top Quality >= 8
154
+ --min-quality <n> Min quality (0-10)
155
+ --min-relevance <n> Min relevance (0-10)
156
+ --full Show full prompt text
196
157
  ```
197
158
 
198
- #### Hook installation — OpenCode
199
-
200
- OpenCode loads plugins from two directories:
201
- - `~/.config/opencode/plugins/` — global (all projects)
202
- - `.opencode/plugins/` — per-project
159
+ ### Context options
203
160
 
204
- **Option A: Quick install (global)**
205
-
206
- ```bash
207
- # Link the plugin into OpenCode's global plugin directory
208
- mkdir -p ~/.config/opencode/plugins
209
- ln -sf /path/to/ph/hooks/opencode/ph-plugin.ts ~/.config/opencode/plugins/ph-plugin.ts
210
161
  ```
211
-
212
- Or use the install script:
213
-
214
- ```bash
215
- ./hooks/opencode/install.sh # global (default)
216
- ./hooks/opencode/install.sh --project # current project only
162
+ --project <name> Project name (default: auto-detect)
163
+ --limit <n> Max results (default 5)
164
+ --prompts-only Skip project knowledge, show only prompts
165
+ --memories-only Skip prompts, show only project knowledge
166
+ --verbose Include full prompt text
217
167
  ```
218
168
 
219
- **Option B: Manual copy**
169
+ ### Sessions options
220
170
 
221
- ```bash
222
- cp hooks/opencode/ph-plugin.ts ~/.config/opencode/plugins/
223
171
  ```
224
-
225
- The plugin is automatically loaded on the next OpenCode startup. No config changes needed — Bun handles TypeScript natively.
226
-
227
- **Verify:**
228
-
229
- ```bash
230
- # Start OpenCode — the plugin loads silently
231
- opencode
232
-
233
- # Check that prompts are being captured
234
- ph search --tool opencode --limit 3
172
+ --gap-hours <n> Hours gap to split sessions (default 2)
173
+ --limit <n> Max sessions (default 20)
174
+ --min-size <n> Min prompts per session (default 1)
175
+ --no-cohesion Skip semantic cohesion computation
176
+ --export <n> Export session N as markdown
235
177
  ```
236
178
 
237
- **Uninstall:**
179
+ ### Cluster options
238
180
 
239
- ```bash
240
- rm ~/.config/opencode/plugins/ph-plugin.ts
181
+ ```
182
+ -k <number> Number of clusters (default 5)
183
+ --limit <n> Max prompts per cluster to show (default 3)
241
184
  ```
242
185
 
243
186
  ---
244
187
 
245
- ### Hook Comparison
188
+ ## 5. TUI Keybindings
246
189
 
247
- | Aspect | Claude Code | Gemini CLI | OpenCode |
248
- |--------|------------|------------|----------|
249
- | Hook mechanism | `Stop` shell script | `AfterAgent` shell script | JS/TS plugin |
250
- | Data delivery | `transcript_path` (JSONL) | Direct JSON on stdin | Event hooks (`chat.message`, `experimental.text.complete`) |
251
- | Prompt extraction | Parse JSONL with `jq` slurp | `jq .prompt` | `message.role === 'user'` parts |
252
- | Response extraction | Last assistant text block | `jq .prompt_response` | `experimental.text.complete` accumulation |
253
- | Async support | Yes (`async: true`) | Yes (`& + disown`) | Yes (Promise fire-and-forget) |
254
- | Blocks AI exit? | Never | Never | Never |
255
- | Install method | Symlink + settings.json | Symlink + settings.json | Copy plugin file to `plugins/` dir |
190
+ | Key | Action |
191
+ |-----|--------|
192
+ | `Up` / `Down`, `Page Up` / `Page Down` | Navigate list |
193
+ | `Tab` | Switch pane (wide mode) |
194
+ | `1`, `2`, `3` | Switch prompt/response/memory tab |
195
+ | `y` | Copy to clipboard |
196
+ | `s` | Toggle star |
197
+ | `e` | Edit metadata |
198
+ | `r` | Rerun prompt (edit before launch) |
199
+ | `Shift+C` | Chat mode: launch tool with project context |
200
+ | `x` | Delete entry |
201
+ | `/` | Search |
202
+ | `o` | Settings panel (toggle auto-analysis, view config) |
203
+ | `f` | Filter panel (flat list, Enter toggle, letter jump) |
204
+ | `c` | Clear all filters |
205
+ | `q` / `Escape` | Quit / back |
206
+
207
+ ### TUI components
208
+
209
+ - **SearchBar** — always visible spotlight bar at top
210
+ - **FilterPanel** — flat scrollable list of filter options with counts `[N]`, toggle with Enter, jump by letter
211
+ - **SettingsView** — config viewer/editor (auto-analysis toggle, ollama URL/model, filters)
212
+ - **PreviewPane** — three tabs (prompt/response/memory). Memory tab shows project-level knowledge
213
+ - **ListEntry** — role marker, analysis status, star, Q/R badges, optional summary line
214
+ - **Footer** — context-sensitive hints (shows `C:chat` only when entry has project)
256
215
 
257
216
  ---
258
217
 
259
- ## 4. Installation
218
+ ## 6. Project Memory System
260
219
 
261
- ### From Source
220
+ ph maintains two levels of per-project knowledge:
262
221
 
263
- ```bash
264
- git clone git@github.com:gi4nks/ph.git
265
- cd ph
266
- npm install
267
- make build
268
- make install # installs the global 'ph' symlink
269
- ```
222
+ ### 6a. `project_summaries` (curated, 1 row per project)
270
223
 
271
- ### Via npm
224
+ Accumulated knowledge with deduped insights and decisions. Updated on every analysis. Primary source for MCP tools.
272
225
 
273
226
  ```bash
274
- # Install globally:
275
- npm install -g @gi4nks/ph
227
+ # View accumulated project knowledge
228
+ ph context --project myproject
229
+
230
+ # Via MCP (for AI agents)
231
+ # get_project_summary(project: "myproject")
276
232
  ```
277
233
 
278
- ### Initial Configuration
234
+ ### 6b. `memories` (append-only timeline)
279
235
 
280
- ```bash
281
- # Set your Gemini API key (optional — Ollama works without it)
282
- ph config set gemini-api-key "YOUR_KEY"
236
+ Full chronological history of every analysis run. Preserved for detailed audit.
283
237
 
284
- # Choose your analysis provider
285
- ph config set analyze-provider ollama # default, fully local
286
- # ph config set analyze-provider gemini # cloud alternative
238
+ ### Memory migration
287
239
 
288
- # Enable background analysis
289
- ph config set background-analysis true
240
+ If you have existing data from before the evolution phases:
290
241
 
291
- # Optional: move the database to a custom location
292
- ph config set db-path "/path/to/your/custom.db"
242
+ ```bash
243
+ ph memory-migrate # one-time: merge all memories into project_summaries
293
244
  ```
294
245
 
295
246
  ---
296
247
 
297
- ## 5. Usage
248
+ ## 7. Retention & Archiving
298
249
 
299
- ### Search
250
+ Configurable auto-archiving to keep the database lean:
300
251
 
301
252
  ```bash
302
- # Full-text search
303
- ph search "how to refactor"
253
+ # Configure
254
+ ph config set retentionDays 90 # archive prompts older than 90 days
255
+ ph config set retentionMinRelevance 3 # prompts below this relevance archived first
256
+ ph config set retentionMinStarred true # starred prompts never archived
257
+ ph config set retentionMinAnalyzed true # analyzed prompts never archived
304
258
 
305
- # Semantic search (vector similarity)
306
- ph search --semantic "refactoring patterns"
307
- ```
259
+ # Run retention cleanup
260
+ ph cleanup --retention # archive matching prompts
261
+ ph cleanup --retention --dry-run # preview only
308
262
 
309
- ### Interactive TUI
263
+ # Search archived prompts
264
+ ph search --archive
310
265
 
311
- ```bash
312
- ph browse
266
+ # Auto-purge: entries older than 2x retentionDays are deleted during cleanup
313
267
  ```
314
268
 
315
- Available hotkeys inside the TUI:
269
+ ---
316
270
 
317
- | Key | Action |
318
- |-----|--------|
319
- | `f` | Open filters panel |
320
- | `e` | Edit prompt metadata (tags, notes) |
321
- | `r` | Re-run selected prompt in your AI tool |
322
- | `y` | Copy prompt to clipboard |
323
- | `x` | Delete prompt from history |
271
+ ## 8. Background Analysis
324
272
 
325
- ### Export
273
+ When enabled, every `ph log` automatically spawns a detached child process that analyzes the new entry (role, tags, relevance, summary, key insights, technical decisions).
326
274
 
327
275
  ```bash
328
- # Export last 5 prompts as Markdown
329
- ph export --format md --limit 5 > prompts.md
276
+ ph config set background-analysis true
330
277
  ```
331
278
 
332
- ### Database Maintenance
279
+ Analysis uses Ollama by default (requires `ollama serve` running). Configure:
333
280
 
334
281
  ```bash
335
- # Remove short or old prompts
336
- ph cleanup --min-length 20 --days 30
282
+ ph config set analyze-provider gemini # use Gemini instead
283
+ ph config set gemini-api-key "YOUR_KEY"
284
+ ph config set ollama-model llama3.1:latest
285
+ ph config set ollama-embed-model nomic-embed-text-v2-moe
286
+ ```
337
287
 
338
- # Compact the database
339
- ph vacuum
288
+ OpenRouter and MLX-Serve generation use `@gi4nks/wise`:
340
289
 
341
- # Dry-run to preview what would be removed
342
- ph cleanup --dry-run --days 60
290
+ ```bash
291
+ # OpenRouter: credentials stay in the environment; model IDs keep provider/model.
292
+ export OPENROUTER_API_KEY="your_openrouter_api_key"
293
+ ph models openrouter
294
+ ph config set openrouter-api-key # hidden prompt; or keep using the environment
295
+ ph config set analyze-provider openrouter
296
+ ph config set openrouter-model "provider/model-id"
297
+ ph config show # provider settings with credentials redacted
298
+ ph analyze
299
+
300
+ # MLX-Serve on Parmenide: open this tunnel in a separate terminal.
301
+ ssh -N -L 11234:127.0.0.1:11234 parmenide
343
302
  ```
344
303
 
345
- ---
304
+ ```bash
305
+ # In the terminal where you run ph:
306
+ ph models mlx-serve
307
+ ph config set analyze-provider mlx-serve
308
+ ph config set mlx-serve-model "exact-model-id-from-server"
309
+ ph analyze
310
+ ```
346
311
 
347
- ## 6. Why Prompt History Matters
312
+ MLX-Serve defaults to `http://127.0.0.1:11234/v1`. Override it with
313
+ `MLX_SERVE_BASE_URL` or `ph config set mlx-serve-url <url>`. Set
314
+ `MLX_SERVE_API_KEY` if the server requires auth; `GLB_OMLX_API_KEY` is also
315
+ accepted for existing setups. Alternatively run `ph config set mlx-serve-api-key`
316
+ to enter it without echoing it in the terminal. `ph config show` redacts
317
+ credentials. `ph models mlx-serve` marks entries `[loaded]` or `[unloaded]`.
348
318
 
349
- Every interaction with an AI tool is a unit of intellectual work. A well-crafted prompt encodes context, intent, and engineering decisions that took time to develop. Without capture, that work is lost the moment the session closes.
319
+ ---
350
320
 
351
- ph treats your prompt history as a first-class artifact: searchable, annotated, versioned with Git context, and available for re-use. Over time, your history becomes a personal knowledge base of how you think and work with AI tools.
321
+ ## 9. MCP Server
352
322
 
353
- > **The problem:** Manually saving prompts takes time, breaks flow, and rarely happens consistently. Without structure, even saved prompts become unsearchable noise.
323
+ ph exposes an MCP (Model Context Protocol) server over stdio for AI agents:
354
324
 
355
- > **The solution:** ph captures everything automatically via hooks, indexes it locally, and gives you semantic search so you can find what you need — even if you only remember the intent, not the exact wording.
325
+ ```bash
326
+ ph mcp
327
+ ```
356
328
 
357
- ---
329
+ ### Available tools
330
+
331
+ | Tool | Description |
332
+ |------|-------------|
333
+ | `search_project_memory` | Semantic search + fallback to project_summaries |
334
+ | `get_project_context` | Merged summary + recent memories + recent prompts |
335
+ | `get_project_summary` | Accumulated key insights and technical decisions |
336
+ | `check_project_knowledge` | Before implementing: checks memories + prompts for existing work |
337
+ | `save_decision` | Persist an architectural decision to memory + summaries |
338
+ | `search_prompts` | Full-text search over prompt history |
339
+ | `get_prompt` | Full details by ID |
340
+ | `search_prompts_semantic` | Vector search over prompts |
341
+ | `get_project_timeline` | Full chronological project history |
342
+ | `get_project_diff` | Compare project state between dates |
343
+ | `list_prompts` | Paginated prompt listing |
358
344
 
359
345
  ---
360
346
 
361
- ## 7. Remote Server Setup
362
-
363
- ph can act as a central sync hub for prompt history across multiple machines.
347
+ ## 10. HTTP Server & Remote Sync
364
348
 
365
- ### Server Installation
349
+ Share prompt history across machines:
366
350
 
367
351
  ```bash
368
- # Install globally
369
- sudo npm install -g @gi4nks/ph
370
-
371
- # Verify
372
- ph --help
352
+ # Start server
353
+ ph server --port 3001 --host 0.0.0.0
354
+
355
+ # From another machine
356
+ ph config set remote-url http://server-ip:3001
357
+ ph remote push # send local unsynced prompts
358
+ ph remote pull # fetch remote prompts
359
+ ph remote status # show sync state
373
360
  ```
374
361
 
375
- ### Ubuntu (systemd service)
362
+ Every `ph log` auto-pushes to remote if configured (fire-and-forget, never blocks).
376
363
 
377
- Create `/etc/systemd/system/ph.service`:
364
+ ---
378
365
 
379
- ```ini
380
- [Unit]
381
- Description=ph remote sync server
382
- After=network.target
366
+ ## 11. Database
383
367
 
384
- [Service]
385
- Type=simple
386
- ExecStart=<path-to-ph> server --port 3001 --host 0.0.0.0
387
- Restart=always
388
- RestartSec=5
389
- User=<your-user>
390
- Environment=NODE_ENV=production
391
- StandardOutput=append:/var/log/ph-server.log
392
- StandardError=append:/var/log/ph-server.log
368
+ **Location:** `~/.prompt_history.db` (configurable via `ph config set db-path`)
393
369
 
394
- [Install]
395
- WantedBy=multi-user.target
396
- ```
370
+ **Tables:**
397
371
 
398
- Replace `<path-to-ph>` with the output of `which ph` on the server, and `<your-user>` with the user running the service.
372
+ | Table | Purpose |
373
+ |-------|---------|
374
+ | `prompts` | Main prompt+response storage with FTS5 index |
375
+ | `prompts_archive` | Archived (retention-aged) prompts |
376
+ | `memories` | Append-only per-project analysis timeline |
377
+ | `project_summaries` | Single curated row per project with merged knowledge |
378
+ | `vec_embeddings` | Vector embeddings (768-dim float, sqlite-vec) |
379
+ | `embeddings` | Legacy BLOB embeddings (migrated on connect) |
399
380
 
400
- ```bash
401
- sudo systemctl daemon-reload
402
- sudo systemctl enable --now ph.service
403
- sudo systemctl status ph.service
404
- sudo ufw allow 3001/tcp # if firewall is enabled
405
- ```
406
-
407
- ### macOS (launchd)
408
-
409
- Create `~/Library/LaunchAgents/com.gi4nks.ph.plist`:
410
-
411
- ```xml
412
- <?xml version="1.0" encoding="UTF-8"?>
413
- <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
414
- <plist version="1.0">
415
- <dict>
416
- <key>Label</key>
417
- <string>com.gi4nks.ph</string>
418
- <key>ProgramArguments</key>
419
- <array>
420
- <string>/usr/local/bin/ph</string>
421
- <string>server</string>
422
- <string>--port</string>
423
- <string>3001</string>
424
- <string>--host</string>
425
- <string>0.0.0.0</string>
426
- </array>
427
- <key>RunAtLoad</key>
428
- <true/>
429
- <key>KeepAlive</key>
430
- <true/>
431
- <key>StandardOutPath</key>
432
- <string>/tmp/ph-server.log</string>
433
- <key>StandardErrorPath</key>
434
- <string>/tmp/ph-server.err</string>
435
- </dict>
436
- </plist>
437
- ```
381
+ **Maintenance:**
438
382
 
439
383
  ```bash
440
- launchctl load ~/Library/LaunchAgents/com.gi4nks.ph.plist
384
+ ph vacuum # compact DB
385
+ ph cleanup # remove short/trivial/duplicate prompts
386
+ ph cleanup --retention # archive per retention policy
387
+ ph embed-all # (re)generate all embeddings
441
388
  ```
442
389
 
443
- ### Client Setup
390
+ ---
444
391
 
445
- ```bash
446
- # Configure remote server URL
447
- ph config set remote-url http://<server-ip>:3001
448
- # Or via env var (takes precedence)
449
- export PH_REMOTE_URL=http://<server-ip>:3001
450
-
451
- # Sync commands
452
- ph remote push # send unsynced local prompts to server
453
- ph remote pull # fetch remote prompts since last pull
454
- ph remote status # show sync state
455
- ```
392
+ ## 12. Filter Pipeline
456
393
 
457
- After `ph remote-url` is configured, every `ph log` automatically does a background push to the server (fire-and-forget, never blocks).
394
+ Before saving, ph filters out:
458
395
 
459
- ### Logs
396
+ - Prompts shorter than `filterMinLength` (default 15 chars)
397
+ - Non-printable content
398
+ - Trivial patterns (single chars, common noise)
399
+ - Exact duplicates (within last 7 days)
400
+ - Low-relevance prompts (when `--min-relevance` is set)
460
401
 
461
- ```bash
462
- # systemd
463
- sudo journalctl -u ph.service -f
402
+ Configure:
464
403
 
465
- # launchd
466
- cat /tmp/ph-server.log
404
+ ```bash
405
+ ph config set filter-min-length 20
406
+ ph config set filter-min-relevance 3
467
407
  ```
468
408
 
469
409
  ---
470
410
 
471
- ## 8. Release Process
411
+ ## 13. Configuration (`~/.ph_config.json`)
412
+
413
+ | Key | Default | Description |
414
+ |-----|---------|-------------|
415
+ | `dbPath` | `~/.prompt_history.db` | SQLite database path |
416
+ | `analyzeProvider` | `ollama` | LLM provider: `ollama`, `gemini`, `openrouter`, or `mlx-serve` |
417
+ | `ollamaUrl` | `http://localhost:11434` | Ollama server URL |
418
+ | `ollamaModel` | `llama3.1:latest` | Analysis model |
419
+ | `ollamaEmbedModel` | `nomic-embed-text-v2-moe` | Embedding model |
420
+ | `geminiApiKey` | — | Gemini API key |
421
+ | `openrouterModel` | — | Exact OpenRouter model ID |
422
+ | `openrouterUrl` | `https://openrouter.ai/api/v1` | OpenRouter-compatible API root |
423
+ | `mlxServeModel` | — | Exact MLX-Serve model ID |
424
+ | `mlxServeUrl` | `http://127.0.0.1:11234/v1` | MLX-Serve API root (Parmenide SSH tunnel by default) |
425
+ | `backgroundAnalysis` | `false` | Auto-analyze after each capture |
426
+ | `filterMinLength` | `15` | Min prompt length to keep |
427
+ | `filterMinRelevance` | `3` | Min relevance to keep (0=disable) |
428
+ | `retentionDays` | `90` | Auto-archive after N days |
429
+ | `retentionMinStarred` | `true` | Keep starred prompts |
430
+ | `retentionMinAnalyzed` | `true` | Keep analyzed prompts |
431
+ | `retentionMinRelevance` | `3` | Archive prompts below this relevance |
432
+ | `remoteUrl` | — | Remote ph server URL (or `PH_REMOTE_URL` env) |
433
+ | `remoteApiKey` | — | Remote server API key |
434
+ | `remoteLastPush` | — | Timestamp of last successful push |
435
+ | `remoteLastPull` | — | Timestamp of last successful pull |
436
+
437
+ Provider API credentials are environment-only: `OPENROUTER_API_KEY` and
438
+ `MLX_SERVE_API_KEY` (`GLB_OMLX_API_KEY` is a fallback). They are not written to
439
+ `~/.ph_config.json`.
440
+
441
+ ---
442
+
443
+ ## 14. Architecture
472
444
 
473
- Releases are fully automated via **semantic-release** using conventional commits.
445
+ ```
446
+ Hook/Import → ph log → prompts table (FTS5 indexed)
447
+ ↓
448
+ Background analysis (optional)
449
+ ↓
450
+ ┌────────────────┴────────────────┐
451
+ ↓ ↓
452
+ memories (append-only, project_summaries
453
+ with TTL) (1 row per project,
454
+ merged + deduped)
455
+ ↓ ↓
456
+ ph cleanup --retention MCP tools read
457
+ → prompts_archive from here
458
+ ```
474
459
 
475
- ### How it works
460
+ ### File layout
476
461
 
477
- 1. All commits must follow the [Conventional Commits](https://www.conventionalcommits.org/) format:
462
+ ```
463
+ src/
464
+ cli.ts # Entry point (~80 lines), switch dispatch
465
+ types.ts # Core types (PromptEntry, MemoryEntry, ProjectSummary, etc.)
466
+ db/index.ts # PhDB public SQLite adapter
467
+ db/semantic-index.ts # Vector encoding, storage, and nearest-neighbor search
468
+ context/index.ts # Shared project-context retrieval and rendering
469
+ capture/index.ts # Shared capture-record normalization
470
+ commands/ # One module per CLI command
471
+ analyzer/ # LLM analysis (role/tag/relevance/summary/insights)
472
+ embedding/ # Ollama embedding generation
473
+ filter/ # Capture-time filter pipeline
474
+ mcp/server.ts # MCP stdio server
475
+ server/index.ts # HTTP REST server (zero deps)
476
+ ui/ # React/Ink TUI, including extracted filter policy and panel
477
+ importer/ # Gemini/Claude/OpenCode/Codex history importers
478
+ hooks/ # Shell scripts and plugins for AI tools
479
+ ```
478
480
 
479
- ```
480
- feat: add new feature → minor release (1.x.0)
481
- fix: resolve bug → patch release (1.0.x)
482
- chore: bump deps → no release
483
- BREAKING CHANGE: ... → major release (x.0.0)
484
- ```
481
+ ---
485
482
 
486
- 2. Push to `main` triggers GitHub Actions workflow `.github/workflows/release.yml`
483
+ ## 15. Importing Existing History
487
484
 
488
- 3. The workflow runs:
489
- - `actions/checkout@v4` with full git history (`fetch-depth: 0`)
490
- - `actions/setup-node@v4` with Node 22
491
- - `npm ci` — clean install
492
- - `npm run build` — tsup bundle
493
- - `npx semantic-release` — analyzes commits, bumps version, updates CHANGELOG.md, creates git tag, publishes to npm
485
+ ```bash
486
+ # Import from Claude Code
487
+ ph import claude --analyze
494
488
 
495
- ### npm publish details
489
+ # Import from Gemini CLI
490
+ ph import gemini --filter
496
491
 
497
- - **OIDC Trusted Publishing**: Package is signed with provenance attestation via GitHub Actions OIDC token
498
- - **Publisher identity**: `GitHub Actions <npm-oidc-no-reply@github.com>`
499
- - **Registry**: `https://registry.npmjs.org/`
500
- - **Access**: public
492
+ # Import from OpenCode
493
+ ph import opencode
501
494
 
502
- ### Verify provenance
495
+ # Import from Codex CLI
496
+ ph import codex --dry-run
497
+ ph import codex
503
498
 
504
- ```bash
505
- npm audit signatures
499
+ # Options:
500
+ # --analyze run LLM analysis on imported prompts
501
+ # --filter apply capture-time filters
502
+ # --dry-run preview without importing
506
503
  ```
507
504
 
508
- ### Manual release (emergency)
505
+ ---
506
+
507
+ ## 16. Versioning and Releases
509
508
 
510
- Create a tag manually and push:
509
+ Use Conventional Commits to describe changes: `feat:` requests a minor release,
510
+ `fix:` requests a patch release, and `BREAKING CHANGE:` requests a major release.
511
+ The GitHub Actions workflow runs `semantic-release` on pushes to `main`, updates
512
+ release metadata, publishes to npm, and creates a GitHub release.
511
513
 
512
- ```bash
513
- git tag v1.2.3
514
- git push origin v1.2.3
515
- ```
514
+ The Make targets `make release-patch`, `make release-minor`, and
515
+ `make release-major` increment `package.json` and `package-lock.json` locally.
516
+ They do not commit, tag, or publish. The automated release workflow determines
517
+ the actual published version from commits since its most recent release tag.
516
518
 
517
519
  ---
518
520