#12986: feat(hooks): wire message_sending and message_sent plugin hooks
stale
## Summary
Wire the `message_sending` and `message_sent` plugin hooks that were defined in the type system but never called in the execution flow.
Related: #6535
## Changes
**`src/auto-reply/reply/dispatch-from-config.ts`**
- Call `runMessageSending()` before final reply delivery
- Supports content modification (`result.content`)
- Supports reply cancellation (`result.cancel`)
- Call `runMessageSent()` after successful delivery (fire-and-forget)
## Scope & Design Decisions
- **Final replies only** — block/streaming and tool results are not hooked to avoid latency impact
- **Fast-abort replies excluded** — system-generated abort messages bypass hooks intentionally
- `message_sending` runs sequentially (modifying hook) — consistent with `runMessageSending()` in hooks.ts
- `message_sent` runs as fire-and-forget with error catching — no impact on delivery flow
- `hasHooks()` guard ensures zero overhead when no plugins register these hooks
- `sendSuccess` reflects queue acceptance (dispatcher) or route result (cross-provider), not final delivery confirmation
## Use Cases
- **Persona enforcement**: Validate/correct responses against SOUL.md after context compaction
- **Content filtering**: Block or modify responses before they reach users
- **Audit logging**: Track all outbound messages with delivery status
- **Analytics**: Measure delivery success rates per channel
## Testing (20/20 passing)
| Test | Coverage |
|------|----------|
| Content modification | Hook modifies `ttsReply.text` before dispatch |
| Reply cancellation | Hook returns `cancel: true`, reply skipped |
| No-op (unregistered) | Zero overhead, hooks not called |
| Multiple replies | Hook fires per reply in array |
| Cross-provider routing | Modified content reaches `routeReply()` |
| Fast-abort exclusion | System abort messages bypass hooks |
| message_sent fires | After successful delivery |
| message_sent no-op | Not called when unregistered |
```
pnpm lint → 0 warnings, 0 errors (2796 files)
pnpm format → All files formatted correctly
vitest → 20/20 tests passing
```
Partially addresses #6535 (2 of 8 remaining hooks)
Most Similar PRs
#20859: fix(hooks): wire message_sent hook into reply dispatcher for all ch...
by davidrudduck · 2026-02-19
76.5%
#19922: feat(hooks): add message:received and message:sent hook events
by NOVA-Openclaw · 2026-02-18
73.2%
#9906: feat: wire message_sending hook in outbound delivery
by teempai · 2026-02-05
72.7%
#12584: feat(hooks): wire outbound message lifecycle hooks
by vincentkoc · 2026-02-09
70.9%
#8084: fix(plugins): wire up message_sending hook in outbound delivery
by lailoo · 2026-02-03
70.2%
#20067: feat(plugins): add before_agent_reply hook for message interception
by JoshuaLelon · 2026-02-18
69.7%
#7545: feat(hooks): add message:received hook for pre-turn automation
by wangtian24 · 2026-02-02
69.6%
#11597: feat(hooks): implement message:received hook
by gnufoo · 2026-02-08
69.4%
#16618: feat: bridge message lifecycle hooks to workspace hook system
by DarlingtonDeveloper · 2026-02-14
69.4%
#22293: Hooks: add message-filter bundled hook with inbound message pre-filter
by MegaPhoenix92 · 2026-02-21
69.1%