@imunitic/synapse 0.4.2 → 0.4.4

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/Index.md.template CHANGED
@@ -3,20 +3,20 @@ title: "Index"
3
3
  ---
4
4
 
5
5
  # Index
6
- Map of the note folders and what each is for. This is the Obsidian second-brain vault, reached through the `synapse` CLI (see the Synapse repo's `CLAUDE.md`).
6
+ Map of the note folders and what each is for. This is the second-brain vault, reached through the `synapse` CLI (see the Synapse repo's `CLAUDE.md`).
7
7
 
8
8
  This index is agent-maintained: whenever an agent creates a new top-level folder (folder depth is capped at two levels, i.e. `folder/subfolder`), it must add a one-line section for it here in the same edit. Treat this file as out of date if a folder exists on disk with no matching section below -- fix the drift rather than working around it.
9
9
 
10
10
  This is a starter index, not a fixed schema. `research/`, `scratchpad/`, and `inbox/` below are yours to rename, restructure, or drop -- an agent reads this file as the authority on what your folders are and mean, not the other way around. `designs/`, `tasks/`, and `synapse/` aren't listed yet because nothing has created one on this vault -- `/synapse-design-note`, `/synapse-task-note`, and `/synapse-init` each add their own section here the first time they actually create that folder.
11
11
 
12
12
  ## research/
13
- Standalone research/reading notes -- general research about a topic, project-related or not: language features, library evaluations, design patterns, reference material. Filenames are plain, human-readable titles.
13
+ Standalone research/reading notes -- general research about a topic, project-related or not: language features, library evaluations, design patterns, reference material. Filenames are plain, human-readable titles. Created via `/synapse-note` (bare mode), which declares `schema: vault-note/v1`.
14
14
 
15
15
  ## scratchpad/
16
- Notes for iterating on an idea just to see whether it works -- high-churn and exploratory, not yet worth filing under a settled category. A note here has a high chance of either being moved into a proper folder once it solidifies, or being deleted wholesale once the idea is settled one way or the other. Filenames are plain, human-readable titles.
16
+ Notes for iterating on an idea just to see whether it works -- high-churn and exploratory, not yet worth filing under a settled category. A note here has a high chance of either being moved into a proper folder once it solidifies, or being deleted wholesale once the idea is settled one way or the other. Filenames are plain, human-readable titles. Created via `/synapse-note` (bare mode), which declares `schema: vault-note/v1`.
17
17
 
18
18
  ## inbox/
19
- A staging area for notes that need more input or reflection before they're settled -- most often the result of being asked to find something and write it down as a note, without yet knowing where it properly belongs, or that otherwise don't cleanly fit `research/` or `scratchpad/`. Filenames are plain, human-readable titles, same as every other folder -- no numbering scheme. Review periodically and move settled notes into a proper category; this folder is meant to stay small.
19
+ A staging area for notes that need more input or reflection before they're settled -- most often the result of being asked to find something and write it down as a note, without yet knowing where it properly belongs, or that otherwise don't cleanly fit `research/` or `scratchpad/`. Filenames are plain, human-readable titles, same as every other folder -- no numbering scheme. Created via `/synapse-note` (bare mode), which declares `schema: vault-note/v1`. Review periodically and move settled notes into a proper category; this folder is meant to stay small.
20
20
 
21
21
  A second kind of note also lives here: standalone ideas that surface mid-discussion (with you, or an agent reasoning out loud) and are worth keeping without yet warranting a full design note of their own -- a small, self-contained "worth doing someday" item rather than an open question tied to a bigger design. Filenames are plain, human-readable titles like any other inbox note. Loosely ticket-shaped (a one-line summary, why it came up, rough acceptance criteria) is a fine, optional format for these -- not a requirement, just a convenient shape for something meant to be picked up and acted on later.
22
22
 
@@ -31,10 +31,10 @@ Not every design discussion ends with something to build. See `Status: Reference
31
31
 
32
32
  ## Determining the project
33
33
 
34
- Every design note is tagged with the project it belongs to both in the title
35
- (`{PROJECT} {Topic}`) and as `project: {prefix}` in frontmatter (the same short prefix
36
- `/synapse-note --task` uses for task IDs) so a flat `designs/` folder still reads clearly, and
37
- both note kinds can be filtered together via `synapse vault-search`.
34
+ Every design note records the project it belongs to as `project: {prefix}` in frontmatter (the
35
+ same short prefix `/synapse-note --task` uses for task IDs) that field also decides the note's
36
+ `designs/{project}/` subfolder, so design notes and task notes can be filtered together via
37
+ `synapse vault-search`. The title itself is plain `{Topic}` — no project prefix, no id.
38
38
 
39
39
  Same resolution `/synapse-note` uses for a missing task ID (its "Resolving a missing task ID"),
40
40
  reading the same file:
@@ -56,7 +56,7 @@ reading the same file:
56
56
  check both fields (`synapse vault-search --fields frontmatter.task_id,frontmatter.note_id`, filter
57
57
  both for `{prefix}-\d+`, take the highest number found across both, add 1; start at 1 if none exist
58
58
  yet). This is frontmatter only — unlike a task note, a design note's title and filename stay
59
- exactly `{PROJECT} — {Topic}`, with no id prepended.
59
+ exactly `{Topic}`, with no id and no project prefix prepended.
60
60
 
61
61
  Never hardcode a specific project/prefix pair in this command's own instructions — the conf file is
62
62
  machine-local and deliberately outside the portable Synapse package, so projects from
@@ -156,11 +156,11 @@ judgment call, not the automatic result of an `## Approach` section existing. Be
156
156
  blocking question is fine to carry forward), but a note with a *blocking* open question is not
157
157
  `Ready`, no matter how developed the rest of it is.
158
158
 
159
- - **Both hold** → `Status: Ready`. Confirm: "Design note ready: `designs/{title}.md`.
159
+ - **Both hold** → `Status: Ready`. Confirm: "Design note ready: `designs/{project}/{title}.md`.
160
160
  Whenever you're ready to implement, generate the task with
161
161
  `/synapse-task-note \"{topic}\"` — no rush, nothing here expires."
162
162
  - **Genuinely nothing to build** → `Status: Reference`. Confirm: "Design note concluded as
163
- Reference: `designs/{title}.md`. No task note needed."
163
+ Reference: `designs/{project}/{title}.md`. No task note needed."
164
164
  - **Anything else** (the approach is still hedged, or an open question blocks it) → stays
165
165
  `Status: Discussing`. This is the default outcome, not a fallback to apologize for — most
166
166
  conversations end here, and that's fine; nothing here expires either.
@@ -178,7 +178,7 @@ so the `## Status` line is the only lifecycle marker that matters. It simply sta
178
178
  ```
179
179
  ---
180
180
  schema: vault-design-note/v1
181
- title: "{PROJECT} — {Topic}"
181
+ title: "{Topic}"
182
182
  project: {prefix}
183
183
  note_id: {id}
184
184
  created: "{now}"
@@ -186,7 +186,7 @@ updated: "{now}"
186
186
  tags: [{comma-separated configured tags, or empty}]
187
187
  ---
188
188
 
189
- # {PROJECT} — {Topic}
189
+ # {Topic}
190
190
 
191
191
  ## Status
192
192
  Discussing | Ready | Reference
@@ -197,16 +197,21 @@ Discussing | Ready | Reference
197
197
  ## Approach
198
198
  {Chosen approach}
199
199
 
200
- ### Alternatives considered (optional)
200
+ ### Alternatives considered
201
201
  - {Option}: why not
202
202
 
203
203
  ## Constraints
204
204
  {Hard constraints, non-negotiables}
205
205
 
206
- ## Open Questions (optional)
206
+ ## Open Questions
207
207
  - {Anything deferred or unresolved}
208
208
  ```
209
209
 
210
+ `### Alternatives considered` and `## Open Questions` are both optional per the schema — omit
211
+ either section entirely rather than leaving it as an empty heading, and never write it as `##
212
+ Open Questions (optional)`: the schema and `/synapse-status`'s own query both match this exact
213
+ heading text, and a suffixed one is invisible to both.
214
+
210
215
  Any string scalar that is all digits (e.g. a numeric-looking title) must be quoted: an
211
216
  unquoted all-digit value is parsed as an integer, which fails a `type: string` schema
212
217
  field. `title`, `project`, `note_id`, and both timestamps are quoted above.
@@ -220,8 +225,10 @@ edit history here worth tracking separately.
220
225
 
221
226
  ## Filename
222
227
 
223
- `designs/{PROJECT}{Topic}.md` — sanitize filesystem-illegal characters (`/ : * ? " < > |`). No
224
- slug, no numbering vault filenames are the title itself.
228
+ `designs/{project}/{Topic}.md` — grouped one level deeper into a per-project
229
+ subfolder named by the note's own `project:` frontmatter value (e.g. `designs/eon/`,
230
+ `designs/synapse/`), the same mapping `tasks/{project}/` uses. Sanitize filesystem-illegal
231
+ characters (`/ : * ? " < > |`). No slug, no numbering — vault filenames are the title itself.
225
232
 
226
233
  ---
227
234
 
@@ -242,12 +249,12 @@ Claude: [searches designs/ for existing matches — none found]
242
249
 
243
250
  User: Replacing the AggregatingMergeTree rollup resolution with direct-value storage.
244
251
 
245
- Claude: [creates designs/{PROJECT}Rollup direct storage.md, Status: Discussing]
252
+ Claude: [creates designs/{project}/Rollup direct storage.md, Status: Discussing]
246
253
 
247
254
  What's driving this over just tuning the current argMaxMerge query?
248
255
  ...
249
256
  User: The resolution cost alone dominates the query, tuning won't fix that. Mark it ready.
250
257
 
251
- Claude: Design note ready: designs/{PROJECT}Rollup direct storage.md.
258
+ Claude: Design note ready: designs/{project}/Rollup direct storage.md.
252
259
  Generate the task with /synapse-task-note "rollup direct storage" whenever you're ready.
253
260
  ```
@@ -100,7 +100,7 @@ yours and cannot be scripted because what counts as signal differs per codebase.
100
100
  **The work directory** defaults to `~/.cache/synapse/work/{repo}@{branch}/`, created on demand, and
101
101
  holds `manifest.tsv`, `all.txt`, `lists/`, the authored `b-NN.md` bodies and the coverage files. Override with `$SYNAPSE_WORK_DIR` if you need to. Two things never to do: point it
102
102
  at the repo (`synapse` runs from inside the repo, so its working files would land in the user's
103
- checkout) or at the vault (Obsidian would index a file list that runs to six figures of lines).
103
+ checkout) or at the vault (a file list that runs to six figures of lines has no business inside it).
104
104
  It is deliberately persistent rather than a temp dir, so a later run finds the previous manifest
105
105
  instead of re-deriving the clustering.
106
106
  - **Interpretation (only you can do this):** deciding what the nodes *are*, and writing their prose.
@@ -153,7 +153,7 @@ emit into tool calls than read into a window. Never hand-author those.
153
153
 
154
154
  **Load the `synapse-orientation` skill** for how to read the vocabulary, the four questions that
155
155
  cover a tree with no grammar, and the grammar-discovery procedure. It is shared with
156
- `/synapse-rebuild`'s re-orient class, which needs the same technique.
156
+ `/synapse-rebuild-diff`'s re-orient class, which needs the same technique.
157
157
  4. **Cluster into nodes — write `manifest.tsv`, the seam.** Group what you learned into a few dozen
158
158
  readable nodes, not one per file — same density Graft aims for. A node is a subsystem or concept,
159
159
  not a file; a file may legitimately belong to more than one node's `sources` when it's genuinely
@@ -249,7 +249,7 @@ emit into tool calls than read into a window. Never hand-author those.
249
249
  **Load the `synapse-node-format` skill too, before writing the first one** — it is the
250
250
  single description of the node contract itself (summary, the crux *pointer*, `## Links`,
251
251
  `grounded_in`, what the writer adds and what it refuses), shared with the `synapse-node`
252
- skill and `/synapse-rebuild`, which write the same artifact. `synapse-node-authoring`
252
+ skill and `/synapse-rebuild-diff`, which write the same artifact. `synapse-node-authoring`
253
253
  covers *how* nodes get written; this covers *what* one is. Do not re-derive either from an
254
254
  existing node: a node you are reading may predate a change to its format.
255
255
  8. **Write `_index.bin`** — mechanics, run `synapse build-index`. It emits
@@ -289,8 +289,8 @@ emit into tool calls than read into a window. Never hand-author those.
289
289
  **Then verify, before reporting success.** Three checks, all cheap:
290
290
  - `synapse query stale` must print nothing. (40s for a 125k-file namespace.)
291
291
  - Every `[[wikilink]]` in the namespace must resolve to a file that exists — extract them all and
292
- test `-f "$link.md"`. Nothing else catches a broken link, since Obsidian treats it as a link to
293
- a note not yet created.
292
+ test `-f "$link.md"`. Nothing else catches a broken link -- a wikilink to a note that does not
293
+ exist yet just fails silently.
294
294
  - Every node file must appear in `Index.md`. An unlisted node exists but is invisible to a reader.
295
295
 
296
296
  ```yaml
@@ -13,7 +13,7 @@ If `$ARGUMENTS` starts with `--search` → **search mode**: see "Search mode" be
13
13
  Otherwise, split `$ARGUMENTS` on `--task`:
14
14
 
15
15
  - If `--task` is present → **task mode**: scaffold the note as a tracked task, following the `synapse-task` skill's conventions. Task notes always live under `tasks/`.
16
- - Otherwise → **bare mode**: create an empty node (title + frontmatter only). Which category folder it lands in is resolved from `Index.md`, per "Choosing a category (bare mode only)" below — not a fixed set.
16
+ - Otherwise → **bare mode**: create an empty node (title + frontmatter only). Which category folder it lands in is resolved from `Index.md`, per "Choosing a category (bare mode only)" below — not a fixed set. The typical categories are `research/`, `scratchpad/`, or `inbox/` — any plain note that isn't a task or design note.
17
17
 
18
18
  The title is everything before `--task` (trimmed). Example:
19
19
 
@@ -97,8 +97,8 @@ this command when it does. What no longer happens is arriving here merely becaus
97
97
  ### 1. Size the job before doing any of it
98
98
 
99
99
  ```sh
100
- ~/.synapse query drift
101
- ~/.synapse query grounding
100
+ synapse query drift
101
+ synapse query grounding
102
102
  ```
103
103
 
104
104
  Report what it says, in the human's terms, **before** touching anything: how far the baseline is from
@@ -118,7 +118,7 @@ Two answers change the plan:
118
118
  ### 2. Mechanical phase — always, and cheap
119
119
 
120
120
  ```sh
121
- ~/.synapse build-lists --reenumerate
121
+ synapse build-lists --reenumerate
122
122
  ```
123
123
 
124
124
  `--reenumerate` matters here: without it an existing `all.txt` is reused, so a branch switch would be
@@ -136,7 +136,7 @@ move a lot and some may reach zero.
136
136
  Then rebuild the reverse index so the hook and the read path agree with the new enumeration:
137
137
 
138
138
  ```sh
139
- ~/.synapse build-index
139
+ synapse build-index
140
140
  ```
141
141
 
142
142
  ### 3. Triage each flagged node — reseat, patch, or re-orient
@@ -193,8 +193,8 @@ straight back stores a quote of a file as it looked at the old baseline, present
193
193
  current. So rebuild the directive from the pointer the writer recorded:
194
194
 
195
195
  ```sh
196
- ~/.synapse query field "{Node}" crux_path
197
- ~/.synapse query field "{Node}" crux_lines
196
+ synapse query field "{Node}" crux_path
197
+ synapse query field "{Node}" crux_lines
198
198
  ```
199
199
 
200
200
  and replace the fenced block with `<!-- crux: <crux_path> <crux_lines> -->` so it is cut from the
@@ -208,7 +208,7 @@ its directives are stripped from the body, so a recovered body contains none —
208
208
  the node's provenance is gone with no error. Recover the pointers per node:
209
209
 
210
210
  ```sh
211
- ~/.synapse query grounding "{Node}" --list # path<TAB>lines
211
+ synapse query grounding "{Node}" --list # path<TAB>lines
212
212
  ```
213
213
 
214
214
  and re-emit a `<!-- grounded_in: <path> <lines> -->` for each. Run `synapse query grounding` before
@@ -256,7 +256,7 @@ selection. Never pipe an unbounded `git diff <commit>..HEAD` into a context wind
256
256
  ### 4. Write each rebuilt node
257
257
 
258
258
  ```sh
259
- ~/.synapse write-node --title "{Node}" --summary "{one line}" \
259
+ synapse write-node --title "{Node}" --summary "{one line}" \
260
260
  --paths "$W/lists/NN.txt" --body "$W/body.md"
261
261
  ```
262
262
 
@@ -267,17 +267,17 @@ not merely stale, if the subsystem's shape differs on this line.
267
267
  ### 5. Rebuild the projections and verify
268
268
 
269
269
  ```sh
270
- ~/.synapse build-index
271
- ~/.synapse build-project-index
272
- ~/.synapse query drift # expect silence
273
- ~/.synapse query stale # expect silence
274
- ~/.synapse query grounding # expect silence: re-pointed, not dropped
275
- ~/.synapse query links --check # expect silence: no dangling targets
270
+ synapse build-index
271
+ synapse build-project-index
272
+ synapse query drift # expect silence
273
+ synapse query stale # expect silence
274
+ synapse query grounding # expect silence: re-pointed, not dropped
275
+ synapse query links --check # expect silence: no dangling targets
276
276
  ```
277
277
 
278
278
  `links --check` covers what used to be a manual instruction here: a broken `[[wikilink]]` is a valid
279
- link to a not-yet-existing note, so Obsidian renders it without complaint and nothing else in the
280
- system notices. It now reports `Node<TAB>relation -> Target (no such node)` per dangling edge.
279
+ link to a not-yet-existing note, silently, and nothing else in the system notices. It now reports
280
+ `Node<TAB>relation -> Target (no such node)` per dangling edge.
281
281
 
282
282
  One check is still yours, because no command performs it: **every node file appears in `Index.md`**. An
283
283
  unlisted node exists and is reachable by search, but is invisible to anyone reading the map.
@@ -54,7 +54,7 @@ Check whether `synapse/{repo}@{branch}/Index.md` exists.
54
54
  ### 2. Preview the wipe and get explicit confirmation
55
55
 
56
56
  ```sh
57
- ~/.synapse graph-wipe --dry-run
57
+ synapse graph-wipe --dry-run
58
58
  ```
59
59
 
60
60
  Report its output plainly: node count, and — the one thing this step exists to surface — how many
@@ -75,7 +75,7 @@ notes attached, which the human hasn't seen a number for yet.
75
75
  Once confirmed:
76
76
 
77
77
  ```sh
78
- ~/.synapse graph-wipe
78
+ synapse graph-wipe
79
79
  ```
80
80
 
81
81
  This deletes `synapse/{repo}@{branch}/` and, if any node had non-empty `## Notes`, first dumps that
@@ -26,7 +26,7 @@ Use those instead of reinventing a parallel view.
26
26
 
27
27
  ## Prerequisites
28
28
 
29
- - Requires a matching Obsidian design note (`designs/`) with `Status: Ready`.
29
+ - Requires a matching design note (`designs/`) with `Status: Ready`.
30
30
  - No matching note → "No Ready design note found for '{topic}'. Run
31
31
  `/synapse-design-note \"{topic}\"` first." Never generate a checklist from scratch.
32
32
  - Matching note but `Status: Discussing` → "Design note for '{topic}' is still in Discussing. Finish
@@ -99,8 +99,8 @@ printf '> Compiled task: [[%s]]\n\n' "{task note title}" | \
99
99
 
100
100
  A small annotation line, same idea as any other cross-reference you'd drop near a note's title. This
101
101
  is a one-time link; the design note's `Status` itself does not change and does not need to track the
102
- task's progress — Obsidian's own backlinks panel (or a plain `synapse vault-search-text` for the task
103
- note's title, on a disk-backed vault) already surfaces the live task note from the design note, and
102
+ task's progress — a plain `synapse vault-search-text` for the task
103
+ note's title already surfaces the live task note from the design note, and
104
104
  the task's `status:` frontmatter is the authoritative progress signal from here on.
105
105
 
106
106
  ## Confirm
@@ -122,7 +122,7 @@ command doesn't set or watch that field itself.
122
122
  ```
123
123
  User: /synapse-task-note "rollup direct storage"
124
124
 
125
- Claude: [reads designs/{PROJECT}Rollup direct storage.md, Status: Ready]
125
+ Claude: [reads designs/{project}/Rollup direct storage.md, Status: Ready]
126
126
  [no existing linked task note]
127
127
 
128
128
  Compiled checklist:
@@ -133,8 +133,8 @@ Claude: [reads designs/{PROJECT} — Rollup direct storage.md, Status: Ready]
133
133
 
134
134
  Project already known: {PROJECT} → {prefix}-005.
135
135
 
136
- Created: tasks/{PROJECT}/Rollup direct storage implementation.md (task_id: {prefix}-005)
137
- Linked back from designs/{PROJECT}Rollup direct storage.md.
136
+ Created: tasks/{project}/Rollup direct storage implementation.md (task_id: {prefix}-005)
137
+ Linked back from designs/{project}/Rollup direct storage.md.
138
138
 
139
139
  Status transitions happen automatically via the synapse-task skill once you start work.
140
140
  ```
@@ -29,15 +29,14 @@ of scope — foundational files, not taxonomy notes.
29
29
  ## Prerequisites
30
30
 
31
31
  Requires the `synapse` CLI on `PATH`, resolving a vault with a working `LinkGraph`
32
- (`synapse vault-backlinks`/`vault-links`/`vault-unresolved`/`vault-orphans`/`vault-deadends` — see
33
- `sb Obsidian CLI as ObsidianStore's transport` and `sb DiskStore's own index, Obsidian becomes
34
- optional`). Both real coding-vault backends have one now — `obsidian` reaching the CLI when
35
- reachable and falling back to `disk`'s own implementation otherwise, `disk` always local. If
36
- `SYNAPSE_VAULT_INTEGRATIONS` ever resolves to a backend with no `LinkGraph` at all, these commands exit 1
37
- saying so; stop and report that rather than falling back to anything else.
32
+ (`synapse vault-backlinks`/`vault-links`/`vault-unresolved`/`vault-orphans`/`vault-deadends`).
33
+ `DiskStore`, the one real backend, always has one -- case-insensitive wikilink resolution over the
34
+ vault folder directly, no external dependency. If `SYNAPSE_VAULT_INTEGRATIONS` ever resolves to a
35
+ backend with no `LinkGraph` at all, these commands exit 1 saying so; stop and report that rather
36
+ than falling back to anything else.
38
37
 
39
38
  This command reaches the vault store only through the `synapse` CLI's `vault-*` subcommands, the
40
- same door every other skill uses — no MCP tool, no direct `ObsidianStore` call. `vault-links`/
39
+ same door every other skill uses — no MCP tool, no direct store call. `vault-links`/
41
40
  `vault-backlinks` each answer for one note at a time, so Step 1's inventory sweep runs one pair per
42
41
  note in scope: `2N` process spawns for an `N`-note vault. Acceptable for an on-demand, rare command.
43
42
  Step 3's broken-link history check is a plain `git log` call (via Bash, not a compiled tool)
@@ -87,10 +86,9 @@ guessing:
87
86
  - Missing `created` → `stat.ctime`, formatted `YYYY-MM-DD HH:MM` to match every other note's
88
87
  convention.
89
88
 
90
- Apply via read-modify-write on the whole file (`synapse vault-read` → edit the one frontmatter line
91
- in the returned content `synapse vault-write` the whole file back) never `vault-patch` with
92
- `--frontmatter`, which re-serializes the entire YAML block and silently reformats unrelated fields,
93
- the same hazard `synapse-vault`/`synapse-task` already document.
89
+ Apply with `synapse frontmatter set <path> <key> <value>` (or `vault-patch --frontmatter`, which
90
+ delegates to the same byte-preserving mechanism) either writes exactly this one field and leaves
91
+ every other line untouched, the way `synapse-vault`/`synapse-task` already document.
94
92
 
95
93
  ## Step 3: Note-health findings (reported, not fixed)
96
94
 
@@ -200,4 +198,4 @@ Print a short summary directly in the response, not left only in tool-call outpu
200
198
  under a `/loop` the user sets up themselves.
201
199
  - Every step above goes through the `synapse` CLI's `vault-*` subcommands, or (Step 3's broken-link
202
200
  history check only) a plain `git log` via Bash against the vault's own local repo; this command
203
- never calls an `mcp__obsidian__*` tool or `ObsidianStore` directly.
201
+ never calls a store implementation directly.
@@ -38,10 +38,10 @@ There is no flag syntax here — read intent from how the user asks:
38
38
 
39
39
  ## Determining the project
40
40
 
41
- Every design note is tagged with the project it belongs to both in the title
42
- (`{PROJECT} {Topic}`) and as `project: {prefix}` in frontmatter (the same short prefix the
43
- synapse-note skill's task mode uses for task IDs) so a flat `designs/` folder still reads clearly,
44
- and both note kinds can be filtered together via `synapse vault-search`.
41
+ Every design note records the project it belongs to as `project: {prefix}` in frontmatter (the
42
+ same short prefix the synapse-note skill's task mode uses for task IDs) that field also decides
43
+ the note's `designs/{project}/` subfolder, so design notes and task notes can be filtered together
44
+ via `synapse vault-search`. The title itself is plain `{Topic}` — no project prefix, no id.
45
45
 
46
46
  Same resolution the synapse-note skill uses for a missing task ID (its "Resolving a missing task
47
47
  ID"), reading the same file:
@@ -58,6 +58,12 @@ ID"), reading the same file:
58
58
  4. If nothing confidently matches, ask the user for a short project tag — plain free-text, not a
59
59
  multiple-choice list, never hinting at any other project's tag as an example — then append the
60
60
  resolved pair to the conf file.
61
+ 5. Once the prefix is known, mint the note's `note_id` the same shared-counter way the synapse-note
62
+ skill's "Resolving a missing task ID" step 6 does: `task_id` and `note_id` share one counter per
63
+ prefix, so check both fields (`synapse vault-search --fields frontmatter.task_id,frontmatter.note_id`,
64
+ filter both for `{prefix}-\d+`, take the highest number found across both, add 1; start at 1 if none
65
+ exist yet). This is frontmatter only — unlike a task note, a design note's title and filename stay
66
+ exactly `{Topic}`, with no id and no project prefix prepended.
61
67
 
62
68
  Never hardcode a specific project/prefix pair in this skill's own instructions — the conf file is
63
69
  machine-local and deliberately outside the portable Synapse package, so projects from
@@ -157,11 +163,11 @@ judgment call, not the automatic result of an `## Approach` section existing. Be
157
163
  blocking question is fine to carry forward), but a note with a *blocking* open question is not
158
164
  `Ready`, no matter how developed the rest of it is.
159
165
 
160
- - **Both hold** → `Status: Ready`. Confirm: "Design note ready: `designs/{title}.md`.
166
+ - **Both hold** → `Status: Ready`. Confirm: "Design note ready: `designs/{project}/{title}.md`.
161
167
  Whenever you're ready to implement, ask me to compile it into a task note — no rush, nothing
162
168
  here expires."
163
169
  - **Genuinely nothing to build** → `Status: Reference`. Confirm: "Design note concluded as
164
- Reference: `designs/{title}.md`. No task note needed."
170
+ Reference: `designs/{project}/{title}.md`. No task note needed."
165
171
  - **Anything else** (the approach is still hedged, or an open question blocks it) → stays
166
172
  `Status: Discussing`. This is the default outcome, not a fallback to apologize for — most
167
173
  conversations end here, and that's fine; nothing here expires either.
@@ -179,7 +185,7 @@ so the `## Status` line is the only lifecycle marker that matters. It simply sta
179
185
  ```
180
186
  ---
181
187
  schema: vault-design-note/v1
182
- title: "{PROJECT} — {Topic}"
188
+ title: "{Topic}"
183
189
  project: {prefix}
184
190
  note_id: {id}
185
191
  created: "{now}"
@@ -187,7 +193,7 @@ updated: "{now}"
187
193
  tags: [{comma-separated configured tags, or empty}]
188
194
  ---
189
195
 
190
- # {PROJECT} — {Topic}
196
+ # {Topic}
191
197
 
192
198
  ## Status
193
199
  Discussing | Ready | Reference
@@ -198,16 +204,21 @@ Discussing | Ready | Reference
198
204
  ## Approach
199
205
  {Chosen approach}
200
206
 
201
- ### Alternatives considered (optional)
207
+ ### Alternatives considered
202
208
  - {Option}: why not
203
209
 
204
210
  ## Constraints
205
211
  {Hard constraints, non-negotiables}
206
212
 
207
- ## Open Questions (optional)
213
+ ## Open Questions
208
214
  - {Anything deferred or unresolved}
209
215
  ```
210
216
 
217
+ `### Alternatives considered` and `## Open Questions` are both optional per the schema — omit
218
+ either section entirely rather than leaving it as an empty heading, and never write it as `##
219
+ Open Questions (optional)`: the schema and `/synapse-status`'s own query both match this exact
220
+ heading text, and a suffixed one is invisible to both.
221
+
211
222
  Resolve tags through the `synapse-vault` skill's configured vocabulary procedure. Fetch machine
212
223
  local time once (`date '+%Y-%m-%d %H:%M:%S %Z'`) — never infer it — and use the exact same value
213
224
  for `created` and `updated`.
@@ -217,8 +228,10 @@ edit history here worth tracking separately.
217
228
 
218
229
  ## Filename
219
230
 
220
- `designs/{PROJECT}{Topic}.md` — sanitize filesystem-illegal characters (`/ : * ? " < > |`). No
221
- slug, no numbering Obsidian filenames are the title itself.
231
+ `designs/{project}/{Topic}.md` — grouped one level deeper into a per-project
232
+ subfolder named by the note's own `project:` frontmatter value (e.g. `designs/eon/`,
233
+ `designs/synapse/`), the same mapping tasks use. Sanitize filesystem-illegal
234
+ characters (`/ : * ? " < > |`). No slug, no numbering — vault filenames are the title itself.
222
235
 
223
236
  ---
224
237
 
@@ -239,12 +252,12 @@ Codex: [searches designs/ for existing matches — none found]
239
252
 
240
253
  User: Replacing the AggregatingMergeTree rollup resolution with direct-value storage.
241
254
 
242
- Codex: [creates designs/{PROJECT}Rollup direct storage.md, Status: Discussing]
255
+ Codex: [creates designs/{project}/Rollup direct storage.md, Status: Discussing]
243
256
 
244
257
  What's driving this over just tuning the current argMaxMerge query?
245
258
  ...
246
259
  User: The resolution cost alone dominates the query, tuning won't fix that. Mark it ready.
247
260
 
248
- Codex: Design note ready: designs/{PROJECT}Rollup direct storage.md.
261
+ Codex: Design note ready: designs/{project}/Rollup direct storage.md.
249
262
  Ask me to compile the task note whenever you're ready to implement.
250
263
  ```
@@ -100,7 +100,7 @@ yours and cannot be scripted because what counts as signal differs per codebase.
100
100
  **The work directory** defaults to `~/.cache/synapse/work/{repo}@{branch}/`, created on demand, and
101
101
  holds `manifest.tsv`, `all.txt`, `lists/`, the authored `b-NN.md` bodies and the coverage files. Override with `$SYNAPSE_WORK_DIR` if you need to. Two things never to do: point it
102
102
  at the repo (`synapse` runs from inside the repo, so its working files would land in the user's
103
- checkout) or at the vault (Obsidian would index a file list that runs to six figures of lines).
103
+ checkout) or at the vault (a file list that runs to six figures of lines has no business inside it).
104
104
  It is deliberately persistent rather than a temp dir, so a later run finds the previous manifest
105
105
  instead of re-deriving the clustering.
106
106
  - **Interpretation (only you can do this):** deciding what the nodes *are*, and writing their prose.
@@ -289,8 +289,8 @@ emit into tool calls than read into a window. Never hand-author those.
289
289
  **Then verify, before reporting success.** Three checks, all cheap:
290
290
  - `synapse query stale` must print nothing. (40s for a 125k-file namespace.)
291
291
  - Every `[[wikilink]]` in the namespace must resolve to a file that exists — extract them all and
292
- test `-f "$link.md"`. Nothing else catches a broken link, since Obsidian treats it as a link to
293
- a note not yet created.
292
+ test `-f "$link.md"`. Nothing else catches a broken link -- a wikilink to a note that does not
293
+ exist yet just fails silently.
294
294
  - Every node file must appear in `Index.md`. An unlisted node exists but is invisible to a reader.
295
295
 
296
296
  ```yaml
@@ -27,7 +27,8 @@ below:
27
27
  - **Asking to create any other note** ("make a note about X", "save this as a note") → **bare
28
28
  mode**: create an empty node (title + frontmatter only). Which category folder it lands in is
29
29
  resolved from the vault's index note, per "Choosing a category (bare mode only)" below — not a
30
- fixed set.
30
+ fixed set. The typical categories are `research/`, `scratchpad/`, or `inbox/` — any plain note
31
+ that isn't a task or design note.
31
32
 
32
33
  The title is whatever the user is naming or describing, minus any mode-signaling phrasing. Example:
33
34
 
@@ -138,7 +139,7 @@ offered.
138
139
 
139
140
  Resolve this to a `category` matching the folder name exactly as
140
141
  the index note currently spells it, before moving on to the creation steps
141
- below. No project-slug question is needed here — Obsidian filenames are
142
+ below. No project-slug question is needed here — vault filenames are
142
143
  the title itself, not a slug-prefixed timestamp, so there's no separate
143
144
  namespacing concern to resolve. The note always lands flat at
144
145
  `{category}/{filename}.md` — never inferred into a subfolder such as a
@@ -97,8 +97,8 @@ this skill when it does. What no longer happens is arriving here merely because
97
97
  ### 1. Size the job before doing any of it
98
98
 
99
99
  ```sh
100
- ~/.synapse query drift
101
- ~/.synapse query grounding
100
+ synapse query drift
101
+ synapse query grounding
102
102
  ```
103
103
 
104
104
  Report what it says, in the human's terms, **before** touching anything: how far the baseline is from
@@ -118,7 +118,7 @@ Two answers change the plan:
118
118
  ### 2. Mechanical phase — always, and cheap
119
119
 
120
120
  ```sh
121
- ~/.synapse build-lists --reenumerate
121
+ synapse build-lists --reenumerate
122
122
  ```
123
123
 
124
124
  `--reenumerate` matters here: without it an existing `all.txt` is reused, so a branch switch would be
@@ -136,7 +136,7 @@ move a lot and some may reach zero.
136
136
  Then rebuild the reverse index so the hook and the read path agree with the new enumeration:
137
137
 
138
138
  ```sh
139
- ~/.synapse build-index
139
+ synapse build-index
140
140
  ```
141
141
 
142
142
  ### 3. Triage each flagged node — reseat, patch, or re-orient
@@ -193,8 +193,8 @@ straight back stores a quote of a file as it looked at the old baseline, present
193
193
  current. So rebuild the directive from the pointer the writer recorded:
194
194
 
195
195
  ```sh
196
- ~/.synapse query field "{Node}" crux_path
197
- ~/.synapse query field "{Node}" crux_lines
196
+ synapse query field "{Node}" crux_path
197
+ synapse query field "{Node}" crux_lines
198
198
  ```
199
199
 
200
200
  and replace the fenced block with `<!-- crux: <crux_path> <crux_lines> -->` so it is cut from the
@@ -208,7 +208,7 @@ its directives are stripped from the body, so a recovered body contains none —
208
208
  the node's provenance is gone with no error. Recover the pointers per node:
209
209
 
210
210
  ```sh
211
- ~/.synapse query grounding "{Node}" --list # path<TAB>lines
211
+ synapse query grounding "{Node}" --list # path<TAB>lines
212
212
  ```
213
213
 
214
214
  and re-emit a `<!-- grounded_in: <path> <lines> -->` for each. Run `synapse query grounding` before
@@ -257,7 +257,7 @@ selection. Never pipe an unbounded `git diff <commit>..HEAD` into a context wind
257
257
  ### 4. Write each rebuilt node
258
258
 
259
259
  ```sh
260
- ~/.synapse write-node --title "{Node}" --summary "{one line}" \
260
+ synapse write-node --title "{Node}" --summary "{one line}" \
261
261
  --paths "$W/lists/NN.txt" --body "$W/body.md"
262
262
  ```
263
263
 
@@ -268,16 +268,16 @@ not merely stale, if the subsystem's shape differs on this line.
268
268
  ### 5. Rebuild the projections and verify
269
269
 
270
270
  ```sh
271
- ~/.synapse build-index
272
- ~/.synapse build-project-index
273
- ~/.synapse query drift # expect silence
274
- ~/.synapse query stale # expect silence
275
- ~/.synapse query grounding # expect silence: re-pointed, not dropped
276
- ~/.synapse query links --check # expect silence: no dangling targets
271
+ synapse build-index
272
+ synapse build-project-index
273
+ synapse query drift # expect silence
274
+ synapse query stale # expect silence
275
+ synapse query grounding # expect silence: re-pointed, not dropped
276
+ synapse query links --check # expect silence: no dangling targets
277
277
  ```
278
278
 
279
279
  `links --check` covers what used to be a manual instruction here: a broken `[[wikilink]]` is a valid
280
- link to a not-yet-existing note, so Obsidian renders it without complaint and nothing else in the
280
+ link to a not-yet-existing note, silently, and nothing else in the
281
281
  system notices. It now reports `Node<TAB>relation -> Target (no such node)` per dangling edge.
282
282
 
283
283
  One check is still yours, because no command performs it: **every node file appears in `Index.md`**. An
@@ -51,7 +51,7 @@ Check whether `synapse/{repo}@{branch}/Index.md` exists.
51
51
  ### 2. Preview the wipe and get explicit confirmation
52
52
 
53
53
  ```sh
54
- ~/.synapse graph-wipe --dry-run
54
+ synapse graph-wipe --dry-run
55
55
  ```
56
56
 
57
57
  Report its output plainly: node count, and — the one thing this step exists to surface — how many
@@ -72,7 +72,7 @@ attached, which the human hasn't seen a number for yet.
72
72
  Once confirmed:
73
73
 
74
74
  ```sh
75
- ~/.synapse graph-wipe
75
+ synapse graph-wipe
76
76
  ```
77
77
 
78
78
  This deletes `synapse/{repo}@{branch}/` and, if any node had non-empty `## Notes`, first dumps that