Skip to content

Hook deliver: false still injects system event into main session #36325

@cioclawcode

Description

@cioclawcode

Description

When a hook mapping sets deliver: false, the delivery announcement is correctly suppressed, but a system event is still injected into the main session via enqueueSystemEvent. This causes the main session to receive "Hook :

" messages for every hook completion, even when the user explicitly opted out of delivery.

Expected Behavior

When deliver: false is set on a hook mapping, no system event should be injected into the main session. The hook should complete silently.

Actual Behavior

The system event Hook <name>: <summary> is always injected into the main session when deliver: false, because the guard only checks whether delivery succeeded — not whether it was requested.

Root Cause

In src/gateway/server/hooks.ts (~line 83):

if (!result.delivered) {
  enqueueSystemEvent(`${prefix}: ${summary}`.trim(), {
    sessionKey: mainSessionKey,
  });
}

When deliver: false:

  1. resolveCronDeliveryPlan (in src/cron/delivery.ts) correctly resolves to { mode: "none", requested: false }
  2. Delivery is never attempted, so result.delivered is always false
  3. The !result.delivered guard passes → system event fires unconditionally

Suggested Fix

Check whether delivery was explicitly disabled before injecting the system event. For example:

// Also suppress system event when delivery was explicitly disabled
if (!result.delivered && value.deliver !== false) {
  enqueueSystemEvent(`${prefix}: ${summary}`.trim(), {
    sessionKey: mainSessionKey,
  });
}

Alternatively, runCronIsolatedAgentTurn could return a deliveryRequested boolean in its result so the caller can make an informed decision.

Impact

This affects any hook with deliver: false. The main session receives a system event for every hook completion, which can cause the main session agent to announce hook results to unrelated channels (e.g., posting triage summaries to a project coordination channel instead of an audit trail channel).

Reproduction

  1. Configure a hook mapping with deliver: false
  2. Trigger the hook
  3. Observe system event Hook <name>: <summary> injected into main session
  4. Main session may then announce the summary to its active channel

Relevant Files

  • src/gateway/server/hooks.tsdispatchAgentHook, the !result.delivered guard
  • src/cron/delivery.tsresolveCronDeliveryPlan, legacy mode handling for deliver: false
  • src/cron/isolated-agent/run.tsrunCronIsolatedAgentTurn, delivery dispatch

Metadata

Metadata

Assignees

No one assigned

    Labels

    staleMarked as stale due to inactivity

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions