grounder 0.4.0 → 0.6.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.
Files changed (221) hide show
  1. package/README.md +150 -271
  2. package/dist/agents/claude.d.ts +4 -4
  3. package/dist/agents/claude.d.ts.map +1 -1
  4. package/dist/agents/claude.js +158 -178
  5. package/dist/agents/claude.js.map +1 -1
  6. package/dist/agents/cursor.d.ts +3 -3
  7. package/dist/agents/cursor.d.ts.map +1 -1
  8. package/dist/agents/cursor.js +97 -143
  9. package/dist/agents/cursor.js.map +1 -1
  10. package/dist/agents/home-skills.d.ts +46 -0
  11. package/dist/agents/home-skills.d.ts.map +1 -0
  12. package/dist/agents/home-skills.js +83 -0
  13. package/dist/agents/home-skills.js.map +1 -0
  14. package/dist/agents/hook-fragment.d.ts +52 -0
  15. package/dist/agents/hook-fragment.d.ts.map +1 -0
  16. package/dist/agents/hook-fragment.js +76 -0
  17. package/dist/agents/hook-fragment.js.map +1 -0
  18. package/dist/agents/hook-install.d.ts +62 -0
  19. package/dist/agents/hook-install.d.ts.map +1 -0
  20. package/dist/agents/hook-install.js +74 -0
  21. package/dist/agents/hook-install.js.map +1 -0
  22. package/dist/agents/hook-runtime.d.ts +80 -13
  23. package/dist/agents/hook-runtime.d.ts.map +1 -1
  24. package/dist/agents/hook-runtime.js +278 -74
  25. package/dist/agents/hook-runtime.js.map +1 -1
  26. package/dist/agents/index.d.ts +8 -14
  27. package/dist/agents/index.d.ts.map +1 -1
  28. package/dist/agents/index.js +13 -19
  29. package/dist/agents/index.js.map +1 -1
  30. package/dist/agents/types.d.ts +56 -16
  31. package/dist/agents/types.d.ts.map +1 -1
  32. package/dist/cli.js +15 -10
  33. package/dist/cli.js.map +1 -1
  34. package/dist/commands/apply.d.ts +69 -0
  35. package/dist/commands/apply.d.ts.map +1 -0
  36. package/dist/commands/apply.js +238 -0
  37. package/dist/commands/apply.js.map +1 -0
  38. package/dist/commands/doctor.d.ts.map +1 -1
  39. package/dist/commands/doctor.js +197 -101
  40. package/dist/commands/doctor.js.map +1 -1
  41. package/dist/commands/handoff/list.d.ts +23 -13
  42. package/dist/commands/handoff/list.d.ts.map +1 -1
  43. package/dist/commands/handoff/list.js +28 -16
  44. package/dist/commands/handoff/list.js.map +1 -1
  45. package/dist/commands/handoff/peek.d.ts +1 -1
  46. package/dist/commands/handoff/peek.d.ts.map +1 -1
  47. package/dist/commands/handoff/peek.js +28 -12
  48. package/dist/commands/handoff/peek.js.map +1 -1
  49. package/dist/commands/handoff.d.ts +2 -0
  50. package/dist/commands/handoff.d.ts.map +1 -1
  51. package/dist/commands/handoff.js +10 -1
  52. package/dist/commands/handoff.js.map +1 -1
  53. package/dist/commands/install-drift.d.ts +34 -0
  54. package/dist/commands/install-drift.d.ts.map +1 -0
  55. package/dist/commands/install-drift.js +72 -0
  56. package/dist/commands/install-drift.js.map +1 -0
  57. package/dist/commands/link.d.ts +12 -0
  58. package/dist/commands/link.d.ts.map +1 -0
  59. package/dist/commands/{repo/init.js → link.js} +35 -27
  60. package/dist/commands/link.js.map +1 -0
  61. package/dist/commands/migrate.d.ts +11 -3
  62. package/dist/commands/migrate.d.ts.map +1 -1
  63. package/dist/commands/migrate.js +66 -34
  64. package/dist/commands/migrate.js.map +1 -1
  65. package/dist/commands/note/list.d.ts +17 -9
  66. package/dist/commands/note/list.d.ts.map +1 -1
  67. package/dist/commands/note/list.js +19 -14
  68. package/dist/commands/note/list.js.map +1 -1
  69. package/dist/commands/note.d.ts +2 -0
  70. package/dist/commands/note.d.ts.map +1 -1
  71. package/dist/commands/note.js +10 -1
  72. package/dist/commands/note.js.map +1 -1
  73. package/dist/commands/output.d.ts +22 -2
  74. package/dist/commands/output.d.ts.map +1 -1
  75. package/dist/commands/output.js +18 -6
  76. package/dist/commands/output.js.map +1 -1
  77. package/dist/commands/overview.d.ts +33 -0
  78. package/dist/commands/overview.d.ts.map +1 -0
  79. package/dist/commands/overview.js +150 -0
  80. package/dist/commands/overview.js.map +1 -0
  81. package/dist/commands/plan/list.d.ts +20 -12
  82. package/dist/commands/plan/list.d.ts.map +1 -1
  83. package/dist/commands/plan/list.js +22 -17
  84. package/dist/commands/plan/list.js.map +1 -1
  85. package/dist/commands/plan.d.ts +2 -0
  86. package/dist/commands/plan.d.ts.map +1 -1
  87. package/dist/commands/plan.js +12 -2
  88. package/dist/commands/plan.js.map +1 -1
  89. package/dist/commands/render-artifact-table.d.ts +85 -0
  90. package/dist/commands/render-artifact-table.d.ts.map +1 -0
  91. package/dist/commands/render-artifact-table.js +232 -0
  92. package/dist/commands/render-artifact-table.js.map +1 -0
  93. package/dist/commands/require-linked.js +2 -2
  94. package/dist/commands/require-linked.js.map +1 -1
  95. package/dist/commands/search.d.ts +23 -0
  96. package/dist/commands/search.d.ts.map +1 -0
  97. package/dist/commands/search.js +288 -0
  98. package/dist/commands/search.js.map +1 -0
  99. package/dist/commands/{vault/init.d.ts → setup.d.ts} +5 -4
  100. package/dist/commands/setup.d.ts.map +1 -0
  101. package/dist/commands/setup.js +210 -0
  102. package/dist/commands/setup.js.map +1 -0
  103. package/dist/commands/status.d.ts +7 -0
  104. package/dist/commands/status.d.ts.map +1 -1
  105. package/dist/commands/status.js +273 -83
  106. package/dist/commands/status.js.map +1 -1
  107. package/dist/commands/upgrade-banner.d.ts +2 -2
  108. package/dist/commands/upgrade-banner.js +2 -2
  109. package/dist/connector/home.d.ts +12 -0
  110. package/dist/connector/home.d.ts.map +1 -1
  111. package/dist/connector/home.js +26 -2
  112. package/dist/connector/home.js.map +1 -1
  113. package/dist/connector/ledger-migrations.d.ts +55 -0
  114. package/dist/connector/ledger-migrations.d.ts.map +1 -0
  115. package/dist/connector/ledger-migrations.js +94 -0
  116. package/dist/connector/ledger-migrations.js.map +1 -0
  117. package/dist/connector/state.d.ts +97 -60
  118. package/dist/connector/state.d.ts.map +1 -1
  119. package/dist/connector/state.js +165 -107
  120. package/dist/connector/state.js.map +1 -1
  121. package/dist/connector/vault.d.ts +2 -0
  122. package/dist/connector/vault.d.ts.map +1 -1
  123. package/dist/connector/vault.js +6 -1
  124. package/dist/connector/vault.js.map +1 -1
  125. package/dist/help.d.ts +3 -3
  126. package/dist/help.d.ts.map +1 -1
  127. package/dist/help.js +97 -56
  128. package/dist/help.js.map +1 -1
  129. package/dist/reconcile/apply.d.ts +31 -0
  130. package/dist/reconcile/apply.d.ts.map +1 -0
  131. package/dist/reconcile/apply.js +97 -0
  132. package/dist/reconcile/apply.js.map +1 -0
  133. package/dist/reconcile/core.d.ts +82 -0
  134. package/dist/reconcile/core.d.ts.map +1 -0
  135. package/dist/reconcile/core.js +163 -0
  136. package/dist/reconcile/core.js.map +1 -0
  137. package/dist/reconcile/disk.d.ts +13 -0
  138. package/dist/reconcile/disk.d.ts.map +1 -0
  139. package/dist/reconcile/disk.js +28 -0
  140. package/dist/reconcile/disk.js.map +1 -0
  141. package/dist/util/frontmatter.d.ts +9 -7
  142. package/dist/util/frontmatter.d.ts.map +1 -1
  143. package/dist/util/frontmatter.js +29 -4
  144. package/dist/util/frontmatter.js.map +1 -1
  145. package/dist/util/fs.d.ts +14 -0
  146. package/dist/util/fs.d.ts.map +1 -1
  147. package/dist/util/fs.js +27 -1
  148. package/dist/util/fs.js.map +1 -1
  149. package/dist/util/merge-json.d.ts +13 -2
  150. package/dist/util/merge-json.d.ts.map +1 -1
  151. package/dist/util/merge-json.js +24 -10
  152. package/dist/util/merge-json.js.map +1 -1
  153. package/dist/util/path.d.ts +23 -0
  154. package/dist/util/path.d.ts.map +1 -1
  155. package/dist/util/path.js +39 -0
  156. package/dist/util/path.js.map +1 -1
  157. package/dist/vault/list-handoffs.d.ts +14 -2
  158. package/dist/vault/list-handoffs.d.ts.map +1 -1
  159. package/dist/vault/list-handoffs.js +40 -23
  160. package/dist/vault/list-handoffs.js.map +1 -1
  161. package/dist/vault/list-markdown.d.ts +8 -0
  162. package/dist/vault/list-markdown.d.ts.map +1 -0
  163. package/dist/vault/list-markdown.js +35 -0
  164. package/dist/vault/list-markdown.js.map +1 -0
  165. package/dist/vault/list-notes.d.ts +15 -6
  166. package/dist/vault/list-notes.d.ts.map +1 -1
  167. package/dist/vault/list-notes.js +23 -27
  168. package/dist/vault/list-notes.js.map +1 -1
  169. package/dist/vault/list-plans.d.ts +12 -3
  170. package/dist/vault/list-plans.d.ts.map +1 -1
  171. package/dist/vault/list-plans.js +20 -24
  172. package/dist/vault/list-plans.js.map +1 -1
  173. package/dist/vault/search.d.ts +55 -0
  174. package/dist/vault/search.d.ts.map +1 -0
  175. package/dist/vault/search.js +432 -0
  176. package/dist/vault/search.js.map +1 -0
  177. package/dist/vault/write-handoff.d.ts +2 -0
  178. package/dist/vault/write-handoff.d.ts.map +1 -1
  179. package/dist/vault/write-handoff.js +5 -0
  180. package/dist/vault/write-handoff.js.map +1 -1
  181. package/dist/vault/write-note.d.ts +2 -0
  182. package/dist/vault/write-note.d.ts.map +1 -1
  183. package/dist/vault/write-note.js +9 -1
  184. package/dist/vault/write-note.js.map +1 -1
  185. package/dist/vault/write-plan.d.ts +4 -0
  186. package/dist/vault/write-plan.d.ts.map +1 -1
  187. package/dist/vault/write-plan.js +14 -1
  188. package/dist/vault/write-plan.js.map +1 -1
  189. package/package.json +11 -4
  190. package/templates/agents/claude/skills/grounder-handoff/SKILL.md +73 -0
  191. package/templates/agents/claude/{commands/grounder-note.md → skills/grounder-note/SKILL.md} +12 -2
  192. package/templates/agents/claude/skills/grounder-overview/SKILL.md +21 -0
  193. package/templates/agents/claude/{commands/grounder-plan.md → skills/grounder-plan/SKILL.md} +13 -5
  194. package/templates/agents/claude/skills/grounder-recall/SKILL.md +34 -0
  195. package/templates/agents/claude/skills/grounder-search/SKILL.md +152 -0
  196. package/templates/agents/cursor/skills/grounder-handoff/SKILL.md +73 -0
  197. package/templates/agents/cursor/{commands/grounder-note.md → skills/grounder-note/SKILL.md} +12 -2
  198. package/templates/agents/cursor/skills/grounder-overview/SKILL.md +21 -0
  199. package/templates/agents/cursor/{commands/grounder-plan.md → skills/grounder-plan/SKILL.md} +13 -5
  200. package/templates/agents/cursor/skills/grounder-recall/SKILL.md +34 -0
  201. package/templates/agents/cursor/skills/grounder-search/SKILL.md +152 -0
  202. package/templates/vault/plan.md +1 -1
  203. package/templates/vault/session-handoff.md +2 -1
  204. package/dist/agents/install-command.d.ts +0 -35
  205. package/dist/agents/install-command.d.ts.map +0 -1
  206. package/dist/agents/install-command.js +0 -65
  207. package/dist/agents/install-command.js.map +0 -1
  208. package/dist/commands/apply-agent-installs.d.ts +0 -34
  209. package/dist/commands/apply-agent-installs.d.ts.map +0 -1
  210. package/dist/commands/apply-agent-installs.js +0 -137
  211. package/dist/commands/apply-agent-installs.js.map +0 -1
  212. package/dist/commands/repo/init.d.ts +0 -11
  213. package/dist/commands/repo/init.d.ts.map +0 -1
  214. package/dist/commands/repo/init.js.map +0 -1
  215. package/dist/commands/vault/init.d.ts.map +0 -1
  216. package/dist/commands/vault/init.js +0 -90
  217. package/dist/commands/vault/init.js.map +0 -1
  218. package/templates/agents/claude/commands/grounder-task-handoff.md +0 -54
  219. package/templates/agents/claude/commands/grounder-task.md +0 -22
  220. package/templates/agents/cursor/commands/grounder-task-handoff.md +0 -54
  221. package/templates/agents/cursor/commands/grounder-task.md +0 -22
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "grounder",
3
- "version": "0.4.0",
4
- "description": "Markdown-native memory for Cursor and Claude Code — session handoffs and plans in a vault you own",
3
+ "version": "0.6.0",
4
+ "description": "Connect projects to an Obsidian vault (or any markdown folder) for AI agent memory — session handoffs, plans, and notes in files you own",
5
5
  "type": "module",
6
6
  "bin": {
7
7
  "grounder": "./dist/cli.js"
@@ -11,7 +11,7 @@
11
11
  "templates"
12
12
  ],
13
13
  "engines": {
14
- "node": ">=18"
14
+ "node": ">=22"
15
15
  },
16
16
  "keywords": [
17
17
  "obsidian",
@@ -20,7 +20,14 @@
20
20
  "handoff",
21
21
  "developer-tools",
22
22
  "ai",
23
- "cli"
23
+ "cli",
24
+ "agent-memory",
25
+ "local-first",
26
+ "vault",
27
+ "session-handoff",
28
+ "context-management",
29
+ "second-brain",
30
+ "pkm"
24
31
  ],
25
32
  "license": "MIT",
26
33
  "repository": {
@@ -0,0 +1,73 @@
1
+ ---
2
+ name: grounder-handoff
3
+ description: Write a session handoff checkpoint to the markdown vault for this project.
4
+ disable-model-invocation: true
5
+ ---
6
+
7
+ Write a session handoff checkpoint to the markdown vault for this project.
8
+
9
+ **Mode lock — write only.**
10
+ - Never hydrate or start work, regardless of typed extra text (resume / load / hydrate / `/grounder-recall`) — never run `handoff list` to pick or overwrite an existing file. The plain write form of `handoff` (a body argument, no `list`) stays required — that's this command's whole job; always write a **new** file.
11
+ - Typed extra text is only what the user wrote after `/grounder-handoff` in the chat line — empty or bare command means no extra instruction; ignore any sibling verb that shows up only in a leftover command-payload wrapper. Otherwise, extra text is body guidance for this handoff.
12
+ - `#N` here means leftover Next item N from *this* session, not file N in a listing.
13
+ - If the typed text does ask to resume/load/hydrate/`/grounder-recall`, still do this command's job, then add one sentence: saved — run `/grounder-recall` in a new chat to resume. Skip that sentence for "continue in a new session" wording (that's the point of saving) or when the mention only appears in stale payload text.
14
+
15
+ Summarize the session into a structured handoff — not a chat transcript.
16
+ Do not dump tool traces, full conversation, or false starts.
17
+
18
+ Build a markdown body with these sections (lean; roughly half a screen to one screen):
19
+
20
+ ```markdown
21
+ # Handoff: <short label>
22
+
23
+ ## Done
24
+ - …
25
+
26
+ ## Next
27
+ 1. … # ordered; most important section for resume — required
28
+ 2. …
29
+
30
+ ## Blockers
31
+ - None | …
32
+
33
+ ## Decisions
34
+ - … # include rejected alternatives / pitfalls when useful
35
+
36
+ ## Files
37
+ - path/to/relevant.ts
38
+ - path/to/plan.md (Status section updated) # if a plan/ticket drove the session, link it here — see Rules
39
+ ```
40
+
41
+ Rules:
42
+ - **Nothing done yet is not a reason to skip writing** — a fresh or empty session still gets a handoff (`Done: None`, `Next: 1. n/a` or one reasonable next step); never reply with a menu of options instead of running the write.
43
+ - **Next is mandatory and ordered** — if only one section is read, this is it
44
+ - Empty sections are OK (`Blockers: None` beats omission)
45
+ - Few concrete file paths, not an exhaustive diff
46
+ - If a vault plan (`grounder plan`) or ticket drove the session, list it first in `## Files` with a short note on what changed — e.g. `path/to/plan.md (Status section updated)`, `#123 (new ticket filed)`
47
+
48
+ Then run from the linked project folder or any subdirectory beneath it:
49
+
50
+ {{GROUNDER_CLI}} handoff "<body>"
51
+
52
+ Optional short title slug (filename + frontmatter):
53
+
54
+ {{GROUNDER_CLI}} handoff --title <slug> "<body>"
55
+
56
+ Always include `--topics` with 3-5 comma-separated lowercase keywords that capture the session's core concepts (e.g. `--topics "auth,middleware,jwt,session"`). Pick terms a future search would use — concrete nouns and technical terms, not verbs or filler:
57
+
58
+ {{GROUNDER_CLI}} handoff --topics "keyword1,keyword2,keyword3" "<body>"
59
+
60
+ For multi-line bodies, prefer a shell heredoc so quoting does not break:
61
+
62
+ ```bash
63
+ {{GROUNDER_CLI}} handoff "$(cat <<'EOF'
64
+ # Handoff: …
65
+
66
+ EOF
67
+ )"
68
+ ```
69
+
70
+ The vault is outside the workspace — grant shell permissions if Claude Code prompts you.
71
+
72
+ Do not compute vault paths or write files yourself — the CLI handles it.
73
+ Report the CLI output path from stdout to the user.
@@ -1,9 +1,15 @@
1
- Save a note to the Obsidian vault for this project.
1
+ ---
2
+ name: grounder-note
3
+ description: Save a note to the markdown vault for this project.
4
+ disable-model-invocation: true
5
+ ---
6
+
7
+ Save a note to the markdown vault for this project.
2
8
 
3
9
  Distill the instruction after `/grounder-note` into a clean note body — not a chat transcript.
4
10
  Do not dump tool traces, full conversation, or false starts.
5
11
 
6
- **Special case: the instruction asks to view existing notes, not write one** (`list`, `list 3 oldest`, `show notes`, etc.) → run `{{GROUNDER_CLI}} note list --limit <N>` (N = count named, else 5; ignore order words like "oldest" — output is always newest-first, never resort or relabel it) and stop — no note write. Relay the CLI stdout as-is (it already includes the count header).
12
+ **Special case: the instruction asks to view existing notes, not write one** (`list`, `list 3 oldest`, `show notes`, etc.) → run `{{GROUNDER_CLI}} note list --limit <N> --markdown` (N = count named, else 5; ignore order words like "oldest" — output is always newest-first, never resort or relabel it) and stop — no note write. Relay the CLI stdout as-is (it already includes the count header; title lines are clickable `[relativePath](fileUri)` links).
7
13
 
8
14
  Rules:
9
15
  - Default → distill the args into a clean note body
@@ -18,6 +24,10 @@ Optional short title slug (filename):
18
24
 
19
25
  {{GROUNDER_CLI}} note --title <slug> "<body>"
20
26
 
27
+ Always include `--topics` with 3-5 comma-separated lowercase keywords that capture the note's core concepts (e.g. `--topics "schema,migration,postgres"`). Pick terms a future search would use — concrete nouns and technical terms, not verbs or filler:
28
+
29
+ {{GROUNDER_CLI}} note --topics "keyword1,keyword2,keyword3" "<body>"
30
+
21
31
  For multi-line bodies, prefer a shell heredoc so quoting does not break:
22
32
 
23
33
  ```bash
@@ -0,0 +1,21 @@
1
+ ---
2
+ name: grounder-overview
3
+ description: Bird's-eye view of this project's vault — counts and recent titles across notes, handoffs, and plans.
4
+ disable-model-invocation: true
5
+ ---
6
+
7
+ Bird's-eye view of this project's vault — counts and recent titles across notes, handoffs, and plans.
8
+
9
+ Read-only — do not write to the vault.
10
+
11
+ Use this when the user wants an overview, inventory, or "what's in the vault" summary — not a single bucket (use `note list` / `handoff list` / `plan list` for that) and not link/wiring health (that's `grounder status`).
12
+
13
+ From the linked project folder or any subdirectory beneath it:
14
+
15
+ {{GROUNDER_CLI}} overview --markdown
16
+
17
+ Relay the CLI stdout as-is — it already includes a per-bucket count header and clickable `[relativePath](fileUri)` title lines for notes, handoffs, and plans. Do not re-run `note list` / `handoff list` / `plan list` afterward; this single call already covers all three.
18
+
19
+ Use free-text after `/grounder-overview` as an optional recent-titles-per-bucket count (e.g. "show 5 each" → `--limit 5`); otherwise omit `--limit` and use the CLI default.
20
+
21
+ The vault is outside the workspace — grant shell permissions if Claude Code prompts you.
@@ -1,4 +1,10 @@
1
- Write a named, updatable plan document to the Obsidian vault for this project.
1
+ ---
2
+ name: grounder-plan
3
+ description: Write a named, updatable plan document to the markdown vault for this project.
4
+ disable-model-invocation: true
5
+ ---
6
+
7
+ Write a named, updatable plan document to the markdown vault for this project.
2
8
 
3
9
  Distill the instruction after `/grounder-plan` into a structured plan — not a chat transcript.
4
10
  Do not dump tool traces, full conversation, or false starts.
@@ -22,7 +28,7 @@ Build a markdown body with these sections:
22
28
 
23
29
  ```
24
30
 
25
- **Special case: the instruction asks to view existing plans, not name a new topic** (`list`, `list 3 oldest`, `show plans`, etc.) → run `{{GROUNDER_CLI}} plan list --limit <N>` (N = count named, else 5; ignore order words like "oldest" — output is always newest-first, never resort or relabel it) and stop — no plan write, no title. Relay the CLI stdout as-is (it already includes the count header).
31
+ **Special case: the instruction asks to view existing plans, not name a new topic** (`list`, `list 3 oldest`, `show plans`, etc.) → run `{{GROUNDER_CLI}} plan list --limit <N> --markdown` (N = count named, else 5; ignore order words like "oldest" — output is always newest-first, never resort or relabel it) and stop — no plan write, no title. Relay the CLI stdout as-is (it already includes the count header; title lines are clickable `[relativePath](fileUri)` links).
26
32
 
27
33
  Otherwise, resolve the target, then **state it plainly before writing** — `Updating plan at <path>.` or `Creating new plan titled <title>.` This is a visible record, not a blocking confirmation — updates overwrite with no `--force`, so get the match right.
28
34
 
@@ -31,12 +37,12 @@ Otherwise, resolve the target, then **state it plainly before writing** — `Upd
31
37
  **2. No path, but update intent** (e.g. "update/continue/revise the plan", or a name that sounds like an existing one) → look it up first:
32
38
 
33
39
  ```bash
34
- {{GROUNDER_CLI}} plan list --limit 5
40
+ {{GROUNDER_CLI}} plan list --limit 5 --markdown
35
41
  ```
36
42
 
37
- CLI output starts with a count header, then each result as a numbered two-line block — `N. ` + title (filename stem) on the first line, the absolute path indented beneath it.
43
+ CLI output starts with a count header, then each result as a numbered two-line block — `N. ` + `[relativePath](fileUri)` on the first line, the absolute path indented beneath it (use that absolute path for `--path`).
38
44
 
39
- A match counts only if its title actually corresponds to what the user named — not just "it's the only plan in the project." No name given and exactly one plan exists → that counts too. If the user refers to a plan by the number shown in *this* listing (e.g. "update plan 2"), that counts as a match too — resolve it to the path from this same output, don't reuse a number from an earlier listing in the conversation (it's positional, not a stable id, and can shift if plans changed since). Otherwise (no match, several matches, or a name/number that doesn't correspond to any existing plan) → ask; never guess.
45
+ A match counts only if the filename stem / relative path actually corresponds to what the user named — not just "it's the only plan in the project." No name given and exactly one plan exists → that counts too. If the user refers to a plan by the number shown in *this* listing (e.g. "update plan 2"), that counts as a match too — resolve it to the indented absolute path from this same output, don't reuse a number from an earlier listing in the conversation (it's positional, not a stable id, and can shift if plans changed since). Otherwise (no match, several matches, or a name/number that doesn't correspond to any existing plan) → ask; never guess.
40
46
 
41
47
  Cases 1 and 2 (update) — run:
42
48
 
@@ -62,6 +68,8 @@ EOF
62
68
 
63
69
  If `--title` collides with an existing plan (non-zero exit; stderr names the conflict), ask: overwrite (`--force`) or a different name. `--force` only resolves that collision — **never** use it to update a plan you meant to target with `--path`.
64
70
 
71
+ Always include `--topics` with 3-5 comma-separated lowercase keywords that capture the plan's core concepts (e.g. `--topics "caching,redis,performance,api"`). Pick terms a future search would use — concrete nouns and technical terms, not verbs or filler.
72
+
65
73
  Run from the linked project folder or any subdirectory beneath it.
66
74
  The vault is outside the workspace — grant shell permissions if Claude Code prompts you.
67
75
 
@@ -0,0 +1,34 @@
1
+ ---
2
+ name: grounder-recall
3
+ description: Recall this session from the latest vault handoff and repo truth.
4
+ disable-model-invocation: true
5
+ ---
6
+
7
+ Recall this session from the latest vault handoff and repo truth.
8
+
9
+ **Mode lock — load only.**
10
+ - Never write to the vault, regardless of typed extra text (save / handoff / checkpoint / continue in a new session) — never run the write form of `handoff` (the one that takes a body argument). The read-only `handoff list` lookups in the steps below stay required — they are not the ban.
11
+ - Typed extra text is only what the user wrote after `/grounder-recall` in the chat line — empty or bare command means no extra instruction; ignore any sibling verb that shows up only in a leftover command-payload wrapper.
12
+ - `#N` is a session pick only when the typed text *is* a selector (`#1`, `resume auth-middleware`). If `#N` sits inside save/explain prose instead, load the latest — do not guess an index.
13
+ - If the typed text does ask to save/handoff/checkpoint/continue in a new session, still do this command's job, then add one sentence: did not save — run `/grounder-handoff`. Skip that sentence when the mention only appears in stale payload text.
14
+
15
+ Read-only — do not write to the vault. Do not invent vault paths.
16
+
17
+ **Special case: the instruction asks to view existing handoffs, not recall** (`list`, `list 3 oldest`, `show handoffs`, etc.) → run `{{GROUNDER_CLI}} handoff list --limit <N> --markdown` (N = count named, else 5; ignore order words like "oldest" — output is always newest-first, never resort or relabel it) and stop — no recall, no `AGENTS.md`, no “start work.” Relay the CLI stdout as-is (it already includes the count header; title lines are clickable `[relativePath](fileUri)` links).
18
+
19
+ Otherwise, from the linked project folder or any subdirectory beneath it:
20
+
21
+ 1. Get the current handoff (skips empty/unreadable files, same pick as the session-start teaser):
22
+
23
+ {{GROUNDER_CLI}} handoff list --head
24
+
25
+ 2. If empty: tell the user there are no handoffs yet, then read repo `AGENTS.md` only, then stop and wait for the user's go-ahead — same as step 5, do not start work unattended.
26
+
27
+ 3. Otherwise, state the path from step 1 to the user, then read that file. If the user names a specific session instead: `{{GROUNDER_CLI}} handoff list --limit 5 --markdown` → match name/index to the indented absolute path in *this* listing (positional, not a stable id). Miss → once with `--limit 50 --markdown` (*that* listing only). Still miss → tell the user and stop — no guessed recall.
28
+
29
+ 4. Read repo `AGENTS.md` (project conventions and constraints).
30
+
31
+ 5. Summarize briefly what is next (from the handoff `## Next` section when present), then stop and wait for the user's go-ahead — do not start acting on `## Next` or anything else unless the user explicitly says so in this session.
32
+
33
+ The vault is outside the workspace — grant shell permissions if Claude Code prompts you.
34
+ Use free-text after `/grounder-recall` as optional focus (session name, index, or task hint).
@@ -0,0 +1,152 @@
1
+ ---
2
+ name: grounder-search
3
+ description: Search this project's vault content for relevant context.
4
+ disable-model-invocation: true
5
+ ---
6
+
7
+ Search this project's vault content for relevant context.
8
+
9
+ **Silence:** write **no assistant text** until step 3. Rounds 1–2 are tool calls with an empty/absent text part — not “I’ll search…”, not “I’ll read…”, not “**Analyzing…**”, not query/terms narration.
10
+
11
+ Use this when the user asks to find prior project-vault context by topic, keyword, concept, or phrase.
12
+
13
+ Scope is this linked project only — the CLI resolves and searches under the linked project vault root. Do not search outside it.
14
+
15
+ ## Turn budget (speed)
16
+
17
+ **Rounds 1–2: tool calls only — no text part in those messages.** Not even one sentence.
18
+
19
+ Exactly **two** assistant turns with tools, then the answer. Allowed tools, nothing else:
20
+
21
+ 1. Round 1 — Shell only: one `search … --json` (optional second search in the *same* round only per the broaden rule below). Message = that tool call, nothing else.
22
+ 2. Round 2 — Read only: **one** parallel batch of full-file reads (hits 1–4). Message = those Read calls, nothing else.
23
+ 3. Final answer to the user (first and only chat text).
24
+
25
+ **Do not** Glob, Grep, extra Shell, or status/UI tools (`UpdateCurrentStep`, `TodoWrite`, and similar). Do not add a third tool turn. Do not explore the repo.
26
+
27
+ ## Output contract (default — hybrid)
28
+
29
+ - Do not echo commands or shell output.
30
+ - **Never paste CLI JSON, snippets, or raw stdout into chat** — parse `--json` internally only.
31
+ - One final synthesized response only.
32
+
33
+ **Path links (mandatory for every listed file):**
34
+ - Visible title = `hits[].relativePath` from JSON **exactly** (project-vault-relative; the folder that contains `notes/`, `logs/`, and `plans/`). Example: `plans/archive/0.2.0 and older/doc.md`.
35
+ - **Do not** derive the title from `hits[].file`, path segments, or parent-vault prefixes.
36
+ - **Wrong titles:** `10-Projects/grounder/plans/…`, `%20` in the visible title, or any path above the project vault root.
37
+ - Link href = `hits[].fileUri` from JSON (spaces already percent-encoded).
38
+ - Markdown form: `[hits[i].relativePath](hits[i].fileUri)`
39
+
40
+ **Numbering (mandatory):**
41
+ - Number every listed file, continuing across sections (`1…` in **Read these**, then `5…` in **Also matched`).
42
+ - Do not restart at 1 in **Also matched**. Do not use bullet-only lists without numbers.
43
+
44
+ **Zero-hit disclosure (mandatory, both modes):** if `totalFileCount` is 0 (after the broaden attempt for topic/request), answer exactly `No matches in [<vaultRoot>](<vaultRootUri>) for this topic.` (`vaultRoot`/`vaultRootUri` from the JSON payload — the vault folder actually searched) instead of the Structure below.
45
+
46
+ Structure (non-empty results):
47
+
48
+ 1. **Opening** — one sentence of what the vault says (not a search recap). Never start with “I have searched…”, “I found…”, or similar.
49
+ 2. **Read these** — hits 1–4 only; numbered linked paths + optional role + short bullets under each. You may list a design/archive authority first *among those four*.
50
+ 3. **Also matched** — leftover top-10 **in CLI order** (do not reshuffle); numbered linked paths + one short phrase each. Use `hits[].alsoMatchedHint` — it is always present, even for a filename-only match with no `matches[]` line. `matches[].term` is a same-length alternative only when `matches[]` is non-empty. Every line must end with ` — phrase`; bare links are invalid. Omit if empty.
51
+
52
+ Example shape (`##` headings required — not bold-only, not `###`):
53
+
54
+ ```markdown
55
+ Vault notes discuss …
56
+
57
+ ## Read these
58
+ 1. [plans/archive/0.3.0/schema_….md](file:///…/schema_….md) — design authority
59
+ - …
60
+ 2. [plans/…](file:///…) — …
61
+ ## Also matched
62
+ 3. [plans/archive/0.2.0 and older/doc.md](file:///…/0.2.0%20and%20older/doc.md) — one phrase
63
+ 4. [plans/…](file:///…) — one phrase
64
+ ```
65
+
66
+ **Lookup mode:** explicit lookup wording (`exact phrase`, `this line`, `the wording`) **or** the entire input after stripping retrieval wrappers is a bare `"quoted span"` → one search with `--json` (no `--terms`, no full reads). Non-empty: list each hit as `[relativePath](fileUri)` (Path links rules) followed by its `matches[]` lines (`L{line} ({term}): {snippet}`), CLI order, no synthesis. A hit with an empty `matches[]` matched only by filename, not content — print `(matched by filename — no line to quote)` instead of inventing a snippet line. Empty (`totalFileCount` 0): Zero-hit disclosure.
67
+
68
+ ## Steps
69
+
70
+ 1. **Query and terms (private)** — classify, then build argv. Classification is silent (no chat text). The CLI line-scans `query` plus `--terms`; a file whose name (not just body) matches a term can also surface with no line hit at all (`matches[]` empty) — see **Also matched** and **Lookup mode** for how to gloss those. Multi-word queries only match lines that contain that phrase verbatim. Rank is dominated by how many distinct terms hit the **same** file — complementary vault words beat extra English synonyms and source module names.
71
+
72
+ **Classify** after stripping retrieval wrappers (`find`, `search for`, `documents discussing`, `notes about`, `look up`). Then pick one:
73
+
74
+ - **Lookup** — explicit lookup wording (`exact phrase`, `this line`, `the wording`), **or** leftover is a bare `"quoted span"`. `query` = the quoted text, unmodified — execution: see **Lookup mode** above.
75
+ - **Request** — leftover still has request syntax (any of): `that mention` / `that discuss` / `that talk about`; leftover starts with `plans that` / `notes that` / `docs that` / `documents that`; trailing scope `both in` / `either in` / `in CLI and`. Do **not** pass that leftover as `query`. `query` = one primary noun or named command from the topic (tight phrase; do not prefix a product name). Extra nouns go in `--terms`.
76
+ - **Topic leftover** — leftover is already a topic noun-phrase. `query` = leftover, same words, same order. Do not paraphrase, shorten, or coin a new phrase.
77
+
78
+ Strip only retrieval wrappers. Do not pass the whole utterance. Do not recycle the query as a `--terms` item.
79
+
80
+ Examples below are a **fictional** domain. Copy the shape; invent tokens for *this* topic. Do not reuse these strings as `--terms`.
81
+
82
+ Example — lookup. User: `find "retry of expired jobs"`
83
+ - class: lookup
84
+ - argv: {{GROUNDER_CLI}} search "retry of expired jobs" --json
85
+
86
+ Example — topic leftover. User: `find documents discussing retry of expired jobs`
87
+ - class: topic leftover
88
+ - query: `retry of expired jobs` (leftover after stripping the wrapper)
89
+ - wrong query: `expired job retries` (rewritten)
90
+ - wrong class: request (`documents discussing` is a wrapper)
91
+
92
+ Example — request. User: `find plans that mention updating the charge or refund command, both in worker and API`
93
+ - class: request (`plans that mention` / `both in` stay leftover — not the topic)
94
+ - query: `charge` (one named command from leftover; not `billing charge`)
95
+ - terms: `refund,settlement,invoices.json,RefundPolicy`
96
+ - from leftover: `refund` (the other named command)
97
+ - invented: `settlement` (domain), `invoices.json` (file), `RefundPolicy` (schema) — guess this project's equivalents
98
+ - wrong query: `plans that mention updating the charge or refund command, both in worker and API`
99
+ - wrong query: `charge refund command` (joined nouns)
100
+ - not as terms: `plan`, `command`, `api`
101
+
102
+ **Terms** — invent 3–5 complementary vault tokens for *this* topic, then stop. They need not appear in the utterance:
103
+ 1. Domain noun/phrase from the topic (skip if it would duplicate the query)
104
+ 2. Named command or product verb if the topic has one — never a lone generic verb (`migrate`, `install`)
105
+ 3. One on-disk identifier (filename, config key, schema field) guessed for this project
106
+ 4–5. Only another vault/product token. No paraphrase of the query.
107
+
108
+ **Never as terms** (unless the user asked about code layout): repo paths, `packages/…`, source module / file stems. Lone high-df words (`plan`, `command`, `cli`) flatten rank. Prefer words that appear in vault notes (named commands, config files, domain identifiers).
109
+
110
+ Example — user: `look up why the retry queue must skip expired jobs`
111
+ - class: topic leftover
112
+ - query: `why the retry queue must skip expired jobs`
113
+ - terms: `retry queue,dead letter,jobs.json,RetryPolicy,ttl` (`retry queue` from leftover; others invented)
114
+ - not: `queue-worker`, `process-jobs`, `skip`, `look up`
115
+
116
+ 2. **Search (tool round 1):**
117
+
118
+ ```bash
119
+ {{GROUNDER_CLI}} search "<query>" --terms "<csv>" --context 2 --json
120
+ ```
121
+
122
+ **Always quote `--terms`.** Unquoted CSV with spaces corrupts argv.
123
+
124
+ Parse JSON privately. Take hits in CLI order (`hits[0]` …). For links use `relativePath` + `fileUri`; for Also matched gloss use `alsoMatchedHint` (always present) — do not quote snippets.
125
+
126
+ **Broaden once (silent)** only if: `totalFileCount` is 0; or ≤2 and every hit is meta (`discussions/search/`, or snippet only quotes the query); or any term in `termHitCounts` has a count of 0 (that term produced no files — it was a bad guess and must be replaced). Otherwise do not re-search.
127
+
128
+ Broaden call (use `--context 3` — weaker matches need more context):
129
+
130
+ ```bash
131
+ {{GROUNDER_CLI}} search "<query>" --terms "<csv-with-replacement>" --context 3 --json
132
+ ```
133
+
134
+ **Broaden strategy (deterministic):** check `termHitCounts` first — if any term has count 0, replace **that term** (not slot-3) with a different product/vault token. If no zero-hit term, drop slot-3 (the on-disk identifier). Keep slots 1–2 (product noun/verb) unchanged. Do not invent new terms or rewrite existing ones.
135
+
136
+ 3. **Read (tool round 2)** — mandatory unless lookup:
137
+ - Full-read CLI hits **1–4** in rank order, **all in one parallel batch**.
138
+ - Read path = `hits[i].file` (absolute). Link title/href = `hits[i].relativePath` + `hits[i].fileUri`.
139
+ - **No skips, no substitutions, no “maybe also hit 5.”** Trust CLI order; judge relevance only when writing the answer.
140
+ - Grant read permissions for vault paths outside the workspace when needed.
141
+
142
+ 4. **Answer** — synthesize immediately after reads:
143
+ - Claims only from files you full-read. Unread hits must not grow new facts.
144
+ - **Read these:** useful full-reads (those 1–4 only). Thin/off-topic reads get one blunt numbered line there or move to **Also matched**.
145
+ - **Also matched:** remaining top-10 you did not deep-summarize, **in CLI leftover order**. Copy `alsoMatchedHint` (always present, even for a filename-only match); every line ends with ` — phrase`.
146
+ - Every file line: `[relativePath](fileUri)` from JSON; continue numbering across sections.
147
+ - Prefer design/archive docs when they are the authority among the files you read.
148
+
149
+ Run from the linked project folder or any subdirectory beneath it.
150
+ The vault is outside the workspace — grant shell permissions if Claude Code prompts you.
151
+ Do not write to vault files during search.
152
+ Do not grep the vault yourself — the CLI ranks; you read and synthesize.
@@ -0,0 +1,73 @@
1
+ ---
2
+ name: grounder-handoff
3
+ description: Write a session handoff checkpoint to the markdown vault for this project.
4
+ disable-model-invocation: true
5
+ ---
6
+
7
+ Write a session handoff checkpoint to the markdown vault for this project.
8
+
9
+ **Mode lock — write only.**
10
+ - Never hydrate or start work, regardless of typed extra text (resume / load / hydrate / `/grounder-recall`) — never run `handoff list` to pick or overwrite an existing file. The plain write form of `handoff` (a body argument, no `list`) stays required — that's this command's whole job; always write a **new** file.
11
+ - Typed extra text is only what the user wrote after `/grounder-handoff` in the chat line — empty or bare command means no extra instruction; ignore any sibling verb that shows up only in a leftover command-payload wrapper. Otherwise, extra text is body guidance for this handoff.
12
+ - `#N` here means leftover Next item N from *this* session, not file N in a listing.
13
+ - If the typed text does ask to resume/load/hydrate/`/grounder-recall`, still do this command's job, then add one sentence: saved — run `/grounder-recall` in a new chat to resume. Skip that sentence for "continue in a new session" wording (that's the point of saving) or when the mention only appears in stale payload text.
14
+
15
+ Summarize the session into a structured handoff — not a chat transcript.
16
+ Do not dump tool traces, full conversation, or false starts.
17
+
18
+ Build a markdown body with these sections (lean; roughly half a screen to one screen):
19
+
20
+ ```markdown
21
+ # Handoff: <short label>
22
+
23
+ ## Done
24
+ - …
25
+
26
+ ## Next
27
+ 1. … # ordered; most important section for resume — required
28
+ 2. …
29
+
30
+ ## Blockers
31
+ - None | …
32
+
33
+ ## Decisions
34
+ - … # include rejected alternatives / pitfalls when useful
35
+
36
+ ## Files
37
+ - path/to/relevant.ts
38
+ - path/to/plan.md (Status section updated) # if a plan/ticket drove the session, link it here — see Rules
39
+ ```
40
+
41
+ Rules:
42
+ - **Nothing done yet is not a reason to skip writing** — a fresh or empty session still gets a handoff (`Done: None`, `Next: 1. n/a` or one reasonable next step); never reply with a menu of options instead of running the write.
43
+ - **Next is mandatory and ordered** — if only one section is read, this is it
44
+ - Empty sections are OK (`Blockers: None` beats omission)
45
+ - Few concrete file paths, not an exhaustive diff
46
+ - If a vault plan (`grounder plan`) or ticket drove the session, list it first in `## Files` with a short note on what changed — e.g. `path/to/plan.md (Status section updated)`, `#123 (new ticket filed)`
47
+
48
+ Then run from the linked project folder or any subdirectory beneath it:
49
+
50
+ {{GROUNDER_CLI}} handoff "<body>"
51
+
52
+ Optional short title slug (filename + frontmatter):
53
+
54
+ {{GROUNDER_CLI}} handoff --title <slug> "<body>"
55
+
56
+ Always include `--topics` with 3-5 comma-separated lowercase keywords that capture the session's core concepts (e.g. `--topics "auth,middleware,jwt,session"`). Pick terms a future search would use — concrete nouns and technical terms, not verbs or filler:
57
+
58
+ {{GROUNDER_CLI}} handoff --topics "keyword1,keyword2,keyword3" "<body>"
59
+
60
+ For multi-line bodies, prefer a shell heredoc so quoting does not break:
61
+
62
+ ```bash
63
+ {{GROUNDER_CLI}} handoff "$(cat <<'EOF'
64
+ # Handoff: …
65
+
66
+ EOF
67
+ )"
68
+ ```
69
+
70
+ Run {{GROUNDER_CLI}} with `required_permissions: ["all"]` (vault is outside the workspace).
71
+
72
+ Do not compute vault paths or write files yourself — the CLI handles it.
73
+ Report the CLI output path from stdout to the user.
@@ -1,9 +1,15 @@
1
- Save a note to the Obsidian vault for this project.
1
+ ---
2
+ name: grounder-note
3
+ description: Save a note to the markdown vault for this project.
4
+ disable-model-invocation: true
5
+ ---
6
+
7
+ Save a note to the markdown vault for this project.
2
8
 
3
9
  Distill the instruction after `/grounder-note` into a clean note body — not a chat transcript.
4
10
  Do not dump tool traces, full conversation, or false starts.
5
11
 
6
- **Special case: the instruction asks to view existing notes, not write one** (`list`, `list 3 oldest`, `show notes`, etc.) → run `{{GROUNDER_CLI}} note list --limit <N>` (N = count named, else 5; ignore order words like "oldest" — output is always newest-first, never resort or relabel it) and stop — no note write. Relay the CLI stdout as-is (it already includes the count header).
12
+ **Special case: the instruction asks to view existing notes, not write one** (`list`, `list 3 oldest`, `show notes`, etc.) → run `{{GROUNDER_CLI}} note list --limit <N> --markdown` (N = count named, else 5; ignore order words like "oldest" — output is always newest-first, never resort or relabel it) and stop — no note write. Relay the CLI stdout as-is (it already includes the count header; title lines are clickable `[relativePath](fileUri)` links).
7
13
 
8
14
  Rules:
9
15
  - Default → distill the args into a clean note body
@@ -18,6 +24,10 @@ Optional short title slug (filename):
18
24
 
19
25
  {{GROUNDER_CLI}} note --title <slug> "<body>"
20
26
 
27
+ Always include `--topics` with 3-5 comma-separated lowercase keywords that capture the note's core concepts (e.g. `--topics "schema,migration,postgres"`). Pick terms a future search would use — concrete nouns and technical terms, not verbs or filler:
28
+
29
+ {{GROUNDER_CLI}} note --topics "keyword1,keyword2,keyword3" "<body>"
30
+
21
31
  For multi-line bodies, prefer a shell heredoc so quoting does not break:
22
32
 
23
33
  ```bash
@@ -0,0 +1,21 @@
1
+ ---
2
+ name: grounder-overview
3
+ description: Bird's-eye view of this project's vault — counts and recent titles across notes, handoffs, and plans.
4
+ disable-model-invocation: true
5
+ ---
6
+
7
+ Bird's-eye view of this project's vault — counts and recent titles across notes, handoffs, and plans.
8
+
9
+ Read-only — do not write to the vault.
10
+
11
+ Use this when the user wants an overview, inventory, or "what's in the vault" summary — not a single bucket (use `note list` / `handoff list` / `plan list` for that) and not link/wiring health (that's `grounder status`).
12
+
13
+ From the linked project folder or any subdirectory beneath it:
14
+
15
+ {{GROUNDER_CLI}} overview --markdown
16
+
17
+ Relay the CLI stdout as-is — it already includes a per-bucket count header and clickable `[relativePath](fileUri)` title lines for notes, handoffs, and plans. Do not re-run `note list` / `handoff list` / `plan list` afterward; this single call already covers all three.
18
+
19
+ Use free-text after `/grounder-overview` as an optional recent-titles-per-bucket count (e.g. "show 5 each" → `--limit 5`); otherwise omit `--limit` and use the CLI default.
20
+
21
+ Run {{GROUNDER_CLI}} with `required_permissions: ["all"]` (vault is outside the workspace).
@@ -1,4 +1,10 @@
1
- Write a named, updatable plan document to the Obsidian vault for this project.
1
+ ---
2
+ name: grounder-plan
3
+ description: Write a named, updatable plan document to the markdown vault for this project.
4
+ disable-model-invocation: true
5
+ ---
6
+
7
+ Write a named, updatable plan document to the markdown vault for this project.
2
8
 
3
9
  Distill the instruction after `/grounder-plan` into a structured plan — not a chat transcript.
4
10
  Do not dump tool traces, full conversation, or false starts.
@@ -22,7 +28,7 @@ Build a markdown body with these sections:
22
28
 
23
29
  ```
24
30
 
25
- **Special case: the instruction asks to view existing plans, not name a new topic** (`list`, `list 3 oldest`, `show plans`, etc.) → run `{{GROUNDER_CLI}} plan list --limit <N>` (N = count named, else 5; ignore order words like "oldest" — output is always newest-first, never resort or relabel it) and stop — no plan write, no title. Relay the CLI stdout as-is (it already includes the count header).
31
+ **Special case: the instruction asks to view existing plans, not name a new topic** (`list`, `list 3 oldest`, `show plans`, etc.) → run `{{GROUNDER_CLI}} plan list --limit <N> --markdown` (N = count named, else 5; ignore order words like "oldest" — output is always newest-first, never resort or relabel it) and stop — no plan write, no title. Relay the CLI stdout as-is (it already includes the count header; title lines are clickable `[relativePath](fileUri)` links).
26
32
 
27
33
  Otherwise, resolve the target, then **state it plainly before writing** — `Updating plan at <path>.` or `Creating new plan titled <title>.` This is a visible record, not a blocking confirmation — updates overwrite with no `--force`, so get the match right.
28
34
 
@@ -31,12 +37,12 @@ Otherwise, resolve the target, then **state it plainly before writing** — `Upd
31
37
  **2. No path, but update intent** (e.g. "update/continue/revise the plan", or a name that sounds like an existing one) → look it up first:
32
38
 
33
39
  ```bash
34
- {{GROUNDER_CLI}} plan list --limit 5
40
+ {{GROUNDER_CLI}} plan list --limit 5 --markdown
35
41
  ```
36
42
 
37
- CLI output starts with a count header, then each result as a numbered two-line block — `N. ` + title (filename stem) on the first line, the absolute path indented beneath it.
43
+ CLI output starts with a count header, then each result as a numbered two-line block — `N. ` + `[relativePath](fileUri)` on the first line, the absolute path indented beneath it (use that absolute path for `--path`).
38
44
 
39
- A match counts only if its title actually corresponds to what the user named — not just "it's the only plan in the project." No name given and exactly one plan exists → that counts too. If the user refers to a plan by the number shown in *this* listing (e.g. "update plan 2"), that counts as a match too — resolve it to the path from this same output, don't reuse a number from an earlier listing in the conversation (it's positional, not a stable id, and can shift if plans changed since). Otherwise (no match, several matches, or a name/number that doesn't correspond to any existing plan) → ask; never guess.
45
+ A match counts only if the filename stem / relative path actually corresponds to what the user named — not just "it's the only plan in the project." No name given and exactly one plan exists → that counts too. If the user refers to a plan by the number shown in *this* listing (e.g. "update plan 2"), that counts as a match too — resolve it to the indented absolute path from this same output, don't reuse a number from an earlier listing in the conversation (it's positional, not a stable id, and can shift if plans changed since). Otherwise (no match, several matches, or a name/number that doesn't correspond to any existing plan) → ask; never guess.
40
46
 
41
47
  Cases 1 and 2 (update) — run:
42
48
 
@@ -62,6 +68,8 @@ EOF
62
68
 
63
69
  If `--title` collides with an existing plan (non-zero exit; stderr names the conflict), ask: overwrite (`--force`) or a different name. `--force` only resolves that collision — **never** use it to update a plan you meant to target with `--path`.
64
70
 
71
+ Always include `--topics` with 3-5 comma-separated lowercase keywords that capture the plan's core concepts (e.g. `--topics "caching,redis,performance,api"`). Pick terms a future search would use — concrete nouns and technical terms, not verbs or filler.
72
+
65
73
  Run from the linked project folder or any subdirectory beneath it.
66
74
  Run {{GROUNDER_CLI}} with `required_permissions: ["all"]` (vault is outside the workspace).
67
75
 
@@ -0,0 +1,34 @@
1
+ ---
2
+ name: grounder-recall
3
+ description: Recall this session from the latest vault handoff and repo truth.
4
+ disable-model-invocation: true
5
+ ---
6
+
7
+ Recall this session from the latest vault handoff and repo truth.
8
+
9
+ **Mode lock — load only.**
10
+ - Never write to the vault, regardless of typed extra text (save / handoff / checkpoint / continue in a new session) — never run the write form of `handoff` (the one that takes a body argument). The read-only `handoff list` lookups in the steps below stay required — they are not the ban.
11
+ - Typed extra text is only what the user wrote after `/grounder-recall` in the chat line — empty or bare command means no extra instruction; ignore any sibling verb that shows up only in a leftover command-payload wrapper.
12
+ - `#N` is a session pick only when the typed text *is* a selector (`#1`, `resume auth-middleware`). If `#N` sits inside save/explain prose instead, load the latest — do not guess an index.
13
+ - If the typed text does ask to save/handoff/checkpoint/continue in a new session, still do this command's job, then add one sentence: did not save — run `/grounder-handoff`. Skip that sentence when the mention only appears in stale payload text.
14
+
15
+ Read-only — do not write to the vault. Do not invent vault paths.
16
+
17
+ **Special case: the instruction asks to view existing handoffs, not recall** (`list`, `list 3 oldest`, `show handoffs`, etc.) → run `{{GROUNDER_CLI}} handoff list --limit <N> --markdown` (N = count named, else 5; ignore order words like "oldest" — output is always newest-first, never resort or relabel it) and stop — no recall, no `AGENTS.md`, no “start work.” Relay the CLI stdout as-is (it already includes the count header; title lines are clickable `[relativePath](fileUri)` links).
18
+
19
+ Otherwise, from the linked project folder or any subdirectory beneath it:
20
+
21
+ 1. Get the current handoff (skips empty/unreadable files, same pick as the session-start teaser):
22
+
23
+ {{GROUNDER_CLI}} handoff list --head
24
+
25
+ 2. If empty: tell the user there are no handoffs yet, then read repo `AGENTS.md` only, then stop and wait for the user's go-ahead — same as step 5, do not start work unattended.
26
+
27
+ 3. Otherwise, state the path from step 1 to the user, then read that file. If the user names a specific session instead: `{{GROUNDER_CLI}} handoff list --limit 5 --markdown` → match name/index to the indented absolute path in *this* listing (positional, not a stable id). Miss → once with `--limit 50 --markdown` (*that* listing only). Still miss → tell the user and stop — no guessed recall.
28
+
29
+ 4. Read repo `AGENTS.md` (project conventions and constraints).
30
+
31
+ 5. Summarize briefly what is next (from the handoff `## Next` section when present), then stop and wait for the user's go-ahead — do not start acting on `## Next` or anything else unless the user explicitly says so in this session.
32
+
33
+ Run {{GROUNDER_CLI}} with `required_permissions: ["all"]` (vault is outside the workspace).
34
+ Use free-text after `/grounder-recall` as optional focus (session name, index, or task hint).