Skip to content

Commit faae171

Browse files
committed
v1.9.5: precompact-flush nudge moves from hookSpecificOutput.additionalContext to top-level systemMessage (PreCompact schema rejects the former)
1 parent eab9fef commit faae171

6 files changed

Lines changed: 58 additions & 31 deletions

File tree

CHANGELOG.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,15 @@
11
# Changelog
22

3+
## 1.9.5 (2026-04-20) — PreCompact nudge schema fix
4+
5+
### Fixed
6+
7+
- **`scripts/hooks/precompact-flush.mjs` now emits the memory-flush nudge as top-level `systemMessage` instead of `hookSpecificOutput.additionalContext`.** Claude Code's PreCompact hook schema only accepts `additionalContext` under `hookSpecificOutput` for `UserPromptSubmit` and `PostToolUse` events — PreCompact has no `additionalContext` shape, so the host was rejecting every response with `Hook JSON output validation failed — (root): Invalid input` and dropping the nudge on the floor. The disk-dump side-effect still ran (that's why the companion `precompact-distill.mjs` reported success), but the pre-compaction "save your context" reminder never reached the transcript. Switched to `systemMessage`, which is accepted for all event types and lands in the transcript ahead of the compacted summary, so the reminder still survives compaction.
8+
9+
### Tests
10+
11+
New assertions cover: (a) PreCompact nudge lands in `systemMessage` and nothing is emitted under `hookSpecificOutput`, (b) `AGENT_KNOWLEDGE_PRECOMPACT_NUDGE=0` suppresses the nudge entirely. Guards against regressing to the broken `hookSpecificOutput.additionalContext` shape.
12+
313
## 1.9.4 (2026-04-19) — visible knowledge-hook feedback + L0-only SessionStart
414

515
### Changed

agent-desk-plugin.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"id": "agent-knowledge",
33
"name": "Knowledge",
44
"icon": "psychology",
5-
"version": "1.9.4",
5+
"version": "1.9.5",
66
"description": "Knowledge base — entries, sessions, search, graph relationships",
77
"ui": "./dist/ui/app.js",
88
"css": "./dist/ui/styles.css",

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "agent-knowledge",
3-
"version": "1.9.4",
3+
"version": "1.9.5",
44
"description": "Cross-session memory and recall for AI agents — git-synced knowledge base, knowledge graph, confidence scoring, hybrid semantic+TF-IDF search, auto-distillation with secrets scrubbing",
55
"type": "module",
66
"main": "dist/index.js",

scripts/hooks/precompact-flush.mjs

Lines changed: 16 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,14 @@
99
// later distillation/promotion has a durable anchor even if the host
1010
// garbage-collects the transcript.
1111
//
12-
// 2. Inject a short "save-your-context" nudge into the host's PreCompact
13-
// response (`hookSpecificOutput.additionalContext`). The compaction pass
14-
// is about to summarize — anything important and unsaved should be
15-
// written to the knowledge base NOW via `knowledge(action="write", …)`.
16-
// Pre-compaction memory-flush primitive.
12+
// 2. Emit a short "save-your-context" nudge as a top-level `systemMessage`.
13+
// The compaction pass is about to summarize — anything important and
14+
// unsaved should be written to the knowledge base NOW via
15+
// `knowledge(action="write", …)`. Pre-compaction memory-flush primitive.
16+
// (PreCompact rejects `hookSpecificOutput.additionalContext` — only
17+
// UserPromptSubmit/PostToolUse accept that shape — so the nudge rides
18+
// in `systemMessage`, which lands in the transcript and survives
19+
// compaction.)
1720
//
1821
// Disable the nudge by exporting AGENT_KNOWLEDGE_PRECOMPACT_NUDGE=0 (the disk
1922
// dump still runs). Set AGENT_KNOWLEDGE_PRECOMPACT_NUDGE=off to suppress both.
@@ -38,28 +41,14 @@ const nudgeEnabled = NUDGE_MODE !== '0' && NUDGE_MODE !== 'false' && NUDGE_MODE
3841
const diskDumpEnabled = NUDGE_MODE !== 'off';
3942

4043
const NUDGE_TEXT = [
41-
'## PreCompact — memory-flush nudge',
42-
'',
43-
'The host is about to compact the conversation. Anything you learned this',
44-
'turn that the next session will need MUST be written to the knowledge base',
45-
'before the summary replaces the transcript. Use:',
46-
'',
47-
' `knowledge(action="write", category="decisions"|"notes"|"workflows", filename=..., content=...)`',
48-
'',
49-
'Candidates worth a write: architectural decisions, non-obvious gotchas,',
50-
'hard-won commands, people/ownership facts, project state. Skip transient',
51-
'things (file diffs, TODO lists, in-flight plans — plan/task systems own those).',
52-
].join('\n');
53-
54-
function emitResult(additionalContext) {
55-
const payload = additionalContext
56-
? {
57-
hookSpecificOutput: {
58-
hookEventName: 'PreCompact',
59-
additionalContext,
60-
},
61-
}
62-
: {};
44+
'knowledge: PreCompact — flush durable facts to the KB before summary replaces the transcript.',
45+
'Write architectural decisions, non-obvious gotchas, hard-won commands, people/ownership facts, project state via',
46+
'`knowledge(action="write", category="decisions"|"notes"|"workflows", filename=..., content=...)`.',
47+
'Skip transient things (file diffs, TODO lists, in-flight plans — plan/task systems own those).',
48+
].join(' ');
49+
50+
function emitResult(nudge) {
51+
const payload = nudge ? { systemMessage: nudge } : {};
6352
process.stdout.write(JSON.stringify(payload) + '\n');
6453
process.exit(0);
6554
}

server.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,12 @@
66
"url": "https://github.com/keshrath/agent-knowledge",
77
"source": "github"
88
},
9-
"version": "1.9.4",
9+
"version": "1.9.5",
1010
"packages": [
1111
{
1212
"registryType": "npm",
1313
"identifier": "agent-knowledge",
14-
"version": "1.9.4",
14+
"version": "1.9.5",
1515
"transport": {
1616
"type": "stdio"
1717
}

tests/hooks/hooks.test.ts

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,34 @@ describe('precompact-flush.mjs', () => {
192192
const { code } = await runHook('precompact-flush.mjs', 'junk');
193193
expect(code).toBe(0);
194194
});
195+
196+
it('emits nudge as top-level systemMessage, not hookSpecificOutput.additionalContext', async () => {
197+
// Claude Code's PreCompact schema only accepts systemMessage at the top
198+
// level; hookSpecificOutput.additionalContext is UserPromptSubmit /
199+
// PostToolUse only. Emitting the latter produces a validation error and
200+
// the nudge is dropped. Guard against regression.
201+
const { json } = await runHook('precompact-flush.mjs', {
202+
session_id: 'sess-precompact-nudge',
203+
hook_event_name: 'PreCompact',
204+
});
205+
const obj = json as {
206+
systemMessage?: string;
207+
hookSpecificOutput?: { additionalContext?: string };
208+
};
209+
expect(obj.systemMessage).toBeTruthy();
210+
expect(obj.systemMessage).toContain('knowledge:');
211+
expect(obj.hookSpecificOutput).toBeUndefined();
212+
});
213+
214+
it('suppresses nudge when AGENT_KNOWLEDGE_PRECOMPACT_NUDGE=0', async () => {
215+
const { json } = await runHook(
216+
'precompact-flush.mjs',
217+
{ session_id: 'sess-nudge-off', hook_event_name: 'PreCompact' },
218+
{ env: { AGENT_KNOWLEDGE_PRECOMPACT_NUDGE: '0' } },
219+
);
220+
const obj = json as { systemMessage?: string };
221+
expect(obj.systemMessage).toBeUndefined();
222+
});
195223
});
196224

197225
// ---------------------------------------------------------------------------

0 commit comments

Comments
 (0)