Skip to content

fix(claude-code): replace hardcoded hook with rich episodic logging - #1

Merged
aliirz merged 1 commit into
masterfrom
fix/claude-code-hook-rich-episodic
Apr 21, 2026
Merged

aliirz merged 1 commit into
masterfrom
fix/claude-code-hook-rich-episodic

Conversation

@aliirz

@aliirz aliirz commented Apr 21, 2026

Copy link
Copy Markdown
Owner

The PostToolUse hook was calling:
memory_reflect.py claude-code post-tool ok
for every tool call, producing identical entries with action='post-tool', detail='ok', and reflection=''. content_cluster() has nothing to cluster on, so the dream cycle staged zero candidates regardless of how many sessions ran.

Changes

.agent/harness/hooks/claude_code_post_tool.py [NEW]
Reads the JSON payload Claude Code sends via stdin on every PostToolUse
event (tool_name, tool_input, tool_response). Falls back to
CLAUDE_TOOL_NAME / CLAUDE_TOOL_INPUT env vars for older versions.

  • Derives a meaningful action label from tool name + input
  • Scores importance from OPERATION (deploy/migration/schema = 9, commit/test/build = 6, routine = 3) not from service brand names
  • Detects failures via exit_code, error stream, interrupted, is_error
  • Generates a non-empty reflection the dream cycle can cluster on
  • Sets pain_score=5 for high-importance successes so recurring patterns cross the 7.0 promotion threshold (was always 2, max salience = 5.4, never reached 7.0)

.agent/protocols/hook_patterns.json [NEW]
User-owned config for stack-specific service names. Ships with empty
high_stakes / medium_stakes arrays and a populated _examples section.
Users copy from _examples to activate (e.g. 'supabase', 'vercel').
The hook merges these with the universal built-in patterns at startup.
Universal patterns (deploy, migration, schema, production, secret, etc.)
stay hardcoded; service names do not.

.agent/harness/hooks/post_execution.py
Add optional pain_score parameter to log_execution(). Default behaviour
unchanged (2 for success, 7 for failure).

.agent/harness/hooks/on_failure.py
When error is a plain string, omit the noisy 'str:' type prefix from
the reflection field. Only add type name for actual Exception objects.

.agent/tools/memory_reflect.py
Expose pain_score via --pain CLI flag so manual reflect calls can set
it explicitly (e.g. --pain 5 for a significant successful discovery,
--pain 9 for a production incident).

adapters/claude-code/settings.json
Point PostToolUse hook at claude_code_post_tool.py. Expand matcher to
include MultiEdit, Task, TodoWrite. Add supabase db reset to deny list.

adapters/claude-code/CLAUDE.md
Add explicit 'when to log manually' section with examples, importance
guide table, and good/bad call examples.

adapters/claude-code/README.md
Document the new hook, why the old one was broken, how to verify,
and common troubleshooting scenarios.

test_claude_code_hook.py [NEW]
54-assertion validation suite. Run from any project that has .agent/
installed. Exit 0 = all good. Tests cover: import, empty stdin,
action labels, importance scoring, pain calibration, failure detection,
reflection non-empty, full write path, dream cycle integration,
--pain CLI flag, hook_patterns.json loading and overrides.

Fixes

  • dream cycle always produced staged=0 (empty reflections)
  • successful high-stakes ops never auto-promoted (salience ceiling 5.4 < 7.0)
  • failures silently logged as success (no exit code / error stream check)
  • all tool calls uniform importance=3 (no domain awareness)
  • service names hardcoded in importance scorer (not portable across stacks)

@aliirz
aliirz force-pushed the fix/claude-code-hook-rich-episodic branch from 9bc5fdc to c782317 Compare April 21, 2026 10:22
The PostToolUse hook was calling:
  memory_reflect.py claude-code post-tool ok
for every tool call, producing identical entries with action='post-tool',
detail='ok', and reflection=''. content_cluster() has nothing to cluster
on, so the dream cycle staged zero candidates regardless of how many
sessions ran.

Changes
-------
.agent/harness/hooks/claude_code_post_tool.py  [NEW]
  Reads the JSON payload Claude Code sends via stdin on every PostToolUse
  event (tool_name, tool_input, tool_response). Falls back to
  CLAUDE_TOOL_NAME / CLAUDE_TOOL_INPUT env vars for older versions.
  - Derives a meaningful action label from tool name + input
  - Scores importance from OPERATION (deploy/migration/schema = 9,
    commit/test/build = 6, routine = 3) not from service brand names
  - Detects failures via exit_code, error stream, interrupted, is_error
  - Generates a non-empty reflection the dream cycle can cluster on
  - Sets pain_score=5 for high-importance successes so recurring patterns
    cross the 7.0 promotion threshold (was always 2, max salience = 5.4,
    never reached 7.0)

.agent/protocols/hook_patterns.json  [NEW]
  User-owned config for stack-specific service names. Ships with empty
  high_stakes / medium_stakes arrays and a populated _examples section.
  Users copy from _examples to activate (e.g. 'supabase', 'vercel').
  The hook merges these with the universal built-in patterns at startup.
  Universal patterns (deploy, migration, schema, production, secret, etc.)
  stay hardcoded; service names do not.

.agent/harness/hooks/post_execution.py
  Add optional pain_score parameter to log_execution(). Default behaviour
  unchanged (2 for success, 7 for failure).

.agent/harness/hooks/on_failure.py
  When error is a plain string, omit the noisy 'str:' type prefix from
  the reflection field. Only add type name for actual Exception objects.

.agent/tools/memory_reflect.py
  Expose pain_score via --pain CLI flag so manual reflect calls can set
  it explicitly (e.g. --pain 5 for a significant successful discovery,
  --pain 9 for a production incident).

adapters/claude-code/settings.json
  Point PostToolUse hook at claude_code_post_tool.py. Expand matcher to
  include MultiEdit, Task, TodoWrite. Add supabase db reset to deny list.

adapters/claude-code/CLAUDE.md
  Add explicit 'when to log manually' section with examples, importance
  guide table, and good/bad call examples.

adapters/claude-code/README.md
  Document the new hook, why the old one was broken, how to verify,
  and common troubleshooting scenarios.

test_claude_code_hook.py  [NEW]
  54-assertion validation suite. Run from any project that has .agent/
  installed. Exit 0 = all good. Tests cover: import, empty stdin,
  action labels, importance scoring, pain calibration, failure detection,
  reflection non-empty, full write path, dream cycle integration,
  --pain CLI flag, hook_patterns.json loading and overrides.

Fixes
-----
- dream cycle always produced staged=0 (empty reflections)
- successful high-stakes ops never auto-promoted (salience ceiling 5.4 < 7.0)
- failures silently logged as success (no exit code / error stream check)
- all tool calls uniform importance=3 (no domain awareness)
- service names hardcoded in importance scorer (not portable across stacks)
@aliirz
aliirz force-pushed the fix/claude-code-hook-rich-episodic branch from c782317 to e984c4a Compare April 21, 2026 10:39
@aliirz
aliirz merged commit 6008332 into master Apr 21, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant