hypomnema 1.8.2 → 1.9.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 (63) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/.claude-plugin/plugin.json +1 -1
  3. package/CHANGELOG.md +141 -51
  4. package/README.ko.md +18 -17
  5. package/README.md +16 -15
  6. package/commands/crystallize.md +89 -24
  7. package/commands/doctor.md +3 -1
  8. package/docs/ARCHITECTURE.md +45 -14
  9. package/docs/CONTRIBUTING.md +26 -8
  10. package/hooks/atomic-write.mjs +44 -0
  11. package/hooks/base-store.mjs +409 -90
  12. package/hooks/close-gate-store.mjs +131 -16
  13. package/hooks/close-journal.mjs +250 -0
  14. package/hooks/close-receipt.mjs +559 -0
  15. package/hooks/hooks.json +3 -38
  16. package/hooks/hypo-auto-commit.mjs +80 -10
  17. package/hooks/hypo-auto-minimal-crystallize.mjs +129 -25
  18. package/hooks/hypo-auto-stage.mjs +13 -1
  19. package/hooks/hypo-close-guard.mjs +2 -1
  20. package/hooks/hypo-cwd-change.mjs +45 -20
  21. package/hooks/hypo-file-watch.mjs +44 -6
  22. package/hooks/hypo-first-prompt.mjs +15 -9
  23. package/hooks/hypo-hot-rebuild.mjs +169 -112
  24. package/hooks/hypo-personal-check.mjs +9 -1
  25. package/hooks/hypo-session-record.mjs +1 -1
  26. package/hooks/hypo-session-start.mjs +566 -20
  27. package/hooks/hypo-shared.mjs +2250 -206
  28. package/hooks/hypo-stop.mjs +207 -0
  29. package/hooks/proposal-store.mjs +201 -35
  30. package/hooks/shared.json +15 -0
  31. package/hooks/version-check.mjs +9 -7
  32. package/package.json +3 -1
  33. package/scripts/crystallize.mjs +3 -4
  34. package/scripts/doctor.mjs +549 -123
  35. package/scripts/init.mjs +86 -109
  36. package/scripts/lib/core-hooks.mjs +48 -22
  37. package/scripts/lib/crystallize-close-apply.mjs +2397 -188
  38. package/scripts/lib/crystallize-close-check.mjs +43 -23
  39. package/scripts/lib/design-history-stale.mjs +36 -9
  40. package/scripts/lib/frontmatter.mjs +39 -0
  41. package/scripts/lib/git-hooks-dir.mjs +427 -52
  42. package/scripts/lib/hook-inventory.mjs +180 -0
  43. package/scripts/lib/page-usage.mjs +1 -1
  44. package/scripts/lib/pkg-provenance.mjs +18 -1
  45. package/scripts/lib/plugin-detect.mjs +43 -9
  46. package/scripts/lib/project-create.mjs +40 -44
  47. package/scripts/lib/schema-vocab.mjs +22 -11
  48. package/scripts/lib/template-schema-version.mjs +48 -0
  49. package/scripts/lib/time.mjs +46 -0
  50. package/scripts/lint.mjs +66 -18
  51. package/scripts/proposal.mjs +423 -18
  52. package/scripts/resume.mjs +3 -2
  53. package/scripts/session-audit.mjs +2 -1
  54. package/scripts/uninstall.mjs +144 -66
  55. package/scripts/upgrade.mjs +523 -234
  56. package/scripts/verify.mjs +2 -1
  57. package/scripts/weekly-report.mjs +2 -1
  58. package/templates/SCHEMA.md +27 -7
  59. package/templates/gitignore +11 -0
  60. package/templates/hypo-automation.md +10 -13
  61. package/templates/hypo-config.md +1 -1
  62. package/templates/hypo-guide.md +53 -25
  63. package/templates/hot.md +0 -24
@@ -19,6 +19,7 @@ import { existsSync, readFileSync, readdirSync, statSync } from 'fs';
19
19
  import { join, relative, extname } from 'path';
20
20
  import { resolveHypoRoot, expandHome } from './lib/hypo-root.mjs';
21
21
  import { loadHypoIgnore, isScanIgnored } from './lib/hypo-ignore.mjs';
22
+ import { DAY_MS } from './lib/time.mjs';
22
23
 
23
24
  // ── arg parsing ──────────────────────────────────────────────────────────────
24
25
 
@@ -130,7 +131,7 @@ for (const file of files) {
130
131
  if (!fm.verify_by) {
131
132
  missing.push(entry);
132
133
  } else if (fm.verify_by_date && /^\d{4}-\d{2}-\d{2}$/.test(fm.verify_by_date)) {
133
- const daysUntil = Math.ceil((new Date(fm.verify_by_date) - new Date(today)) / 86400000);
134
+ const daysUntil = Math.ceil((new Date(fm.verify_by_date) - new Date(today)) / DAY_MS);
134
135
  if (fm.verify_by_date < today) {
135
136
  overdue.push({ ...entry, daysOverdue: -daysUntil });
136
137
  } else if (daysUntil <= 14) {
@@ -18,6 +18,7 @@ import { existsSync, mkdirSync, writeFileSync } from 'fs';
18
18
  import { join } from 'path';
19
19
  import { resolveHypoRoot, expandHome } from './lib/hypo-root.mjs';
20
20
  import { loadSessionEntries, auditEntries } from './session-audit.mjs';
21
+ import { DAY_MS } from './lib/time.mjs';
21
22
 
22
23
  function parseArgs(argv) {
23
24
  const args = {
@@ -46,7 +47,7 @@ function isoWeek(date) {
46
47
  const dayNum = d.getUTCDay() || 7;
47
48
  d.setUTCDate(d.getUTCDate() + 4 - dayNum);
48
49
  const yearStart = new Date(Date.UTC(d.getUTCFullYear(), 0, 1));
49
- const week = Math.ceil(((d - yearStart) / 86400000 + 1) / 7);
50
+ const week = Math.ceil(((d - yearStart) / DAY_MS + 1) / 7);
50
51
  return `${d.getUTCFullYear()}-W${String(week).padStart(2, '0')}`;
51
52
  }
52
53
 
@@ -2,7 +2,7 @@
2
2
  title: Wiki Schema
3
3
  type: schema
4
4
  updated: YYYY-MM-DD
5
- version: 2.2
5
+ version: 2.3
6
6
  ---
7
7
 
8
8
  # Wiki Schema
@@ -59,18 +59,38 @@ Files responsible for session continuity — separate from the type taxonomy abo
59
59
 
60
60
  **Operations**:
61
61
  - Session start: root `hot.md` → project `hot.md` → `session-state.md`
62
- - Session close: update project `hot.md` (what was done) + `session-state.md` (what to do next) + root `hot.md`
62
+ - Session close: update project `hot.md` (what was done) + `session-state.md` (what to do next)
63
63
 
64
- **Pointer table row format** (`hypo-hot-rebuild.mjs` parses this with a fixed regex — wrong col3 format causes the row to be silently skipped):
64
+ Root `hot.md` is not something a session writes. It is a generated file: the
65
+ hooks rebuild it by scanning `projects/*/hot.md` at every session start and
66
+ stop, so a hand edit to it is overwritten by the next rebuild. This is the
67
+ one place to look when a project does not show up in the table.
68
+
69
+ **Pointer table row format** (generated by `formatRootHotProjection` in
70
+ `hooks/hypo-shared.mjs`, fed by a directory scan in
71
+ `scanRootHotProjectionSources` in the same file):
65
72
 
66
73
  ```
67
- | <Project Name> | YYYY-MM-DD | [[projects/<slug>/hot]] |
74
+ | <slug> | YYYY-MM-DD | [[projects/<slug>/hot]] |
68
75
  ```
69
76
 
77
+ The table holds one row per subdirectory of `projects/` that has a `hot.md`
78
+ file. A project with no `hot.md` yet gets no row; delete or move that file to
79
+ drop the project from the table.
80
+
70
81
  Column semantics:
71
- - col 1 (name): preserved as-is from the existing row
72
- - col 2 (date): **ignored on read** — rebuilt from `projects/<slug>/hot.md` frontmatter `updated:` (falls back to today if the file is absent)
73
- - col 3 (wikilink): must be `[[projects/<slug>/hot]]` — no trailing path, no markdown link `[text](url)`. Extra trailing columns are discarded during canonical rebuild (not dropped).
82
+ - col 1 (name): always the slug (the directory name under `projects/`), never
83
+ that project's frontmatter `title`
84
+ - col 2 (date): that project's `hot.md` frontmatter `updated:` field, left
85
+ blank when the file is missing, unreadable, or the value is not a
86
+ well-formed `YYYY-MM-DD` string. It is never defaulted to today.
87
+ - col 3 (wikilink): always `[[projects/<slug>/hot]]`
88
+
89
+ Rows sort by date descending, blank dates last, ties broken by slug
90
+ ascending, so two machines scanning the same tree produce byte-identical
91
+ output. The root file's own frontmatter `updated:` is the max of the row
92
+ dates (or blank when every row is dateless), not the day the file itself was
93
+ last rewritten.
74
94
 
75
95
  ---
76
96
 
@@ -12,3 +12,14 @@
12
12
  # match the staging name, and a crash between the link and its cleanup leaves one
13
13
  # behind — where `git add -A` would happily pick it up.
14
14
  *.lock.*.tmp
15
+
16
+ # Migration backup of a hand-authored root hot.md, written the first time
17
+ # writeRootHotProjection takes over a file it does not already own (see
18
+ # hooks/hypo-shared.mjs). Never tracked: it can hold whatever a person's own
19
+ # uncommitted notes held, and a scoped auto-commit must never pick it up.
20
+ /hot.md.pre-projection-backup*.md
21
+ # atomicWrite's own temp file for the backup write above
22
+ # (`<backupPath>.<pid>.<random>.tmp`): carries the same hand-authored bytes
23
+ # until the rename that produces the file matched above, so a kill or power
24
+ # loss mid-write must not leave it exposed to `git add -A` either.
25
+ /hot.md.pre-projection-backup*.tmp
@@ -14,12 +14,12 @@ session continuity, and git sync.
14
14
 
15
15
  ## Hook Overview
16
16
 
17
- All 15 hooks registered in `hooks/hooks.json` are listed below, in registration order.
17
+ All 12 hooks registered in `hooks/hooks.json` are listed below, in registration order.
18
18
 
19
19
  | Hook | Event | Purpose |
20
20
  |------|-------|---------|
21
21
  | `hypo-close-guard.mjs` | `PreToolUse` | Blocks a direct Write/Edit/MultiEdit bypass of the session-close approval flow |
22
- | `hypo-session-start.mjs` | `SessionStart` | Injects `hot.md` and `session-state.md` into context on session start |
22
+ | `hypo-session-start.mjs` | `SessionStart` | Rebuilds the root `hot.md` projection, then injects `hot.md` and `session-state.md` into context on session start |
23
23
  | `hypo-session-end.mjs` | `SessionEnd` | Records the dying session's identity so a `/clear` can be detected and recovered from on the next start |
24
24
  | `hypo-first-prompt.mjs` | `UserPromptSubmit` | Injects a one-line resume summary on the first prompt after a session start or cwd change |
25
25
  | `hypo-lookup.mjs` | `UserPromptSubmit` | Searches the wiki index for each prompt and injects matched pages as context |
@@ -27,12 +27,9 @@ All 15 hooks registered in `hooks/hooks.json` are listed below, in registration
27
27
  | `hypo-personal-check.mjs` | `PreCompact` | Detects missing session-close files, uncommitted wiki changes, or lint blockers and surfaces them as a `systemMessage`; it does not block `/compact` |
28
28
  | `hypo-auto-stage.mjs` | `PostToolUse` | Auto-stages a wiki file after it is written |
29
29
  | `hypo-web-fetch-ingest.mjs` | `PostToolUse` | Nudges Claude to ingest WebFetch/WebSearch results into `sources/` |
30
- | `hypo-hot-rebuild.mjs` | `Stop` | Rebuilds root `hot.md`'s pointer table and frontmatter at session end |
31
- | `hypo-session-record.mjs` | `Stop` | Appends the completed session to the session index |
32
- | `hypo-auto-commit.mjs` | `Stop` | Stages, commits, and pushes this session's touched wiki paths |
33
- | `hypo-auto-minimal-crystallize.mjs` | `Stop` | Blocks `Stop` when the session did substantial work, the user signalled wrap-up, and no close was recorded. A substantial session with no close signal is let through |
34
- | `hypo-cwd-change.mjs` | `CwdChanged` | Builds `additionalContext` with the matching project's `hot.md` when the working directory changes mid-session, but `CwdChanged` has no field Claude Code forwards to the model, so this output does not currently reach Claude |
35
- | `hypo-file-watch.mjs` | `FileChanged` | Builds `additionalContext` for a changed vault file once it passes the ignore and visibility filters. Nothing in this package registers watch paths, so the event has no trigger here, and `FileChanged` output does not reach Claude either way |
30
+ | `hypo-stop.mjs` | `Stop` | Runs the session-end chain as four ordered stages, one after another, not in parallel: rebuilds the root `hot.md` projection, appends the session to the session index, stages/commits/pushes this session's touched wiki paths, then blocks `Stop` if the session did substantial work, the user signalled wrap-up, and no close was recorded |
31
+ | `hypo-cwd-change.mjs` | `CwdChanged` | Builds a `systemMessage` with the matching project's `hot.md` when the working directory changes mid-session. `additionalContext` is not among `CwdChanged`'s documented output fields, so this never becomes `additionalContext`; the reference says only that it "shows the `systemMessage` as a brief terminal notification," without saying whether it also reaches the model. As of Claude Code 2.1.276 (checked 2026-09-18) and reconfirmed on 2.1.283, tracing the installed binary shows the only consumer of that `systemMessage` is the terminal notification queue, with no branch that forwards it to the model; no live-session observation of this path exists either way, and this event is treated as not reaching the model until the documentation says otherwise |
32
+ | `hypo-file-watch.mjs` | `FileChanged` | Builds a `systemMessage` for a changed vault file once it passes the ignore and visibility filters, over the same field as `hypo-cwd-change` whose reach to the model the reference leaves undocumented; as of Claude Code 2.1.276 (checked 2026-09-18) and reconfirmed on 2.1.283 it is likewise treated as not reaching the model (see the row above). On a stock install the event still has no trigger here, because nothing in this package returns `watchPaths` to seed the watch list; that list is session-global, so another hook or plugin seeding it would still make this matcher-less group fire, though it returns immediately for any path that does not start with `HYPO_DIR` (a string-prefix check, not a symlink-resolving one) |
36
33
 
37
34
  This file is copied into a vault only at `init` time, and no update channel pushes a later fix here into a vault that already exists. So this copy can be older than the shipped one. `hooks/hooks.json` in the package is the source of truth for which hook runs on which event; when this table disagrees with it, the table is what went stale.
38
35
 
@@ -45,8 +42,8 @@ remove the remote if you do not want it.
45
42
 
46
43
  - `hypo-session-start.mjs` (`SessionStart`) runs `git pull --ff-only` before it reads any
47
44
  vault file. It waits for that pull, up to a 10 second timeout.
48
- - `hypo-auto-commit.mjs` (`Stop`) runs `git pull` and `git push` after committing this
49
- session's touched paths.
45
+ - `hypo-stop.mjs` (`Stop`) runs `git pull` and `git push`, via its `hypo-auto-commit.mjs`
46
+ stage, after committing this session's touched paths.
50
47
 
51
48
  **The update check.** `hypo-session-start.mjs` also spawns a background check that fetches
52
49
  two URLs:
@@ -65,15 +62,15 @@ affect the git sync above.
65
62
 
66
63
  ```
67
64
  Session start
68
- └─ hypo-session-start.mjs → reads hot.md + session-state.md → injects context
65
+ └─ hypo-session-start.mjs → rebuilds root hot.md → reads hot.md + session-state.md → injects context
69
66
 
70
67
  During session
71
68
  └─ hypo-auto-stage.mjs → git-adds any wiki path a tool touched (not only .md edits)
72
69
  └─ hypo-web-fetch-ingest.mjs → after WebFetch/WebSearch, nudges an ingest
73
70
  └─ hypo-lookup.mjs → BM25-matches each prompt against the wiki index
74
71
 
75
- Session end (Stop chain, in order)
76
- └─ hypo-hot-rebuild.mjs → refreshes root hot.md
72
+ Session end (single Stop hook, hypo-stop.mjs, running four stages in order)
73
+ └─ hypo-hot-rebuild.mjs → refreshes root hot.md (same generator SessionStart also calls)
77
74
  └─ hypo-session-record.mjs → appends to the session index
78
75
  └─ hypo-auto-commit.mjs → git commit + push
79
76
  └─ hypo-auto-minimal-crystallize.mjs → blocks Stop if session close never ran
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  title: Hypomnema Config
3
3
  type: config
4
- version: "1.8.2"
4
+ version: "1.9.0"
5
5
  created: YYYY-MM-DD
6
6
  ---
7
7
 
@@ -2,7 +2,7 @@
2
2
  title: Wiki Operations Guide
3
3
  type: reference
4
4
  updated: YYYY-MM-DD
5
- version: 1
5
+ version: 2
6
6
  tags: [wiki, guide, operations]
7
7
  ---
8
8
 
@@ -82,36 +82,63 @@ Ask: *"이 작업이 마무리되었나요? 세션을 정리(crystallize)할까
82
82
  1. Update `projects/<name>/session-state.md` (next tasks, overwrite)
83
83
  2. Update `projects/<name>/hot.md` (what was done, ≤500 words, overwrite)
84
84
  3. Append to `projects/<name>/session-log/YYYY-MM-DD.md` (daily shard, narrative entry, append-only)
85
- 4. Update root `hot.md` pointer table + date
85
+ 4. Root `hot.md` is regenerated by the hooks from `projects/*/hot.md`, not hand-edited: step 2 above is what actually moves it.
86
86
  5. Run `/hypo:lint` and fix errors in files **you** touched — debt in other
87
87
  projects / shared pages you did not author is reported as a non-blocking
88
88
  notice, not a gate. (The documented `/hypo:crystallize` session-close path
89
89
  runs this lint automatically, scoped to the files it writes.)
90
- 6. Verify with `/hypo:crystallize` in its `--check-session-close` mode: a dry-run of the
90
+ 6. Check with `/hypo:crystallize` in its `--check-session-close` mode: a dry-run of the
91
91
  **full** set of checks the PreCompact hook itself runs (close files + lint + design-history + feedback
92
- projection), sharing one function (`precompactGateStatus`) with that hook. Only declare the
93
- session closed once it prints **"Compact-ready"**. A "close files updated"
94
- check alone is not enough to earn that signal: a lint error in a close file
95
- or a feedback projection over-cap keeps the check red on its own.
92
+ projection), sharing one function (`precompactGateStatus`) with that hook. Its
93
+ **"Compact-ready"** line is a diagnostic of the whole vault, not the bar for calling a
94
+ session closed. It goes red for anything in the vault, including an uncommitted file
95
+ another session wrote, so on a shared vault a normal close can finish while it is still
96
+ red. A "close files updated" check alone is not enough to turn it green: a lint error in
97
+ a close file or a feedback projection over-cap keeps it red on its own.
96
98
  The live hook can still see a different set than this check does, because of
97
99
  `HYPO_SKIP_GATE` or a transcript-scoped lint error (pass `--transcript-path`
98
- to include the last). Note that neither one stops `/compact` any more: the
99
- hook reports what it finds and lets the compact through, so "Compact-ready"
100
- is the bar for calling a session closed, not a lock on the command.
101
- Pass `--session-id=<id>` to also see `marker_present`
102
- (step 7). `--project=<slug>` narrows the check to one project (a scoped
100
+ to include the last). Neither one stops `/compact` any more: the hook reports what it
101
+ finds and lets the compact through.
102
+ Pass `--session-id=<id>` to also see `marker_present` and `close_state` (step 7).
103
+ `--project=<slug>` narrows the check to one project (a scoped
103
104
  diagnostic, JSON `scope: "project"`): green there means only that slug is
104
105
  close-complete, **not** that every project in the vault is. Use the plain
105
- check for the go/no-go signal.
106
- 7. Record the session-closed marker. The Stop hook blocks until this
107
- session's per-session marker exists, and a hand-edit close (writing the files
108
- directly + committing) never writes it; the marker is written only by the
109
- crystallize writer, never by the hook (bypass guard). Normal path:
110
- close via `/hypo:crystallize` (`--apply-session-close --session-id=<id> --transcript-path=<path>`),
111
- which writes the marker once the gate is green. Hand-edit recovery: after
112
- committing the files, run `/hypo:crystallize` (`--mark-session-closed --session-id=<id> --transcript-path=<path>`).
113
- Both writers gate the marker on the SAME `precompactGateStatus` as `/compact`,
114
- so the marker only lands when step 6 would print **"Compact-ready"**.
106
+ check when you want to know whether the whole vault is clean.
107
+ 7. Record the close checkpoint. The Stop hook blocks until this session's close
108
+ checkpoint receipt (`.cache/sessions/<id>/close-receipt.json`) is valid, and a hand-edit
109
+ close (writing the files directly + committing) never writes one; the receipt
110
+ is filed only by the crystallize writer, never by the hook (bypass guard). A
111
+ compat marker (`.cache/session-closed-<id>.marker`) is written right after the
112
+ receipt, for consumers that have not been updated to read the receipt itself.
113
+ The receipt certifies only what it names: that the file versions this close
114
+ wrote are in a specific commit. It does not certify that every change this
115
+ session made is saved, so the Stop hook still surfaces any other uncommitted
116
+ vault change as a separate notice, once per close, even after the checkpoint
117
+ is recorded. Normal path: close via `/hypo:crystallize`
118
+ (`--apply-session-close --session-id=<id> --transcript-path=<path>`), which files the
119
+ checkpoint once the gate is green. Hand-edit recovery: after committing the
120
+ files, run `/hypo:crystallize` (`--mark-session-closed --session-id=<id> --transcript-path=<path>`).
121
+ Both writers gate the checkpoint on `precompactGateStatus`, the gate `/compact`
122
+ uses, with one difference: the git check is narrower. An uncommitted file
123
+ inside the project folder being closed (`projects/<project>/`) blocks whether
124
+ or not this session has a record of writing it. An uncommitted file at the
125
+ root or in another project's folder blocks only when this session wrote it
126
+ through Write or Edit since its last auto-commit, and is otherwise a notice
127
+ (another session's, one of unknown ownership, or one this session changed
128
+ through a shell command). If the record of this session's writes cannot be
129
+ read, the check does not block on it and adds a notice that it could not
130
+ determine ownership. So it can land while step 6 still shows a git blocker
131
+ for someone else's dirty file.
132
+ Every other check (close files, hot.md, lint, feedback) is the same as step 6.
133
+ **The session is closed once the checkpoint receipt is issued**: the writer's result
134
+ reports `markerWritten: true` (apply) or `ok: true` (`--mark`), and
135
+ `--check-session-close --session-id=<id>` then reports `close_state: closed`. Declare the
136
+ close on that, not on "Compact-ready". If the writer reports the marker as not written, or
137
+ `close_state` is anything other than `closed`, the session is still open whatever step 6 says.
138
+ If `close_state` is `broken` because the commit an earlier close proved was dropped from
139
+ history (a reset or rebase), `--mark-session-closed` refuses with
140
+ `prior-checkpoint-rewritten` and leaves the old receipt alone: restore that commit, or ask
141
+ the user to close again with a new payload.
115
142
  `--session-id` is not optional on the apply path. Before it writes anything, the
116
143
  apply reads that session's transcript for evidence the **user** asked to close, and
117
144
  refuses the whole close (exit 1, nothing on disk, nothing committed) when the id is
@@ -157,10 +184,11 @@ Skip session close for: single bug fix, single-file edit, Q&A only.
157
184
  projects/<name>/
158
185
  ├── index.md (working_dir: /path/to/repo)
159
186
  ├── prd.md
187
+ ├── hot.md (copy from projects/_template/hot.md, then fill in the name and `updated:`)
160
188
  └── session-state.md
161
189
  ```
162
190
 
163
- Add to root `hot.md` active projects table.
191
+ `hot.md` is the file that puts the project in the root table: the table is built by scanning `projects/*/hot.md`, so a project without one never gets a row, and `/hypo:resume` cannot find it from there. Copy it from `projects/_template/hot.md` rather than starting blank. Once it exists, the next session start or stop rebuilds root `hot.md` and the row appears on its own. The auto-project offer below creates all of these files for you.
164
192
 
165
193
  #### Auto-project offer
166
194
 
@@ -173,7 +201,7 @@ ignore it:**
173
201
  1. Ask the user with `AskUserQuestion` (or a plain Y/n question) whether to
174
202
  create the project.
175
203
  2. **On Yes** — run the scaffold helper once (it substitutes tokens, creates
176
- the project files, adds the root `hot.md` row, and logs the entry):
204
+ the project files, regenerates root `hot.md` so the new row appears, and logs the entry):
177
205
  ```
178
206
  node ${CLAUDE_PLUGIN_ROOT}/scripts/lib/project-create.mjs --name <slug> --working-dir "$(pwd)"
179
207
  ```
@@ -198,7 +226,7 @@ ignore it:**
198
226
 
199
227
  1. Write final `session-state.md` (mark as complete)
200
228
  2. Update `projects/<name>/index.md` status
201
- 3. Remove from root `hot.md` active table (or mark archived)
229
+ 3. There is no hand path to drop the root `hot.md` row: it is regenerated from `projects/*/hot.md` on every session start and stop, so the row stays as long as that file exists. To archive the project, move or delete `projects/<name>/hot.md` (or the whole project directory) so the next rebuild no longer finds it.
202
230
 
203
231
  ---
204
232
 
package/templates/hot.md DELETED
@@ -1,24 +0,0 @@
1
- ---
2
- title: Hot Cache — Pointer
3
- type: reference
4
- updated: YYYY-MM-DD
5
- tags: [wiki, operations]
6
- ---
7
-
8
- # Hot Cache
9
-
10
- > Read at session start → navigate to the relevant project session-state.md and hot.md.
11
- > Update at session close: project session-state.md, project hot.md, and this file's "Active Projects" table.
12
-
13
- ## Active Projects
14
-
15
- | Project | Last Session | Hot Cache |
16
- |---|---|---|
17
- <!-- Row format: | Project Name | YYYY-MM-DD | projects/<slug>/hot (wikilink) | -->
18
- <!-- col2 date is rebuilt from projects/<slug>/hot.md frontmatter on each session close -->
19
-
20
- ## Session Start Checklist
21
-
22
- 1. Check this file for the relevant project link
23
- 2. Read `projects/<name>/session-state.md` for next tasks if it exists
24
- 3. Read `projects/<name>/hot.md` for project background