@imunitic/synapse 0.1.1 → 0.2.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.
@@ -69,7 +69,7 @@ function readObsidianPluginData() {
69
69
  const { resolveVaultDir } = require("../lib/obsidian-mcp-refresh.cjs");
70
70
  const vault = resolveVaultDir();
71
71
  if (!vault || !fs.existsSync(vault)) {
72
- fail("no OBSIDIAN_VAULT_DIR resolvable (see synapse.conf) -- can't configure the obsidian MCP connection");
72
+ fail("no SYNAPSE_VAULT_DIR resolvable (see synapse.conf) -- can't configure the obsidian MCP connection");
73
73
  }
74
74
  const pluginDataPath = path.join(vault, ".obsidian", "plugins", "obsidian-local-rest-api", "data.json");
75
75
  if (!fs.existsSync(pluginDataPath)) {
@@ -17,14 +17,14 @@ Not every design discussion ends with something to build. See `Status: Reference
17
17
  ```
18
18
  /synapse-design-note "topic" # Start or resume a design discussion
19
19
  /synapse-design-note --continue # Resume an incomplete design note
20
- /synapse-design-note --list # List every Obsidian design note, regardless of status
20
+ /synapse-design-note --list # List every design note in the vault, regardless of status
21
21
  ```
22
22
 
23
23
  ## Prerequisites
24
24
 
25
- - Requires the `obsidian` MCP server (`mcp__obsidian__*` tools). If unreachable, say so and stop —
26
- there is no local-file fallback for this command.
27
- - If `designs/` doesn't exist in the vault yet, `mcp__obsidian__vault_write` creates it implicitly on
25
+ - Requires the `synapse` CLI on `PATH`. If it errors (no vault configured), say so and stop —
26
+ there is no other fallback for this command.
27
+ - If `designs/` doesn't exist in the vault yet, `synapse vault-write` creates it implicitly on
28
28
  first write — but add a `designs/` entry to the vault's `Index.md` folder layout in the same
29
29
  action (per the Synapse Vault folder-layout rule: a new top-level folder must never fall behind the
30
30
  index).
@@ -34,7 +34,7 @@ Not every design discussion ends with something to build. See `Status: Reference
34
34
  Every design note is tagged with the project it belongs to — both in the title
35
35
  (`{PROJECT} — {Topic}`) and as `project: {prefix}` in frontmatter (the same short prefix
36
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 `search_query`.
37
+ both note kinds can be filtered together via `synapse vault-search`.
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:
@@ -59,15 +59,22 @@ unrelated contexts (e.g. personal vs. work) never end up in the same place.
59
59
  ## Handling Arguments
60
60
 
61
61
  **No arguments:**
62
- 1. Check for incomplete design notes: search `designs/` (via `mcp__obsidian__vault_list` +
63
- `vault_read`, or `search_query` scoped to the `designs/` path) for notes whose `## Status` line
64
- reads `Discussing`.
62
+ 1. Check for incomplete design notes: `synapse vault-search --fields frontmatter.title` with the
63
+ query below on stdin one call, no separate read needed:
64
+
65
+ ```
66
+ {"and": [
67
+ {"glob": ["designs/*", {"var": "path"}]},
68
+ {"regexp": ["## Status\\nDiscussing", {"var": "content"}]}
69
+ ]}
70
+ ```
65
71
  2. If found: show a short state summary — title and current section — and offer to resume.
66
72
  3. If none: ask "What are we designing?"
67
73
 
68
74
  **With a topic:**
69
- 1. Search first — `mcp__obsidian__search_simple` for the topic text across `designs/` (per the
70
- Synapse Vault rule: link/reuse over duplicate). Also check for an obvious title match.
75
+ 1. Search first — `synapse vault-search-text "{topic}"` for the topic text, then filter matches to
76
+ `designs/` paths (per the Synapse Vault rule: link/reuse over duplicate). Also check for an
77
+ obvious title match.
71
78
  2. If found with `Status: Discussing` → ask "Resume this design?" or "Start fresh?"
72
79
  3. If found with `Status: Ready` → ask "Already marked Ready. Reopen to revise, or start a new note?"
73
80
  4. If found with `Status: Reference` → ask "This concluded as Reference (no implementation intended).
@@ -82,8 +89,9 @@ unrelated contexts (e.g. personal vs. work) never end up in the same place.
82
89
  4. None → "No incomplete design note found. Start one with `/synapse-design-note \"topic\"`."
83
90
 
84
91
  **--list:**
85
- 1. `mcp__obsidian__vault_list` on `designs/`, then `vault_read` each (or a `search_query` scoped to
86
- that path) to pull title and `## Status`.
92
+ 1. `synapse vault-search --fields frontmatter.title,content` with `{"glob": ["designs/*", {"var":
93
+ "path"}]}` on stdin — every design note regardless of status, title and `## Status` line both in
94
+ the same row.
87
95
  2. None found → "No design notes yet. Start one with `/synapse-design-note \"topic\"`."
88
96
  3. Group into **Active** (`Discussing`, `Ready`) and **Closed** (`Reference`) — active first, title
89
97
  and status in backticks, not bold.
@@ -23,7 +23,7 @@ No arguments — always operates on the repo containing the current working dire
23
23
 
24
24
  ## Prerequisites
25
25
 
26
- - Requires the `obsidian` MCP server (`mcp__obsidian__*` tools). If unreachable, say so and stop.
26
+ - Requires the `synapse` CLI on `PATH`. If it errors (no vault configured), say so and stop.
27
27
  - Must be run from inside a git repository. Synapse assumes git throughout (source hashing uses
28
28
  `git hash-object`, file enumeration uses `git ls-files`) — if `git rev-parse --show-toplevel`
29
29
  fails, stop and say this only works inside a git repo.
@@ -65,8 +65,8 @@ Every step below needs the same three facts, resolved once up front:
65
65
 
66
66
  ## Already initialized?
67
67
 
68
- Check whether `synapse/{repo}@{branch}/Index.md` exists (`mcp__obsidian__vault_list` on
69
- `synapse/{repo}@{branch}/`, or a direct `vault_read` attempt).
68
+ Check whether `synapse/{repo}@{branch}/Index.md` exists: `synapse vault-read
69
+ "synapse/{repo}@{branch}/Index.md"` and see whether it succeeds or reports "no such note".
70
70
 
71
71
  - **Doesn't exist** → this is a first-time build. Go to "First-time build" below.
72
72
  - **Exists, `remote` frontmatter matches** the resolved remote/path → this namespace already
@@ -97,7 +97,7 @@ yours and cannot be scripted because what counts as signal differs per codebase.
97
97
  (hash, digest, `## Sources` mirror, PUT), `synapse push-nodes`, `synapse build-index`,
98
98
  `synapse build-project-index`.
99
99
 
100
- **The work directory** defaults to `~/.claude/synapse-work/{repo}@{branch}/`, created on demand, and
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
103
  checkout) or at the vault (Obsidian would index a file list that runs to six figures of lines).
@@ -26,7 +26,7 @@ If no match is found, **don't just leave it blank** — see "Resolving a missing
26
26
 
27
27
  ## List mode
28
28
 
29
- Use `mcp__obsidian__search_query` with the JsonLogic query `{"var": "frontmatter.task_id"}` — this returns every file that has a `task_id` set, along with that file's `task_id` value as `result`. For each match, also read the file's `status` and `title` (either via a second query `{"var": "frontmatter.status"}` / `{"var": "frontmatter.title"}`, or via `mcp__obsidian__vault_read` on the handful of matched files — whichever is fewer round-trips for the count involved).
29
+ Run `synapse vault-search --fields frontmatter.task_id,frontmatter.status,frontmatter.title` with the JsonLogic query `{"var": "frontmatter.task_id"}` on stdin one call returns every file that has a `task_id` set, each row already carrying `task_id`/`status`/`title` together, no second query or extra read needed.
30
30
 
31
31
  Categorize:
32
32
  - **Prefixed notes**: `task_id` matches `{prefix}-\d+`. Group by the distinct prefix found (whatever
@@ -43,8 +43,8 @@ Do not modify any files in list mode.
43
43
 
44
44
  Everything after `--search` (trimmed, quotes stripped) is the query.
45
45
 
46
- 1. Run `mcp__obsidian__search_simple` with the query — this gives full-text relevance-ranked matches with context, the closest equivalent to a title/body search.
47
- 2. If the query looks like it's targeting metadata specifically (a tag, a task ID, a status value) rather than free text, also run `mcp__obsidian__search_query` with an appropriate JsonLogic filter (e.g. `{"==": [{"var": "frontmatter.task_id"}, "proj-032"]}`).
46
+ 1. Run `synapse vault-search-text "{query}"` — this gives full-text relevance-ranked matches with context, the closest equivalent to a title/body search.
47
+ 2. If the query looks like it's targeting metadata specifically (a tag, a task ID, a status value) rather than free text, also run `synapse vault-search --fields frontmatter.title` with an appropriate JsonLogic filter on stdin (e.g. `{"==": [{"var": "frontmatter.task_id"}, "proj-032"]}`).
48
48
  3. Report matches as `{title} — {file path relative to vault root}`, deduped across both. If nothing matches, say so plainly — the caller (agent or user) needs a clear "no existing note" signal to proceed with `--task`-less creation.
49
49
 
50
50
  Do not modify any files in search mode.
@@ -54,8 +54,8 @@ Do not modify any files in search mode.
54
54
  Triggered when `--task` is given but the title doesn't match `{prefix}-\d+`.
55
55
 
56
56
  The known project/prefix pairs live in a plain local file named `synapse-projects.conf` (one
57
- `project-name=prefix` line each) — read/appended with the Read/Edit tools, not the `obsidian`
58
- MCP server, since it's outside the vault. It is deliberately **not** part of the portable
57
+ `project-name=prefix` line each) — read/appended with the Read/Edit tools, not the `vault-*` subcommands,
58
+ since it's outside the vault. It is deliberately **not** part of the portable
59
59
  Synapse package and never copied between machines, so contexts that shouldn't mix (e.g.
60
60
  personal vs. work projects) never end up in the same file. It's self-managed — this command appends
61
61
  newly resolved pairs to it — but also plain text, so the user can add, fix, or remove a line by hand
@@ -77,8 +77,8 @@ unchanged for anyone who has never touched an XDG config directory.
77
77
  2. Check the resolved `synapse-projects.conf` for a line whose project name matches (loosely —
78
78
  case/whitespace-insensitive). If found, use that prefix directly — no need to ask.
79
79
  3. If the file doesn't have it yet, fall back to deducing from the vault itself (useful the first
80
- time this runs, or for a project whose notes predate this file): `search_simple` for the
81
- project/repo name across existing notes, and/or `search_query` on
80
+ time this runs, or for a project whose notes predate this file): `synapse vault-search-text` for
81
+ the project/repo name across existing notes, and/or `synapse vault-search` on
82
82
  `{"var": "frontmatter.task_id"}` to see which prefixes exist, then check whether any of those
83
83
  prefixed notes reference this project. If exactly one prefix confidently matches, use it.
84
84
  4. If nothing confidently matches (new project, or an ambiguous/multiple match), ask the user
@@ -87,11 +87,10 @@ unchanged for anyone who has never touched an XDG config directory.
87
87
  5. Whenever step 3 or step 4 resolves a pair not already in the conf file (including a fresh
88
88
  `project-name=prefix` line matching what was just deduced or asked), append it — so the next task
89
89
  for this project resolves from step 2 without a search or a question.
90
- 6. Once the prefix is known, find the next number: run
91
- `mcp__obsidian__search_query` with `{"var": "frontmatter.task_id"}`,
92
- filter the returned `result` values client-side for ones matching
93
- `{prefix}-\d+`, take the highest number found, add 1. If none exist yet
94
- for that prefix, start at 1.
90
+ 6. Once the prefix is known, find the next number: run `synapse vault-search --fields
91
+ frontmatter.task_id` with `{"var": "frontmatter.task_id"}` on stdin, filter the returned values
92
+ client-side for ones matching `{prefix}-\d+`, take the highest number found, add 1. If none exist
93
+ yet for that prefix, start at 1.
95
94
  7. Format the new task ID **zero-padded to 3 digits** (`{prefix}-001`, `{prefix}-030`,
96
95
  `{prefix}-037`, ...), matching the org-roam-era convention — widening
97
96
  naturally past 3 digits if a prefix ever needs it.
@@ -181,7 +180,7 @@ or supplied directly by a caller like `/synapse-task-note`):
181
180
  ## Notes
182
181
 
183
182
  ```
184
- 4. Write it with `mcp__obsidian__vault_write`. Task mode: path
183
+ 4. Write it with `synapse vault-write <path>` (content on stdin). Task mode: path
185
184
  `tasks/{project}/{filename}.md` (project resolved in "Resolving the
186
185
  project folder" above). Bare mode: path `{category}/{filename}.md`
187
186
  (category resolved above).
@@ -85,7 +85,7 @@ this command when it does. What no longer happens is arriving here merely becaus
85
85
  because it is not this checkout's namespace to diff at all. Never conflate the two: a non-ancestor
86
86
  baseline on a branch-identity match still proceeds normally, per the "One mechanical fact about
87
87
  branches" section above.
88
- - The work directory (`$SYNAPSE_WORK_DIR`, default `~/.claude/synapse-work/{repo}@{branch}/`) ideally
88
+ - The work directory (`$SYNAPSE_WORK_DIR`, default `~/.cache/synapse/work/{repo}@{branch}/`) ideally
89
89
  holds the `manifest.tsv` from the original build. Without it, new paths cannot be classified as
90
90
  auto-claimable, and clustering decisions have to be re-derived — say so rather than proceeding as if
91
91
  nothing were missing. `synapse/{repo}@{branch}/_manifest.tsv` is the fallback copy.
@@ -29,7 +29,7 @@ No arguments — always operates on the repo and branch containing the current w
29
29
 
30
30
  ## Prerequisites
31
31
 
32
- - Requires the `obsidian` MCP server (`mcp__obsidian__*` tools). If unreachable, say so and stop —
32
+ - Requires the `synapse` CLI on `PATH`. If it errors (no vault configured), say so and stop —
33
33
  same requirement `/synapse-init` has.
34
34
  - Must be run from inside a git repository, on a named branch (not detached `HEAD`) — same
35
35
  requirement `/synapse-init` has, since `synapse_namespace` needs a branch to key on.
@@ -6,12 +6,11 @@ description: Print a read-only report of what in Synapse Vault currently needs a
6
6
 
7
7
  A read-only sweep over Synapse Vault answering one question: what currently needs a human decision?
8
8
  Five categories, one pass, printed as plain chat text -- an org-agenda-style check-in, not a document
9
- to hand to someone else and not a live dashboard (a published Artifact has no route to the local
10
- Obsidian REST API, so nothing here is ever presented that way). Run it on demand, or from a
11
- scheduled `/loop`/cron invocation of this same command -- never wired into `SessionStart`: two of
12
- the five categories need a per-note body read, not just a frontmatter check, and unlike `Index.md`
13
- this report is a periodic human check-in, not something the agent needs injected every session to
14
- behave correctly.
9
+ to hand to someone else and not a live dashboard (a published Artifact has no route to the vault, so
10
+ nothing here is ever presented that way). Run it on demand, or from a scheduled `/loop`/cron
11
+ invocation of this same command -- never wired into `SessionStart`: some of the five categories need
12
+ a per-note content read, not just a frontmatter check, and unlike `Index.md` this report is a
13
+ periodic human check-in, not something the agent needs injected every session to behave correctly.
15
14
 
16
15
  Scoped to `designs/`/`tasks/` only -- the two folders `/synapse-design-note`/`/synapse-note --task`
17
16
  structurally require, so every Synapse install has them in the same shape. The free-form taxonomy
@@ -27,87 +26,104 @@ periodic look on their own schedule -- this report doesn't cover it.
27
26
 
28
27
  ## Prerequisites
29
28
 
30
- Requires the `obsidian` MCP server (`mcp__obsidian__*` tools). If unreachable, say so and stop --
31
- there is no local-file fallback.
29
+ Requires the `synapse` CLI on `PATH`. Backend-agnostic -- every query below goes through `synapse
30
+ vault-search`, so it works the same whether the vault is Obsidian-backed or plain-disk-backed. If the
31
+ CLI errors (no vault configured), say so and stop -- there is no other fallback.
32
32
 
33
33
  ## Producing the report
34
34
 
35
- Run all five queries in parallel where the tool call shape allows it; none depends on another's
36
- result.
35
+ Run each query below via `synapse vault-search --fields <fields>`, with the JsonLogic query on stdin.
36
+ `--fields` asks for exactly the columns the query needs back -- no separate read per match required,
37
+ since a matched row already carries them.
37
38
 
38
39
  **1. Design notes still `Discussing`.** Design notes carry status in-body under `## Status`, not in
39
- frontmatter (unlike task notes) -- a content match, scoped to `designs/`:
40
+ frontmatter (unlike task notes) -- a content match, scoped to `designs/`. Needs only the title:
40
41
 
41
42
  ```
43
+ synapse vault-search --fields frontmatter.title <<'EOF'
42
44
  {"and": [
43
45
  {"glob": ["designs/*", {"var": "path"}]},
44
46
  {"regexp": ["## Status\\nDiscussing", {"var": "content"}]}
45
47
  ]}
48
+ EOF
46
49
  ```
47
50
 
48
51
  **2. `Ready` design notes with no compiled task yet.** `/synapse-task-note`'s own "Linking back"
49
52
  step patches a compiled design note with a `> Compiled task: [[...]]` line right after its title --
50
- "`Ready` and missing that line" is a direct signal, not fuzzy title-matching against `tasks/`:
53
+ "`Ready` and missing that line" is a direct signal, not fuzzy title-matching against `tasks/`. Needs
54
+ only the title:
51
55
 
52
56
  ```
57
+ synapse vault-search --fields frontmatter.title <<'EOF'
53
58
  {"and": [
54
59
  {"glob": ["designs/*", {"var": "path"}]},
55
60
  {"regexp": ["## Status\\nReady", {"var": "content"}]},
56
61
  {"!": [{"regexp": ["Compiled task:", {"var": "content"}]}]}
57
62
  ]}
63
+ EOF
58
64
  ```
59
65
 
60
66
  **3. Design notes (any status) with a non-empty `## Open Questions`.** Match the heading followed by
61
67
  at least one bullet -- a heading with nothing under it (fully pruned, per the Ready-gate convention
62
68
  `/synapse-design-note` now follows) doesn't count as open. Since this section spans every status,
63
- each line in the composed report also shows *which* status the note is currently in:
69
+ each line in the composed report also shows *which* status the note is currently in, and whether it
70
+ has a compiled task note -- request `content` too, and pull both directly out of the returned text
71
+ rather than reading the note again:
64
72
 
65
73
  ```
74
+ synapse vault-search --fields frontmatter.title,content <<'EOF'
66
75
  {"and": [
67
76
  {"glob": ["designs/*", {"var": "path"}]},
68
77
  {"regexp": ["## Open Questions\\n- ", {"var": "content"}]}
69
78
  ]}
79
+ EOF
70
80
  ```
71
81
 
72
- `regexp` is boolean-only (no captured groups), so getting each match's actual status needs a second
73
- pass. Run the same query three more times, `and`-ed with `{"regexp": ["## Status\\nDiscussing", ...]}`
74
- / `Ready` / `Reference` respectively, to sort the matches from the first query into the three known
75
- statuses without a body read. **A design note written before `## Status` was standardized on those
76
- exact three words can carry free text there instead** (e.g. `Superseded by [[...]]`) -- it matches
77
- the first query but none of the three status-scoped ones. Whatever's left over after removing the
78
- Discussing/Ready/Reference matches from the first query's full result set is exactly this case:
79
- report those under a fourth bucket, "Other", rather than silently dropping them -- surfacing an odd
80
- note beats losing it, the same reasoning behind reporting a 0-unchecked task instead of hiding it
81
- (see Query 4 below).
82
+ Do not chain further `and`/`regexp` conditions onto this query to sort matches by status -- compound
83
+ `regexp` conditions against `content` have been observed to return results that are logically
84
+ impossible (a query with strictly more AND-ed conditions returning *more* matches than one with
85
+ fewer), so any query beyond a single `glob` + single `regexp` pair is unverified and not to be
86
+ trusted here. Instead, take two things from each row's `content` column directly, no second call
87
+ needed for either: the line following `## Status` (normally `Discussing`/`Ready`/`Reference`, but a
88
+ note written before the three-word convention can carry free text instead, e.g. `Superseded by
89
+ [[...]]` -- report that verbatim rather than forcing it into a bucket, surfacing an odd note beats
90
+ losing it) and the target of a `> Compiled task: [[...]]` line, if present -- that's the compiled
91
+ task, parsed straight out of the wikilink text rather than resolved through any vault-wide link
92
+ index.
82
93
 
83
94
  **4. Open task notes with at least one unchecked item.** Task notes carry `status:` in frontmatter,
84
- unlike design notes -- filter there first:
95
+ unlike design notes -- filter there first, and request `content` to count `- [ ]` lines directly from
96
+ the row rather than reading each match again:
85
97
 
86
98
  ```
99
+ synapse vault-search --fields frontmatter.title,content <<'EOF'
87
100
  {"in": [{"var": "frontmatter.status"}, ["TODO", "IN-PROGRESS"]]}
101
+ EOF
88
102
  ```
89
103
 
90
- Then `mcp__obsidian__vault_read` each match and count `- [ ]` lines in the body. A match with zero
91
- unchecked lines (a checklist that's fully checked but hasn't been promoted to `REVIEW` yet) is still
92
- worth surfacing -- report it under this section with its count shown as 0, rather than silently
93
- dropping it, since that state itself is worth a human noticing.
104
+ A match with zero unchecked lines (a checklist that's fully checked but hasn't been promoted to
105
+ `REVIEW` yet) is still worth surfacing -- report it under this section with its count shown as 0,
106
+ rather than silently dropping it, since that state itself is worth a human noticing.
94
107
 
95
- **5. Task notes stuck in `REVIEW`.** Frontmatter-only, no body read needed -- a fully-checked
96
- checklist waiting specifically on human sign-off, since `synapse-task` deliberately never promotes a
97
- note past `REVIEW` on its own:
108
+ **5. Task notes stuck in `REVIEW`.** Frontmatter-only, no body needed -- a fully-checked checklist
109
+ waiting specifically on human sign-off, since `synapse-task` deliberately never promotes a note past
110
+ `REVIEW` on its own:
98
111
 
99
112
  ```
113
+ synapse vault-search --fields frontmatter.title <<'EOF'
100
114
  {"==": [{"var": "frontmatter.status"}, "REVIEW"]}
115
+ EOF
101
116
  ```
102
117
 
103
118
  ## Composing the report
104
119
 
105
120
  One section per category, in the order above. Each line names the note (title, or filename if no
106
121
  `title` frontmatter) plus the one identifying detail that category needs. The Open Questions section
107
- is the one place a note's status also belongs on the line -- every other section's heading already
108
- implies it (the "Discussing" section only ever holds `Discussing` notes), but Open Questions spans
109
- every status (`Discussing`/`Ready`/`Reference`/the "Other" catch-all from Query 3 above), so put the
110
- status first, before the title, so it's the first thing scanned:
122
+ is the one place a note's status and compiled-task link also belong on the line -- every other
123
+ section's heading already implies status (the "Discussing" section only ever holds `Discussing`
124
+ notes) and compiled-task-ness (the "Ready, not yet compiled" section only ever holds notes without
125
+ one), but Open Questions spans every status and both compiled and uncompiled notes, so put the status
126
+ first, before the title, so it's the first thing scanned:
111
127
 
112
128
  ```
113
129
  ## Discussing
@@ -117,7 +133,7 @@ status first, before the title, so it's the first thing scanned:
117
133
  - {title}
118
134
 
119
135
  ## Open questions
120
- - **{status}** — {title}
136
+ - **{status}** — {title} — {compiled task title, or "not compiled"}
121
137
 
122
138
  ## In progress (unchecked items)
123
139
  - {title} ({N} unchecked)
@@ -136,9 +152,8 @@ go dig for.
136
152
 
137
153
  ## Constraints
138
154
 
139
- - Read-only end to end. Never calls `vault_write`/`vault_patch`/`vault_move`/`vault_delete`/
140
- `vault_copy` -- if a step here ever seems to need one, that step is out of scope, not a case to
141
- special-case around.
155
+ - Read-only end to end. Never calls `vault-write`/`vault-patch` -- if a step here ever seems to need
156
+ one, that step is out of scope, not a case to special-case around.
142
157
  - No Artifact/web-UI output. No `SessionStart` wiring. Not a new binary CLI subcommand -- every
143
- category above is a plain mechanical query already reachable through `mcp__obsidian__*` tools.
158
+ category above is a plain mechanical query already reachable through `synapse vault-search`.
144
159
  - Scoped to `designs/`/`tasks/` only -- never `inbox/`/`research/`/`scratchpad/`.
@@ -89,12 +89,19 @@ duplicate that scaffolding here, just supply its inputs:
89
89
 
90
90
  ## Linking back
91
91
 
92
- After creation, patch the design note: add `> Compiled task: [[{task note title}]]` near the top
93
- (via `mcp__obsidian__vault_patch`) a small annotation line, same idea as any other cross-reference
94
- you'd drop near a note's title. This is a one-time link; the design note's `Status` itself does not
95
- change and does not need to track the task's progress — Obsidian's own backlinks panel already
96
- surfaces the live task note from the design note, and the task's `status:` frontmatter is the
97
- authoritative progress signal from here on.
92
+ After creation, patch the design note: add `> Compiled task: [[{task note title}]]` near the top
93
+ right after the `# {title}` heading, before `## Status`:
94
+
95
+ ```
96
+ printf '> Compiled task: [[%s]]\n\n' "{task note title}" | \
97
+ synapse vault-patch "{design note path}" --heading "{design note title}" --prepend
98
+ ```
99
+
100
+ A small annotation line, same idea as any other cross-reference you'd drop near a note's title. This
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
104
+ the task's `status:` frontmatter is the authoritative progress signal from here on.
98
105
 
99
106
  ## Confirm
100
107
 
@@ -89,7 +89,7 @@ instead of a silent edit:
89
89
  local git history to say *why* it's broken instead of leaving that to guesswork — the vault is
90
90
  usually a git repo (`db-sync` auto-commits every agent-driven edit into it, opt-in per vault, same
91
91
  precondition as that hook). Resolve the vault's filesystem path the same way `synapse.conf`
92
- already does (`OBSIDIAN_VAULT_DIR`), skip this sub-step entirely if `{vault}/.git` doesn't exist,
92
+ already does (`SYNAPSE_VAULT_DIR`), skip this sub-step entirely if `{vault}/.git` doesn't exist,
93
93
  and never let a missing/unreachable git repo block the rest of the finding — worst case it's
94
94
  reported with no history context, same as today.
95
95
  - `git -C {vault} log --all --diff-filter=A --name-only --pretty=format: -- "**/{target}.md"` — a
@@ -22,7 +22,7 @@
22
22
  ],
23
23
  "PostToolUse": [
24
24
  {
25
- "matcher": "Write|Edit|mcp__obsidian__vault_(write|patch|append|delete|move)",
25
+ "matcher": "Write|Edit|Bash|mcp__obsidian__vault_(write|patch|append|delete|move)",
26
26
  "hooks": [
27
27
  {
28
28
  "type": "command",
@@ -22,7 +22,7 @@
22
22
  ],
23
23
  "PostToolUse": [
24
24
  {
25
- "matcher": "apply_patch|mcp__obsidian__vault_(write|patch|append|delete|move)",
25
+ "matcher": "apply_patch|Bash|mcp__obsidian__vault_(write|patch|append|delete|move)",
26
26
  "hooks": [
27
27
  {
28
28
  "type": "command",
@@ -29,9 +29,9 @@ There is no flag syntax here — read intent from how the user asks:
29
29
 
30
30
  ## Prerequisites
31
31
 
32
- - Requires the `obsidian` MCP server (`mcp__obsidian__*` tools). If unreachable, say so and stop —
33
- there is no local-file fallback for this skill.
34
- - If `designs/` doesn't exist in the vault yet, `mcp__obsidian__vault_write` creates it implicitly on
32
+ - Requires the `synapse` CLI on `PATH`. If it errors (no vault configured), say so and stop —
33
+ there is no other fallback for this skill.
34
+ - If `designs/` doesn't exist in the vault yet, `synapse vault-write` creates it implicitly on
35
35
  first write — but add a `designs/` entry to the vault's index note's folder layout in the same
36
36
  action (per the Synapse Vault folder-layout rule: a new top-level folder must never fall behind the
37
37
  index).
@@ -41,7 +41,7 @@ There is no flag syntax here — read intent from how the user asks:
41
41
  Every design note is tagged with the project it belongs to — both in the title
42
42
  (`{PROJECT} — {Topic}`) and as `project: {prefix}` in frontmatter (the same short prefix the
43
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 `search_query`.
44
+ and both note kinds can be filtered together via `synapse vault-search`.
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:
@@ -66,15 +66,22 @@ unrelated contexts (e.g. personal vs. work) never end up in the same place.
66
66
  ## Handling intent
67
67
 
68
68
  **No specific signal:**
69
- 1. Check for incomplete design notes: search `designs/` (via `mcp__obsidian__vault_list` +
70
- `vault_read`, or `search_query` scoped to the `designs/` path) for notes whose `## Status` line
71
- reads `Discussing`.
69
+ 1. Check for incomplete design notes: `synapse vault-search --fields frontmatter.title` with the
70
+ query below on stdin one call, no separate read needed:
71
+
72
+ ```
73
+ {"and": [
74
+ {"glob": ["designs/*", {"var": "path"}]},
75
+ {"regexp": ["## Status\\nDiscussing", {"var": "content"}]}
76
+ ]}
77
+ ```
72
78
  2. If found: show a short state summary — title and current section — and offer to resume.
73
79
  3. If none: ask "What are we designing?"
74
80
 
75
81
  **With a topic:**
76
- 1. Search first — `mcp__obsidian__search_simple` for the topic text across `designs/` (per the
77
- Synapse Vault rule: link/reuse over duplicate). Also check for an obvious title match.
82
+ 1. Search first — `synapse vault-search-text "{topic}"` for the topic text, then filter matches to
83
+ `designs/` paths (per the Synapse Vault rule: link/reuse over duplicate). Also check for an
84
+ obvious title match.
78
85
  2. If found with `Status: Discussing` → ask "Resume this design?" or "Start fresh?"
79
86
  3. If found with `Status: Ready` → ask "Already marked Ready. Reopen to revise, or start a new note?"
80
87
  4. If found with `Status: Reference` → ask "This concluded as Reference (no implementation intended).
@@ -89,8 +96,9 @@ unrelated contexts (e.g. personal vs. work) never end up in the same place.
89
96
  4. None → "No incomplete design note found. Tell me what you'd like to design and I'll start one."
90
97
 
91
98
  **Listing design notes:**
92
- 1. `mcp__obsidian__vault_list` on `designs/`, then `vault_read` each (or a `search_query` scoped to
93
- that path) to pull title and `## Status`.
99
+ 1. `synapse vault-search --fields frontmatter.title,content` with `{"glob": ["designs/*", {"var":
100
+ "path"}]}` on stdin — every design note regardless of status, title and `## Status` line both in
101
+ the same row.
94
102
  2. None found → "No design notes yet. Tell me what you'd like to design and I'll start one."
95
103
  3. Group into **Active** (`Discussing`, `Ready`) and **Closed** (`Reference`) — active first, title
96
104
  and status in backticks, not bold.
@@ -23,7 +23,7 @@ directory.
23
23
 
24
24
  ## Prerequisites
25
25
 
26
- - Requires the `obsidian` MCP server (`mcp__obsidian__*` tools). If unreachable, say so and stop.
26
+ - Requires the `synapse` CLI on `PATH`. If it errors (no vault configured), say so and stop.
27
27
  - Must be run from inside a git repository. Synapse assumes git throughout (source hashing uses
28
28
  `git hash-object`, file enumeration uses `git ls-files`) — if `git rev-parse --show-toplevel`
29
29
  fails, stop and say this only works inside a git repo.
@@ -65,8 +65,8 @@ Every step below needs the same three facts, resolved once up front:
65
65
 
66
66
  ## Already initialized?
67
67
 
68
- Check whether `synapse/{repo}@{branch}/Index.md` exists (`mcp__obsidian__vault_list` on
69
- `synapse/{repo}@{branch}/`, or a direct `vault_read` attempt).
68
+ Check whether `synapse/{repo}@{branch}/Index.md` exists: `synapse vault-read
69
+ "synapse/{repo}@{branch}/Index.md"` and see whether it succeeds or reports "no such note".
70
70
 
71
71
  - **Doesn't exist** → this is a first-time build. Go to "First-time build" below.
72
72
  - **Exists, `remote` frontmatter matches** the resolved remote/path → this namespace already
@@ -97,7 +97,7 @@ yours and cannot be scripted because what counts as signal differs per codebase.
97
97
  (hash, digest, `## Sources` mirror, PUT), `synapse push-nodes`, `synapse build-index`,
98
98
  `synapse build-project-index`.
99
99
 
100
- **The work directory** defaults to `~/.claude/synapse-work/{repo}@{branch}/`, created on demand, and
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
103
  checkout) or at the vault (Obsidian would index a file list that runs to six figures of lines).
@@ -44,7 +44,7 @@ proceeding.
44
44
 
45
45
  ## List mode
46
46
 
47
- Use `mcp__obsidian__search_query` with the JsonLogic query `{"var": "frontmatter.task_id"}` — this returns every file that has a `task_id` set, along with that file's `task_id` value as `result`. For each match, also read the file's `status` and `title` (either via a second query `{"var": "frontmatter.status"}` / `{"var": "frontmatter.title"}`, or via `mcp__obsidian__vault_read` on the handful of matched files — whichever is fewer round-trips for the count involved).
47
+ Run `synapse vault-search --fields frontmatter.task_id,frontmatter.status,frontmatter.title` with the JsonLogic query `{"var": "frontmatter.task_id"}` on stdin one call returns every file that has a `task_id` set, each row already carrying `task_id`/`status`/`title` together, no second query or extra read needed.
48
48
 
49
49
  Categorize:
50
50
  - **Prefixed notes**: `task_id` matches `{prefix}-\d+`. Group by the distinct prefix found (whatever
@@ -61,8 +61,8 @@ Do not modify any files in list mode.
61
61
 
62
62
  The user's search text is the query — whatever they named after asking to search, quotes stripped.
63
63
 
64
- 1. Run `mcp__obsidian__search_simple` with the query — this gives full-text relevance-ranked matches with context, the closest equivalent to a title/body search.
65
- 2. If the query looks like it's targeting metadata specifically (a tag, a task ID, a status value) rather than free text, also run `mcp__obsidian__search_query` with an appropriate JsonLogic filter (e.g. `{"==": [{"var": "frontmatter.task_id"}, "proj-032"]}`).
64
+ 1. Run `synapse vault-search-text "{query}"` — this gives full-text relevance-ranked matches with context, the closest equivalent to a title/body search.
65
+ 2. If the query looks like it's targeting metadata specifically (a tag, a task ID, a status value) rather than free text, also run `synapse vault-search --fields frontmatter.title` with an appropriate JsonLogic filter on stdin (e.g. `{"==": [{"var": "frontmatter.task_id"}, "proj-032"]}`).
66
66
  3. Report matches as `{title} — {file path relative to vault root}`, deduped across both. If nothing matches, say so plainly — the caller (agent or user) needs a clear "no existing note" signal to proceed with task-mode-less creation.
67
67
 
68
68
  Do not modify any files in search mode.
@@ -72,8 +72,8 @@ Do not modify any files in search mode.
72
72
  Triggered when task mode is requested but the title doesn't match `{prefix}-\d+`.
73
73
 
74
74
  The known project/prefix pairs live in a plain local file named `synapse-projects.conf` (one
75
- `project-name=prefix` line each) — read/appended as a plain text file, not the `obsidian`
76
- MCP server, since it's outside the vault. It is deliberately **not** part of the portable
75
+ `project-name=prefix` line each) — read/appended as a plain text file, not the `vault-*` subcommands,
76
+ since it's outside the vault. It is deliberately **not** part of the portable
77
77
  Synapse package and never copied between machines, so contexts that shouldn't mix (e.g.
78
78
  personal vs. work projects) never end up in the same file. It's self-managed — this skill appends
79
79
  newly resolved pairs to it — but also plain text, so the user can add, fix, or remove a line by hand
@@ -95,8 +95,8 @@ unchanged for anyone who has never touched an XDG config directory.
95
95
  2. Check the resolved `synapse-projects.conf` for a line whose project name matches (loosely —
96
96
  case/whitespace-insensitive). If found, use that prefix directly — no need to ask.
97
97
  3. If the file doesn't have it yet, fall back to deducing from the vault itself (useful the first
98
- time this runs, or for a project whose notes predate this file): `search_simple` for the
99
- project/repo name across existing notes, and/or `search_query` on
98
+ time this runs, or for a project whose notes predate this file): `synapse vault-search-text` for
99
+ the project/repo name across existing notes, and/or `synapse vault-search` on
100
100
  `{"var": "frontmatter.task_id"}` to see which prefixes exist, then check whether any of those
101
101
  prefixed notes reference this project. If exactly one prefix confidently matches, use it.
102
102
  4. If nothing confidently matches (new project, or an ambiguous/multiple match), ask the user
@@ -105,9 +105,9 @@ unchanged for anyone who has never touched an XDG config directory.
105
105
  5. Whenever step 3 or step 4 resolves a pair not already in the conf file (including a fresh
106
106
  `project-name=prefix` line matching what was just deduced or asked), append it — so the next task
107
107
  for this project resolves from step 2 without a search or a question.
108
- 6. Once the prefix is known, find the next number: run
109
- `mcp__obsidian__search_query` with `{"var": "frontmatter.task_id"}`,
110
- filter the returned `result` values client-side for ones matching
108
+ 6. Once the prefix is known, find the next number: run `synapse vault-search --fields
109
+ frontmatter.task_id` with `{"var": "frontmatter.task_id"}` on stdin,
110
+ filter the returned values client-side for ones matching
111
111
  `{prefix}-\d+`, take the highest number found, add 1. If none exist yet
112
112
  for that prefix, start at 1.
113
113
  7. Format the new task ID **zero-padded to 3 digits** (`{prefix}-001`, `{prefix}-030`,
@@ -197,7 +197,7 @@ or supplied directly by a caller like the synapse-task-note skill):
197
197
  ## Notes
198
198
 
199
199
  ```
200
- 4. Write it with `mcp__obsidian__vault_write`. Task mode: path
200
+ 4. Write it with `synapse vault-write <path>` (content on stdin). Task mode: path
201
201
  `tasks/{project}/{filename}.md` (project resolved in "Resolving the
202
202
  project folder" above). Bare mode: path `{category}/{filename}.md`
203
203
  (category resolved above).
@@ -85,7 +85,7 @@ this skill when it does. What no longer happens is arriving here merely because
85
85
  because it is not this checkout's namespace to diff at all. Never conflate the two: a non-ancestor
86
86
  baseline on a branch-identity match still proceeds normally, per the "One mechanical fact about
87
87
  branches" section above.
88
- - The work directory (`$SYNAPSE_WORK_DIR`, default `~/.claude/synapse-work/{repo}@{branch}/`) ideally
88
+ - The work directory (`$SYNAPSE_WORK_DIR`, default `~/.cache/synapse/work/{repo}@{branch}/`) ideally
89
89
  holds the `manifest.tsv` from the original build. Without it, new paths cannot be classified as
90
90
  auto-claimable, and clustering decisions have to be re-derived — say so rather than proceeding as if
91
91
  nothing were missing. `synapse/{repo}@{branch}/_manifest.tsv` is the fallback copy.