sensemaking 0.2.1 → 0.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +108 -132
- package/dist/cjs/cli.js +172 -182
- package/dist/cjs/cli.js.map +1 -1
- package/dist/cjs/commands/find.d.cts +3 -0
- package/dist/cjs/commands/find.d.ts +3 -0
- package/dist/cjs/commands/find.js +73 -0
- package/dist/cjs/commands/find.js.map +1 -0
- package/dist/cjs/commands/index.d.cts +5 -0
- package/dist/cjs/commands/index.d.ts +5 -0
- package/dist/cjs/commands/index.js +94 -0
- package/dist/cjs/commands/index.js.map +1 -0
- package/dist/cjs/commands/init.d.cts +3 -0
- package/dist/cjs/commands/init.d.ts +3 -0
- package/dist/cjs/commands/init.js +18 -0
- package/dist/cjs/commands/init.js.map +1 -0
- package/dist/cjs/commands/map.d.cts +3 -0
- package/dist/cjs/commands/map.d.ts +3 -0
- package/dist/cjs/commands/map.js +21 -0
- package/dist/cjs/commands/map.js.map +1 -0
- package/dist/cjs/commands/named.d.cts +2 -0
- package/dist/cjs/commands/named.d.ts +2 -0
- package/dist/cjs/commands/named.js +23 -0
- package/dist/cjs/commands/named.js.map +1 -0
- package/dist/cjs/commands/peek.d.cts +3 -0
- package/dist/cjs/commands/peek.d.ts +3 -0
- package/dist/cjs/commands/peek.js +69 -0
- package/dist/cjs/commands/peek.js.map +1 -0
- package/dist/cjs/commands/query.d.cts +3 -0
- package/dist/cjs/commands/query.d.ts +3 -0
- package/dist/cjs/commands/query.js +43 -0
- package/dist/cjs/commands/query.js.map +1 -0
- package/dist/cjs/commands/rebuild.d.cts +3 -0
- package/dist/cjs/commands/rebuild.d.ts +3 -0
- package/dist/cjs/commands/rebuild.js +20 -0
- package/dist/cjs/commands/rebuild.js.map +1 -0
- package/dist/cjs/commands/status.d.cts +3 -0
- package/dist/cjs/commands/status.d.ts +3 -0
- package/dist/cjs/commands/status.js +24 -0
- package/dist/cjs/commands/status.js.map +1 -0
- package/dist/cjs/commands/types.d.cts +15 -0
- package/dist/cjs/commands/types.d.ts +15 -0
- package/dist/cjs/commands/types.js +5 -0
- package/dist/cjs/commands/types.js.map +1 -0
- package/dist/cjs/commands/vault.d.cts +6 -0
- package/dist/cjs/commands/vault.d.ts +6 -0
- package/dist/cjs/commands/vault.js +94 -0
- package/dist/cjs/commands/vault.js.map +1 -0
- package/dist/cjs/commands/watch.d.cts +3 -0
- package/dist/cjs/commands/watch.d.ts +3 -0
- package/dist/cjs/commands/watch.js +173 -0
- package/dist/cjs/commands/watch.js.map +1 -0
- package/dist/cjs/config.d.cts +11 -1
- package/dist/cjs/config.d.ts +11 -1
- package/dist/cjs/config.js +82 -9
- package/dist/cjs/config.js.map +1 -1
- package/dist/cjs/db.d.cts +1 -1
- package/dist/cjs/db.d.ts +1 -1
- package/dist/cjs/db.js +107 -16
- package/dist/cjs/db.js.map +1 -1
- package/dist/cjs/errors.d.cts +1 -1
- package/dist/cjs/errors.d.ts +1 -1
- package/dist/cjs/errors.js.map +1 -1
- package/dist/cjs/features/index.d.cts +7 -0
- package/dist/cjs/features/index.d.ts +7 -0
- package/dist/cjs/features/index.js +36 -0
- package/dist/cjs/features/index.js.map +1 -0
- package/dist/cjs/features/links.d.cts +4 -0
- package/dist/cjs/features/links.d.ts +4 -0
- package/dist/cjs/features/links.js +217 -0
- package/dist/cjs/features/links.js.map +1 -0
- package/dist/cjs/features/rank.d.cts +2 -0
- package/dist/cjs/features/rank.d.ts +2 -0
- package/dist/cjs/features/rank.js +95 -0
- package/dist/cjs/features/rank.js.map +1 -0
- package/dist/cjs/features/sections.d.cts +9 -0
- package/dist/cjs/features/sections.d.ts +9 -0
- package/dist/cjs/features/sections.js +54 -0
- package/dist/cjs/features/sections.js.map +1 -0
- package/dist/cjs/features/types.d.cts +11 -0
- package/dist/cjs/features/types.d.ts +11 -0
- package/dist/cjs/features/types.js +5 -0
- package/dist/cjs/features/types.js.map +1 -0
- package/dist/cjs/graph.d.cts +7 -0
- package/dist/cjs/graph.d.ts +7 -0
- package/dist/cjs/graph.js +237 -0
- package/dist/cjs/graph.js.map +1 -0
- package/dist/cjs/index.d.cts +9 -2
- package/dist/cjs/index.d.ts +9 -2
- package/dist/cjs/index.js +39 -0
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/output.d.cts +22 -0
- package/dist/cjs/output.d.ts +22 -0
- package/dist/cjs/output.js +113 -3
- package/dist/cjs/output.js.map +1 -1
- package/dist/cjs/scan.d.cts +3 -1
- package/dist/cjs/scan.d.ts +3 -1
- package/dist/cjs/scan.js +62 -14
- package/dist/cjs/scan.js.map +1 -1
- package/dist/cjs/verbs.d.cts +32 -0
- package/dist/cjs/verbs.d.ts +32 -0
- package/dist/cjs/verbs.js +280 -0
- package/dist/cjs/verbs.js.map +1 -0
- package/dist/esm/cli.js +63 -107
- package/dist/esm/cli.js.map +1 -1
- package/dist/esm/commands/find.d.ts +3 -0
- package/dist/esm/commands/find.js +14 -0
- package/dist/esm/commands/find.js.map +1 -0
- package/dist/esm/commands/index.d.ts +5 -0
- package/dist/esm/commands/index.js +13 -0
- package/dist/esm/commands/index.js.map +1 -0
- package/dist/esm/commands/init.d.ts +3 -0
- package/dist/esm/commands/init.js +7 -0
- package/dist/esm/commands/init.js.map +1 -0
- package/dist/esm/commands/map.d.ts +3 -0
- package/dist/esm/commands/map.js +10 -0
- package/dist/esm/commands/map.js.map +1 -0
- package/dist/esm/commands/named.d.ts +2 -0
- package/dist/esm/commands/named.js +12 -0
- package/dist/esm/commands/named.js.map +1 -0
- package/dist/esm/commands/peek.d.ts +3 -0
- package/dist/esm/commands/peek.js +12 -0
- package/dist/esm/commands/peek.js.map +1 -0
- package/dist/esm/commands/query.d.ts +3 -0
- package/dist/esm/commands/query.js +7 -0
- package/dist/esm/commands/query.js.map +1 -0
- package/dist/esm/commands/rebuild.d.ts +3 -0
- package/dist/esm/commands/rebuild.js +9 -0
- package/dist/esm/commands/rebuild.js.map +1 -0
- package/dist/esm/commands/status.d.ts +3 -0
- package/dist/esm/commands/status.js +13 -0
- package/dist/esm/commands/status.js.map +1 -0
- package/dist/esm/commands/types.d.ts +15 -0
- package/dist/esm/commands/types.js +1 -0
- package/dist/esm/commands/types.js.map +1 -0
- package/dist/esm/commands/vault.d.ts +6 -0
- package/dist/esm/commands/vault.js +29 -0
- package/dist/esm/commands/vault.js.map +1 -0
- package/dist/esm/commands/watch.d.ts +3 -0
- package/dist/esm/commands/watch.js +19 -0
- package/dist/esm/commands/watch.js.map +1 -0
- package/dist/esm/config.d.ts +11 -1
- package/dist/esm/config.js +68 -12
- package/dist/esm/config.js.map +1 -1
- package/dist/esm/db.d.ts +1 -1
- package/dist/esm/db.js +27 -9
- package/dist/esm/db.js.map +1 -1
- package/dist/esm/errors.d.ts +1 -1
- package/dist/esm/errors.js.map +1 -1
- package/dist/esm/features/index.d.ts +7 -0
- package/dist/esm/features/index.js +14 -0
- package/dist/esm/features/index.js.map +1 -0
- package/dist/esm/features/links.d.ts +4 -0
- package/dist/esm/features/links.js +81 -0
- package/dist/esm/features/links.js.map +1 -0
- package/dist/esm/features/rank.d.ts +2 -0
- package/dist/esm/features/rank.js +17 -0
- package/dist/esm/features/rank.js.map +1 -0
- package/dist/esm/features/sections.d.ts +9 -0
- package/dist/esm/features/sections.js +41 -0
- package/dist/esm/features/sections.js.map +1 -0
- package/dist/esm/features/types.d.ts +11 -0
- package/dist/esm/features/types.js +3 -0
- package/dist/esm/features/types.js.map +1 -0
- package/dist/esm/graph.d.ts +7 -0
- package/dist/esm/graph.js +79 -0
- package/dist/esm/graph.js.map +1 -0
- package/dist/esm/index.d.ts +9 -2
- package/dist/esm/index.js +4 -1
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/output.d.ts +22 -0
- package/dist/esm/output.js +29 -0
- package/dist/esm/output.js.map +1 -1
- package/dist/esm/scan.d.ts +3 -1
- package/dist/esm/scan.js +56 -7
- package/dist/esm/scan.js.map +1 -1
- package/dist/esm/verbs.d.ts +32 -0
- package/dist/esm/verbs.js +135 -0
- package/dist/esm/verbs.js.map +1 -0
- package/package.json +4 -4
- package/schema.json +23 -4
- package/skills/sense/EXAMPLES.md +52 -79
- package/skills/sense/SKILL.md +71 -92
package/README.md
CHANGED
|
@@ -1,175 +1,151 @@
|
|
|
1
1
|
# sensemaking
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
SQL over a tree of markdown notes: filter by frontmatter, search the prose, follow the links,
|
|
4
|
+
read the structure. A CLI that starts, answers, and exits — no server, no build step.
|
|
4
5
|
|
|
5
|
-
##
|
|
6
|
+
## Problem
|
|
6
7
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
8
|
+
Working with AI agents produces piles of small notes. Past a few dozen, finding the right ones
|
|
9
|
+
means grepping or reading whole folders into context. The structure that makes notes navigable —
|
|
10
|
+
frontmatter, wikilinks, headings — is exactly what an agent needs, but nothing exposes it as a
|
|
11
|
+
query surface.
|
|
10
12
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
rebuilds knowledge that already exists three files away.
|
|
13
|
+
`sense` indexes all of it into SQLite and reconciles against file timestamps on every query, so
|
|
14
|
+
results are never stale and nothing has to be running.
|
|
14
15
|
|
|
15
|
-
|
|
16
|
-
the pile navigable. `sensemaking` is the layer that acts on it, without an app running, a build
|
|
17
|
-
step, or you re-explaining anything. The intended shape is a small vault per project, not one big
|
|
18
|
-
one — starting a new one is a single command with no schema to design.
|
|
16
|
+
## Quick start
|
|
19
17
|
|
|
20
|
-
|
|
18
|
+
```bash
|
|
19
|
+
npm install -g sensemaking
|
|
20
|
+
cd your-notes && sense init
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
sense map # orient: fields, hub notes, recent changes
|
|
25
|
+
sense find "revenue OR earnings" --k 10 # locate: ranked references with excerpts
|
|
26
|
+
sense peek notes/q3-report.md # structure: outline + links, before reading
|
|
27
|
+
sense query "SELECT path FROM frontmatter WHERE has(tags, ?)" urgent
|
|
28
|
+
```
|
|
21
29
|
|
|
22
|
-
|
|
23
|
-
index you can join against. You write named SQL queries once and run them by name.
|
|
30
|
+
## Model
|
|
24
31
|
|
|
25
|
-
|
|
26
|
-
---
|
|
27
|
-
title: Ship the Q3 report
|
|
28
|
-
summary: where the Q3 numbers came from and who signed off
|
|
29
|
-
status: active
|
|
30
|
-
tags: [urgent, reports]
|
|
31
|
-
---
|
|
32
|
+
Every file becomes rows in four tables:
|
|
32
33
|
|
|
33
|
-
|
|
34
|
-
|
|
34
|
+
| table | holds | for |
|
|
35
|
+
|---|---|---|
|
|
36
|
+
| `frontmatter` | one column per key, plus `path`, `_mtime`, `_size`, `_rank` | filtering |
|
|
37
|
+
| `content` | FTS5 index: `title`, `summary`, `text` | search and ranking |
|
|
38
|
+
| `links` | `src`, `target` as written, `dst` resolved (`NULL` = dead link) | graph |
|
|
39
|
+
| `sections` | heading, `level`, `start_line`, `end_line`, `tokens` estimate | structure |
|
|
40
|
+
|
|
41
|
+
Results are references — path, title, summary, excerpt — never file contents. Reading happens
|
|
42
|
+
afterward through the filesystem, scoped to the line ranges `peek` returns. This is the
|
|
43
|
+
[just-in-time context pattern](https://www.anthropic.com/engineering/effective-context-engineering-for-ai-agents):
|
|
44
|
+
the agent holds lightweight identifiers and loads payloads only when needed.
|
|
45
|
+
|
|
46
|
+
Measured costs: a `find` row is ~20–40 tokens, a `peek` is ~17% of reading the file, and the
|
|
47
|
+
section it points at is a direct `Read` range.
|
|
35
48
|
|
|
36
49
|
```sql
|
|
37
|
-
--
|
|
38
|
-
SELECT f.path, content.title,
|
|
50
|
+
-- filter and search compose in one query
|
|
51
|
+
SELECT f.path, content.title, snippet(content, -1, '«', '»', '…', 10) AS hit
|
|
39
52
|
FROM frontmatter f JOIN content ON content.path = f.path
|
|
40
53
|
WHERE f.status = 'active' AND content MATCH 'revenue'
|
|
41
54
|
ORDER BY bm25(content, 10.0, 5.0, 1.0) LIMIT 10
|
|
42
55
|
```
|
|
43
56
|
|
|
44
|
-
|
|
45
|
-
path, title, summary, matching excerpt — is enough to decide whether to open the file, without
|
|
46
|
-
carrying the file. On a real 26-note vault that's a few hundred tokens, against ~6,000 to read the
|
|
47
|
-
three files it points at. Cheap enough to run before deciding what to open; reading afterward is
|
|
48
|
-
the expensive step, and it happens through the filesystem, not SQL.
|
|
49
|
-
|
|
50
|
-
## Use it
|
|
57
|
+
## Verbs
|
|
51
58
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
59
|
+
| verb | does |
|
|
60
|
+
|---|---|
|
|
61
|
+
| `map` | doc count, frontmatter field coverage, top hubs by link rank, recent changes |
|
|
62
|
+
| `find "<terms>" [--where "<sql>"] [--k n]` | BM25 + link-graph expansion, fused; `via` marks each row `match`, `link`, or `match+link` |
|
|
63
|
+
| `peek <path>` | frontmatter + heading outline (`[L143-162, ~380t]`) + links both ways, capped at 20 per list |
|
|
64
|
+
| `query "<sql>" [params...]` | ad-hoc SQL over all four tables; `?` binds positional args |
|
|
56
65
|
|
|
57
|
-
|
|
66
|
+
`find` seeds a personalized-PageRank walk with the BM25 matches, so a note that never contains
|
|
67
|
+
the terms but is linked from ones that do still surfaces. Terms pass verbatim to FTS5 `MATCH`
|
|
68
|
+
(bare words AND-join; operators are yours to write). `--where` takes a frontmatter condition
|
|
69
|
+
against alias `f`.
|
|
70
|
+
`--format json` on any verb returns structured output.
|
|
58
71
|
|
|
59
|
-
|
|
60
|
-
sense query "SELECT … FROM frontmatter" # ad-hoc SQL; positional args bind to ? placeholders
|
|
61
|
-
sense query "…" --format json # structured output (the default is a table)
|
|
62
|
-
sense --list # what named queries exist
|
|
63
|
-
sense status | rebuild # cache info / delete .sense/ and re-crawl
|
|
64
|
-
```
|
|
72
|
+
## Config
|
|
65
73
|
|
|
66
|
-
|
|
67
|
-
|
|
74
|
+
`sense init` writes `sense.config.json`; discovery walks up from cwd like git
|
|
75
|
+
(`--config <path>` overrides). Name reusable queries and run them as `sense <name> [params...]`:
|
|
68
76
|
|
|
69
77
|
```json
|
|
70
78
|
{
|
|
71
79
|
"$schema": "https://unpkg.com/sensemaking/schema.json",
|
|
72
|
-
"version":
|
|
80
|
+
"version": 2,
|
|
73
81
|
"scan": { "include": ["**/*.md"] },
|
|
82
|
+
"features": { "links": true, "sections": true, "rank": true },
|
|
74
83
|
"queries": {
|
|
75
|
-
"by-tag": "SELECT path, title
|
|
84
|
+
"by-tag": "SELECT path, title FROM frontmatter WHERE has(tags, ?) ORDER BY path"
|
|
76
85
|
}
|
|
77
86
|
}
|
|
78
87
|
```
|
|
79
88
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
`
|
|
83
|
-
|
|
84
|
-
The one custom SQL function is `has(field, value)`: array membership on a JSON-array field (like
|
|
85
|
-
`tags`), substring match on a string, always false on a missing key. Reserved names: `path`,
|
|
86
|
-
`_mtime`, `_size`, `content`.
|
|
89
|
+
Features toggle independently; disabling one degrades its verb instead of failing it (`find`
|
|
90
|
+
goes BM25-only without `links`, `map` drops hubs without `rank`, `peek` drops the outline
|
|
91
|
+
without `sections`). Toggling rebuilds the cache. Older config versions auto-migrate on load,
|
|
92
|
+
noted on stderr.
|
|
87
93
|
|
|
88
|
-
|
|
94
|
+
## Reference
|
|
89
95
|
|
|
90
|
-
`
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
96
|
+
- `has(field, value)` — the one custom SQL function: array membership on JSON-array fields,
|
|
97
|
+
substring on strings, false on missing keys.
|
|
98
|
+
- Reserved frontmatter keys (dropped with a warning): `path`, `_mtime`, `_size`, `_rank`,
|
|
99
|
+
`content`, `links`, `sections`.
|
|
100
|
+
- FTS5 syntax in `MATCH`: `a OR b`, `"phrase"`, `pref*`, `NEAR(a b, 5)`, `summary: term`.
|
|
101
|
+
Stemmed; markdown is stripped at index time. `bm25(content, 10.0, 5.0, 1.0)` weights title
|
|
102
|
+
over summary over body.
|
|
103
|
+
- A one-line `summary:` in frontmatter is both a selectable column and a weighted search field.
|
|
104
|
+
- Exit codes: `0` ok, `1` error (SQLite message verbatim), `2` usage.
|
|
105
|
+
- Frontmatter parsing is lenient: syntax errors (an alias starting with `@`, say) are per-file
|
|
106
|
+
warnings and the values are still indexed.
|
|
97
107
|
|
|
98
|
-
|
|
99
|
-
dump your notes into an agent's context — reaching it takes an explicit join. Select `path`,
|
|
100
|
-
`title`, `summary`, and a `snippet()`, keep a `LIMIT`, and read the files worth reading. `sense`
|
|
101
|
-
warns on stderr when a result grows past 50 KB.
|
|
108
|
+
## Scale
|
|
102
109
|
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
110
|
+
Every query starts with a freshness check against the cache in `.sense/`; only changed files are
|
|
111
|
+
re-parsed. Measured per release in [BENCHMARKING.md](BENCHMARKING.md) — at 6,566 notes: full
|
|
112
|
+
crawl ~5 s, warm query ~100 ms, one-file change ~200 ms. `sense watch` (optional) moves
|
|
113
|
+
re-parsing into the background — see [WATCH.md](WATCH.md). `sense rebuild` deletes the cache and
|
|
114
|
+
re-crawls.
|
|
106
115
|
|
|
107
|
-
|
|
116
|
+
## For AI agents
|
|
108
117
|
|
|
109
118
|
```bash
|
|
110
|
-
|
|
111
|
-
npx skills add kmalakoff/sensemaking # the agent skill (add -g for global, -a claude-code to target)
|
|
119
|
+
npx skills add kmalakoff/sensemaking # -g for global, -a claude-code to target
|
|
112
120
|
```
|
|
113
121
|
|
|
114
|
-
The skill teaches
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
##
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
and
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
-
|
|
141
|
-
scripts and agents can't query it headless. Your vault works unmodified either way; Obsidian
|
|
142
|
-
stays a fine viewer for the same files.
|
|
143
|
-
- **RAG / semantic search:** ranks by similarity, not hard constraints like "only active notes from
|
|
144
|
-
this project" — that needs a `WHERE` clause. The two compose: filter first, rank later; vector
|
|
145
|
-
similarity, if added later, would join the same way.
|
|
146
|
-
- **An LLM-written index file** (à la Karpathy's llm-wiki `index.md`): a good instinct, but a
|
|
147
|
-
second artifact that drifts out of sync. `frontmatter` is that catalog, derived from the notes
|
|
148
|
-
themselves on every query.
|
|
149
|
-
- **Index-on-build tools (MarkdownDB and similar):** query a snapshot that's stale the moment a
|
|
150
|
-
file changes, instead of reconciling live.
|
|
151
|
-
- **Note CLIs (zk and similar):** good at their own model — tags, links, full text — but can't
|
|
152
|
-
filter on arbitrary frontmatter fields, which is the whole point here.
|
|
153
|
-
- **grep / one-off scripts:** fine until you want named, reusable, parameterized queries with real
|
|
154
|
-
AND/OR/ORDER BY — at which point you're writing your own query engine.
|
|
155
|
-
|
|
156
|
-
`sensemaking` is deliberately thin glue: [gray-matter](https://github.com/jonschlinkert/gray-matter)
|
|
157
|
-
parses, [remove-markdown](https://github.com/zuchka/remove-markdown) cleans the prose for indexing,
|
|
158
|
-
[fast-glob](https://github.com/mrmlnc/fast-glob) walks, and Node's built-in SQLite (`node:sqlite`)
|
|
159
|
-
does all the querying. Three small dependencies, no native builds, no background services required.
|
|
160
|
-
|
|
161
|
-
## Roadmap
|
|
162
|
-
|
|
163
|
-
Vector similarity is the natural next facet — a `doc_vec` table joined the same way `content` is,
|
|
164
|
-
so semantic recall composes with the frontmatter filter instead of living in a separate tool
|
|
165
|
-
(`SELECT path, distance`, never the embedding). It's deferred, not planned: today it would require
|
|
166
|
-
a native SQLite extension (sqlite-vec is pre-v1 and ships platform binaries), which breaks the
|
|
167
|
-
no-native-builds line above. It becomes worth revisiting when Node can do it dependency-free — and
|
|
168
|
-
only if BM25 demonstrably misses things; on a curated vault of a few hundred notes it often
|
|
169
|
-
doesn't.
|
|
170
|
-
|
|
171
|
-
Beyond that, the corpus model isn't tied to markdown — anything carrying structured metadata
|
|
172
|
-
(document properties, sidecar JSON) can join it without changing the query surface.
|
|
122
|
+
The skill teaches the descent: `map` to orient, `find` to locate, `peek` before reading,
|
|
123
|
+
`Read` line ranges instead of files.
|
|
124
|
+
|
|
125
|
+
## Prior art
|
|
126
|
+
|
|
127
|
+
- [Effective context engineering for AI agents](https://www.anthropic.com/engineering/effective-context-engineering-for-ai-agents)
|
|
128
|
+
(Anthropic): agents should hold lightweight identifiers — file paths, links — and load payloads
|
|
129
|
+
just in time, because context is a finite resource. The four verbs implement that pattern as a CLI.
|
|
130
|
+
- [llm-wiki](https://gist.github.com/karpathy/442a6bf555914893e9891c11519de94f) (Karpathy): an
|
|
131
|
+
agent-maintained wiki navigated by an `index.md` and links, which he notes needs real search
|
|
132
|
+
infrastructure past a few hundred pages. `sense map` derives that index from the notes instead of
|
|
133
|
+
maintaining it; `find` is the hybrid local search it calls for.
|
|
134
|
+
|
|
135
|
+
## Alternatives
|
|
136
|
+
|
|
137
|
+
- **Obsidian Bases/Dataview** — same filters, but only inside the running app; agents can't
|
|
138
|
+
query it headless.
|
|
139
|
+
- **Index-on-build tools (MarkdownDB)** — query a snapshot; `sense` reconciles on every query.
|
|
140
|
+
- **Note CLIs (zk)** — fixed schema; `sense` filters on arbitrary frontmatter.
|
|
141
|
+
- **RAG / vector stores** — similarity can't express `WHERE status = 'active'`. Vector recall is
|
|
142
|
+
planned as an optional `embed` feature (pure-JS provider package, fused into `find`) — not
|
|
143
|
+
blocked (`node:sqlite` can load extensions since Node 22.13), just deferred until BM25 + links
|
|
144
|
+
measurably miss.
|
|
145
|
+
|
|
146
|
+
Dependencies: [yaml](https://github.com/eemeli/yaml),
|
|
147
|
+
[remove-markdown](https://github.com/zuchka/remove-markdown),
|
|
148
|
+
[fast-glob](https://github.com/mrmlnc/fast-glob), and Node's built-in SQLite. No native builds.
|
|
173
149
|
|
|
174
150
|
## License
|
|
175
151
|
|