Metadata-Version: 2.4
Name: claude-scored-memory
Version: 0.1.0
Summary: A Claude Code hook that scores and remembers bad responses, then injects them back into future turns
Author: OpenClaw
License: MIT
Project-URL: Homepage, https://github.com/openclaw/claude-scored-memory
Project-URL: Issues, https://github.com/openclaw/claude-scored-memory/issues
Keywords: claude,claude-code,hooks,compliance,scoring,memory
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Software Development :: Quality Assurance
Requires-Python: >=3.11
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: pyyaml>=6.0
Provides-Extra: dev
Requires-Dist: pytest>=8.0; extra == "dev"
Dynamic: license-file

# 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

```bash
pipx install claude-scored-memory
claude-scored-memory install
claude-scored-memory doctor
```

The install command:

1. Creates `~/.claude/scored-memory/` (state dir).
2. Writes a default `config.toml` and an empty `compliance-rules.yaml`.
3. Initializes `compliance.sqlite3` with WAL mode.
4. Merges hook entries into `~/.claude/settings.json` — preserving any
   existing hooks in the `UserPromptSubmit` or `Stop` arrays.

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 memory
- `security.yaml` — committing secrets, shell interpolation
- `unverified-claims.yaml` — "should work", "probably fine", "I assume"

See `docs/writing-rules.md` for the full format reference and scoring
math.

```bash
claude-scored-memory rules validate   # lint your rules file
```

## Observability

```bash
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.0` is 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`:

```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

```bash
SCORED_MEMORY_DISABLE=1 claude
```

Or remove the hook entries from `~/.claude/settings.json` via:

```bash
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`.
