Parent: #34
Priority: P2 (extensibility — gateway/cron/memd all rely on hooks)
Branch base: release/0.1.53
Why
Hermes' plugin contract registers six lifecycle hooks: pre_tool_call, post_tool_call, pre_llm_call, post_llm_call, on_session_start, on_session_end. graff-agent's gateway uses on_session_start/end for chat mapping; memd uses post_tool_call to detect failure patterns; cron uses on_session_end to log cron-run outcomes.
Scope
Rust side
forge_domain::Hook trait + a HookRegistry on ForgeAPI.
- Six hooks fired from
forge_app:
pre_tool_call(tool_call) — can mutate or veto (return HookOutcome::Veto(reason)).
post_tool_call(tool_call, result).
pre_llm_call(request).
post_llm_call(response).
on_session_start(cid).
on_session_end(cid).
- Hooks are async, invoked sequentially per registration order, errors logged but don't crash the agent.
SDK side
graff.plugins.on(event, handler) — typed events.
- TS:
graff.plugins.on("preToolCall", async (tc) => { /* ... */ });
Acceptance
Parent: #34
Priority: P2 (extensibility — gateway/cron/memd all rely on hooks)
Branch base:
release/0.1.53Why
Hermes' plugin contract registers six lifecycle hooks:
pre_tool_call,post_tool_call,pre_llm_call,post_llm_call,on_session_start,on_session_end. graff-agent's gateway useson_session_start/endfor chat mapping; memd usespost_tool_callto detect failure patterns; cron useson_session_endto log cron-run outcomes.Scope
Rust side
forge_domain::Hooktrait + aHookRegistryonForgeAPI.forge_app:pre_tool_call(tool_call)— can mutate or veto (returnHookOutcome::Veto(reason)).post_tool_call(tool_call, result).pre_llm_call(request).post_llm_call(response).on_session_start(cid).on_session_end(cid).SDK side
graff.plugins.on(event, handler)— typed events.Acceptance
preToolCallskips the tool and surfaces an error to the agent