A Claude Code hook that scores and remembers bad responses, then injects them back into future turns
Project description
claude-scored-memory
A Claude Code hook that scores and remembers bad responses, then injects the top offenders back into future turns as system context.
Think of it as a per-user behavioral feedback loop layered on top of
vanilla Claude Code. Every time Claude finishes a turn, the Stop hook
regex-matches the response against your rules and stores hits in SQLite
with frequency + recency + severity scoring. On the next turn, the
UserPromptSubmit hook queries the store for violations semantically
relevant to the current prompt and injects the top K as an XML block
into the conversation. Claude sees its past mistakes before it acts.
This does not adjust temperature, logits, or sampling — Claude Code hooks can't touch those. The "probability weighting" effect comes entirely from contextual prompt injection.
Install
pipx install claude-scored-memory
claude-scored-memory install
claude-scored-memory doctor
The install command:
- Creates
~/.claude/scored-memory/(state dir). - Writes a default
config.tomland an emptycompliance-rules.yaml. - Initializes
compliance.sqlite3with WAL mode. - Merges hook entries into
~/.claude/settings.json— preserving any existing hooks in theUserPromptSubmitorStoparrays.
Restart any running Claude Code sessions to pick up the new hooks.
Write some rules
claude-scored-memory ships as a framework, not a rule set. Out of the
box it stores and injects nothing because there's nothing to match.
Open ~/.claude/scored-memory/compliance-rules.yaml and author rules in
YAML. The docs/example-rules/ directory in the package has copy-paste
starting points for common failure modes:
behavioral.yaml— pandering, empty promises, answering from memorysecurity.yaml— committing secrets, shell interpolationunverified-claims.yaml— "should work", "probably fine", "I assume"
See docs/writing-rules.md for the full format reference and scoring
math.
claude-scored-memory rules validate # lint your rules file
Observability
claude-scored-memory stats # counts by category
claude-scored-memory list --category behavior # violation table
claude-scored-memory query "<prompt text>" # dry-run the injection
claude-scored-memory tail # live log of hook activity
The log file ~/.claude/scored-memory/logs/bridge.log is one JSON line per
hook invocation with event, duration_ms, and hit counts. It's the
single source of truth when you want to know whether the hooks are firing.
How it works
user prompt
│
▼
UserPromptSubmit hook ──► bridge build_prompt_context ──► SQLite
│ │
│ additionalContext = <compliance-violations>... │
▼ │
Claude processes the turn │
│ │
▼ │
Stop hook ───────────────► bridge check ─────────────────────►┘
(regex match + upsert)
On the next turn, the violations stored by the previous Stop are eligible
for injection by UserPromptSubmit.
Scoring
score = min(freq, 10)/10 × 2^(-days_since/7) × severity × cosine(prompt, violation)
- Frequency caps at 10 so a single obnoxious rule can't dominate forever.
- Recency decays with a 7-day half-life.
- Severity is rule-declared.
1.0is normal;2.0+ means one occurrence is enough to surface immediately. - Semantic relevance (hashed 128-dim cosine) acts as a tiebreaker so rules fire on contextually-relevant turns, not every turn indiscriminately.
Tune top_k, min_score, max_prompt_chars in
~/.claude/scored-memory/config.toml.
Per-project state
By default, the store is global per user (~/.claude/scored-memory/).
Behavioral lessons are about the model, not the project, and you want
the frequency counters to actually accumulate.
If you want isolated counters per project, set this in the project's
.claude/settings.json:
{
"env": {
"SCORED_MEMORY_ROOT": "${CLAUDE_PROJECT_DIR}/.claude/scored-memory",
"SCORED_MEMORY_RULES": "${CLAUDE_PROJECT_DIR}/.claude/scored-memory/compliance-rules.yaml"
}
}
Disabling temporarily
SCORED_MEMORY_DISABLE=1 claude
Or remove the hook entries from ~/.claude/settings.json via:
claude-scored-memory uninstall
Uninstall never touches your state dir — the DB, rules, and logs stay put so you can re-enable later or copy them to another machine.
Non-goals
- Temperature / logit manipulation — not possible via hooks.
- Curated default rules — rule selection is user-owned, by design.
- LLM-as-judge scoring — rules are regex-only.
- Real-time streaming inspection — Stop fires after the response is complete.
- GUI, dashboard, menu bar app — CLI only.
Provenance
The scoring engine, SQLite schema, and bridge CLI are vendored from
Scored-Memory (MIT) with primitives (_embed, _cosine, _iso,
_now_utc, _parse_iso) inlined from its clawmemory dependency
(MIT, Nattapong) into _vendored/_primitives.py, so this package has
no hidden runtime dependencies beyond pyyaml. See
src/claude_scored_memory/_vendored/ for annotated sources.
License
MIT — see LICENSE.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file claude_scored_memory-0.1.1.tar.gz.
File metadata
- Download URL: claude_scored_memory-0.1.1.tar.gz
- Upload date:
- Size: 27.9 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b6a31979c7f35afe32b8119d65141dbaa565bffdd5b3ed04df3f12d1a5d9d7fb
|
|
| MD5 |
4741bce9bda2d3cee710f5d952fd1f16
|
|
| BLAKE2b-256 |
9f38f49b67e23c464f3274d86cb3a679798ca5d30d381ee81a9f511652d7774f
|
File details
Details for the file claude_scored_memory-0.1.1-py3-none-any.whl.
File metadata
- Download URL: claude_scored_memory-0.1.1-py3-none-any.whl
- Upload date:
- Size: 28.4 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
1b51a8470db3853b0a51e61ba9994e7f8d8780797051a045a09524898a43f2de
|
|
| MD5 |
ba6d98c3545953030bf260b7783fdefd
|
|
| BLAKE2b-256 |
8b0d5cc3d14c51c626edfe9b6b49ce9744149269160701b1ee774662d465f5e3
|