Skip to content

feat(hooks): PostToolBatch lane (default-off) + schema-driven render migrations - #115

Merged
mahmoudimus merged 1 commit into
mainfrom
feat/post-tool-batch-lane
Jul 21, 2026
Merged

mahmoudimus merged 1 commit into
mainfrom
feat/post-tool-batch-lane

Conversation

@mahmoudimus

Copy link
Copy Markdown
Owner

What

Adopts Claude Code's new PostToolBatch hook event (fires once per tool-call round, before the next model call; supports additionalContext) and completes the schema-driven render migrations the new hook schema forced.

Leg 1 — PostToolBatch lane (default-OFF)

  • Claude-only registration in .claude-plugin/hooks.json (Codex has no such event; its config verified untouched by test).
  • New hooks/post_tool_batch.py canonical module; hooks.post_tool_batch_enabled (default False — unmeasured lever) and hooks.post_tool_batch_max_payload_kb (default 256).
  • Mandatory client-side payload trim before any daemon forward: per-item budget (input:response split 1:3), over-budget fields JSON-serialized, UTF-8-truncated, and marked ...[simba: truncated]. The daemon never receives an unbounded batch payload — batch tool_responses can be large by design and this repo just spent a week killing unbounded inputs.
  • When enabled: builds a compact recall query from the batch and injects results via the (already-correct) generic {"hookSpecificOutput": {"hookEventName": "PostToolBatch", "additionalContext": ...}} envelope. When disabled: immediate empty result, zero daemon calls.

Leg 2 — PreToolUse render migration (client-gated)

The new schema removed additionalContext from the PreToolUse variant. For claude clients, PreToolUse renders no longer emit it (deny/rewrite/empty + top-level systemMessage remain); the recall-context production layer is untouched and the injection re-homes to the PostToolBatch lane. Codex output preserved byte-for-byte.

Leg 3 — Stop/SubagentStop additionalContext migration (client-gated)

Stop-feedback moves from the top-level stopReason workaround to the documented hookSpecificOutput.additionalContext channel ("Feedback for the model; the conversation continues") for claude clients; Codex keeps stopReason byte-for-byte.

Tests

Red-first: payload trim (under-cap identity, over-cap ≤ cap with markers), disabled-lane inertness (recall stub raises if called), enabled-lane envelope shape, per-client before/after render assertions for all three migrations. Full suite exit 0, ruff clean.

…migrations

Adds the new Claude Code PostToolBatch event as a default-off recall lane
(simba.hooks.post_tool_batch): a mandatory client-side payload trim bounds
the tool_calls batch before any query is built or daemon call is made, then
a compact recall query (tool names, input heads, error-looking response
fragments) drives the same recall/format machinery pre_tool_use.py uses.

Migrates two render surfaces off schema variants Claude Code has since
dropped or added: PreToolUse no longer emits additionalContext for the
claude client (it silently drops -- the PostToolBatch lane is its
replacement), and Stop/SubagentStop render additionalContext via
hookSpecificOutput instead of the legacy top-level stopReason. Both
migrations are client-gated on the resolved SIMBA_CLIENT so Codex keeps its
byte-identical legacy shapes until its own schema tolerance is verified.

Registered PostToolBatch in .claude-plugin/hooks.json only (no Codex
equivalent exists). TDD red-first throughout; full suite + ruff clean.
@mahmoudimus
mahmoudimus merged commit 03cb4d2 into main Jul 21, 2026
1 check passed
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