Problem
When an agent has hitl_enabled: true, every pending_approval send fires an approval-notification email to the account owner via internal/hitlnotify/notifier.go. There is no way to opt out short of disabling HITL entirely.
This is painful in a few real cases:
- E2E / load testing. During a prod test session, ~70 pending sends produced ~70 notification emails to the owner's inbox. The "queue then reject" pattern is not safe for testing because the notification already left by the time
/messages/{id}/reject is called.
- Dashboard-only reviewers. Some operators watch the dashboard live (or have a Slack integration polling pending messages) and don't want their inbox to fill up.
- Programmatic approval flows. Agents whose approvals are driven by API/CLI/webhook callers don't need the magic-link email — the link goes unused.
Proposed solution
Add a per-agent boolean hitl_notify_email (default true to preserve existing behavior). When false, the HITL gate skips the call to Notifier.NotifyPendingApproval for that agent. All other HITL paths (dashboard view, CLI approve/reject, /messages/{id}/approve|reject, TTL expiration worker) remain unchanged.
Per-agent matches the existing HITL granularity (hitl_enabled, hitl_expiration_action, hitl_ttl_seconds) and is the simplest mental model for users.
Implementation sketch
- Migration:
ALTER TABLE agents ADD COLUMN IF NOT EXISTS hitl_notify_email BOOL NOT NULL DEFAULT TRUE; (idempotent, non-destructive — safe per the migration guidelines in CLAUDE.md)
- Add the field to
RegisterAgentRequest, UpdateAgentRequest, and Agent response with swag annotations
- Branch in the HITL gate (where
Notifier.NotifyPendingApproval is currently called) to skip when the agent's flag is false
make generate to regen TS + Python SDK types
- CLI: surface as
--no-notify on the relevant commands (or part of agents update)
- Web: add a checkbox to the agent's HITL settings panel
Tradeoff to document
If a user disables notifications and stops watching the dashboard, pending messages will silently expire and act per hitl_expiration_action (approve or reject). The API description for hitl_notify_email should call this out.
Alternative considered
A per-request header override (X-E2A-Skip-Notification: 1 on /send) is more flexible but adds API surface for a niche case. Per-agent boolean covers all the use cases above with less complexity.
Out of scope
- Per-recipient notification rules (deferred)
- Notification channels other than email (Slack, webhook) — separate feature
Problem
When an agent has
hitl_enabled: true, everypending_approvalsend fires an approval-notification email to the account owner via internal/hitlnotify/notifier.go. There is no way to opt out short of disabling HITL entirely.This is painful in a few real cases:
/messages/{id}/rejectis called.Proposed solution
Add a per-agent boolean
hitl_notify_email(defaulttrueto preserve existing behavior). Whenfalse, the HITL gate skips the call toNotifier.NotifyPendingApprovalfor that agent. All other HITL paths (dashboard view, CLI approve/reject,/messages/{id}/approve|reject, TTL expiration worker) remain unchanged.Per-agent matches the existing HITL granularity (
hitl_enabled,hitl_expiration_action,hitl_ttl_seconds) and is the simplest mental model for users.Implementation sketch
ALTER TABLE agents ADD COLUMN IF NOT EXISTS hitl_notify_email BOOL NOT NULL DEFAULT TRUE;(idempotent, non-destructive — safe per the migration guidelines in CLAUDE.md)RegisterAgentRequest,UpdateAgentRequest, andAgentresponse with swag annotationsNotifier.NotifyPendingApprovalis currently called) to skip when the agent's flag is falsemake generateto regen TS + Python SDK types--no-notifyon the relevant commands (or part ofagents update)Tradeoff to document
If a user disables notifications and stops watching the dashboard, pending messages will silently expire and act per
hitl_expiration_action(approve or reject). The API description forhitl_notify_emailshould call this out.Alternative considered
A per-request header override (
X-E2A-Skip-Notification: 1on/send) is more flexible but adds API surface for a niche case. Per-agent boolean covers all the use cases above with less complexity.Out of scope