@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.
- package/CHANGELOG.md +9 -2
- package/LICENSE +1 -1
- package/README.md +155 -145
- package/dist/cli.js +2279 -1052
- package/dist/cli.js.map +1 -1
- package/docs/evals/context-retrieval-golden.json +26 -0
- package/docs/evals/context-retrieval.md +27 -0
- package/docs/hooks.md +13 -7
- package/docs/ph-analysis.html +145 -0
- package/docs/ph-manual.md +375 -373
- package/docs/specs/SPEC-001-architecture-cli.md +82 -0
- package/docs/specs/SPEC-002-database-layer.md +105 -0
- package/docs/specs/SPEC-003-capture-modes.md +110 -0
- package/docs/specs/SPEC-004-filter-metadata.md +82 -0
- package/docs/specs/SPEC-005-search.md +102 -0
- package/docs/specs/SPEC-006-analysis-pipeline.md +98 -0
- package/docs/specs/SPEC-007-memory-summaries.md +96 -0
- package/docs/specs/SPEC-008-embeddings.md +90 -0
- package/docs/specs/SPEC-009-retention-archive.md +91 -0
- package/docs/specs/SPEC-010-remote-sync.md +106 -0
- package/docs/specs/SPEC-011-mcp-server.md +94 -0
- package/docs/specs/SPEC-012-tui-browser.md +98 -0
- package/docs/specs/SPEC-013-importers.md +109 -0
- package/docs/specs/SPEC-014-analytics-commands.md +109 -0
- package/docs/specs/SPEC-015-config-env.md +85 -0
- package/docs/specs/SPEC-INDEX.md +35 -0
- package/docs/specs/SPEC-ISSUES.md +122 -0
- package/docs/specs/_TEMPLATE.md +65 -0
- package/docs/superpowers/plans/2026-06-12-ph-evolution-phase1.md +466 -0
- package/docs/superpowers/plans/2026-06-12-ph-evolution-phase2.md +351 -0
- package/docs/superpowers/specs/2026-06-12-ph-evolution-design.md +173 -0
- package/hooks/claude/README.md +1 -1
- package/hooks/codex/README.md +54 -0
- package/hooks/codex/ph-hook.sh +14 -0
- package/hooks/gemini/README.md +1 -1
- package/hooks/opencode/ph-plugin.ts +60 -57
- package/package.json +18 -12
package/docs/ph-manual.md
CHANGED
|
@@ -1,518 +1,520 @@
|
|
|
1
|
-
# ph — Prompt History
|
|
1
|
+
# ph — Prompt History and Project Memory
|
|
2
2
|
|
|
3
|
-
**
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
##
|
|
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
|
-
|
|
34
|
+
```bash
|
|
35
|
+
# Via npm
|
|
36
|
+
npm install -g @gi4nks/ph
|
|
48
37
|
|
|
49
|
-
|
|
50
|
-
|
|
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
|
-
|
|
46
|
+
### Quick config
|
|
53
47
|
|
|
54
|
-
|
|
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
|
-
|
|
56
|
+
## 3. Capture Modes
|
|
59
57
|
|
|
60
|
-
|
|
58
|
+
### 3a. Hook mode (recommended)
|
|
61
59
|
|
|
62
|
-
|
|
60
|
+
AI CLI tools invoke `ph log` automatically after each interaction.
|
|
63
61
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
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
|
-
|
|
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
|
-
|
|
94
|
-
|
|
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
|
-
|
|
76
|
+
**OpenCode** — plugin at `hooks/opencode/ph-plugin.ts`:
|
|
77
|
+
```bash
|
|
78
|
+
./hooks/opencode/install.sh # global install
|
|
79
|
+
```
|
|
118
80
|
|
|
119
|
-
|
|
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
|
-
|
|
85
|
+
### 3b. Wrapper mode
|
|
122
86
|
|
|
123
|
-
```
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
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
|
-
|
|
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
|
-
|
|
147
|
-
|
|
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
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
|
177
|
-
|
|
178
|
-
| `
|
|
179
|
-
| `
|
|
180
|
-
|
|
181
|
-
|
|
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
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
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
|
-
|
|
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
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
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
|
-
|
|
169
|
+
### Sessions options
|
|
220
170
|
|
|
221
|
-
```bash
|
|
222
|
-
cp hooks/opencode/ph-plugin.ts ~/.config/opencode/plugins/
|
|
223
171
|
```
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
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
|
-
|
|
179
|
+
### Cluster options
|
|
238
180
|
|
|
239
|
-
```
|
|
240
|
-
|
|
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
|
-
|
|
188
|
+
## 5. TUI Keybindings
|
|
246
189
|
|
|
247
|
-
|
|
|
248
|
-
|
|
249
|
-
|
|
|
250
|
-
|
|
|
251
|
-
|
|
|
252
|
-
|
|
|
253
|
-
|
|
|
254
|
-
|
|
|
255
|
-
|
|
|
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
|
-
##
|
|
218
|
+
## 6. Project Memory System
|
|
260
219
|
|
|
261
|
-
|
|
220
|
+
ph maintains two levels of per-project knowledge:
|
|
262
221
|
|
|
263
|
-
|
|
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
|
-
|
|
224
|
+
Accumulated knowledge with deduped insights and decisions. Updated on every analysis. Primary source for MCP tools.
|
|
272
225
|
|
|
273
226
|
```bash
|
|
274
|
-
#
|
|
275
|
-
|
|
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
|
-
###
|
|
234
|
+
### 6b. `memories` (append-only timeline)
|
|
279
235
|
|
|
280
|
-
|
|
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
|
-
|
|
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
|
-
|
|
289
|
-
ph config set background-analysis true
|
|
240
|
+
If you have existing data from before the evolution phases:
|
|
290
241
|
|
|
291
|
-
|
|
292
|
-
ph
|
|
242
|
+
```bash
|
|
243
|
+
ph memory-migrate # one-time: merge all memories into project_summaries
|
|
293
244
|
```
|
|
294
245
|
|
|
295
246
|
---
|
|
296
247
|
|
|
297
|
-
##
|
|
248
|
+
## 7. Retention & Archiving
|
|
298
249
|
|
|
299
|
-
|
|
250
|
+
Configurable auto-archiving to keep the database lean:
|
|
300
251
|
|
|
301
252
|
```bash
|
|
302
|
-
#
|
|
303
|
-
ph
|
|
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
|
-
#
|
|
306
|
-
ph
|
|
307
|
-
|
|
259
|
+
# Run retention cleanup
|
|
260
|
+
ph cleanup --retention # archive matching prompts
|
|
261
|
+
ph cleanup --retention --dry-run # preview only
|
|
308
262
|
|
|
309
|
-
|
|
263
|
+
# Search archived prompts
|
|
264
|
+
ph search --archive
|
|
310
265
|
|
|
311
|
-
|
|
312
|
-
ph browse
|
|
266
|
+
# Auto-purge: entries older than 2x retentionDays are deleted during cleanup
|
|
313
267
|
```
|
|
314
268
|
|
|
315
|
-
|
|
269
|
+
---
|
|
316
270
|
|
|
317
|
-
|
|
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
|
-
|
|
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
|
-
|
|
329
|
-
ph export --format md --limit 5 > prompts.md
|
|
276
|
+
ph config set background-analysis true
|
|
330
277
|
```
|
|
331
278
|
|
|
332
|
-
|
|
279
|
+
Analysis uses Ollama by default (requires `ollama serve` running). Configure:
|
|
333
280
|
|
|
334
281
|
```bash
|
|
335
|
-
|
|
336
|
-
ph
|
|
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
|
-
|
|
339
|
-
ph vacuum
|
|
288
|
+
OpenRouter and MLX-Serve generation use `@gi4nks/wise`:
|
|
340
289
|
|
|
341
|
-
|
|
342
|
-
|
|
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
|
-
|
|
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
|
-
|
|
319
|
+
---
|
|
350
320
|
|
|
351
|
-
|
|
321
|
+
## 9. MCP Server
|
|
352
322
|
|
|
353
|
-
|
|
323
|
+
ph exposes an MCP (Model Context Protocol) server over stdio for AI agents:
|
|
354
324
|
|
|
355
|
-
|
|
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
|
-
##
|
|
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
|
-
|
|
349
|
+
Share prompt history across machines:
|
|
366
350
|
|
|
367
351
|
```bash
|
|
368
|
-
#
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
#
|
|
372
|
-
ph
|
|
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
|
-
|
|
362
|
+
Every `ph log` auto-pushes to remote if configured (fire-and-forget, never blocks).
|
|
376
363
|
|
|
377
|
-
|
|
364
|
+
---
|
|
378
365
|
|
|
379
|
-
|
|
380
|
-
[Unit]
|
|
381
|
-
Description=ph remote sync server
|
|
382
|
-
After=network.target
|
|
366
|
+
## 11. Database
|
|
383
367
|
|
|
384
|
-
|
|
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
|
-
|
|
395
|
-
WantedBy=multi-user.target
|
|
396
|
-
```
|
|
370
|
+
**Tables:**
|
|
397
371
|
|
|
398
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
390
|
+
---
|
|
444
391
|
|
|
445
|
-
|
|
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
|
-
|
|
394
|
+
Before saving, ph filters out:
|
|
458
395
|
|
|
459
|
-
|
|
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
|
-
|
|
462
|
-
# systemd
|
|
463
|
-
sudo journalctl -u ph.service -f
|
|
402
|
+
Configure:
|
|
464
403
|
|
|
465
|
-
|
|
466
|
-
|
|
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
|
-
##
|
|
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
|
-
|
|
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
|
-
###
|
|
460
|
+
### File layout
|
|
476
461
|
|
|
477
|
-
|
|
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
|
-
|
|
483
|
+
## 15. Importing Existing History
|
|
487
484
|
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
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
|
-
|
|
489
|
+
# Import from Gemini CLI
|
|
490
|
+
ph import gemini --filter
|
|
496
491
|
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
- **Registry**: `https://registry.npmjs.org/`
|
|
500
|
-
- **Access**: public
|
|
492
|
+
# Import from OpenCode
|
|
493
|
+
ph import opencode
|
|
501
494
|
|
|
502
|
-
|
|
495
|
+
# Import from Codex CLI
|
|
496
|
+
ph import codex --dry-run
|
|
497
|
+
ph import codex
|
|
503
498
|
|
|
504
|
-
|
|
505
|
-
|
|
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
|
-
|
|
505
|
+
---
|
|
506
|
+
|
|
507
|
+
## 16. Versioning and Releases
|
|
509
508
|
|
|
510
|
-
|
|
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
|
-
|
|
513
|
-
|
|
514
|
-
|
|
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
|
|