Summary
Add beforeDeliver and afterDeliver lifecycle hooks to the outbound message delivery path, allowing user scripts to suppress, filter, or audit replies before they reach a channel.
Problem
All outbound replies (from cron jobs, agent sessions, subagents) flow through the delivery layer with no interception point. There is no way to suppress a reply based on content, log outbound messages to an audit trail, or transform delivery targets without modifying core code.
Acceptance criteria
Implementation plan
- Identify the shared delivery dispatch point (likely
src/cron/delivery.ts + agent reply path in src/agents/subagent-announce-dispatch.ts)
- Add
DeliveryHooksConfig type to src/config/types.hooks.ts (or extend shared hook types)
- Wire
beforeDeliver check before channel send; wire afterDeliver after send completes
- Re-use
runCronHooks / loadHookEntries from src/cron/hooks.ts (already workflow-agnostic)
- Add config schema entry and Zod validation
- Add unit tests
Files affected
src/cron/hooks.ts (reuse — no changes expected)
src/config/types.hooks.ts (add DeliveryHooksConfig)
src/config/zod-schema.ts (add Zod schema for delivery hooks)
src/cron/delivery.ts (wire beforeDeliver)
src/agents/subagent-announce-dispatch.ts (wire beforeDeliver for agent replies)
src/cron/hooks.test.ts or new src/delivery/hooks.test.ts (tests)
Additional notes
beforeDeliver is hook point 7 in the original cron hooks plan (cron-lifecycle-hooks.md) — it was deferred from the cron PR intentionally
- Highest leverage of the four planned hook workflows: all outbound messages share one delivery path
ctx.workflow distinguishes source so a single global hook can target cron-only or agent-only delivery
Summary
Add
beforeDeliverandafterDeliverlifecycle hooks to the outbound message delivery path, allowing user scripts to suppress, filter, or audit replies before they reach a channel.Problem
All outbound replies (from cron jobs, agent sessions, subagents) flow through the delivery layer with no interception point. There is no way to suppress a reply based on content, log outbound messages to an audit trail, or transform delivery targets without modifying core code.
Acceptance criteria
beforeDeliverhook fires before any reply is sent to a channel; returning{ abort: true }suppresses deliveryafterDeliverhook fires after successful or failed delivery with status, channel, and duration contextopenclaw.jsonunder ahooks.delivery(or sharedhooks) sectionfilter.workflow(cron,agent,subagent) to target specific sourcesImplementation plan
src/cron/delivery.ts+ agent reply path insrc/agents/subagent-announce-dispatch.ts)DeliveryHooksConfigtype tosrc/config/types.hooks.ts(or extend shared hook types)beforeDelivercheck before channel send; wireafterDeliverafter send completesrunCronHooks/loadHookEntriesfromsrc/cron/hooks.ts(already workflow-agnostic)Files affected
src/cron/hooks.ts(reuse — no changes expected)src/config/types.hooks.ts(add DeliveryHooksConfig)src/config/zod-schema.ts(add Zod schema for delivery hooks)src/cron/delivery.ts(wire beforeDeliver)src/agents/subagent-announce-dispatch.ts(wire beforeDeliver for agent replies)src/cron/hooks.test.tsor newsrc/delivery/hooks.test.ts(tests)Additional notes
beforeDeliveris hook point 7 in the original cron hooks plan (cron-lifecycle-hooks.md) — it was deferred from the cron PR intentionallyctx.workflowdistinguishes source so a single global hook can target cron-only or agent-only delivery