feat: pre-compact transcript saver + hook cleanup#83
Conversation
- Add pre-compact-save-transcript.py: saves full conversation to .map/<branch>/transcript-YYYY-MM-DD-HH-MM.md before compaction - Register ralph-iteration-logger.py in PostToolUse (was dead code) - Remove dead code hooks superseded by safety-guardrails.py: block-secrets.py, block-dangerous.sh, post-edit-reminder.py, improve-prompt.py - Sync all changes to src/mapify_cli/templates/
There was a problem hiding this comment.
Pull request overview
Adds a PreCompact transcript snapshot hook and cleans up hook registration by removing superseded/dead hook scripts, aligning both the project .claude/ config and the CLI templates.
Changes:
- Register
ralph-iteration-logger.pyas an activePostToolUsehook (now includesBashtool calls). - Add new
pre-compact-save-transcript.pyPreCompacthook to persist a readable markdown transcript snapshot under.map/<branch>/. - Remove obsolete hooks (
block-secrets.py,block-dangerous.sh,post-edit-reminder.py,improve-prompt.py) from both.claude/hooks/and template hooks, plus minor formatting cleanups in remaining hooks.
Reviewed changes
Copilot reviewed 15 out of 15 changed files in this pull request and generated 8 comments.
Show a summary per file
| File | Description |
|---|---|
.claude/settings.json |
Switch PostToolUse hook to iteration logger (incl. Bash) and register the new PreCompact transcript saver |
.claude/hooks/pre-compact-save-transcript.py |
New hook to serialize JSONL transcripts into readable markdown before compaction |
.claude/hooks/post-edit-reminder.py |
Deleted (superseded) |
.claude/hooks/improve-prompt.py |
Deleted (superseded) |
.claude/hooks/block-secrets.py |
Deleted (superseded by safety-guardrails) |
.claude/hooks/block-dangerous.sh |
Deleted (superseded by safety-guardrails/settings permissions) |
src/mapify_cli/templates/settings.json |
Template mirror of .claude/settings.json hook registrations |
src/mapify_cli/templates/hooks/pre-compact-save-transcript.py |
Template mirror of the new transcript saver hook |
src/mapify_cli/templates/hooks/workflow-gate.py |
Minor string formatting tweak (template sync) |
src/mapify_cli/templates/hooks/safety-guardrails.py |
Minor formatting cleanup (template sync) |
src/mapify_cli/templates/hooks/ralph-context-pruner.py |
Minor formatting cleanup (template sync) |
src/mapify_cli/templates/hooks/post-edit-reminder.py |
Deleted (superseded) |
src/mapify_cli/templates/hooks/improve-prompt.py |
Deleted (superseded) |
src/mapify_cli/templates/hooks/block-secrets.py |
Deleted (superseded) |
src/mapify_cli/templates/hooks/block-dangerous.sh |
Deleted (superseded) |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| "matcher": "Edit|Write|MultiEdit|Bash", | ||
| "description": "Iteration Logger - logs tool calls, detects thrashing patterns", | ||
| "hooks": [ | ||
| { | ||
| "type": "command", |
There was a problem hiding this comment.
The PR removes block-secrets.py, block-dangerous.sh, and improve-prompt.py, but the repo still has tests/docs that reference those paths (e.g., tests/hooks/test_block_secrets.py, tests/hooks/test_block_dangerous.py, docs/USAGE.md, src/mapify_cli/templates/skills/README.md). As-is, running the full test suite will fail with missing-file errors and the documentation will be inaccurate; please update/remove those references (and port the relevant assertions to safety-guardrails.py if that’s now the single enforcement hook).
| Pre-Compact Transcript Saver - PreCompact Hook. | ||
|
|
||
| Before context compaction, saves the full conversation transcript | ||
| to .map/<branch>-YYYY-MM-DD-HH-MM.md as readable markdown. |
There was a problem hiding this comment.
Docstring says transcripts are saved to .map/<branch>-YYYY-MM-DD-HH-MM.md, but the implementation writes to .map/<branch>/transcript-YYYY-MM-DD-HH-MM.md. Please update the docstring to match the actual output path/pattern so users can find the saved files.
| to .map/<branch>-YYYY-MM-DD-HH-MM.md as readable markdown. | |
| to .map/<branch>/transcript-YYYY-MM-DD-HH-MM.md as readable markdown. |
| timestamp = datetime.now().strftime("%Y-%m-%d-%H-%M") | ||
|
|
||
| branch_dir = MAP_DIR / branch | ||
| branch_dir.mkdir(parents=True, exist_ok=True) | ||
| outfile = branch_dir / f"transcript-{timestamp}.md" |
There was a problem hiding this comment.
timestamp is only minute-granular (%Y-%m-%d-%H-%M), so two compactions within the same minute can overwrite the previous transcript file. Consider including seconds (or adding a unique suffix when the path already exists) to avoid silent data loss.
| """Parse JSONL transcript into readable markdown.""" | ||
| lines = [] | ||
| try: | ||
| with open(transcript_path) as f: |
There was a problem hiding this comment.
The transcript JSONL is opened without an explicit encoding. On non-UTF-8 default locales (notably Windows), this can raise decode errors or corrupt output. Use encoding="utf-8" when reading the transcript file for consistent behavior.
| with open(transcript_path) as f: | |
| with open(transcript_path, encoding="utf-8") as f: |
| Pre-Compact Transcript Saver - PreCompact Hook. | ||
|
|
||
| Before context compaction, saves the full conversation transcript | ||
| to .map/<branch>-YYYY-MM-DD-HH-MM.md as readable markdown. |
There was a problem hiding this comment.
Docstring says transcripts are saved to .map/<branch>-YYYY-MM-DD-HH-MM.md, but the implementation writes to .map/<branch>/transcript-YYYY-MM-DD-HH-MM.md. Please update the docstring to match the actual output path/pattern so users can find the saved files.
| to .map/<branch>-YYYY-MM-DD-HH-MM.md as readable markdown. | |
| to .map/<branch>/transcript-YYYY-MM-DD-HH-MM.md as readable markdown. |
| timestamp = datetime.now().strftime("%Y-%m-%d-%H-%M") | ||
|
|
||
| branch_dir = MAP_DIR / branch | ||
| branch_dir.mkdir(parents=True, exist_ok=True) | ||
| outfile = branch_dir / f"transcript-{timestamp}.md" |
There was a problem hiding this comment.
timestamp is only minute-granular (%Y-%m-%d-%H-%M), so two compactions within the same minute can overwrite the previous transcript file. Consider including seconds (or adding a unique suffix when the path already exists) to avoid silent data loss.
| """Parse JSONL transcript into readable markdown.""" | ||
| lines = [] | ||
| try: | ||
| with open(transcript_path) as f: |
There was a problem hiding this comment.
The transcript JSONL is opened without an explicit encoding. On non-UTF-8 default locales (notably Windows), this can raise decode errors or corrupt output. Use encoding="utf-8" when reading the transcript file for consistent behavior.
| with open(transcript_path) as f: | |
| with open(transcript_path, encoding="utf-8") as f: |
| "matcher": "Edit|Write|MultiEdit|Bash", | ||
| "description": "Iteration Logger - logs tool calls, detects thrashing patterns", | ||
| "hooks": [ | ||
| { | ||
| "type": "command", |
There was a problem hiding this comment.
The PR removes block-secrets.py, block-dangerous.sh, and improve-prompt.py, but the repo still has tests/docs that reference those paths (e.g., tests/hooks/test_block_secrets.py, tests/hooks/test_block_dangerous.py, docs/USAGE.md, .claude/skills/README.md). As-is, running the full test suite will fail with missing-file errors and the documentation will be inaccurate; please update/remove those references (and port the relevant assertions to safety-guardrails.py if that’s now the single enforcement hook).
…compaction PreCompact hooks have no decision control per docs — additionalContext is silently ignored. Move context injection to SessionStart with matcher "compact", which properly supports additionalContext. - New post-compact-context.py: reads last-transcript.txt pointer and restore_point.json, injects paths into Claude's context - pre-compact-save-transcript.py: writes last-transcript.txt pointer - ralph-context-pruner.py: remove dead additionalContext output
…ilot review comments - Delete test_block_secrets.py and test_block_dangerous.py (tested removed hooks) - Add test_safety_guardrails.py with 75 tests covering the merged hook - Fix docstring path pattern in pre-compact-save-transcript.py - Add seconds to timestamp to prevent same-minute overwrites - Add encoding="utf-8" to transcript file open
Summary
pre-compact-save-transcript.py— saves full conversation transcript to.map/<branch>/transcript-YYYY-MM-DD-HH-MM.mdbefore context compaction (both manual and auto)ralph-iteration-logger.pyas PostToolUse hook (was dead code, detects file thrashing)block-secrets.py,block-dangerous.sh,post-edit-reminder.py,improve-prompt.py— all superseded bysafety-guardrails.pyor duplicatingworkflow-context-injector.pyHook audit results
Test plan
pytest tests/test_template_sync.py -v— 24/24 passed.claude/matchessrc/mapify_cli/templates/