#19565: feat: add agent lifecycle hook events (session, message, error)
docs
agents
size: S
## Summary
Adds five new internal hook event types for agent lifecycle, enabling workspace/managed hooks to react to the full agent work loop — not just slash commands.
## New Events
| Event | Fires When | Location |
|-------|-----------|----------|
| `session:start` | After `/new` or `/reset` creates a new session | `commands-core.ts` |
| `session:end` | After `/stop` command | `commands-session.ts` |
| `agent:error` | Agent encounters LLM/tool error | `pi-embedded-subscribe.handlers.lifecycle.ts` |
| `message:received` | Inbound message arrives from user | `dispatch-from-config.ts` |
| `message:sent` | Outbound message delivered to user | `deliver.ts` |
## Changes
- **`src/hooks/internal-hooks.ts`**: Added `message` to `InternalHookEventType` union
- **`src/auto-reply/reply/commands-core.ts`**: Fire `session:start` after /new and /reset
- **`src/auto-reply/reply/commands-session.ts`**: Fire `session:end` after /stop
- **`src/agents/pi-embedded-subscribe.handlers.lifecycle.ts`**: Fire `agent:error` on agent errors
- **`src/auto-reply/reply/dispatch-from-config.ts`**: Fire `message:received` on inbound messages
- **`src/infra/outbound/deliver.ts`**: Fire `message:sent` on outbound delivery
- **`docs/automation/hooks.md`**: Moved events from 'Future Events' to documented sections
## Design
- All new hooks are fire-and-forget (`void triggerInternalHook(...).catch()`) to avoid blocking the main message/agent flow
- Events are emitted alongside existing plugin hooks where applicable (e.g., `message_received` plugin hook)
- Minimal changes — no refactoring of unrelated code
## Testing
- `npm run build` ✅ compiles clean
- All existing hook tests pass (`npx vitest run src/hooks/` — 86 tests, 9 files)
<!-- greptile_comment -->
<h3>Greptile Summary</h3>
Adds five new internal hook event types (`session:start`, `session:end`, `agent:error`, `message:received`, `message:sent`) to enable workspace/managed hooks to react to the full agent lifecycle. All hooks follow the existing fire-and-forget pattern and are placed alongside existing plugin hooks.
- The `message:sent` hook in `deliver.ts` derives its `sessionKey` from `params.mirror?.sessionKey`, but `mirror` is optional and absent at the majority of call sites (~61%). This causes the hook to fire with an empty session key in many delivery paths (heartbeat, cron, CLI sends), which limits usefulness for session-aware hook consumers.
- The Event Context type example in the docs (`hooks.md` line 210) still shows the old 4-type union and is missing the newly added `'message'` type.
- Code changes are otherwise clean: deduplication is respected for `message:received`, hook placement is correct relative to existing hooks, and error handling is consistent.
<h3>Confidence Score: 3/5</h3>
- Generally safe — hooks are fire-and-forget and won't block the main flow, but the `message:sent` session key gap warrants a fix before merging.
- Most of the hook additions are clean and well-placed. However, the `message:sent` hook will frequently fire with an empty `sessionKey` due to `mirror` being absent at most call sites, and the docs have a stale type definition. These issues reduce confidence from what would otherwise be a straightforward feature addition.
- `src/infra/outbound/deliver.ts` (empty sessionKey in most delivery paths), `docs/automation/hooks.md` (stale Event Context type)
<sub>Last reviewed commit: 5f57b02</sub>
<!-- greptile_other_comments_section -->
<!-- /greptile_comment -->
Most Similar PRs
#19922: feat(hooks): add message:received and message:sent hook events
by NOVA-Openclaw · 2026-02-18
84.6%
#11597: feat(hooks): implement message:received hook
by gnufoo · 2026-02-08
83.0%
#16618: feat: bridge message lifecycle hooks to workspace hook system
by DarlingtonDeveloper · 2026-02-14
82.6%
#9782: feat(hooks): implement session:start and session:end lifecycle events
by kentaro · 2026-02-05
82.1%
#6630: feat(hooks): add agent:turn_start and agent:turn_end lifecycle events
by drdigital13 · 2026-02-01
82.0%
#7580: feat: add message:received internal hook with prompt injection
by rodrigoschott · 2026-02-03
81.9%
#7771: Hooks: wire lifecycle events and tests
by rabsef-bicrym · 2026-02-03
81.8%
#13415: fix(hooks): bridge agent_end events to internal/workspace hooks
by mcaxtr · 2026-02-10
81.1%
#20418: feat(hooks): add session:pre-spawn and agent:pre-run hook events
by NOVA-Openclaw · 2026-02-18
80.2%
#20268: feat(hooks): emit subagent:complete internal hook event
by AytuncYildizli · 2026-02-18
80.2%