@imunitic/synapse 0.13.5 → 0.13.7

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.
@@ -238,7 +238,7 @@ edit history here worth tracking separately.
238
238
  ## Filename
239
239
 
240
240
  `designs/{project}/{Topic}.md` — grouped one level deeper into a per-project
241
- subfolder named by the note's own `project:` frontmatter value (e.g. `designs/eon/`,
241
+ subfolder named by the note's own `project:` frontmatter value (e.g. `designs/widget/`,
242
242
  `designs/synapse/`), the same mapping `tasks/{project}/` uses. Sanitize filesystem-illegal
243
243
  characters (`/ : * ? " < > |`). No slug, no numbering — vault filenames are the title itself.
244
244
 
@@ -40,8 +40,8 @@ No arguments — always operates on the repo containing the current working dire
40
40
  Every step below needs the same three facts, resolved once up front:
41
41
 
42
42
  1. **Repo root:** `git rev-parse --show-toplevel`.
43
- 2. **Namespace key:** `{repo}@{branch}`, resolved by `synapse_namespace` in
44
- `synapse namespace` — never derived by hand here, since every component resolves it the same way
43
+ 2. **Namespace key:** `{repo}@{branch}`, resolved by `synapse namespace`
44
+ (`core.identity.namespace`) — never derived by hand here, since every component resolves it the same way
45
45
  from that one place and a second derivation is how they start disagreeing. The repo half comes
46
46
  from the *remote's* basename, not the directory: a linked worktree's directory name differs from
47
47
  its parent's, and that difference is exactly what must not matter. The branch half is
@@ -51,8 +51,8 @@ Every step below needs the same three facts, resolved once up front:
51
51
  and `stale` describing a single tree, and it means a branch switch leaves the old graph intact
52
52
  rather than invalidating it wholesale.
53
53
 
54
- **On a detached HEAD, stop.** There is no branch, so there is no key — `synapse_namespace` exits
55
- 1 and says so. Do not invent one, and do not fall back to the directory name: every detached
54
+ **On a detached HEAD, stop.** There is no branch, so there is no key — `synapse namespace` exits
55
+ 1 with `core.identity.detached_message`. Do not invent one, and do not fall back to the directory name: every detached
56
56
  checkout everywhere would collide on the same value. Tell the user to check out a branch first.
57
57
 
58
58
  Distinct from the short task-prefix scheme (`project-name=prefix`) used by
@@ -32,7 +32,7 @@ Categorize:
32
32
  - **Prefixed notes**: `task_id` matches `{prefix}-\d+`. Group by the distinct prefix found (whatever
33
33
  prefixes actually appear — don't assume a fixed set). Within each prefix, split further into:
34
34
  - **Open**: `status` is `TODO`, `IN-PROGRESS`, or `REVIEW` (or missing — treat as open)
35
- - **Closed**: `status` is `DONE`, `CANCELED`, or `CANCELLED`
35
+ - **Closed**: `status` is `DONE` or `CANCELED`
36
36
  - **Other notes**: no `task_id`, or one that doesn't match `{prefix}-\d+`
37
37
 
38
38
  Sort each prefix group's notes numerically by task id (`{prefix}-9` before `{prefix}-10`); sort other notes alphabetically by title. Report one section per prefix found — "{prefix} notes — open", "{prefix} notes — closed" — plus "Other notes", each line as `{task-id or filename} — {title} [{status}]`. Omit a section header if it has zero entries. End with a total count.
@@ -32,7 +32,7 @@ No arguments — always operates on the repo and branch containing the current w
32
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
- requirement `/synapse-init` has, since `synapse_namespace` needs a branch to key on.
35
+ requirement `/synapse-init` has, since `synapse namespace` needs a branch to key on.
36
36
 
37
37
  ## Procedure
38
38
 
@@ -35,7 +35,7 @@ Use those instead of reinventing a parallel view.
35
35
  nothing to compile. Reopen it with `/synapse-design-note \"{topic}\"` and mark it Ready if that's
36
36
  changed."
37
37
  - A task note already exists for this design (check the design note's `> Compiled task:` annotation,
38
- or `search_query` for a `tasks/` note linking to it) → show its current state (title, `status:`,
38
+ or `synapse vault-search-text` for a `tasks/` note linking to it) → show its current state (title, `status:`,
39
39
  checked/total) and ask: view it, or recompile (only on explicit confirmation — recompiling rewrites
40
40
  the checklist, so any progress on items that no longer exist is lost).
41
41
 
@@ -83,8 +83,9 @@ just two fields (`title`, `created` — see `synapse-note`'s bare-mode format),
83
83
  guessing:
84
84
 
85
85
  - Missing `title` → the filename with its `.md` extension stripped.
86
- - Missing `created` → `stat.ctime`, formatted `YYYY-MM-DD HH:MM` to match every other note's
87
- convention.
86
+ - Missing `created` → `stat.ctime`, formatted as RFC3339 with a numeric offset (`synapse now`'s
87
+ own shape) to match every other note's real `created`/`updated` convention — not `built_at`'s
88
+ coarser `YYYY-MM-DD HH:MM`, which is graph-node-only.
88
89
 
89
90
  Apply with `synapse frontmatter set <path> <key> <value>` (or `vault-patch --frontmatter`, which
90
91
  delegates to the same byte-preserving mechanism) — either writes exactly this one field and leaves
@@ -154,7 +155,7 @@ proposal, for the vault owner to act on.
154
155
  ## Step 6: Compose the proposal
155
156
 
156
157
  One note, `inbox/Vault tidy — {YYYY-MM-DD}.md` (fetch machine local time, never infer it), written
157
- via `vault_write` (creates `inbox/` automatically if it doesn't exist yet; if `inbox/` isn't already
158
+ via `vault-write` (creates `inbox/` automatically if it doesn't exist yet; if `inbox/` isn't already
158
159
  in `Index.md`'s folder list, add it there in the same pass, matching the folder-layout rule every
159
160
  other command that can create a top-level folder already follows). Two sections:
160
161
 
@@ -231,6 +231,10 @@ already follows above, just additive instead of pruned. Named `References` rathe
231
231
  `## Links` for something unrelated (source files, typed relations) in that other kind of note
232
232
  sharing the same vault.
233
233
 
234
+ Any string scalar that is all digits (e.g. a numeric-looking title) must be quoted: an
235
+ unquoted all-digit value is parsed as an integer, which fails a `type: string` schema
236
+ field. `title`, `project`, `note_id`, and both timestamps are quoted above.
237
+
234
238
  Resolve tags through the `synapse-vault` skill's configured vocabulary procedure. Fetch machine
235
239
  local time once (`synapse now`) — never infer it — and use the exact same value for `created` and
236
240
  `updated`.
@@ -241,7 +245,7 @@ edit history here worth tracking separately.
241
245
  ## Filename
242
246
 
243
247
  `designs/{project}/{Topic}.md` — grouped one level deeper into a per-project
244
- subfolder named by the note's own `project:` frontmatter value (e.g. `designs/eon/`,
248
+ subfolder named by the note's own `project:` frontmatter value (e.g. `designs/widget/`,
245
249
  `designs/synapse/`), the same mapping tasks use. Sanitize filesystem-illegal
246
250
  characters (`/ : * ? " < > |`). No slug, no numbering — vault filenames are the title itself.
247
251
 
@@ -250,6 +250,11 @@ or supplied directly by a caller like the synapse-task-note skill):
250
250
 
251
251
  {constraints or context}
252
252
  ```
253
+
254
+ Quote every scalar string value. In particular, a value that is all digits
255
+ (a numeric-looking `title`, or any future numeric id) must be quoted — an
256
+ unquoted all-digit value is parsed as an integer and fails a `type: string`
257
+ schema field.
253
258
  5. Write it with `synapse vault-write <path>` (content on stdin). Task mode: path
254
259
  `tasks/{project}/{filename}.md` (project resolved in "Resolving the
255
260
  project folder" above). Bare mode: path `{category}/{filename}.md`
@@ -155,7 +155,7 @@ proposal, for the vault owner to act on.
155
155
  ## Step 6: Compose the proposal
156
156
 
157
157
  One note, `inbox/Vault tidy — {YYYY-MM-DD}.md` (fetch machine local time, never infer it), written
158
- via `vault_write` (creates `inbox/` automatically if it doesn't exist yet; if `inbox/` isn't already
158
+ via `vault-write` (creates `inbox/` automatically if it doesn't exist yet; if `inbox/` isn't already
159
159
  in the index note's folder list, add it there in the same pass, matching the folder-layout rule every
160
160
  other skill that can create a top-level folder already follows). Two sections:
161
161
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@imunitic/synapse",
3
- "version": "0.13.5",
3
+ "version": "0.13.7",
4
4
  "description": "Memory for Claude Code, Codex CLI, and OpenCode: a durable markdown vault plus a per-repo code graph.",
5
5
  "repository": {
6
6
  "type": "git",
@@ -23,9 +23,9 @@
23
23
  "*.conf.template"
24
24
  ],
25
25
  "optionalDependencies": {
26
- "@imunitic/synapse-darwin-arm64": "0.13.5",
27
- "@imunitic/synapse-linux-x64": "0.13.5",
28
- "@imunitic/synapse-linux-arm64": "0.13.5"
26
+ "@imunitic/synapse-darwin-arm64": "0.13.7",
27
+ "@imunitic/synapse-linux-x64": "0.13.7",
28
+ "@imunitic/synapse-linux-arm64": "0.13.7"
29
29
  },
30
30
  "license": "SEE LICENSE IN LICENSE"
31
31
  }
@@ -14,7 +14,7 @@ speculatively.
14
14
 
15
15
  Whenever a `synapse/{project}/{Node}.md` file is about to be read **for its content to actually be
16
16
  used** (orienting on a subsystem, answering a question about it, deciding where to make a change)
17
- — not for a `vault_list`/title-only skim. Run this procedure *before* trusting what comes back from
17
+ — not for a `vault-list`/title-only skim. Run this procedure *before* trusting what comes back from
18
18
  that read. This is the one Synapse mechanism that isn't a hook: a hook is compiled code with no
19
19
  reasoning, and classifying whether a file "fits" a node is exactly the kind of judgment call that
20
20
  needs one.
@@ -133,7 +133,7 @@ needs one.
133
133
 
134
134
  It replaces only the generated region and re-emits everything after the closing fence verbatim,
135
135
  which is what makes the `## Notes` guarantee enforceable rather than a promise.
136
- - **Never hand-write the frontmatter**, with `vault_patch` at `targetType: frontmatter` or
136
+ - **Never hand-write the frontmatter**, with `vault-patch --frontmatter <key>` or
137
137
  otherwise. `--frontmatter` only ever writes a single scalar value, so it can't represent
138
138
  `sources:`/`grounded_in:` at all, and enumerating the rest of a node's fields by hand one call
139
139
  at a time is how `summary` and `commit` get silently dropped — which then breaks the next
@@ -195,7 +195,7 @@ needs one.
195
195
  - Never treat the script's exit 1 as a clean result. It means the check could not run.
196
196
  - Never regenerate a node that neither the script nor its `stale:` flag named — regeneration is real
197
197
  cost, reserved for actual staleness.
198
- - Never `vault_read` a hub node just to read its summary. Offset past the frontmatter (step 3).
198
+ - Never `vault-read` a hub node just to read its summary. Offset past the frontmatter (step 3).
199
199
  - Never silently fold a regeneration or an unassigned-file attachment into normal output — both
200
200
  get an explicit, visible announcement line.
201
201
  - `## Notes` content is sacrosanct across regeneration — if a rewrite would touch it, that's a bug
@@ -9,11 +9,9 @@ Loaded wherever a *batch* of nodes needs prose written, not a single lazy regene
9
9
  is the `synapse-node` skill's job, one node, triggered by a stale read). Today's caller is
10
10
  `/synapse-init`'s node-authoring step. `/synapse-rebuild-full` inherits this for free — it
11
11
  delegates to `/synapse-init`'s procedure by reference rather than repeating it.
12
- `/synapse-rebuild-diff`'s *re-orient* class is a natural second caller (see the design's own
13
- Open Questions and the vault's `inbox/wire synapse-rebuild-diff's re-orient class onto the
14
- parallel-authoring skill` note) but is not wired to this skill yet — it still
15
- gathers its facts ad hoc rather than through `rank --lists`/`link-graph`, and needs that fixed
16
- first.
12
+ `/synapse-rebuild-diff`'s *re-orient* class is a natural second caller but is not wired to this
13
+ skill yet — it still gathers its facts ad hoc rather than through `rank --lists`/`link-graph`,
14
+ and needs that fixed first.
17
15
 
18
16
  This skill owns two things: **deciding how many authors run at once**, and **the standing
19
17
  contract every author works under**, whichever pool size is in play. Which nodes need
@@ -132,23 +130,22 @@ flowing text.
132
130
 
133
131
  Same model as the orchestrating session, no override — matches the constraint that "a
134
132
  parallel author produces exactly what a sequential one does," and keeps the quality
135
- comparison in the design's own checklist item to one variable (isolation/concurrency) rather
136
- than two (that, plus a cheaper model).
133
+ comparison to one variable (isolation/concurrency) rather than two (that, plus a cheaper model).
137
134
 
138
135
  **Why this is spelled out explicitly rather than assumed inherited:** a prior pooled run shipped
139
- hard-wrapped nodes despite the vault's no-hard-wrap rule living in global `CLAUDE.md`
140
- instructions — evidently not reliably carried into a fresh subagent's behavior on its own.
141
- Loading `synapse-node-format` does not cover it either, since that skill is about the node's
142
- structure, not the vault's prose-formatting convention. State it here, every time, rather than
143
- assuming it travels for free.
136
+ hard-wrapped nodes despite the vault's own no-hard-wrap convention (every paragraph is one
137
+ continuous line in the source, letting the viewer soft-wrap it) — evidently not reliably carried
138
+ into a fresh subagent's behavior on its own. Loading `synapse-node-format` does not cover it
139
+ either, since that skill is about the node's structure, not the vault's prose-formatting
140
+ convention. State it here, every time, rather than assuming it travels for free.
144
141
 
145
142
  ### 3d. Verify on completion, retry once, then fall back
146
143
 
147
144
  When a completion notification arrives, read `b-NN.md` yourself — this is a check you read the
148
- file for, same as the section check next to it, not a shell one-liner (this codebase's own
149
- frontmatter reader deliberately avoids `grep`/`sed`/`awk` for exactly this field, per
150
- `core/query.zig`'s docstring — a hand-rolled pattern here would drift from it the same way the
151
- gap this section exists to close first happened). Confirm the file exists, opens with
145
+ file for, same as the section check next to it, not a shell one-liner (`core/query.zig` is this
146
+ codebase's own tested, compiled frontmatter reader — a fresh hand-rolled `grep`/`sed`/`awk`
147
+ pattern here would drift from it the same way the gap this section exists to close first
148
+ happened). Confirm the file exists, opens with
152
149
  frontmatter carrying a non-empty `summary:` field (`synapse-node-format`'s own contract — see
153
150
  its "Each `b-NN.md` opens with its own one-line summary in frontmatter" line), and has
154
151
  `## Summary`, `## Crux`, and `## Links` sections. Pass → dispatch the next queued node (§3b) and
@@ -177,9 +174,8 @@ Not a synonym for §2. It still bundles a brief, dispatches to an isolated subag
177
174
  and retries-then-falls-back — only the concurrency is 1. Useful on its own terms: it isolates
178
175
  whether a quality difference against the sequential baseline comes from *isolation* (no
179
176
  author sees another's output or memory — present even at pool 1) or from *concurrency*
180
- itself (only present at pool ≥ 2). Reach for it specifically when running the design's
181
- still-open "compare prose quality against a sequential build" checklist item, before
182
- committing to a higher pool size.
177
+ itself (only present at pool ≥ 2). Reach for it specifically when comparing prose quality
178
+ against a sequential build, before committing to a higher pool size.
183
179
 
184
180
  ## Guardrails
185
181
 
@@ -188,13 +184,12 @@ committing to a higher pool size.
188
184
  read-only during it — this is what removes the concurrent-writer problem rather than merely
189
185
  managing it.
190
186
  - **No author reads another node's brief or body.** Overlap in *source* reads (two nodes'
191
- file lists sharing a path) is expected and accepted — see the design's Open Questions — but
192
- an author's own inputs are its brief and nothing else.
187
+ file lists sharing a path) is expected and accepted, but an author's own inputs are its
188
+ brief and nothing else.
193
189
  - **Never grow the pool mid-run.** The size is resolved once at the start (§1); do not read
194
190
  `synapse.conf` again partway through a build.
195
191
  - **A retry gets the same brief, not a rewritten one.** If the brief itself was the problem,
196
192
  fixing it is a §3a-level fix (regenerate every brief and restart), not something to
197
193
  improvise per-node inside the retry.
198
194
  - **`part_of` is never computed, at any pool size.** It is containment, not reference, and
199
- deriving it from directory nesting would turn a folder layout into a claim about concepts —
200
- the same reasoning the design's own Alternatives section already rejected this on.
195
+ deriving it from directory nesting would turn a folder layout into a claim about concepts.
@@ -60,6 +60,8 @@ to orient someone already inside. A node without one is an error, not a default.
60
60
  a single-key lookup never has to scan past it. `graph-node/v1`'s schema enforces this order
61
61
  directly (`field_order: relative`); this document and `synapse write-node`'s own emission order
62
62
  agree with it, not the other way around.
63
+ - **`branch`:** the branch half of the namespace key (`synapse namespace --branch`), filled in by
64
+ the writer — never hand-authored.
63
65
  - **`sources_digest`:** `sha256` over the sorted `path:hash` lines of `sources` (see "Computing
64
66
  `sources_digest`" below). Lets a staleness check answer "has this node changed" by reading one
65
67
  field instead of every hash.
@@ -157,6 +159,7 @@ schema: graph-node/v1
157
159
  title: "World — entity/component/resource core"
158
160
  node_type: synapse-node
159
161
  project: acme
162
+ branch: main
160
163
  sources_digest: <sha256 over the sorted "path:hash" lines>
161
164
  stale: false
162
165
  built_at: "<now>"
@@ -88,14 +88,14 @@ resolve the specific symbol-level question:
88
88
  ## Guardrails
89
89
 
90
90
  - **Never grep the whole repo before checking `synapse/{project}/Index.md`**, unless this repo has
91
- no Synapse namespace at all (`vault_list` on `synapse/{project}/` comes back empty). Before
91
+ no Synapse namespace at all (`vault-list` on `synapse/{project}/` comes back empty). Before
92
92
  concluding there's nothing to consult, check whether the task actually concerns a *different*
93
93
  checkout — `synapse query --namespace <repo>@<branch> body "{Node}"` reaches that repo's graph
94
94
  without switching directories or checking it out. Only when no namespace anywhere covers the task
95
95
  is there truly nothing to consult; say so and proceed normally.
96
96
  - **Never treat a node's summary as ground truth for a symbol-level claim** it wasn't built to make
97
97
  precisely — see "When a node isn't enough" above.
98
- - **Never `vault_read` a node just to read its prose — including a node in another checkout's
98
+ - **Never `vault-read` a node just to read its prose — including a node in another checkout's
99
99
  namespace.** That pulls the full frontmatter, which can run to megabytes on a hub node. Use
100
100
  `synapse query body` (add `--namespace <repo>@<branch>` for a graph outside this checkout) — see
101
101
  the cost note above.
@@ -34,8 +34,11 @@ synapse vault-read <path> the whole note -- no partial/targeted
34
34
  ```
35
35
 
36
36
  `vault-search`'s JsonLogic filter and `--fields` projection both stop at frontmatter/tags/content/
37
- path -- there is no `links`/`backlinks`/`unresolvedLinks` equivalent (no whole-vault wikilink index
38
- exists yet), and `vault-read` always returns the full body, never one section on its own -- request
37
+ path -- links aren't filterable through search itself, though a dedicated whole-vault wikilink
38
+ index does exist as its own set of subcommands (`vault-backlinks`/`vault-links`/`vault-unresolved`/
39
+ `vault-orphans`/`vault-deadends`/`vault-ambiguous`/`vault-rename`), reach for one of those directly
40
+ instead of trying to express a link query through `vault-search`. `vault-read` always returns the
41
+ full body, never one section on its own -- request
39
42
  exactly what you need with `--fields` instead of over-fetching, and pull a specific section out of
40
43
  `vault-read`'s output locally when that's all you actually need.
41
44
 
@@ -110,15 +113,15 @@ Every new note is created through an authoring command, never by freeforming a f
110
113
  - `/synapse-note` (bare mode) creates plain notes in any category -- `research/`,
111
114
  `scratchpad/`, `inbox/`, anything that is not a tracked task or a design note. It mints the
112
115
  frontmatter (`schema`, `title`, `note_id`, `created`, `updated`, `tags`) to the note schema's
113
- contract, including full-timestamp format.
116
+ contract, sampling `created`/`updated` from `synapse now`.
114
117
  - `/synapse-note --task` creates tracked task notes under `tasks/{project}/`.
115
118
  - `/synapse-design-note` and `/synapse-task-note` handle design discussions and compiled tasks --
116
119
  both delegate the file-minting mechanics to `/synapse-note` internally.
117
120
 
118
121
  `vault-write` is for *editing existing notes*, or the rare read-modify-write round trip. If a
119
122
  direct creation is ever genuinely unavoidable, follow bare mode's frontmatter contract exactly
120
- (`schema`/`title`/`note_id`/`created`/`updated`/`tags`, full `%Y-%m-%d %H:%M:%S %Z` timestamps)
121
- rather than improvising a shape.
123
+ (`schema`/`title`/`note_id`/`created`/`updated`/`tags`, with `created`/`updated` taken from
124
+ `synapse now` -- never hand-typed) rather than improvising a shape.
122
125
 
123
126
  Schemas are opt-in by declaration: a note whose frontmatter declares `schema:` is held to that
124
127
  schema's contract on every `vault-write`/`vault-patch`; a note without the field is never