Skip to content
15 changes: 15 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,21 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).

## [Unreleased]

### Fixed

- `SessionStart` hook output now reaches the model as `hookSpecificOutput.additionalContext` instead
of the terminal-only `systemMessage` chip, so the pinned-conventions index and meta-instruction
actually seed the conversation on session start. (#N)

### Changed

- `PostCompact` no longer emits a hook payload. Claude Code's hook output validator rejects
`hookSpecificOutput` for this event, leaving only the chip-only `systemMessage` envelope — which
never reaches the model and renders as long terminal noise on every `/compact`. The handler now
does its dedup-file truncation silently; on-demand pattern injection via PreToolUse continues to
work. The always-on pinned tier is unavailable post-compact pending a future re-prime mechanism.
See `docs/hook-pipeline-reference.md` and `ROADMAP.md`. (#N)

## [0.4.0] - 2026-05-19

### Changed
Expand Down
10 changes: 10 additions & 0 deletions ROADMAP.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,16 @@

## Future

- [ ] PostCompact re-prime workaround — Claude Code's hook output validator rejects
`hookSpecificOutput` for the PostCompact event, leaving `systemMessage` as the only envelope
and the pinned-conventions tier unable to re-seed the model context after `/compact`. Options
to investigate: (a) wait for Claude Code to accept `additionalContext` for PostCompact; (b)
re-prime opportunistically on the first PreToolUse after compaction by detecting a truncated
dedup file and injecting the pinned tier as additionalContext alongside the normal search
results; (c) a `lore reprime`-style agent-callable surface the model can invoke when it
notices its context has been compacted. Surfaced in PR #N (SessionStart envelope fix); see
`docs/hook-pipeline-reference.md` for the limitation as it stands today.

- [ ] Pre-release UX polish (deferred from edge-case-handling brainstorm) — friendlier
empty-directory copy beyond the current tier-2 warning, empty-DB search hints, and a
structured `SlugCollisionError` type (with `existing_path` / `existing_title` fields for
Expand Down
42 changes: 36 additions & 6 deletions docs/hook-pipeline-reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,34 @@ event payload from stdin and writes structured JSON to stdout.

| Event | Output field | Matcher | Purpose |
| ------------ | ------------------- | ------------------- | ---------------------------------------------------------------------- |
| SessionStart | `systemMessage` | All tools | Primes the session with a pattern index and meta-instruction |
| SessionStart | `additionalContext` | All tools | Primes the session with a pattern index and meta-instruction |
| PreToolUse | `additionalContext` | `Edit\|Write\|Bash` | Searches for relevant patterns and injects them before the tool runs |
| PostToolUse | `additionalContext` | `Bash` | Searches for patterns related to Bash errors (non-zero exit code only) |
| PostCompact | `systemMessage` | All tools | Re-primes the session after context compression |
| PostCompact | _(none)_ | All tools | Resets the per-session dedup file; emits no hook output (see below) |

> **Why `additionalContext` for the first three events?** Claude Code routes
> `hookSpecificOutput.additionalContext` into the model's conversation as a system reminder, while
> the alternate `systemMessage` envelope renders as a transient terminal chip and never reaches the
> model. SessionStart, PreToolUse, and PostToolUse all use `additionalContext` so their payloads
> seed or augment the agent's context. Earlier releases mistakenly used `systemMessage` for
> SessionStart, so the pinned-conventions index never entered the conversation; this was corrected
> in 0.4.1.
>
> **Why PostCompact emits nothing.** Claude Code's hook output validator rejects
> `hookSpecificOutput` for the PostCompact event, leaving only the chip-only `systemMessage`
> envelope — which never reaches the model and would render as a long, recurring terminal chip with
> no use to either user or agent. Rather than emit noise, the handler suppresses output entirely and
> limits itself to its load-bearing side effect: truncating the per-session dedup file so the next
> PreToolUse re-injects patterns the agent saw before compaction. The always-on pinned tier is
> therefore unavailable post-compact, but on-demand injection continues to work. The hook is
> retained as an extension point: when Claude Code accepts `additionalContext` for PostCompact, or
> when a cleverer re-prime mechanism becomes available, the handler is the right place to plug it
> in. The roadmap tracks candidate workarounds.

### SessionStart

Fires once at the beginning of every session. The hook creates (or truncates) the session
deduplication file, then returns a `systemMessage` containing:
deduplication file, then returns an `additionalContext` payload containing:

- A meta-instruction telling the agent that patterns are injected automatically and should be
followed as default conventions
Expand Down Expand Up @@ -96,9 +115,20 @@ PostToolUse does not fire for successful commands or for non-Bash tools.
### PostCompact

Fires when the agent's context window is compressed (a natural event during long sessions). The hook
truncates the deduplication file and re-emits the same content as SessionStart — the full pattern
index and meta-instruction. This ensures the agent retains awareness of the knowledge base even
after earlier injections have been compressed away.
truncates the per-session deduplication file so subsequent PreToolUse calls re-inject patterns the
agent saw before compaction.

The handler produces no hook output. Claude Code's validator rejects `hookSpecificOutput` for
PostCompact, and the alternate `systemMessage` envelope would render as a long terminal chip that
never reaches the model — pure noise with no audience. Suppressing the output keeps the terminal
clean and is honest about the harness limitation: the always-on pinned-conventions tier cannot be
re-seeded after compaction with the channels currently available. On-demand injection via PreToolUse
continues to work normally.

The handler is retained as an extension point — when Claude Code accepts `additionalContext` for
PostCompact, or when a different re-prime mechanism becomes feasible (a `lore reprime`
agent-callable surface, an opportunistic re-seed on the first PreToolUse after a truncated dedup
file is observed, or similar), this is where it plugs in. See the corresponding roadmap entry.

## Engine and Adapter

Expand Down
Loading
Loading