feat: split hooks.auto_save and hooks.auto_mine for independent control of diary vs mine#1110
feat: split hooks.auto_save and hooks.auto_mine for independent control of diary vs mine#1110sha2fiddy wants to merge 2 commits intoMemPalace:developfrom
Conversation
jphein
left a comment
There was a problem hiding this comment.
Pulled and verified on Python 3.12:
- 1080/1080 non-benchmark tests pass (matches your claim).
- Gate placement checks out:
_save_diary_directstays unconditional;_ingest_transcript+_maybe_auto_ingestboth guarded in silent AND legacy-block branches; precompact early-returns cleanly whenauto_mine=false. Exception fallback defaults toTrue, so a broken config never accidentally disables mining — same defensive posture assilent_save. - Env-var override (
MEMPALACE_HOOKS_AUTO_MINE+ legacy alias) works as documented; falsey parsing matches theMEMPALACE_PALACE_PATHprecedent.
Design aligns with what I proposed in #1083 — thanks for picking this up. _mine_sync's recursive walk has been our production's biggest CPU headache on a 165K-drawer palace; first-class opt-out is much cleaner than the wrapper workarounds I was queueing in a fork-ahead PR. I'll drop that row from our tracker in favor of yours.
Nit, not a blocker: hook_precompact re-instantiates MempalaceConfig() on its own rather than reusing the instance loaded elsewhere in the module. Fires once per session so probably not worth a re-roll — just flagging.
2805524 to
dd86086
Compare
…ackground mine
Adds a `hooks.auto_mine` config flag so users can keep the fast diary
write in stop/precompact hooks but skip the recursive
`~/.claude/projects/<cwd>/` mine that can peg a CPU core for hours on
large transcript archives.
- config.py: new `hook_auto_mine` property (default True; file config
under `hooks.auto_mine`; `MEMPALACE_HOOKS_AUTO_MINE` env var override
with legacy `MEMPAL_HOOKS_AUTO_MINE` alias). Falsey values: 0, false,
no, off.
- hooks_cli.py:
- `hook_stop` silent branch: gates `_ingest_transcript` and
`_maybe_auto_ingest` on `auto_mine`. `_save_diary_direct` stays
unconditional — the diary write is the memory-preservation core
and must not depend on the mine flag.
- `hook_stop` legacy-block branch: same gating applied to
`_ingest_transcript` + `_maybe_auto_ingest`.
- `hook_precompact`: gates the whole ingest+mine block on
`auto_mine`; compaction still proceeds when disabled.
- mcp_server.py / `mempalace_hook_settings`: accepts `auto_mine`
alongside `silent_save` and `desktop_toast`, and returns it in the
settings payload.
- Tests: 13 new cases covering defaults, file config, env var
override (including legacy `MEMPAL_` prefix), parametrized falsey
values, and the stop/precompact hook gating behavior.
- Docs: MCP tool reference and CHANGELOG entry.
Default remains `True` — existing users see zero behavior change until
they opt out.
dd86086 to
4967008
Compare
|
Hi, Severity: remediation recommended | Category: correctness How to fix: Handle empty env values Agent prompt to fix - you can give this to your LLM of choice:
Found by Qodo code review |
|
Fixed in ec33d18. Changed the guard from Added 5 parametrized tests in |
Problem
The Stop and PreCompact hooks currently do three things with no way to enable them independently:
_save_diary_directis cheap, a few hundred ms. Writes the distilled memory entry._ingest_transcriptis medium cost. Syncs the current session's.jsonl._maybe_auto_ingest/_mine_syncis expensive. Walks the whole~/.claude/projects/<cwd>/tree and can peg a CPU core for hours on large archives.So users are stuck picking between "no hook-driven memory" and "burn a core every 15 exchanges." Some people want the fast diary write but not the recursive mine, especially on machines with thousands of accumulated transcripts. #1068 and #1069 have context.
Solution
Adds a new config flag
hooks.auto_mine(defaulttrue) that gates the two mine paths in both hooks. The diary save stays unconditional because it's cheap and it's the thing users actually want.With
auto_mine: false, hook-driven diary writes keep working but the recursive mine is skipped. "Combined mode" is just leaving bothsilent_saveandauto_mineon.Flags
hooks.silent_savetrue{"decision": "block"}AI-driven savehooks.auto_mine(new)trueOverride precedence follows the existing pattern in
config.py: env var (MEMPALACE_HOOKS_AUTO_MINE, legacy aliasMEMPAL_HOOKS_AUTO_MINE) >~/.mempalace/config.json> defaultTrue.Usage
Via the existing MCP tool:
Via config file:
{ "hooks": { "auto_mine": false } }Via env var:
export MEMPALACE_HOOKS_AUTO_MINE=falseFalsey values:
0,false,no,off(case-insensitive). Anything else is truthy. Empty-string env var falls through to the config file, matching the pattern used byMEMPALACE_PALACE_PATHandMEMPALACE_ENTITY_LANGUAGES.Scope note
This PR doesn't touch
hooks.silent_saveor any other existing flag. It's independent of #711 (hooks.auto_save, the outer hook enable/disable). Either can land first; the other rebases cleanly. I kept them as separate PRs.Test plan
tests/test_config.py: 5 new tests plus 7 parametrize cases covering default, file override, env override, and the legacy env prefix.tests/test_hooks_cli.py: 3 new tests for the stop-hook silent branch (auto_mine on and off) and precompact with auto_mine off.ruff check .passes.ruff format --checkpasses on touched files under both current ruff and CI-pinnedruff>=0.4.0,<0.5.Backwards compatibility
hook_auto_minedefaults toTrue. Users who don't set the flag see no behavior change.Files touched
mempalace/config.py: newhook_auto_minepropertymempalace/hooks_cli.py: gate mine calls inhook_stop(both branches) andhook_precompactmempalace/mcp_server.py:auto_mineparameter onmempalace_hook_settingstests/test_config.py: config coveragetests/test_hooks_cli.py: hook coverage (helper_capture_hook_outputgains anauto_mine=Truedefault)website/reference/mcp-tools.md: doc updateCHANGELOG.md:[Unreleased]entryRelated
mempalace minepins 400–500 % CPU — ORT intra_op pool ignores OMP env vars #1068 (ORT CPU pin diagnosis) and Consolidatehooks/mempal_*_hook.shinto thin wrappers delegating tomempalace hook run#1069 (hooks consolidation refactor)hooks.auto_save)