dsh-hypatia-auto-memory 0.1.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.
@@ -0,0 +1,585 @@
1
+ ---
2
+ name: hypatia
3
+ description: "Interact with the Hypatia AI memory system using natural language. Translate user requests into hypatia CLI commands for knowledge CRUD, statement (RDF triple) management, JSE queries, full-text search, and shelf management. Trigger when: user mentions memories, knowledge bases, knowledge graphs, triples, statements, relationships, shelves, or asks to store, recall, remember, record, save, find, or search information in hypatia. Also trigger when user wants to create or explore relationships between concepts, query existing knowledge, or manage shelves. Examples: 'remember that Rust is a systems language', 'find everything about Alice', 'record that Alice knows Bob', 'search for programming', 'show all knowledge', 'list shelves'."
4
+ user-invocable: true
5
+ allowed-tools: Bash, Read, Grep, Glob
6
+ argument-hint: <natural-language instruction>
7
+ ---
8
+
9
+ # Hypatia Query Skill
10
+
11
+ You are operating the Hypatia CLI — an AI-oriented memory management system. Translate the user's natural language request into the appropriate `hypatia` CLI command and execute it via Bash.
12
+
13
+ ## Binary Location
14
+
15
+ First check which binary is available:
16
+
17
+ 1. `hypatia` — if installed on PATH
18
+ 2. `./target/debug/hypatia` — debug build in current project
19
+ 3. `./target/release/hypatia` — release build in current project
20
+
21
+ Use the first one found. All examples below use `hypatia` for brevity.
22
+
23
+ ## Shelf Management
24
+
25
+ | User says | Command |
26
+ |---|---|
27
+ | "list shelves" / "show connected shelves" | `hypatia list` |
28
+ | "connect shelf at PATH" / "open data at PATH" | `hypatia connect <path> [-n <name>]` |
29
+ | "disconnect shelf NAME" / "close shelf NAME" | `hypatia disconnect <name>` |
30
+ | "export shelf NAME to DEST" | `hypatia export <name> <dest>` |
31
+
32
+ ## Archive Files
33
+
34
+ Archive files (images, PDFs, data, etc.) are stored in the shelf's `archives/` directory and referenced via `archive://` paths.
35
+
36
+ | User says | Command |
37
+ |---|---|
38
+ | "store this image" / "add figure fig.png" | `hypatia archive-store <file> -n <dest_path>` |
39
+ | "get archive fig.png" / "show image path" | `hypatia archive-get <name>` |
40
+ | "copy archive to /tmp" | `hypatia archive-get <name> -o /tmp/output.png` |
41
+ | "list archives" / "show all files" | `hypatia archive-list` |
42
+
43
+ `archive-store` automatically creates a knowledge entry with file metadata (size, MIME type) and an `is_a archive` statement. Archive files can be queried via JSE:
44
+
45
+ ```bash
46
+ hypatia query '["$knowledge", ["$contains", "tags", "archive"]]'
47
+ hypatia query '["$knowledge", ["$content", {"mime_type": "image/png"}]]'
48
+ ```
49
+
50
+ To reference an archive when creating knowledge:
51
+
52
+ ```bash
53
+ hypatia knowledge-create "Euclid Prop 1" -d "equilateral triangle" --figures "archive://euclid/fig1.png"
54
+ ```
55
+
56
+ ### Scopes
57
+
58
+ Use `--scopes` to assign project or global scope to knowledge and statements. The value is comma-separated. **Global scope is stored as an empty-string entry, and only a trailing comma writes it**: `--scopes ","` is global only, and `--scopes "my-project,"` is both. `--scopes ""` stores no scope at all, so global lookups such as `["$has", "scopes", ""]` will never find the entry.
59
+
60
+ ```bash
61
+ # Project-scoped only
62
+ hypatia knowledge-create "API convention" -d "REST endpoints use kebab-case" --tags "rule" --scopes "my-project"
63
+
64
+ # Global scope only (trailing comma; `--scopes ""` would store no scope)
65
+ hypatia knowledge-create "prefer immutable" -d "always create new objects" --tags "rule" --scopes ","
66
+
67
+ # Both project and global (trailing comma)
68
+ hypatia knowledge-create "no mock DB" -d "never mock database in tests" --tags "taboo" --scopes "my-project,"
69
+ ```
70
+
71
+ ## Knowledge CRUD
72
+
73
+ Knowledge entries are independent information points with a name, content, and tags.
74
+
75
+ ### Create
76
+
77
+ ```
78
+ hypatia knowledge-create <name> -d "<data>" -t "<tag1,tag2>" --figures "archive://path/to/file"
79
+ ```
80
+
81
+ | User says | Command |
82
+ |---|---|
83
+ | "remember Rust as a systems programming language" | `hypatia knowledge-create "Rust" -d "systems programming language" -t "language,compiled"` |
84
+ | "save knowledge about Go with tags language and compiled" | `hypatia knowledge-create "Go" -d "" -t "language,compiled"` |
85
+ | "store that Python is a scripting language, tag it as dynamic" | `hypatia knowledge-create "Python" -d "scripting language" -t "dynamic"` |
86
+
87
+ ### Read
88
+
89
+ ```
90
+ hypatia knowledge-get <name>
91
+ ```
92
+
93
+ | User says | Command |
94
+ |---|---|
95
+ | "show me knowledge about Rust" / "get Rust entry" | `hypatia knowledge-get "Rust"` |
96
+
97
+ ### Update
98
+
99
+ ```
100
+ hypatia knowledge-update <name> [-d "<data>"] [-t "<tags>"] [--synonyms "<csv>"] [--figures "<refs>"] [--scopes "<scopes>"]
101
+ ```
102
+
103
+ Only the fields you pass change. An omitted field keeps its stored value, and exactly `""` clears a field, such as `-t ""`; for tags, `","` or `" "` would store blank tags instead. `--scopes` replaces the stored scopes and is parsed as on create: end the list with a comma, such as `"q,"`, to include the global scope, or the entry drops out of global lookups. The entry keeps its `created_at`. Its old vector is discarded, and a new one is generated on the next flush, as after `knowledge-create`. Updating an entry that does not exist is an error. An update that changes nothing prints `Knowledge unchanged: <name>` and writes nothing.
104
+
105
+ | User says | Command |
106
+ |---|---|
107
+ | "update Rust's description to mention memory safety" | `hypatia knowledge-update "Rust" -d "systems programming language with memory safety"` |
108
+ | "retag Go as language and google" | `hypatia knowledge-update "Go" -t "language,google"` |
109
+ | "remove all tags from Python" | `hypatia knowledge-update "Python" -t ""` |
110
+
111
+ ### Delete
112
+
113
+ ```
114
+ hypatia knowledge-delete <name>
115
+ ```
116
+
117
+ | User says | Command |
118
+ |---|---|
119
+ | "delete knowledge Rust" / "remove the Rust entry" | `hypatia knowledge-delete "Rust"` |
120
+
121
+ ## Statement Creation — Proactive Graph Building
122
+
123
+ Statements are RDF-style triples: `(head, relation, tail)`. They form the edges of the knowledge graph.
124
+
125
+ ### Key Principle: Always Enrich with Relationships
126
+
127
+ When the user asks to store or remember information, **always create statements alongside knowledge entries** to build graph connectivity. The goal is a rich, traversable knowledge graph, not isolated data points.
128
+
129
+ **Pattern**: After creating a knowledge entry, identify entities mentioned in the content and create `$triple` relationships between them. At minimum, create one `is_a` statement for every new knowledge entry.
130
+
131
+ ```
132
+ hypatia statement-create <head> <relation> <tail> -d "<data>"
133
+ ```
134
+
135
+ ### Triple Extraction Patterns
136
+
137
+ | User says | head | relation | tail |
138
+ |---|---|---|---|
139
+ | "record that Alice knows Bob" | Alice | knows | Bob |
140
+ | "X is a Y" / "X is an Y" | X | is_a | Y |
141
+ | "X belongs to Y" / "X is part of Y" | X | belongs_to | Y |
142
+ | "X works for Y" | X | works_for | Y |
143
+ | "X is related to Y" | X | related_to | Y |
144
+ | "X depends on Y" | X | depends_on | Y |
145
+ | "X uses Y" | X | uses | Y |
146
+ | "X contains Y" | X | contains | Y |
147
+ | "X created Y" | X | created_by | Y (reversed) |
148
+
149
+ Normalize relations to `snake_case`. Common relations: `is_a`, `knows`, `related_to`, `works_for`, `belongs_to`, `depends_on`, `uses`, `contains`, `created_by`.
150
+
151
+ ### Proactive Creation Examples
152
+
153
+ When the user says **"remember that Rust is a systems programming language"**, execute BOTH:
154
+
155
+ ```bash
156
+ hypatia knowledge-create "Rust" -d "systems programming language" -t "language,compiled"
157
+ hypatia statement-create "Rust" "is_a" "systems programming language"
158
+ ```
159
+
160
+ When the user says **"remember that PostgreSQL is a relational database used by the API"**, execute:
161
+
162
+ ```bash
163
+ hypatia knowledge-create "PostgreSQL" -d "relational database" -t "database,relational"
164
+ hypatia statement-create "PostgreSQL" "is_a" "relational database"
165
+ hypatia statement-create "API" "depends_on" "PostgreSQL" -d "primary data store"
166
+ ```
167
+
168
+ When the user says **"note that Alice is a senior engineer on the Backend team"**, execute:
169
+
170
+ ```bash
171
+ hypatia knowledge-create "Alice" -d "senior engineer on Backend team" -t "person,engineer"
172
+ hypatia statement-create "Alice" "is_a" "senior engineer"
173
+ hypatia statement-create "Alice" "works_for" "Backend team"
174
+ ```
175
+
176
+ ### Auto-linking Rules
177
+
178
+ When creating knowledge entries, automatically extract and create statements for:
179
+ 1. **Category**: `"X" is_a "<category>"` — every entity has a type
180
+ 2. **Dependencies**: if the content mentions tools, frameworks, or systems X depends on → `X depends_on Y`
181
+ 3. **Relationships**: if the content mentions other entities → link them with appropriate relations
182
+ 4. **Containment**: if X is part of Y → `X belongs_to Y`
183
+
184
+ ## Thinking Aloud Protocol
185
+
186
+ **Every query execution MUST be preceded by a brief explanation.** Before running any hypatia command, output a thinking block in this format:
187
+
188
+ ```
189
+ **Step N: <goal>**
190
+
191
+ > `hypatia <command>`
192
+
193
+ 为什么用这个查询:<1-2 sentence explanation of why this operator/strategy was chosen>
194
+ 预期结果:<what kind of results to expect>
195
+ ```
196
+
197
+ Then execute the command. After results come back, briefly interpret them before deciding the next step.
198
+
199
+ ### Example Walkthrough
200
+
201
+ User asks: *"查找与 Alice 相关的所有知识,以及她的关系网络"*
202
+
203
+ ```
204
+ **Step 1: 直接获取 Alice 的知识条目**
205
+
206
+ > `hypatia knowledge-get "Alice"`
207
+
208
+ 为什么用这个查询:用户提到了明确的实体名 "Alice",先尝试直接 lookup 获取完整条目。
209
+ 预期结果:如果存在,返回 Alice 的知识条目(content, tags, figures 等)。
210
+ ```
211
+
212
+ (执行... 得到结果或 "not found")
213
+
214
+ ```
215
+ **Step 2: 查找 Alice 参与的所有三元组关系**
216
+
217
+ > `hypatia query '["$statement", ["$triple", "Alice", "$*", "$*"]]'`
218
+
219
+ 为什么用这个查询:用 $triple 对 head 位精确匹配 "Alice",wildcard relation 和 tail,
220
+ 这样可以拿到 Alice 作为主语的所有关系(knows, is_a, works_for 等),$triple 走索引,比 $search 更快更精确。
221
+ 预期结果:返回所有 Alice 作为 head 的 statement triples。
222
+ ```
223
+
224
+ (执行... 得到结果)
225
+
226
+ ```
227
+ **Step 3: 查找指向 Alice 的关系(Alice 作为 tail)**
228
+
229
+ > `hypatia query '["$statement", ["$triple", "$*", "$*", "Alice"]]'`
230
+
231
+ 为什么用这个查询:上一步只查了 Alice 作为 head 的关系,但其他人可能指向 Alice(如 "Bob knows Alice"),
232
+ 需要查 tail 位 = Alice 的三元组才能得到完整的关系网络。
233
+ 预期结果:返回所有以 Alice 为宾语的 statement triples。
234
+ ```
235
+
236
+ (执行... 得到结果)
237
+
238
+ ```
239
+ **Step 4: 2-hop 图遍历,探索 Alice 的更远关系**
240
+
241
+ > `hypatia query '["$statement", ["$k-hop", "Alice", "$*", 2]]'`
242
+
243
+ 为什么用这个查询:前两步只查了 Alice 的直接关系,用户问的是"关系网络",需要通过 2-hop 递归遍历
244
+ 发现 Alice → Bob → Charlie 这样的间接关系。$k-hop 用递归 CTE 实现,适合图探索。
245
+ 预期结果:返回 Alice 的 2-hop 邻域内所有 statement triples。
246
+ ```
247
+
248
+ ### Rules for Thinking Aloud
249
+
250
+ 1. **Always explain before executing** — never run a query silently
251
+ 2. **Explain the "why"** — which operator was chosen and why, not just what it does
252
+ 3. **Keep it concise** — 1-2 sentences for explanation, 1 sentence for expected results
253
+ 4. **Interpret results** — after each step, briefly note what was found before deciding next steps
254
+ 5. **Multi-step reasoning** — for complex requests, show the decomposition into steps and explain the strategy
255
+ 6. **Empty results are informative** — if a query returns nothing, explain what that tells us and adjust strategy
256
+
257
+ ## Search Strategy — Graph-First Retrieval
258
+
259
+ When searching for information, prefer precise graph operators over broad FTS search. Use the following decision tree:
260
+
261
+ ### Search Decision Tree
262
+
263
+ For each step, include the thinking aloud explanation before executing.
264
+
265
+ ```
266
+ 1. User mentions a specific entity name?
267
+ → knowledge-get (direct lookup)
268
+
269
+ 2. User asks about relationships involving a known entity?
270
+ → $triple operator (fastest, indexed)
271
+
272
+ 3. User asks about a type of relationship (e.g., "who works for X")?
273
+ → $triple with wildcard on entity positions
274
+
275
+ 4. User wants to explore graph neighborhood (e.g., "who can X reach in 2 hops")?
276
+ → $k-hop operator (graph traversal)
277
+
278
+ 5. User wants semantic/similarity search (e.g., "find similar concepts")?
279
+ → hypatia similar (vector search)
280
+
281
+ 6. User wants to match a pattern (e.g., "names starting with X")?
282
+ → $like operator
283
+
284
+ 7. User wants to filter by content attributes (e.g., "markdown entries", "entries with specific format")?
285
+ → $content operator
286
+
287
+ 8. User asks about a specific entity's relationships?
288
+ → $triple + knowledge-get combined
289
+
290
+ 9. Broad/ambiguous query?
291
+ → $search (FTS fallback)
292
+ ```
293
+
294
+ ### Prefer $triple over $search for entity queries
295
+
296
+ When the query involves a known entity (person, tool, concept), use `$triple` for precise, indexed lookups instead of FTS:
297
+
298
+ | Instead of | Use |
299
+ |---|---|
300
+ | `["$statement", ["$search", "Alice"]]` | `["$statement", ["$triple", "Alice", "$*", "$*"]]` |
301
+ | `["$statement", ["$search", "manages"]]` | `["$statement", ["$triple", "$*", "manages", "$*"]]` |
302
+ | `["$statement", ["$contains", "triple", "Alice"]]` | `["$statement", ["$triple", "Alice", "$*", "$*"]]` |
303
+
304
+ ### Combined Queries
305
+
306
+ For rich retrieval, combine graph traversal with content filtering:
307
+
308
+ ```bash
309
+ # Find all relationships involving Alice, created after a date
310
+ hypatia query '["$statement", ["$and", ["$triple", "Alice", "$*", "$*"], ["$gt", "created_at", "2025-01-01"]]]'
311
+
312
+ # Find all knowledge entries in markdown format about a topic
313
+ hypatia query '["$knowledge", ["$and", ["$content", {"format": "markdown"}], ["$search", "database"]]]'
314
+
315
+ # Find all people (entities that are_a "engineer")
316
+ hypatia query '["$statement", ["$triple", "$*", "is_a", "engineer"]]'
317
+ ```
318
+
319
+ ## Full-text Search
320
+
321
+ Search is the fallback for broad or ambiguous queries. It covers both knowledge and statements.
322
+
323
+ ```
324
+ hypatia search <query> [-c <catalog>] [--limit N] [--offset N]
325
+ ```
326
+
327
+ - `-c knowledge` — search only knowledge entries
328
+ - `-c statement` — search only statements
329
+ - No `-c` — search everything
330
+
331
+ ### Examples
332
+
333
+ | User says | Command |
334
+ |---|---|
335
+ | "search for programming" / "find everything about programming" | `hypatia search "programming"` |
336
+ | "search knowledge for rust" | `hypatia search "rust" -c knowledge` |
337
+ | "what do you know about databases?" | `hypatia search "databases"` |
338
+
339
+ ## Vector Similarity Search
340
+
341
+ Semantic search using embedding vectors. Finds entries with similar meaning, even when keywords don't match.
342
+
343
+ ```
344
+ hypatia similar <query> [--limit N]
345
+ ```
346
+
347
+ Requires an embedding model configured in `shelf.toml` (default: BAAI/bge-m3).
348
+
349
+ Entries are embedded in batches after they are written or updated. With a remote embedding API, `similar` can miss entries changed in the last minute; `search` finds them at once.
350
+
351
+ ### Examples
352
+
353
+ | User says | Command |
354
+ |---|---|
355
+ | "find similar to distributed systems" | `hypatia similar "distributed systems"` |
356
+ | "semantic search for memory management" | `hypatia similar "memory management" --limit 5` |
357
+
358
+ ## JSE Query Translation
359
+
360
+ JSE (JSON Search Expression) enables precise queries against the knowledge or statement tables.
361
+
362
+ ```
363
+ hypatia query '<JSE-JSON>' [-s <shelf>]
364
+ ```
365
+
366
+ ### Query Structure
367
+
368
+ The top-level operator is always `$knowledge` or `$statement`:
369
+
370
+ ```json
371
+ ["$knowledge", condition1, condition2, ...]
372
+ ["$statement", condition1, condition2, ...]
373
+ ```
374
+
375
+ No conditions means "return all":
376
+
377
+ ```json
378
+ ["$knowledge"]
379
+ ```
380
+
381
+ ### Operator Reference
382
+
383
+ | Operator | Purpose | Syntax |
384
+ |---|---|---|
385
+ | `$eq` | Equals | `["$eq", "field", "value"]` |
386
+ | `$ne` | Not equals | `["$ne", "field", "value"]` |
387
+ | `$gt` | Greater than | `["$gt", "field", "value"]` |
388
+ | `$lt` | Less than | `["$lt", "field", "value"]` |
389
+ | `$gte` | Greater than or equal | `["$gte", "field", "value"]` |
390
+ | `$lte` | Less than or equal | `["$lte", "field", "value"]` |
391
+ | `$like` | SQL LIKE pattern match | `["$like", "field", "pattern"]` |
392
+ | `$contains` | Substring match in content JSON | `["$contains", "field", "value"]` |
393
+ | `$content` | Match content JSON key-value pairs | `["$content", {"key": "value"}]` |
394
+ | `$search` | Full-text search (FTS) | `["$search", "query text"]` |
395
+ | `$and` | Logical AND | `["$and", cond1, cond2, ...]` |
396
+ | `$or` | Logical OR | `["$or", cond1, cond2, ...]` |
397
+ | `$not` | Logical NOT | `["$not", condition]` |
398
+ | `$triple` | Triple position match | `["$triple", "Alice", "$*", "Bob"]` |
399
+ | `$k-hop` | K-hop graph traversal (statement only) | `["$k-hop", "head", "relation", depth]` |
400
+ | `$has` | Exact membership in a JSON field (arrays: element; scalars: equality; array value = any-of) — indexed | `["$has", "tags", "rust"]` |
401
+ | `$json-contains` | Structural containment (PG `@>`) — indexed recall + exact recheck | `["$json-contains", {"tags": ["rust"]}]` |
402
+
403
+ ### Critical Syntax Rules
404
+
405
+ 1. **`$and` and `$or` take multiple operands directly**, NOT a nested array:
406
+ - CORRECT: `["$and", ["$eq", "name", "rust"], ["$contains", "tags", "systems"]]`
407
+ - WRONG: `["$and", [["$eq", "name", "rust"], ["$contains", "tags", "systems"]]]`
408
+
409
+ 2. **`$search` must be inside `$knowledge` or `$statement`**, never top-level. When inside `$knowledge`, it searches FTS with catalog=knowledge. When inside `$statement`, it searches with catalog=statement.
410
+
411
+ 3. **Field names** like `"name"`, `"triple"` are used as plain strings. For content JSON sub-fields (e.g., tags), `$contains` uses `json_extract_string` automatically.
412
+
413
+ 4. **Available fields for knowledge**: `name`, `created_at`, plus any content JSON field via `$contains`.
414
+
415
+ 5. **Available fields for statement**: `triple` (CSV-formatted head,relation,tail), `head`, `relation`, `tail`, `created_at`, `tr_start`, `tr_end`, plus content JSON fields via `$has`/`$contains`. For position-based triple matching, prefer `$triple` over `$contains`.
416
+
417
+ 6. **New in 0.3**: `$has` is the exact-membership operator (indexed; use it for tags/scopes lookups). `$contains` on array fields (`tags`/`scopes`/`figures`) routes to exact membership too; on other fields it stays substring. `$json-contains` matches whole-document containment (PG `@>`), e.g. `["$json-contains", {"tags": ["rust"]}]`.
418
+
419
+ ### `$triple` Operator
420
+
421
+ The `$triple` operator provides position-based matching on statement triples. Each argument corresponds to head, relation, or tail. Use `"$*"` as a wildcard to match any value.
422
+
423
+ ```
424
+ ["$triple", <head_pattern>, <relation_pattern>, <tail_pattern>]
425
+ ```
426
+
427
+ | Pattern | Meaning |
428
+ |---------|---------|
429
+ | `"Alice"` | Exact match |
430
+ | `"$*"` | Wildcard — match any value |
431
+
432
+ **Behavior**:
433
+ - All 3 specified (no wildcards): uses `triple = ?` (primary key lookup, fastest)
434
+ - Partial match: generates conditions on individual columns (`head = ? AND tail = ?`, etc.)
435
+ - At least one non-wildcard required — all wildcards is an error
436
+ - Arguments must be exactly 3
437
+
438
+ | User says | JSE | Command |
439
+ |---|---|---|
440
+ | "find all relationships where Alice is the head" | `["$statement", ["$triple", "Alice", "$*", "$*"]]` | `hypatia query '["$statement", ["$triple", "Alice", "$*", "$*"]]'` |
441
+ | "find all knows relationships" | `["$statement", ["$triple", "$*", "knows", "$*"]]` | `hypatia query '["$statement", ["$triple", "$*", "knows", "$*"]]'` |
442
+ | "find everything related to Bob as tail" | `["$statement", ["$triple", "$*", "$*", "Bob"]]` | `hypatia query '["$statement", ["$triple", "$*", "$*", "Bob"]]'` |
443
+ | "find the exact Alice knows Bob triple" | `["$statement", ["$triple", "Alice", "knows", "Bob"]]` | `hypatia query '["$statement", ["$triple", "Alice", "knows", "Bob"]]'` |
444
+ | "Alice's relationships with Bob, combined with date filter" | `["$statement", ["$and", ["$triple", "Alice", "$*", "Bob"], ["$gt", "created_at", "2025-01-01"]]]` | `hypatia query '["$statement", ["$and", ["$triple", "Alice", "$*", "Bob"], ["$gt", "created_at", "2025-01-01"]]]'` |
445
+
446
+ ### `$like` Operator
447
+
448
+ SQL LIKE pattern matching with user-defined wildcards (`%` = any chars, `_` = single char).
449
+
450
+ ```
451
+ ["$like", "field", "pattern"]
452
+ ```
453
+
454
+ | User says | JSE | Command |
455
+ |---|---|---|
456
+ | "find entries whose name starts with Rust" | `["$knowledge", ["$like", "name", "Rust%"]]` | `hypatia query '["$knowledge", ["$like", "name", "Rust%"]]'` |
457
+ | "find entries created in January 2025" | `["$knowledge", ["$like", "created_at", "2025-01-%"]]` | `hypatia query '["$knowledge", ["$like", "created_at", "2025-01-%"]]'` |
458
+ | "find statements with head matching pattern" | `["$statement", ["$like", "head", "Alice%"]]` | `hypatia query '["$statement", ["$like", "head", "Alice%"]]'` |
459
+
460
+ ### `$content` Operator
461
+
462
+ Match key-value pairs inside the `content` JSON column. Checks exact string equality for each specified key.
463
+
464
+ ```
465
+ ["$content", {"key1": "value1", "key2": "value2"}]
466
+ ```
467
+
468
+ | User says | JSE | Command |
469
+ |---|---|---|
470
+ | "find all markdown-format entries" | `["$knowledge", ["$content", {"format": "markdown"}]]` | `hypatia query '["$knowledge", ["$content", {"format": "markdown"}]]'` |
471
+ | "find json-format statements" | `["$statement", ["$content", {"format": "json"}]]` | `hypatia query '["$statement", ["$content", {"format": "json"}]]'` |
472
+ | "find entries with specific data and format" | `["$knowledge", ["$content", {"format": "markdown", "data": "hello"}]]` | `hypatia query '["$knowledge", ["$content", {"format": "markdown", "data": "hello"}]]'` |
473
+
474
+ ### `$k-hop` Operator
475
+
476
+ K-hop graph traversal on statement triples using recursive CTE. Explores entity neighborhoods and relationship paths.
477
+
478
+ ```
479
+ ["$k-hop", "head", "relation", depth]
480
+ ```
481
+
482
+ - `"head"` — starting entity (required)
483
+ - `"relation"` — filter by relation, or use `"$*"` for any
484
+ - `depth` — number of hops (positive integer)
485
+
486
+ | User says | JSE | Command |
487
+ |---|---|---|
488
+ | "who can Alice reach in 2 hops?" | `["$statement", ["$k-hop", "Alice", "$*", 2]]` | `hypatia query '["$statement", ["$k-hop", "Alice", "$*", 2]]'` |
489
+ | "what's reachable from Alice via knows in 3 hops?" | `["$statement", ["$k-hop", "Alice", "knows", 3]]` | `hypatia query '["$statement", ["$k-hop", "Alice", "knows", 3]]'` |
490
+ | "explore the graph around PostgreSQL" | `["$statement", ["$k-hop", "PostgreSQL", "$*", 2]]` | `hypatia query '["$statement", ["$k-hop", "PostgreSQL", "$*", 2]]'` |
491
+
492
+ ### Natural Language to JSE Examples
493
+
494
+ | User says | JSE | Command |
495
+ |---|---|---|
496
+ | "find knowledge named rust" | `["$knowledge", ["$eq", "name", "rust"]]` | `hypatia query '["$knowledge", ["$eq", "name", "rust"]]'` |
497
+ | "find all relationships involving Alice" | `["$statement", ["$triple", "Alice", "$*", "$*"]]` | `hypatia query '["$statement", ["$triple", "Alice", "$*", "$*"]]'` |
498
+ | "who does Alice know?" | `["$statement", ["$triple", "Alice", "knows", "$*"]]` | `hypatia query '["$statement", ["$triple", "Alice", "knows", "$*"]]'` |
499
+ | "what type of things relate to Bob?" | `["$statement", ["$triple", "$*", "$*", "Bob"]]` | `hypatia query '["$statement", ["$triple", "$*", "$*", "Bob"]]'` |
500
+ | "find knowledge named rust that contains 'systems' in tags" | `["$knowledge", ["$and", ["$eq", "name", "rust"], ["$contains", "tags", "systems"]]]` | `hypatia query '["$knowledge", ["$and", ["$eq", "name", "rust"], ["$contains", "tags", "systems"]]]'` |
501
+ | "find knowledge NOT named rust" | `["$knowledge", ["$not", ["$eq", "name", "rust"]]]` | `hypatia query '["$knowledge", ["$not", ["$eq", "name", "rust"]]]'` |
502
+ | "find all is_a relationships" | `["$statement", ["$triple", "$*", "is_a", "$*"]]` | `hypatia query '["$statement", ["$triple", "$*", "is_a", "$*"]]'` |
503
+ | "find entries whose name starts with 'Al'" | `["$knowledge", ["$like", "name", "Al%"]]` | `hypatia query '["$knowledge", ["$like", "name", "Al%"]]'` |
504
+ | "show all knowledge" | `["$knowledge"]` | `hypatia query '["$knowledge"]'` |
505
+ | "find knowledge created after 2025-01-01" | `["$knowledge", ["$gt", "created_at", "2025-01-01"]]` | `hypatia query '["$knowledge", ["$gt", "created_at", "2025-01-01"]]'` |
506
+ | "find knowledge containing 'language' in data" | `["$knowledge", ["$contains", "data", "language"]]` | `hypatia query '["$knowledge", ["$contains", "data", "language"]]'` |
507
+
508
+ ### Options (limit, offset, catalog)
509
+
510
+ Use object form for the top-level operator to pass options:
511
+
512
+ ```json
513
+ {"$knowledge": [["$search", "rust"]], "limit": 10, "offset": 0}
514
+ ```
515
+
516
+ Command: `hypatia query '{"$knowledge": [["$search", "rust"]], "limit": 10}'`
517
+
518
+ ## Disambiguation Rules
519
+
520
+ When the user's request is ambiguous, follow this priority:
521
+
522
+ 1. **Exact name mentioned** ("get Rust", "show Alice") → `knowledge-get` for direct lookup
523
+ 2. **Explicit type** ("find knowledge about X" / "find statements about X") → JSE query with the corresponding top-level operator
524
+ 3. **Relationship language** ("who does Alice know?", "what is Rust related to?", "relationships of X") → JSE `$statement` query with `$triple` operator
525
+ 4. **Graph exploration** ("who can Alice reach?", "what's connected to X", "neighborhood of X") → JSE with `$k-hop` operator
526
+ 5. **Semantic/similarity** ("find similar to X", "things like X", "semantically related") → `hypatia similar` (vector search)
527
+ 6. **Pattern matching** ("names starting with X", "entries from January") → JSE with `$like` operator
528
+ 7. **Content filtering** ("markdown entries", "entries with format X") → JSE with `$content` operator
529
+ 8. **Broad/ambiguous** ("find everything about X", "what do you know about X") → `hypatia search` (covers both knowledge and statements)
530
+ 9. **Create/store/remember** → knowledge-create + statement-create (always create relationships alongside knowledge entries)
531
+
532
+ ## Shell Escaping
533
+
534
+ Always wrap JSE JSON in **single quotes** to prevent shell interpretation of `$`, `"`, `!`, etc.:
535
+
536
+ ```bash
537
+ hypatia query '["$knowledge", ["$eq", "name", "rust"]]'
538
+ ```
539
+
540
+ If the content contains single quotes, escape them:
541
+
542
+ ```bash
543
+ hypatia query '["$knowledge", ["$eq", "name", "Alice'\''s project"]]'
544
+ ```
545
+
546
+ ## Output Format
547
+
548
+ - **Knowledge entries**: `{"name": "...", "content": {"format": "...", "data": "...", "tags": [...]}, "created_at": "..."}`
549
+ - **Statements**: `{"triple": "head,relation,tail", "head": "...", "relation": "...", "tail": "...", "content": {...}, "created_at": "...", "tr_start": "...", "tr_end": "..."}`
550
+ - **Search results**: `{"id": N, "catalog": "...", "key": "...", "content": "...", "rank": N.N}`
551
+ - **Empty results**: prints "No results found."
552
+
553
+ ## Sandboxed / Read-Only Direct Access (known workaround)
554
+
555
+ When running inside a sandboxed harness (e.g. DSH `workspace-write`), the hypatia CLI and plain
556
+ `sqlite3 ~/.hypatia/...` may both fail with SQLite error 14 (`unable to open database file`):
557
+ even read-only SQLite needs to create WAL/journal temp files next to the database, and
558
+ `~/.hypatia` lies outside the writable workspace. **Do not retry the same failing command** —
559
+ go straight to the immutable read-only URI, which needs no journal and no directory writes:
560
+
561
+ ```bash
562
+ sqlite3 "file:$HOME/.hypatia/default/hypatia.sqlite?mode=ro&immutable=1" "SELECT count(*) FROM knowledge;"
563
+ ```
564
+
565
+ - Use only for **reads** (SELECT). Never write through this path — `immutable=1` tells SQLite the
566
+ file never changes, so writes would corrupt state or be lost.
567
+ - Adjust the shelf path for non-default shelves (`~/.hypatia/<shelf>/<db>.sqlite`).
568
+ - First, locate the actual DB file: `ls ~/.hypatia/*/` (also check `-wal`/`-shm` siblings; if a
569
+ WAL exists and is non-empty, `immutable=1` may miss recent un-checkpointed rows — in that case
570
+ prefer requesting wider sandbox permissions for a normal read instead).
571
+ - Schema hints: tables include `knowledge` and `statement`; statement triples are stored in
572
+ `head` / `relation` / `tail` columns.
573
+
574
+ This fallback was validated: the same query fails at error 14 without the URI params and returns
575
+ correctly with them.
576
+
577
+ ## Important Notes
578
+
579
+ - There is no `statement-get` CLI command. Use JSE queries (`$statement` with conditions) to find statements. `statement-delete` is available for deletion.
580
+ - The `-s` / `--shelf` flag defaults to `"default"` for all commands.
581
+ - The REPL mode (`hypatia repl`) is interactive and should NOT be used from this skill. Always use one-shot CLI commands.
582
+ - Content (`-d`) is stored as a string in the content JSON's `data` field.
583
+ - Tags (`-t`) are comma-separated strings.
584
+ - **Always create statements alongside knowledge entries** to maintain graph connectivity. Every knowledge entry should have at least one corresponding `is_a` statement.
585
+ - **Normalize relative temporal expressions to absolute dates/times before storing.** When content contains "明天", "下周一", "三小时后", "tonight", etc., rewrite them using the current date/time as the reference point. Example: "明天提醒我备份数据" → store "2026年8月29日提醒我备份数据". A relative date is meaningless when the memory is recalled later.