hypomnema 1.8.4 → 1.9.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/marketplace.json +1 -1
- package/.claude-plugin/plugin.json +1 -1
- package/CHANGELOG.md +74 -0
- package/README.ko.md +17 -16
- package/README.md +15 -14
- package/commands/crystallize.md +89 -34
- package/commands/doctor.md +3 -1
- package/commands/feedback.md +10 -0
- package/docs/ARCHITECTURE.md +32 -9
- package/docs/CONTRIBUTING.md +6 -1
- package/hooks/atomic-write.mjs +44 -0
- package/hooks/base-store.mjs +409 -90
- package/hooks/close-gate-store.mjs +131 -16
- package/hooks/close-journal.mjs +141 -19
- package/hooks/close-receipt.mjs +564 -0
- package/hooks/hooks.json +2 -29
- package/hooks/hypo-auto-commit.mjs +80 -10
- package/hooks/hypo-auto-minimal-crystallize.mjs +129 -25
- package/hooks/hypo-auto-stage.mjs +13 -1
- package/hooks/hypo-close-guard.mjs +2 -1
- package/hooks/hypo-cwd-change.mjs +45 -20
- package/hooks/hypo-file-watch.mjs +44 -6
- package/hooks/hypo-first-prompt.mjs +15 -9
- package/hooks/hypo-hot-rebuild.mjs +169 -112
- package/hooks/hypo-personal-check.mjs +85 -7
- package/hooks/hypo-session-record.mjs +1 -1
- package/hooks/hypo-session-start.mjs +381 -18
- package/hooks/hypo-shared.mjs +2235 -214
- package/hooks/hypo-stop.mjs +207 -0
- package/hooks/proposal-store.mjs +166 -34
- package/hooks/shared.json +7 -1
- package/hooks/version-check.mjs +9 -7
- package/package.json +3 -1
- package/scripts/crystallize.mjs +6 -7
- package/scripts/doctor.mjs +529 -37
- package/scripts/feedback-sync.mjs +1786 -162
- package/scripts/feedback.mjs +16 -2
- package/scripts/init.mjs +32 -3
- package/scripts/lib/code-fence.mjs +197 -0
- package/scripts/lib/crystallize-close-apply.mjs +2023 -320
- package/scripts/lib/crystallize-close-check.mjs +62 -41
- package/scripts/lib/design-history-stale.mjs +117 -24
- package/scripts/lib/frontmatter.mjs +39 -0
- package/scripts/lib/git-hooks-dir.mjs +1 -1
- package/scripts/lib/hook-inventory.mjs +31 -1
- package/scripts/lib/page-usage.mjs +1 -1
- package/scripts/lib/pkg-provenance.mjs +7 -1
- package/scripts/lib/project-create.mjs +40 -44
- package/scripts/lib/schema-vocab.mjs +22 -11
- package/scripts/lib/template-schema-version.mjs +1 -0
- package/scripts/lib/time.mjs +46 -0
- package/scripts/lint.mjs +141 -27
- package/scripts/proposal.mjs +423 -18
- package/scripts/resume.mjs +3 -2
- package/scripts/session-audit.mjs +2 -1
- package/scripts/uninstall.mjs +15 -1
- package/scripts/upgrade.mjs +281 -90
- package/scripts/verify.mjs +2 -1
- package/scripts/weekly-report.mjs +2 -1
- package/templates/SCHEMA.md +27 -7
- package/templates/gitignore +11 -0
- package/templates/hypo-automation.md +11 -14
- package/templates/hypo-config.md +1 -1
- package/templates/hypo-guide.md +58 -26
- package/templates/hot.md +0 -24
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,75 @@ All notable changes to Hypomnema are documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [1.9.1] - 2026-10-12
|
|
9
|
+
|
|
10
|
+
### Bug Fixes
|
|
11
|
+
#### English
|
|
12
|
+
- feedback-sync keeps drafts and copies of your text out of git in a vault that is not a git repo (judged by what git really ignores), appends the managed block to CLAUDE.md instead of rewriting it, and no longer loses a "kept the hand-written line" notice from a run nobody saw. ([#314](https://github.com/sk-lim19f/Hypomnema/pull/314))
|
|
13
|
+
- feedback-sync drafts of your own CLAUDE.md and MEMORY.md text are now written under `.cache/feedback-drafts/`, only when the vault's git ignores `.cache/`, never over another file, and old drafts git can see are reported ([#313](https://github.com/sk-lim19f/Hypomnema/pull/313))
|
|
14
|
+
- `feedback-sync` adds `--accept-wiki` for hand-edited managed blocks, removes exactly the hand-written index line a promoted bootstrap draft came from, keeps a copy before every write that can destroy your own text, never overwrites a side file you edited, leaves marker examples inside code alone, and PreCompact and doctor now show edited side files and write-time warnings. ([#312](https://github.com/sk-lim19f/Hypomnema/pull/312))
|
|
15
|
+
- Lint ignores session-log and design-history headings inside code fences, HTML comments and frontmatter, ends a fence one session left open at the next session entry, and session close lists W19 (a heading date not on the calendar) as a non-blocking notice instead of printing "lint clean". ([#311](https://github.com/sk-lim19f/Hypomnema/pull/311))
|
|
16
|
+
- `--check-session-close` and the close docs no longer say `/compact` is blocked. The verdict line says what it measures, the text output names `close_state` with `--session-id`, and a receipt is described as recording the close checkpoint with the Stop hook having the final say. ([#310](https://github.com/sk-lim19f/Hypomnema/pull/310))
|
|
17
|
+
- A session-log heading with a date that is not on the calendar (`2026-02-30`, month 13) no longer invents a date or a day gap. Lint names it and tells you to fix it; when it is the only reason for a finding, it is a new non-blocking warning, W19, so a typo heading alone no longer blocks close. ([#309](https://github.com/sk-lim19f/Hypomnema/pull/309))
|
|
18
|
+
- When the vault sits inside a larger git repository under a directory whose name starts with a space, close and commit attribution now see the vault's uncommitted files instead of none. Paths printed by git are no longer trimmed, only their line ending is removed. ([#308](https://github.com/sk-lim19f/Hypomnema/pull/308))
|
|
19
|
+
- feedback-sync writes its MEMORY.md index lines as `- [Title](file): summary` and its learned-behavior lines as `- [date] rule. 근거: [[slug]]`, with no dash separator. Blocks written in the old form are rewritten once on the next sync, and `--bootstrap` reads both forms. ([#307](https://github.com/sk-lim19f/Hypomnema/pull/307))
|
|
20
|
+
#### 한국어
|
|
21
|
+
- git 저장소가 아닌 볼트에서도 feedback-sync 의 초안과 사용자 글 사본이 git 에 들어가지 않고(git 이 실제로 무시하는지로 판정), CLAUDE.md 를 다시 쓰지 않고 관리 블록을 덧붙이며, 아무도 보지 못한 실행의 "손으로 쓴 줄을 남겼다" 알림을 더 이상 잃지 않습니다. ([#314](https://github.com/sk-lim19f/Hypomnema/pull/314))
|
|
22
|
+
- 직접 쓴 CLAUDE.md·MEMORY.md 를 복사한 feedback-sync 초안을 이제 `.cache/feedback-drafts/` 에, 볼트의 git 이 `.cache/` 를 무시할 때만, 다른 파일을 덮지 않고 쓰며, git 이 볼 수 있는 옛 초안은 알려 줍니다 ([#313](https://github.com/sk-lim19f/Hypomnema/pull/313))
|
|
23
|
+
- `feedback-sync` 에 손으로 고친 관리 블록을 위한 `--accept-wiki` 가 생기고, 승격된 bootstrap 초안의 근거가 된 손 색인 줄만 정확히 지우며, 사용자 글을 지울 수 있는 쓰기 전에 항상 사본을 남기고, 사용자가 고친 side 파일을 덮지 않고, 코드 안의 마커 예시를 건드리지 않습니다. PreCompact 와 doctor 는 고친 side 파일과 쓰기 시점 경고를 보입니다. ([#312](https://github.com/sk-lim19f/Hypomnema/pull/312))
|
|
24
|
+
- lint 가 코드펜스, HTML 주석, frontmatter 안의 session-log·design-history 헤딩을 읽지 않고, 한 세션이 열어 둔 펜스를 다음 세션 항목에서 끊으며, session close 는 "lint clean" 대신 W19(달력에 없는 헤딩 날짜)를 막지 않는 알림으로 보입니다. ([#311](https://github.com/sk-lim19f/Hypomnema/pull/311))
|
|
25
|
+
- `--check-session-close` 와 close 문서가 더 이상 `/compact` 가 막혀 있다고 말하지 않습니다. 판정 줄은 실제로 재는 것을 말하고, `--session-id` 를 주면 텍스트 출력이 `close_state` 를 이름째로 보이며, 영수증은 close 체크포인트를 기록하는 것이고 최종 판정은 Stop 훅이 한다고 설명합니다. ([#310](https://github.com/sk-lim19f/Hypomnema/pull/310))
|
|
26
|
+
- 달력에 없는 날짜(`2026-02-30`, 13월)를 단 session-log 헤딩이 더 이상 날짜나 일 차이를 지어내지 않습니다. lint 가 그 헤딩을 짚어 고치라고 안내하고, 그것만이 이유일 때는 막지 않는 새 경고 W19 로 냅니다. 오타 헤딩 하나만으로는 close 가 막히지 않습니다. ([#309](https://github.com/sk-lim19f/Hypomnema/pull/309))
|
|
27
|
+
- 볼트가 더 큰 git 저장소 안에서 이름이 공백으로 시작하는 디렉터리 아래에 있을 때, close 와 커밋 귀속이 볼트의 미커밋 파일을 하나도 못 보던 문제를 고쳤습니다. git 이 출력한 경로는 더 이상 trim 하지 않고 줄 끝만 지웁니다. ([#308](https://github.com/sk-lim19f/Hypomnema/pull/308))
|
|
28
|
+
- feedback-sync 가 MEMORY.md 색인 줄을 `- [제목](파일): 설명`, learned-behavior 줄을 `- [날짜] 규칙. 근거: [[slug]]` 형식으로 대시 구분자 없이 씁니다. 옛 형식으로 쓰인 블록은 다음 동기화 때 한 번 다시 쓰이고, `--bootstrap` 은 두 형식을 모두 읽습니다. ([#307](https://github.com/sk-lim19f/Hypomnema/pull/307))
|
|
29
|
+
|
|
30
|
+
### Changelog
|
|
31
|
+
- [#314](https://github.com/sk-lim19f/Hypomnema/pull/314) fix(feedback-sync): keep user text out of git and stop losing notices an old hook never showed
|
|
32
|
+
- [#313](https://github.com/sk-lim19f/Hypomnema/pull/313) fix(feedback-sync): keep drafts of your own text out of git and never write over another file
|
|
33
|
+
- [#312](https://github.com/sk-lim19f/Hypomnema/pull/312) fix(feedback-sync): resolve hand-edited blocks and keep a copy before every destructive write
|
|
34
|
+
- [#311](https://github.com/sk-lim19f/Hypomnema/pull/311) fix(lint): ignore session-log headings in fences, comments and frontmatter, and show W19 at close
|
|
35
|
+
- [#310](https://github.com/sk-lim19f/Hypomnema/pull/310) fix(close): stop telling the model that /compact is blocked
|
|
36
|
+
- [#309](https://github.com/sk-lim19f/Hypomnema/pull/309) fix(lint): keep calendar-overflow session-log dates as written and report them as W19
|
|
37
|
+
- [#308](https://github.com/sk-lim19f/Hypomnema/pull/308) fix(hooks): keep spaces in git-printed paths, strip only the line ending
|
|
38
|
+
- [#307](https://github.com/sk-lim19f/Hypomnema/pull/307) fix(feedback-sync): write projected lines without a dash separator
|
|
39
|
+
Contributors: @sk-lim19f
|
|
40
|
+
|
|
41
|
+
## [1.9.0] - 2026-09-30
|
|
42
|
+
|
|
43
|
+
### New Features
|
|
44
|
+
#### English
|
|
45
|
+
- Stop hooks now run as one ordered chain, so the Stop commit no longer misses files the same Stop just rebuilt, and a failed step is reported instead of passing as a clean Stop. upgrade removes the old Stop registrations on npm installs so no step runs twice. A close that dies before its commit is no longer read as finished, and a subagent hand-back no longer cancels a close the user approved. Plugin users are pointed at `/hypo:doctor` and `/hypo:crystallize` wherever an npm-only command was named. The root `hot.md` is now generated from the projects' own `hot.md` at every session start and stop instead of being edited by hand at session close; whenever it finds root `hot.md` content it did not write, it saves that content as `hot.md.pre-projection-backup.md` before overwriting. ([#301](https://github.com/sk-lim19f/Hypomnema/pull/301))
|
|
46
|
+
#### 한국어
|
|
47
|
+
- Stop 훅이 순서대로 한 줄로 돌아, 같은 Stop 이 방금 다시 만든 파일을 Stop 커밋이 빠뜨리지 않고 실패한 단계는 정상 종료처럼 넘어가지 않고 보고됩니다. npm 설치에서 upgrade 가 옛 Stop 등록을 지워 어느 단계도 두 번 돌지 않습니다. 커밋 전에 죽은 close 를 끝난 것으로 읽지 않고, 서브에이전트 결과 반환이 사용자가 승인한 close 를 취소하지 않습니다. npm 전용 명령을 안내하던 자리마다 plugin 사용자에게 `/hypo:doctor` 와 `/hypo:crystallize` 를 함께 알려 줍니다. 루트 `hot.md` 는 이제 세션 close 때 손으로 고치지 않고, 세션을 시작하고 멈출 때마다 각 프로젝트의 `hot.md` 로 다시 만들어집니다. 생성기가 직접 쓰지 않은 내용을 발견하면, 덮어쓰기 전에 그 내용을 `hot.md.pre-projection-backup.md` 로 저장합니다. ([#301](https://github.com/sk-lim19f/Hypomnema/pull/301))
|
|
48
|
+
|
|
49
|
+
### Bug Fixes
|
|
50
|
+
#### English
|
|
51
|
+
- Session close no longer fails on another session's uncommitted root files: it issues a commit-backed close checkpoint receipt that certifies only the files this close wrote, blocks on this session's recorded writes and on uncommitted files in the project being closed, and reports the rest as notices; Stop, `--check-session-close` (new `close_state`), doctor and PreCompact now agree on when a close is finished. ([#305](https://github.com/sk-lim19f/Hypomnema/pull/305))
|
|
52
|
+
- lint and session close now reject dates that do not exist on the calendar (such as `2026-02-30`), and warn (W16) when a synthesis page's own `updated` is not a real date or when `sources_consulted` is written as a YAML block list ([#304](https://github.com/sk-lim19f/Hypomnema/pull/304))
|
|
53
|
+
- `doctor` now reports a plugin-plus-manual install on every run, and says the state is undetermined instead of advising an uninstall when the plugin's files cannot be located. `proposal list` shows each parked proposal's age and whether its target changed since it was parked. `hypo-cwd-change` and `hypo-file-watch` moved their notices onto a field the host does not ignore. ([#300](https://github.com/sk-lim19f/Hypomnema/pull/300))
|
|
54
|
+
- A proposal you approve now finishes the close that parked it, instead of leaving that close stuck re-running with nothing to show for it. `"restructure": true` no longer lets a payload approve its own destructive overwrite; a human approves the parked write. `doctor` names the hook files it reports missing, tells a real double registration apart from a healthy install, and distinguishes an approved-but-unfinished proposal from one awaiting review. New `hypomnema proposal reconcile` recovers an interrupted handoff without rewriting any page. ([#299](https://github.com/sk-lim19f/Hypomnema/pull/299))
|
|
55
|
+
#### 한국어
|
|
56
|
+
- 다른 세션의 미커밋 루트 파일 때문에 session close 가 실패하지 않습니다. close 는 이 close 가 쓴 파일만 증명하는 커밋 기반 close checkpoint receipt 를 발급하고, 이 세션이 기록한 쓰기와 close 하는 프로젝트 폴더의 미커밋 파일만 막으며 나머지는 알림으로 보고합니다. Stop, `--check-session-close`(새 `close_state`), doctor, PreCompact 가 close 완료 판정을 같이 합니다. ([#305](https://github.com/sk-lim19f/Hypomnema/pull/305))
|
|
57
|
+
- lint 와 세션 종료가 달력에 없는 날짜(`2026-02-30` 등)를 거절하고, synthesis 페이지 자신의 `updated` 가 실제 날짜가 아니거나 `sources_consulted` 를 YAML 블록 목록으로 쓴 경우 W16 경고를 냅니다 ([#304](https://github.com/sk-lim19f/Hypomnema/pull/304))
|
|
58
|
+
- `doctor`가 플러그인과 수동 설치의 공존을 매 실행 보고하고, 플러그인 파일을 못 찾으면 제거를 권하는 대신 판정 불가라고 말합니다. `proposal list`가 보류된 제안마다 나이와 대상이 파킹 이후 바뀌었는지를 보여 줍니다. `hypo-cwd-change`와 `hypo-file-watch`는 호스트가 무시하지 않는 필드로 알림을 옮겼습니다. ([#300](https://github.com/sk-lim19f/Hypomnema/pull/300))
|
|
59
|
+
- 승인한 proposal이 그것을 park한 close를 실제로 끝냅니다. 전에는 그 close가 아무 성과 없이 재실행만 반복했습니다. `"restructure": true`로 payload가 자기 파괴적 덮어쓰기를 승인할 수 없고, 파킹된 쓰기는 사람이 승인합니다. `doctor`가 누락된 훅 파일의 이름을 대고, 진짜 이중 등록을 정상 설치와 가르고, 승인됐지만 안 끝난 proposal을 검토 대기 중인 것과 구별합니다. 새 `hypomnema proposal reconcile`이 중단된 handoff를 페이지 수정 없이 복구합니다. ([#299](https://github.com/sk-lim19f/Hypomnema/pull/299))
|
|
60
|
+
|
|
61
|
+
### Chores
|
|
62
|
+
#### English
|
|
63
|
+
- The README and docs now say that the `cd` and file-change notices are brief terminal notifications that do not reach Claude, that the resume cue fires only when Claude moves directories in-session, and when the auto-project offer actually reaches Claude. The no-match notice no longer claims to inject the global `hot.md`. ([#303](https://github.com/sk-lim19f/Hypomnema/pull/303))
|
|
64
|
+
#### 한국어
|
|
65
|
+
- README 와 문서가 `cd` 알림과 파일 변경 알림은 Claude 에게 닿지 않는 짧은 터미널 알림이라는 것, 재개 신호는 Claude 가 세션 안에서 디렉터리를 옮길 때만 걸린다는 것, 프로젝트 자동 생성 제안이 실제로 Claude 에게 닿는 조건을 사실대로 설명합니다. 매칭되는 프로젝트가 없을 때의 알림도 더 이상 전역 `hot.md` 를 주입한다고 말하지 않습니다. ([#303](https://github.com/sk-lim19f/Hypomnema/pull/303))
|
|
66
|
+
|
|
67
|
+
### Changelog
|
|
68
|
+
- [#305](https://github.com/sk-lim19f/Hypomnema/pull/305) fix(close): certify only what a close wrote, so another session's uncommitted files no longer block it
|
|
69
|
+
- [#304](https://github.com/sk-lim19f/Hypomnema/pull/304) fix(lint): reject calendar-overflow dates, and warn when a synthesis's own updated is not a real date or sources_consulted is a block list
|
|
70
|
+
- [#303](https://github.com/sk-lim19f/Hypomnema/pull/303) docs(hooks): say what the cd and file-change notices actually reach, and when the auto-project offer shows
|
|
71
|
+
- [#302](https://github.com/sk-lim19f/Hypomnema/pull/302) refactor(scripts): share one day-length constant, and pin proposal age and failure branches with tests
|
|
72
|
+
- [#301](https://github.com/sk-lim19f/Hypomnema/pull/301) feat(hooks,close,upgrade): run Stop as one ordered chain, and keep close-intent until the commit
|
|
73
|
+
- [#300](https://github.com/sk-lim19f/Hypomnema/pull/300) fix(doctor,hooks): report a dual install without guessing, and stop parking bytes from being auto-deleted
|
|
74
|
+
- [#299](https://github.com/sk-lim19f/Hypomnema/pull/299) fix(close): carry approved proposals back to their close, and stop the writers that reported success while doing nothing
|
|
75
|
+
Contributors: @sk-lim19f
|
|
76
|
+
|
|
8
77
|
## [1.8.4] - 2026-09-14
|
|
9
78
|
|
|
10
79
|
### Bug Fixes
|
|
@@ -59,6 +128,11 @@ Contributors: @sk-lim19f
|
|
|
59
128
|
|
|
60
129
|
- 위키 결정 문서 포인터를 이 changelog 를 포함한 모든 공개 표면에서 없앴습니다. 레포가 그 문서를 담은 디렉터리를 출하하지 않아서, 관리자의 개인 기록 밖에 있는 독자에게는 아무것도 가리키지 않는 포인터였습니다. ([#294](https://github.com/sk-lim19f/Hypomnema/pull/294))
|
|
61
130
|
|
|
131
|
+
### Notes
|
|
132
|
+
|
|
133
|
+
- This version shipped on the plugin channel only. It was never tagged and never published to npm, so `npm view` does not list it.
|
|
134
|
+
- 이 버전은 플러그인 채널로만 나갔습니다. 태그와 npm 발행이 없어서 `npm view` 목록에는 없습니다.
|
|
135
|
+
|
|
62
136
|
## [1.8.2] - 2026-09-10
|
|
63
137
|
|
|
64
138
|
### Bug Fixes
|
package/README.ko.md
CHANGED
|
@@ -31,15 +31,15 @@ Andrej Karpathy의 "LLM 네이티브 위키" 스케치에서 출발했습니다.
|
|
|
31
31
|
|
|
32
32
|
- 신선도 신호. `verify_by_date`가 지난 페이지는 세션 시작 주입이나 lookup 주입 시 `[STALE ...]`로 표시되고, lookup 사용을 로컬에서 추적해 최근 90일간 lookup으로 주입된 적 없는 페이지를 crystallize가 cold 후보로 끌어올려 보여 줍니다.
|
|
33
33
|
- 피드백 한 곳만 고치면 나머지는 따라옵니다. `pages/feedback/`에 한 번 적으면 위키가 `MEMORY.md`와 `~/.claude/CLAUDE.md`의 `<learned_behaviors>` 블록을 자동으로 갱신합니다(단방향 projection).
|
|
34
|
-
-
|
|
35
|
-
- 프로젝트 자동 생성. 프로젝트 표식(`package.json`·`Cargo.toml` 등)이 있는 git
|
|
34
|
+
- Claude가 세션 안에서 셸 명령으로 디렉터리를 옮기면 재개 신호가 걸립니다. 옮긴 곳이 위키 프로젝트의 `working_dir`와 맞고 그 프로젝트 `hot.md`에 내용이 있으며 이 기기에서 보이는 경우, 이동 후 10분 안에 다음 프롬프트를 보내면 Claude의 응답이 "Resuming `<project>`" 한 줄로 시작합니다. (터미널에서 먼저 `cd`한 뒤 Claude를 여는 경우는 다른 경로입니다. `SessionStart`가 그 `hot.md`를 바로 컨텍스트에 넣어 주므로 별도 신호가 필요 없습니다.) 터미널 알림도 함께 뜨는데, 그 프로젝트 `hot.md`를 최대 3천 자까지 담습니다. 훅 문서는 이를 짧은 터미널 알림이라 하고 SDK 메시지 스트림에는 닿지 않는다고만 밝히며, 모델에 닿는지는 말하지 않습니다. Claude Code 2.1.276과 2.1.283의 동작을 분석한 결과로는 모델에 닿는 경로가 없었습니다(아래 전송 안내 참조). 모델에게 `hot.md`를 직접 보여 주려면 `/hypo:resume`을 부르세요.
|
|
35
|
+
- 프로젝트 자동 생성. 프로젝트 표식(`package.json`·`Cargo.toml` 등)이 있는 git 저장소에서 세션을 시작하면, 대응하는 위키 프로젝트가 없을 때 생성 제안이 Claude 컨텍스트에 바로 들어가서 그 자리에서 반응할 수 있습니다. 단 같은 디렉터리에 대한 같은 제안이 최근 5분 안에 이미 기록됐으면 뜨지 않습니다. 이 쿨다운은 세션 중 `cd` 경로, 그리고 `claude()` 셸 함수(아래 설치 안내 참조)가 세션 전에 한 번 돌리는 사전 실행과 함께 씁니다. 그래서 그 함수로 세션을 시작하면 Claude가 첫 프롬프트를 받기도 전에 제안이 이미 억제돼 있을 수 있습니다. 세션 도중 같은 조건의 디렉터리로 `cd`하면 같은 제안이 뜨지만, 위 재개 항목에서 설명한 터미널 토스트로만 나타나 Claude는 보지 못합니다. 한 번 거절한 디렉터리에는 제안이 다시 뜨지 않습니다. 제안이 보이지 않으면 기다리지 말고 Claude에게 직접 프로젝트를 만들어 달라고 요청하세요. 기본 `claude()` 함수로 시작하는 세션은 사전 실행이 쿨다운을 다시 기록하므로, 5분을 기다려도 자동 제안이 다시 뜬다는 보장은 없습니다.
|
|
36
36
|
- 세션 종료 자동 정리와 `/clear` 복구. 의미 있는 세션을 마치겠다고 신호하면 "마무리 메모를 짧게 남길까요?"가 자동으로 뜹니다. 단 진행 중인 작업(백그라운드 셸 작업이나 예약된 wake 포함)이 남아 있으면 강제로 닫거나 매 턴 다시 묻지 않고, 지금 닫을지만 되묻습니다. 마무리하지 않은 채 `/clear`를 입력해도 다음 세션 시작 때 이어서 정리할 수 있습니다.
|
|
37
37
|
|
|
38
38
|
버전별로 무엇이 바뀌었는지는 [CHANGELOG](CHANGELOG.md)에 있습니다.
|
|
39
39
|
|
|
40
40
|
업그레이드 정책 하나만 미리 알아 두세요. `hypomnema upgrade --apply`는 사용자가 직접 편집한 `SCHEMA.md`를 덮어쓰지 않습니다. 스키마가 올라가면 위키 루트에 마이그레이션 보고서만 써 주고, 실제 반영은 사용자가 직접 합니다(코드에서 Option C라고 부르는 정책).
|
|
41
41
|
|
|
42
|
-
같은 보류 방식이 세션 마무리 파일을 쓸 때에도 적용됩니다. 세션 종료 쓰기의 대상 파일이 이 세션이 읽은 뒤에 바뀌었다면 Hypomnema는 덮어쓰지 않습니다. 그 내용을 `<위키>/.cache/proposals/` 아래에 보류하고 알려 줍니다. 검토와 적용은 직접 하세요. `hypomnema proposal list`로 목록을 보고 터미널에서 `hypomnema proposal apply <id>` 또는 `hypomnema proposal discard <id>`를 씁니다. 세션 안에서는 타이핑할 터미널이 없으므로 같은 승인을 대화에서 받습니다. `hypomnema proposal challenge`가 diff를 보여 주고, 거기 적힌 줄을 직접 입력하면, `hypomnema proposal resolve`가 본 그대로를 씁니다. 자동 적용은 없습니다.
|
|
42
|
+
같은 보류 방식이 세션 마무리 파일을 쓸 때에도 적용됩니다. 세션 종료 쓰기의 대상 파일이 이 세션이 읽은 뒤에 바뀌었다면 Hypomnema는 덮어쓰지 않습니다. 그 내용을 `<위키>/.cache/proposals/` 아래에 보류하고 알려 줍니다. 검토와 적용은 직접 하세요. `hypomnema proposal list`로 목록을 보고 터미널에서 `hypomnema proposal apply <id>` 또는 `hypomnema proposal discard <id>`를 씁니다. 세션 안에서는 타이핑할 터미널이 없으므로 같은 승인을 대화에서 받습니다. `hypomnema proposal challenge`가 diff를 보여 주고, 거기 적힌 줄을 직접 입력하면, `hypomnema proposal resolve`가 본 그대로를 씁니다. 자동 적용은 없습니다. `list`는 보류마다 나이와 대상이 그 뒤에 움직였는지를 함께 보여 주어, diff를 일일이 열지 않고도 버릴 것을 고를 수 있습니다. 스스로 빠지는 것은 없습니다. 모든 제거는 사용자가 돌리는 `discard` 입니다.
|
|
43
43
|
|
|
44
44
|
자동처럼 보이지만 실제로는 직접 실행해야 하는 기능이 두 가지 있습니다. extensions sync와 역방향 capture입니다. 위키 안 `~/hypomnema/extensions/{agents,commands,hooks,skills}/`에 둔 파일은 `~/.claude/`에 반영되는데(`--codex`를 붙이면 `hooks`·`commands`는 `~/.codex/`에도), 직접 `hypomnema init`, `hypomnema upgrade --apply`, 또는 dry-run이 아닌 `hypomnema capture`를 돌려야만 반영됩니다. 저절로 밀어 넣는 트리거는 없습니다. `hypomnema capture`(또는 `/hypo:capture`)는 반대 방향으로, 직접 만든 command·agent·hook·skill을 위키로 가져오는 경로인데 이것도 마찬가지로 명시적으로 불러야 동작합니다. 자세한 내용은 아래 명령어 표를 보세요.
|
|
45
45
|
|
|
@@ -211,7 +211,11 @@ Hypomnema는 청크가 아니라 페이지를 지식 단위로 봅니다. 새
|
|
|
211
211
|
|
|
212
212
|
### 4. 왜 재개에 `hot.md` 캐시를 쓰는가
|
|
213
213
|
|
|
214
|
-
멈춘 프로젝트에서 가장 비싼 건 일을 다시 하는 게 아니라 컨텍스트를 다시 쌓는 일입니다. `session-log/`를 처음부터 다시 읽으면 분 단위 시간과 토큰이 들지만, 한 페이지짜리 `hot.md`를 읽는 건 둘 다 들지 않습니다. 그래서 최근 상태를
|
|
214
|
+
멈춘 프로젝트에서 가장 비싼 건 일을 다시 하는 게 아니라 컨텍스트를 다시 쌓는 일입니다. `session-log/`를 처음부터 다시 읽으면 분 단위 시간과 토큰이 들지만, 한 페이지짜리 `hot.md`를 읽는 건 둘 다 들지 않습니다. 그래서 최근 상태를 명시적으로 캐싱합니다. `hot.md`는 두 층입니다. 프로젝트별 `hot.md`는 세션 마무리(`crystallize`)가 쓰고, 볼트 루트의 `hot.md`는 그 파일들을 훑어 만드는 포인터 표입니다. 루트 쪽은 `SessionStart`와 `Stop`에서 훅이 다시 만드니 손으로 고치지 마세요. 둘 다 `SessionStart`에 주입됩니다. 재개는 O(1)입니다.
|
|
215
|
+
|
|
216
|
+
루트 `hot.md`는 훅이 만들어 내는 결과물이지, 손으로 편집하는 자리가 아닙니다. 거기 직접 써 넣은 내용은 다음번 재생성(다음 `SessionStart`나 `Stop`) 때 사라집니다. 훅이 만든 내용인지 사람이 쓴 내용인지 구분해서 판단할 방법이 없기 때문입니다. 파일 rename에는 범용 compare and swap이 없고, 편집기도 훅이 잡은 advisory lock을 따르지 않습니다. 그래서 훅은 자기가 쓴 내용인지 먼저 확인하고, 아니라고 판단되면 그 내용을 버리는 대신 `hot.md.pre-projection-backup.md`(둘 이상 쌓이면 `-2.md`, `-3.md`, ...)로 같은 자리에 백업해 둡니다. 다만 이 백업은 보장이 아니라 최선을 다한 구조일 뿐입니다. 재작성 도중에 저장이 겹치거나, 편집기가 제자리 저장 방식을 쓰면 백업이 일부만 담기거나 아예 안 남을 수도 있습니다. 안전망이지 쓰는 자리가 아니라는 뜻입니다.
|
|
217
|
+
|
|
218
|
+
백업을 다시 루트 `hot.md`로 되돌리지 마세요. 다음 훅 실행이 곧바로 또 덮어씁니다. 대신 백업 파일을 열어 읽어 보고, 남길 내용은 해당 프로젝트의 `projects/<slug>/hot.md`나 별도 페이지로 옮긴 뒤(어느 프로젝트 것인지는 훅이 판단 못 하니 사람이 정합니다) 백업을 지우세요. 볼트 전체에 얼마나 쌓였는지 보려면 볼트 루트에서 `ls hot.md.pre-projection-backup*.md`를 실행하면 됩니다.
|
|
215
219
|
|
|
216
220
|
### 5. 왜 feedback → behavior 파이프라인인가
|
|
217
221
|
|
|
@@ -252,20 +256,17 @@ Hypomnema는 청크가 아니라 페이지를 지식 단위로 봅니다. 새
|
|
|
252
256
|
| 훅 | 이벤트 | 역할 |
|
|
253
257
|
|---|---|---|
|
|
254
258
|
| `hypo-close-guard.mjs` | `PreToolUse` | Write/Edit/MultiEdit가 세션 마무리 쓰기로 보이는데 트랜스크립트에 사용자의 마무리 신호가 없으면, 파일이 바뀌기 전에 확인을 받음 |
|
|
255
|
-
| `hypo-session-start.mjs` | `SessionStart` | `hot.md` / `session-state.md` 주입
|
|
259
|
+
| `hypo-session-start.mjs` | `SessionStart` | `git pull --ff-only`, 루트 `hot.md` 투영 재생성, `hot.md` / `session-state.md` 주입 |
|
|
256
260
|
| `hypo-first-prompt.mjs` | `UserPromptSubmit` | 마커 기반으로 첫 프롬프트에 재개 한 줄을 요구한다(10분 TTL). `hot.md`를 다시 읽지는 않는다 |
|
|
257
261
|
| `hypo-lookup.mjs` | `UserPromptSubmit` | BM25 top-3 HIT 주입 / MISS면 가까운 슬러그 신호 |
|
|
258
262
|
| `hypo-compact-guard.mjs` | `UserPromptSubmit` | 채팅에 입력된 `/compact`나 `/clear`를 감지해 마무리가 덜 됐으면 알린다. compact 자체는 막지 않는다 |
|
|
259
|
-
| `hypo-cwd-change.mjs` | `CwdChanged` | cwd에 맞는 프로젝트 `hot.md`로
|
|
260
|
-
| `hypo-file-watch.mjs` | `FileChanged` | 바뀐 위키 파일로
|
|
263
|
+
| `hypo-cwd-change.mjs` | `CwdChanged` | cwd에 맞는 프로젝트 `hot.md`로 알림을 만든다(아래 전송 안내 참조) |
|
|
264
|
+
| `hypo-file-watch.mjs` | `FileChanged` | 바뀐 위키 파일로 알림을 만든다(`.hypoignore` 준수). 이 패키지는 감시 경로를 등록하지 않아 기본 설치에서는 이벤트가 발생할 계기 자체가 없다(아래 전송 안내 참조) |
|
|
261
265
|
| `hypo-auto-stage.mjs` | `PostToolUse(Write/Edit/MultiEdit)` | 위키 파일 자동 stage |
|
|
262
|
-
| `hypo-
|
|
263
|
-
| `hypo-
|
|
264
|
-
| `hypo-
|
|
265
|
-
| `hypo-
|
|
266
|
-
| `hypo-session-record.mjs` | `Stop` | observability 점수 + auto-resume 신호용 세션 메타데이터 기록 |
|
|
267
|
-
| `hypo-auto-minimal-crystallize.mjs` | `Stop` | 사용자가 마무리를 신호한 뒤, 의미 있는 작업을 했는데 세션 마무리가 확인되지 않으면 Stop을 막고 `crystallize.mjs --mark-session-closed` 명령을 돌려줌. 미커밋 변경이나 진행 중인 작업이 있으면 명령 대신 지금 닫을지 되물음 |
|
|
268
|
-
| `hypo-web-fetch-ingest.mjs` | `PostToolUse(WebFetch/WebSearch)` | WebFetch/WebSearch 뒤 `additionalContext`에 `/hypo:ingest` 권유 주입 (URL의 query/hash/userinfo 제거) |
|
|
266
|
+
| `hypo-stop.mjs` | `Stop` | 등록된 유일한 `Stop` 훅이다. 네 단계를 병렬이 아니라 순서대로 돌린다: 루트 `hot.md` 투영 재생성(`SessionStart`도 같은 생성기를 부른다), observability 점수와 auto-resume 신호용 세션 메타데이터 기록, commit + pull + push, 그리고 사용자가 마무리를 신호한 뒤 의미 있는 작업을 했는데 마무리가 확인되지 않으면 Stop을 막고 `crystallize.mjs --mark-session-closed` 명령을 돌려준다(미커밋 변경이나 진행 중인 작업이 있으면 명령 대신 지금 닫을지 되묻는다) |
|
|
267
|
+
| `hypo-personal-check.mjs` | `PreCompact` | session-close 미완, 위키 커밋/푸시 누락, hot.md 구조 위반, lint 블로커를 `systemMessage`로 알린다. `/compact`는 여기서 막지 않는다. 세션 마무리 강제는 다른 자리에 남아 있다: `hypo-stop.mjs`의 crystallize 단계가 마무리 확인 없는 의미 있는 세션을 막고, `--mark-session-closed`는 여전히 red 게이트에서 마커를 거부한다 |
|
|
268
|
+
| `hypo-session-end.mjs` | `SessionEnd` | SessionEnd 마커를 기록해 다음 SessionStart가 `source=clear` 복구를 감지하게 한다 |
|
|
269
|
+
| `hypo-web-fetch-ingest.mjs` | `PostToolUse(WebFetch/WebSearch)` | WebFetch/WebSearch 뒤 `additionalContext`에 `/hypo:ingest` 권유를 주입한다(URL의 query/hash/userinfo는 제거) |
|
|
269
270
|
|
|
270
271
|
PostToolUse 훅 둘은 matcher 없이 등록되고 각자 tool_name으로 거릅니다.
|
|
271
272
|
|
|
@@ -396,7 +397,7 @@ E. 멈춘 프로젝트 재개.
|
|
|
396
397
|
|
|
397
398
|
`HYPO_SKIP_GATE=1`은 세션 중간에 사용자를 막을 수 있는 게이트가 존중합니다. `hypo-compact-guard`, `hypo-close-guard`, `hypo-auto-minimal-crystallize`, 그리고 `hypo-web-fetch-ingest`의 ingest 안내가 여기 해당합니다. `hypo-personal-check`(PreCompact)도 이 플래그를 읽지만, 이 훅은 이제 `/compact`를 막지 않으므로 플래그는 반복될 뻔한 미완성-마무리 `systemMessage`만 억제합니다. 기록할 필요 없는 가벼운 세션에 씁니다.
|
|
398
399
|
|
|
399
|
-
> 모델 제공사에게 전송되는 범위: Hypomnema 훅은 위키 본문을 Claude Code의 추가 컨텍스트(`additionalContext`)에 실어 보내고, 이 내용은 프롬프트의 일부로 Claude 모델 제공사로 전송됩니다. 이 경로가 실제로 모델까지 닿는 것은 `hypo-session-start`와 `hypo-lookup`입니다. `hypo-cwd-change`와 `hypo-file-watch`는 `CwdChanged`와 `FileChanged` 이벤트에서 동작하는데, Claude Code가 이
|
|
400
|
+
> 모델 제공사에게 전송되는 범위: Hypomnema 훅은 위키 본문을 Claude Code의 추가 컨텍스트(`additionalContext`)에 실어 보내고, 이 내용은 프롬프트의 일부로 Claude 모델 제공사로 전송됩니다. 이 경로가 실제로 모델까지 닿는 것은 `hypo-session-start`와 `hypo-lookup`입니다. `hypo-cwd-change`와 `hypo-file-watch`는 대신 `CwdChanged`와 `FileChanged` 이벤트에서 동작하는데, 두 이벤트 모두 `additionalContext` 필드를 문서화하지 않습니다. 훅 문서는 이 두 이벤트 출력에서 Claude Code가 읽는 필드로 `watchPaths`와 `systemMessage`만 적고, "대화형 세션에서는 `systemMessage`를 짧은 터미널 알림으로 보여줍니다"와 "이 메시지는 SDK 메시지 스트림에 닿지 않습니다"라고만 말할 뿐, 모델에 닿는지는 어느 쪽으로도 밝히지 않습니다. 문서 자체가 이 물음을 열어 두고 있는 셈입니다. 2026-09-18 기준 Claude Code 2.1.276을 직접 뜯어 추적하고 2.1.283에서 다시 확인해 봐도, 그 터미널 알림에서 모델로 가는 경로는 찾지 못했습니다. 실세션에서 이 경로를 직접 관찰한 기록도 없습니다. 문서가 뒤집기 전까지는 `CwdChanged`와 `FileChanged`를 모델에 닿지 않는 것으로 다룹니다. `hypo-file-watch`는 기본 설치 기준으로 트리거 자체가 없습니다. 이 그룹은 matcher 키 자체가 없는데(빈 문자열이 아닙니다), 훅 문서는 생략된 matcher가 감시 중인 파일 전부에 매치되면서 감시 목록에는 아무것도 더하지 않는다고 적습니다. 이 패키지 안 어디서도 `watchPaths`를 내서 그 목록에 씨를 뿌리지 않으니, 기본 설치라면 이 패키지 때문에 위키 파일이 감시 대상에 오르는 일은 없습니다. 다만 감시 목록은 이 플러그인 전용이 아니라 세션 전역이라서, 사용자의 `settings.json`이나 함께 설치된 다른 플러그인이 목록에 씨를 뿌리면 matcher가 없는 이 그룹은 위키 파일뿐 아니라 감시 중인 모든 파일에서 발화합니다. 그런 경우에도 이 훅 자체가 `HYPO_DIR`로 시작하지 않는 경로에는 즉시 되돌아가므로(`hooks/hypo-file-watch.mjs` 참고, 문자열 접두사 검사라 symlink는 풀지 않습니다), 다른 데서 씨 뿌려진 감시가 위키 밖 경로를 직접 가리키게 만들지는 못합니다. 다만 이 검사는 경로 문자열만 보므로, 위키 안에 있으면서 밖을 가리키는 symlink는 여전히 `HYPO_DIR`로 시작해 통과하고, 이 훅은 그 링크를 따라 읽으므로 그런 symlink가 있으면 가리키는 곳의 내용이 그대로 실릴 수 있습니다. `.hypoignore`는 출력이 모델까지 닿는지와 무관하게 이 네 훅 모두와 `ingest`에서 적용됩니다. 등록하지 않은 파일은 모델에 닿는 두 훅이 그대로 전송합니다. (`hypo-auto-stage`/`hypo-auto-commit`은 git 스테이징용 훅이라 컨텍스트를 주입하지는 않지만, 스테이징 판단에도 `.hypoignore`를 참고합니다.) 비밀 정보는 위키에 두지 마시고, `HYPO_DIR` 아래에 민감한 내용을 저장하기 전에 `.hypoignore` 패턴을 먼저 점검하세요.
|
|
400
401
|
|
|
401
402
|
> git sync 범위: Hypomnema는 `~/hypomnema/` 위키 자체만 git sync합니다. 단 `init` / `upgrade`는 `~/.claude/` 안의 관리 대상 영역(Hypomnema 자체 hook `~/.claude/hooks/`, 슬래시 커맨드 `~/.claude/commands/hypo/`, `settings.json` 등록)을 설치·SHA 추적하고, extensions companion sync로 위키의 `~/hypomnema/extensions/`에 둔 `agents/`·`commands/`·`hooks/`·`skills/`도 미러링합니다(직접 `init`·`upgrade --apply`·`capture`를 돌릴 때. `--codex`면 `hooks`·`commands` 부분집합만 `~/.codex/`로). 이 관리 대상 바깥에 있는 `~/.claude/` 콘텐츠는 일부러 관리하지 않습니다. 위키를 거치지 않는 기타 agent/skill, 머신 고유 `settings.local.json` 같은 일반 Claude Code 설정의 기기 간 동기화는 [chezmoi](https://www.chezmoi.io/) 같은 별도 dotfiles 매니저를 권합니다.
|
|
402
403
|
|
|
@@ -435,7 +436,7 @@ Claude(또는 다른 코딩 에이전트)로서 Hypomnema 위키를 운영한다
|
|
|
435
436
|
|
|
436
437
|
위키가 단일 원천입니다. 사용자가 기억해 달라고 한 것은 전부 위키 루트 아래 마크다운으로 있고, 기억에 의존해 답하기 전에 그것부터 읽습니다. 한 프로젝트의 배경은 `projects/<name>/hot.md`에, 다음에 할 일은 `projects/<name>/session-state.md`에 있으며 `/hypo:resume`이 둘 다 불러옵니다. 위키 루트의 `hot.md`는 다른 파일입니다. 어떤 프로젝트가 활성인지 가리키는 포인터 테이블입니다.
|
|
437
438
|
|
|
438
|
-
그 상태를 위키 밖에 또 두지 마세요. `MEMORY.md`와 `~/.claude/CLAUDE.md`의 `<learned_behaviors>` 블록은 스스로의 메모리처럼 보이지만, Hypomnema가 `pages/feedback/`에서 뽑아내는 단방향 projection입니다. 교정은 `/hypo:feedback`으로 적고 동기화가 다시 만들게 두면 됩니다. projection을 손으로 고치면 다음 동기화가 그것을 병합하지 않고 conflict로 멈춥니다. 어느 쪽이 진실인지 판단할 근거가 없기 때문이고, 그때부터 feedback 페이지로 되돌려 정리하는 일이 남습니다. 위키에 있어야 할 내용을 혼자만 보는 곳에 따로 챙겨 두면, 사용자의 다른 기기에는 끝내 닿지 않습니다.
|
|
439
|
+
그 상태를 위키 밖에 또 두지 마세요. `MEMORY.md`와 `~/.claude/CLAUDE.md`의 `<learned_behaviors>` 블록은 스스로의 메모리처럼 보이지만, Hypomnema가 `pages/feedback/`에서 뽑아내는 단방향 projection입니다. 교정은 `/hypo:feedback`으로 적고 동기화가 다시 만들게 두면 됩니다. projection을 손으로 고치면 다음 동기화가 그것을 병합하지 않고 conflict로 멈춥니다. 어느 쪽이 진실인지 판단할 근거가 없기 때문이고, 그때부터 feedback 페이지로 되돌려 정리하는 일이 남습니다. 손으로 고친 내용이 위키가 쓸 내용과 이미 같다면 예외로, 다음 `--write`가 그대로 받아들입니다. 충돌한 블록을 위키 버전으로 되돌리려면 먼저 `hypomnema feedback-sync --import-target-change --from=<target>`으로 고친 내용을 초안으로 남겨 두고, 이어서 `hypomnema feedback-sync --accept-wiki=<slug>`를 실행하세요. 위키에 있어야 할 내용을 혼자만 보는 곳에 따로 챙겨 두면, 사용자의 다른 기기에는 끝내 닿지 않습니다.
|
|
439
440
|
|
|
440
441
|
`sources/`는 불변입니다. 그 아래는 무엇도 고치지 않습니다. 대신 `pages/`로 합성하고 출처를 링크로 되짚습니다.
|
|
441
442
|
|
package/README.md
CHANGED
|
@@ -31,8 +31,8 @@ An observability score measures how often the wiki is actually used per session.
|
|
|
31
31
|
|
|
32
32
|
- Freshness signaling. A page whose `verify_by_date` has passed is flagged `[STALE ...]` when it's injected at session start or via lookup, and lookup usage is tracked locally so crystallize can surface a page not injected via lookup in the last 90 days as a cold candidate.
|
|
33
33
|
- Edit feedback in one place and the rest follows. `pages/feedback/` is the single source of truth for behavior corrections, and Hypomnema derives `MEMORY.md` and the `<learned_behaviors>` block inside `~/.claude/CLAUDE.md` from it automatically.
|
|
34
|
-
- Project-aware resume
|
|
35
|
-
- Auto-project creation.
|
|
34
|
+
- Project-aware resume when Claude changes directories in-session. When Claude runs a shell command that moves the working directory to one matching a wiki project's `working_dir`, and that project's `hot.md` has content and is visible on this machine, it arms a one-line "Resuming `<project>`" cue: Claude's reply leads with that line, as long as your next prompt comes within 10 minutes of the move. (`cd`ing in the terminal before you start Claude takes a different path: `SessionStart` puts that `hot.md` directly in context, no cue needed.) A terminal notification also fires, carrying up to 3,000 characters of that project's `hot.md`. Per the hook reference it is a brief terminal notification that doesn't reach the SDK message stream; the reference doesn't say whether it reaches the model, and tracing Claude Code 2.1.276 and 2.1.283 found no path that does (see the transmission note below). To put the project's `hot.md` in front of the model, run `/hypo:resume`.
|
|
35
|
+
- Auto-project creation. Starting a session inside a git repo with a project marker (`package.json`, `Cargo.toml`, etc.) and no matching wiki project puts the create-a-project offer in Claude's own context, so it can act on it right away, provided the same offer for that exact directory has not already fired in the last 5 minutes. That cooldown is shared with the mid-session `cd` path and with the `claude()` shell function's throwaway pre-run (see the shell-setup note under installation), so a session launched through that function can find the offer already suppressed before Claude ever sees a prompt. `cd`ing into the same kind of directory mid-session raises the identical offer, but only as the terminal toast described in the resume bullet above, which Claude never sees. A directory you declined once is never offered again. If the offer doesn't show, ask Claude to create the project directly rather than waiting: a session started through the default `claude()` function records the cooldown again in its pre-run, so waiting 5 minutes does not guarantee the offer comes back.
|
|
36
36
|
- Session-close cleanup and `/clear` recovery. When you signal wrap-up after a non-trivial session, a "save a minimal session-close note?" prompt appears automatically, but not if work is still in flight (a running background shell task or a scheduled wake); in that case Hypomnema asks whether to close now instead of forcing it or nagging every turn. A `/clear` after a forgotten close is detected and recovered at the next session start.
|
|
37
37
|
|
|
38
38
|
> The `<learned_behaviors>` projection has one precondition, and no install step sets it up for you: `~/.claude/CLAUDE.md` must contain an empty `<learned_behaviors></learned_behaviors>` pair. Without it every sync is a silent no-op and no global rule loads. Run `hypomnema feedback-sync --ensure-container` once after install; it appends the pair to an existing `CLAUDE.md`, is idempotent, and refuses rather than guessing if the container is malformed. If you have no `CLAUDE.md` at all it is a no-op, so create the file first. Confirm with `hypomnema feedback-sync --check`; `/hypo:doctor` reports the broken state as a Feedback projection failure.
|
|
@@ -209,7 +209,11 @@ Once installed, you stop _managing_ the wiki. It just accumulates.
|
|
|
209
209
|
|
|
210
210
|
### 4. Why a `hot.md` cache for resume
|
|
211
211
|
|
|
212
|
-
The most expensive part of a paused project isn't redoing the work, it's rebuilding context. Reading `session-log/` from scratch costs minutes and tokens; reading a one-page `hot.md` costs neither. So we cache the most recent state explicitly: the root `hot.md` pointer table
|
|
212
|
+
The most expensive part of a paused project isn't redoing the work, it's rebuilding context. Reading `session-log/` from scratch costs minutes and tokens; reading a one-page `hot.md` costs neither. So we cache the most recent state explicitly: the root `hot.md` pointer table is a projection rebuilt from every project's own `hot.md` on both `SessionStart` and `Stop`, never hand-edited, while each project's own `hot.md` is written by crystallize; both get injected on `SessionStart`. Resume is O(1).
|
|
213
|
+
|
|
214
|
+
The root `hot.md` is a generated file, not a place to edit by hand. Whatever you type into it will be replaced the next time a hook rebuilds the projection (the next `SessionStart` or `Stop`), because the projection has no way to tell "content worth keeping" from "content in the way": there's no general-purpose compare-and-swap for a file rename, and your editor doesn't honor the advisory lock the hook takes. The first time the projection overwrites content it doesn't recognize as its own, it backs that content up next to the file as `hot.md.pre-projection-backup.md` (or `-2.md`, `-3.md`, ... if more than one has piled up), so nothing is silently discarded. But that backup is a best-effort save, not a safety guarantee: a save that lands mid-rewrite, or an editor that saves in place, can still leave a partial or missing copy. Treat it as a rescue net, not a place to write.
|
|
215
|
+
|
|
216
|
+
Don't copy a backup back into the root `hot.md`. The next hook run will just replace it again. Instead: open the backup, read it, move whatever's worth keeping into the right project's `projects/<slug>/hot.md` or a standalone page (you decide which project it belongs to, the hook can't), then delete the backup. To see how many have piled up across the vault, list them from the vault root: `ls hot.md.pre-projection-backup*.md`.
|
|
213
217
|
|
|
214
218
|
### 5. Why a feedback → behavior pipeline
|
|
215
219
|
|
|
@@ -248,19 +252,16 @@ Nine commands cover the full capture → retrieval → consolidation cycle.
|
|
|
248
252
|
| Hook | Event | Role |
|
|
249
253
|
|---|---|---|
|
|
250
254
|
| `hypo-close-guard.mjs` | `PreToolUse` | When a Write/Edit/MultiEdit looks like a session-close write and the transcript carries no close signal from you, ask before it lands |
|
|
251
|
-
| `hypo-session-start.mjs` | `SessionStart` |
|
|
255
|
+
| `hypo-session-start.mjs` | `SessionStart` | `git pull --ff-only`, rebuild the root `hot.md` projection, inject `hot.md` / `session-state.md` |
|
|
252
256
|
| `hypo-first-prompt.mjs` | `UserPromptSubmit` | Marker-based one-shot request for a resume line on the first prompt (10-min TTL). It does not re-read `hot.md` |
|
|
253
257
|
| `hypo-lookup.mjs` | `UserPromptSubmit` | BM25 top-3 HIT inject / MISS → closest-slug signal |
|
|
254
258
|
| `hypo-compact-guard.mjs` | `UserPromptSubmit` | Detect a typed `/compact` or `/clear` and report an incomplete session close. It never blocks the compact |
|
|
255
|
-
| `hypo-cwd-change.mjs` | `CwdChanged` | Build
|
|
256
|
-
| `hypo-file-watch.mjs` | `FileChanged` | Build
|
|
259
|
+
| `hypo-cwd-change.mjs` | `CwdChanged` | Build a notice from the matching project's `hot.md` (see the transmission note below) |
|
|
260
|
+
| `hypo-file-watch.mjs` | `FileChanged` | Build a notice for a changed wiki file (honors `.hypoignore`); nothing in this package registers watch paths, so on a stock install the event has no trigger here at all (see the transmission note below) |
|
|
257
261
|
| `hypo-auto-stage.mjs` | `PostToolUse(Write/Edit/MultiEdit)` | Auto-stage wiki-file edits |
|
|
258
|
-
| `hypo-
|
|
259
|
-
| `hypo-
|
|
260
|
-
| `hypo-personal-check.mjs` | `PreCompact` | Surfaces an unfinished session-close, an uncommitted or unpushed wiki, malformed `hot.md`, or lint blockers as a `systemMessage`; it never blocks `/compact`. Session close is still enforced elsewhere: the Stop hook (`hypo-auto-minimal-crystallize.mjs`) blocks on a substantial session with no verified close, and `--mark-session-closed` still refuses the marker on a red gate |
|
|
262
|
+
| `hypo-stop.mjs` | `Stop` | The only registered `Stop` hook. Runs four stages in order, not in parallel: rebuild the root `hot.md` projection (`SessionStart` calls the same generator), record session metadata for the observability score and auto-resume signaling, commit + pull + push, then, after the user signals wrap-up, block `Stop` on a substantial session with no verified close and hand back the `crystallize.mjs --mark-session-closed` command (with uncommitted changes or work still in flight it asks whether to close now instead) |
|
|
263
|
+
| `hypo-personal-check.mjs` | `PreCompact` | Surfaces an unfinished session-close, an uncommitted or unpushed wiki, malformed `hot.md`, or lint blockers as a `systemMessage`; it never blocks `/compact`. Session close is still enforced elsewhere: `hypo-stop.mjs`'s crystallize stage blocks on a substantial session with no verified close, and `--mark-session-closed` still refuses the marker on a red gate |
|
|
261
264
|
| `hypo-session-end.mjs` | `SessionEnd` | Write a SessionEnd marker so SessionStart can detect `source=clear` recovery |
|
|
262
|
-
| `hypo-session-record.mjs` | `Stop` | Record session metadata for the observability score and auto-resume signaling |
|
|
263
|
-
| `hypo-auto-minimal-crystallize.mjs` | `Stop` | After the user signals wrap-up, blocks Stop on a substantial session with no verified close and hands back the `crystallize.mjs --mark-session-closed` command. With uncommitted changes or work still in flight it asks whether to close now instead |
|
|
264
265
|
| `hypo-web-fetch-ingest.mjs` | `PostToolUse(WebFetch/WebSearch)` | Inject a `/hypo:ingest` nudge into `additionalContext` after a WebFetch (URL redacted of query/hash/userinfo) or a WebSearch |
|
|
265
266
|
|
|
266
267
|
Both PostToolUse hooks are registered without a matcher and filter on `tool_name` themselves.
|
|
@@ -394,9 +395,9 @@ Place a `hypo-config.md` at the wiki root to make it portable across machines wi
|
|
|
394
395
|
|
|
395
396
|
> Gate bypass: `HYPO_SKIP_GATE=1` is honored by every gate that can stop you mid-session: `hypo-compact-guard`, `hypo-close-guard`, `hypo-auto-minimal-crystallize`, and the ingest nudge in `hypo-web-fetch-ingest`. `hypo-personal-check` (PreCompact) also reads the flag, but since that hook never blocks `/compact` anymore, the flag only suppresses the incomplete-close `systemMessage` it would otherwise repeat. Set it for a trivial session you do not want recorded.
|
|
396
397
|
|
|
397
|
-
> If a session-close write finds its target changed since this session read it, Hypomnema does not overwrite it. It parks the bytes under `<wiki>/.cache/proposals/` and tells you. Review and apply them yourself: `hypomnema proposal list`, then `hypomnema proposal apply <id>` (at a terminal) or `hypomnema proposal discard <id>`. Inside a session, where there is no terminal to type at, the same approval is collected in the conversation: `hypomnema proposal challenge` prints the diffs, you type the line it gives you, and `hypomnema proposal resolve` writes exactly what you saw. There is no auto-apply.
|
|
398
|
+
> If a session-close write finds its target changed since this session read it, Hypomnema does not overwrite it. It parks the bytes under `<wiki>/.cache/proposals/` and tells you. Review and apply them yourself: `hypomnema proposal list`, then `hypomnema proposal apply <id>` (at a terminal) or `hypomnema proposal discard <id>`. Inside a session, where there is no terminal to type at, the same approval is collected in the conversation: `hypomnema proposal challenge` prints the diffs, you type the line it gives you, and `hypomnema proposal resolve` writes exactly what you saw. There is no auto-apply. `list` shows each park's age and whether its target moved since, so you can pick what to drop without opening every diff. Nothing leaves on its own: every removal is a `discard` you run.
|
|
398
399
|
|
|
399
|
-
> Provider transmission disclaimer: Hypomnema hooks emit wiki content into Claude Code's `additionalContext`, which is transmitted to the Claude model provider as part of the prompt. That path actually reaches the model for `hypo-session-start` and `hypo-lookup`. `hypo-cwd-change` and `hypo-file-watch` fire on `CwdChanged` and `FileChanged
|
|
400
|
+
> Provider transmission disclaimer: Hypomnema hooks emit wiki content into Claude Code's `additionalContext`, which is transmitted to the Claude model provider as part of the prompt. That path actually reaches the model for `hypo-session-start` and `hypo-lookup`. `hypo-cwd-change` and `hypo-file-watch` fire on `CwdChanged` and `FileChanged` instead, and neither event documents an `additionalContext` field: the hook reference documents `watchPaths` and `systemMessage` as the fields Claude Code reads from these two events' output, and says only, "it shows the `systemMessage` as a brief terminal notification" and "the message doesn't reach the SDK message stream," without saying either way whether it reaches the model. So the reference itself leaves that open. Tracing the installed Claude Code binary (2.1.276, checked 2026-09-18, and reconfirmed on 2.1.283) found no branch that forwards that terminal notification to the model. No live-session observation of this path exists either way. Until the documentation says otherwise, we treat `CwdChanged` and `FileChanged` as not reaching the model. `hypo-file-watch` additionally has no registered trigger on a stock install: the group's matcher key is omitted (not an empty string), which the reference says matches every watched file while adding nothing to the watch list, and nothing in this package returns `watchPaths` to seed that list, so on a stock install nothing here ever puts a wiki file under watch. The watch list is session-global, though, not scoped to this plugin: your own `settings.json` or another installed plugin can seed it, and if anything else does, this matcher-less group fires for every watched file, not only wiki ones. Even then, the hook itself returns immediately for any path that does not start with `HYPO_DIR` (see `hooks/hypo-file-watch.mjs`; a string-prefix check, not one that resolves symlinks), so a watch seeded elsewhere cannot point it at a path outside the wiki. That check only looks at the path string, though: a symlink that lives inside the wiki and points outside it still starts with `HYPO_DIR`, and the hook reads through it, so such a symlink can still surface content from wherever it points. `.hypoignore` is enforced at all four of these hooks (whether or not their output reaches the model) and at `ingest`, but any file _not_ matched by `.hypoignore` is fair game for transmission through the two hooks that do reach the model. (`hypo-auto-stage` and `hypo-auto-commit` are git-staging hooks, not injection points, and also honor `.hypoignore` for their staging decisions.) Keep secrets out of the wiki, and review `.hypoignore` patterns before storing anything sensitive under `HYPO_DIR`.
|
|
400
401
|
|
|
401
402
|
> Scope of git sync: Hypomnema git-syncs only the `~/hypomnema/` wiki itself. `init` / `upgrade` do install and SHA-track a defined surface inside `~/.claude/`: Hypomnema's own hooks at `~/.claude/hooks/`, slash commands at `~/.claude/commands/hypo/`, and `settings.json` registrations. The extensions companion sync covers one more surface: whatever you put in `~/hypomnema/extensions/` (`agents/`, `commands/`, `hooks/`, `skills/`) lands in `~/.claude/`. With `--codex`, hooks and commands also go to `~/.codex/`. Anything _outside_ that defined surface in `~/.claude/` is intentionally not managed by Hypomnema. For general cross-machine sync of Claude Code config (other agents/skills not staged via the wiki, machine-specific `settings.local.json`, etc.), use a separate dotfiles manager such as [chezmoi](https://www.chezmoi.io/).
|
|
402
403
|
|
|
@@ -435,7 +436,7 @@ If you are Claude (or another coding agent) operating a Hypomnema wiki, these ar
|
|
|
435
436
|
|
|
436
437
|
The wiki is the single source of truth. Everything the user asked you to remember about their work is markdown under the wiki root, and you read it before answering from recollection. `projects/<name>/hot.md` holds the background for one project, `projects/<name>/session-state.md` holds what to do next, and `/hypo:resume` loads both. The `hot.md` at the wiki root is a different file: a pointer table of which projects are active.
|
|
437
438
|
|
|
438
|
-
Keep no second copy of that state. `MEMORY.md` and the `<learned_behaviors>` block inside `~/.claude/CLAUDE.md` look like your own memory, but they are one-way projections that Hypomnema derives from `pages/feedback/`. Record a correction with `/hypo:feedback` and let the sync regenerate them. Edit a projection by hand and the next sync stops on it as a conflict instead of merging it, because nothing can tell which side is now the truth; reconciling it back into the feedback page becomes your job. And a wiki fact you stash somewhere only you can see never reaches the user's other machines at all.
|
|
439
|
+
Keep no second copy of that state. `MEMORY.md` and the `<learned_behaviors>` block inside `~/.claude/CLAUDE.md` look like your own memory, but they are one-way projections that Hypomnema derives from `pages/feedback/`. Record a correction with `/hypo:feedback` and let the sync regenerate them. Edit a projection by hand and the next sync stops on it as a conflict instead of merging it, because nothing can tell which side is now the truth; reconciling it back into the feedback page becomes your job. The one exception is a hand edit that already matches what the wiki would write, which the next `--write` takes over. To keep the wiki version of a conflicted block instead, run `hypomnema feedback-sync --import-target-change --from=<target>` first to save a copy of the edit as a draft, then `hypomnema feedback-sync --accept-wiki=<slug>`. And a wiki fact you stash somewhere only you can see never reaches the user's other machines at all.
|
|
439
440
|
|
|
440
441
|
Captured sources are immutable. Never edit anything under `sources/`. Synthesize into `pages/` instead, and link back to the source.
|
|
441
442
|
|