The missing feature is not that every ingress rule should be externalized.
anti-loop should remain an internal safety rule.
The real gap is that the flow has no configurable external rules stage for operator-defined policy such as:
whitelist management
sender/domain-based routing
attaching different context/instructions before dispatch
other configurable pre-dispatch decisions
Intended split
Internal rules: invariants/guardrails owned by the bridge itself, such as anti-loop
External rules: operator-configurable policy, such as whitelist and sender-specific context selection
Current flow in code
IMAP ingress -> anti-loop -> whitelist -> idempotency -> threading -> save RECEIVED -> dispatch
Why this is incomplete
Right now, whitelist is implemented like an internal hardcoded rule instead of an external/configurable rule stage.
There is also no extension point where the system can derive different dispatch context based on the incoming email.
Evidence
internal/mail/imap.go:219-245 evaluates anti-loop, whitelist, and idempotency directly inside processMessage
internal/config/config.go:29-38 only supports a static env-based WHITELIST_EMAILS; there is no external rule source or rules pipeline config
internal/database/models.go:19-34 has no persisted field for rule-derived routing/context output
internal/ai_client/client.go:70-76 dispatch payload has no rule-enriched context stage before sending to OpenClaw
whitelist becomes part of the external rules stage
external rules can derive per-email context or metadata for dispatch
Impact
Without this separation, the bridge cannot support configurable pre-dispatch policy cleanly. The most obvious missing capability is externalized whitelist handling, but the same gap also blocks sender-aware context routing.
## Summary
The missing feature is not that every ingress rule should be externalized.
`anti-loop` should remain an internal safety rule.
The real gap is that the flow has no configurable external rules stage for operator-defined policy such as:
- whitelist management
- sender/domain-based routing
- attaching different context/instructions before dispatch
- other configurable pre-dispatch decisions
## Intended split
- **Internal rules:** invariants/guardrails owned by the bridge itself, such as anti-loop
- **External rules:** operator-configurable policy, such as whitelist and sender-specific context selection
## Current flow in code
`IMAP ingress -> anti-loop -> whitelist -> idempotency -> threading -> save RECEIVED -> dispatch`
## Why this is incomplete
Right now, `whitelist` is implemented like an internal hardcoded rule instead of an external/configurable rule stage.
There is also no extension point where the system can derive different dispatch context based on the incoming email.
## Evidence
- `internal/mail/imap.go:219-245` evaluates anti-loop, whitelist, and idempotency directly inside `processMessage`
- `internal/config/config.go:29-38` only supports a static env-based `WHITELIST_EMAILS`; there is no external rule source or rules pipeline config
- `internal/database/models.go:19-34` has no persisted field for rule-derived routing/context output
- `internal/ai_client/client.go:70-76` dispatch payload has no rule-enriched context stage before sending to OpenClaw
## Expected behavior
A more accurate flow would be:
`IMAP ingress -> internal safety checks -> evaluate external rules -> apply policy/context -> save task -> dispatch`
Where:
- anti-loop stays internal
- whitelist becomes part of the external rules stage
- external rules can derive per-email context or metadata for dispatch
## Impact
Without this separation, the bridge cannot support configurable pre-dispatch policy cleanly. The most obvious missing capability is externalized whitelist handling, but the same gap also blocks sender-aware context routing.
codex
changed title from Ingress-to-dispatch flow lacks a configurable external rules pipeline to Ingress-to-dispatch flow lacks a configurable external rules pipeline for whitelist and context routing2026-04-27 18:45:25 +07:00
But the detailed processing flow in requirements.md:66-87 already models multiple pre-dispatch steps inside ingress, and the feature gap discussed in this issue is specifically about making that stage explicit and configurable for external rules.
So this issue should also include documentation work:
update README.md so the flow no longer implies a direct Ingress -> Dispatch jump
update docs/specs to distinguish:
internal safety checks such as anti-loop
external rules such as whitelist and sender-aware context routing
keep the high-level architecture and the detailed pipeline aligned, otherwise the code/docs drift will continue even after implementation
Additional note on documentation drift:
The current README presents the top-level flow as:
`Ingress (IMAP) -> Dispatch (OpenClaw) -> Callback -> Egress (SMTP reply)`
See `README.md:3-7`.
But the detailed processing flow in `requirements.md:66-87` already models multiple pre-dispatch steps inside ingress, and the feature gap discussed in this issue is specifically about making that stage explicit and configurable for external rules.
So this issue should also include documentation work:
- update `README.md` so the flow no longer implies a direct `Ingress -> Dispatch` jump
- update docs/specs to distinguish:
- internal safety checks such as anti-loop
- external rules such as whitelist and sender-aware context routing
- keep the high-level architecture and the detailed pipeline aligned, otherwise the code/docs drift will continue even after implementation
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Summary
The missing feature is not that every ingress rule should be externalized.
anti-loopshould remain an internal safety rule.The real gap is that the flow has no configurable external rules stage for operator-defined policy such as:
Intended split
Current flow in code
IMAP ingress -> anti-loop -> whitelist -> idempotency -> threading -> save RECEIVED -> dispatchWhy this is incomplete
Right now,
whitelistis implemented like an internal hardcoded rule instead of an external/configurable rule stage.There is also no extension point where the system can derive different dispatch context based on the incoming email.
Evidence
internal/mail/imap.go:219-245evaluates anti-loop, whitelist, and idempotency directly insideprocessMessageinternal/config/config.go:29-38only supports a static env-basedWHITELIST_EMAILS; there is no external rule source or rules pipeline configinternal/database/models.go:19-34has no persisted field for rule-derived routing/context outputinternal/ai_client/client.go:70-76dispatch payload has no rule-enriched context stage before sending to OpenClawExpected behavior
A more accurate flow would be:
IMAP ingress -> internal safety checks -> evaluate external rules -> apply policy/context -> save task -> dispatchWhere:
Impact
Without this separation, the bridge cannot support configurable pre-dispatch policy cleanly. The most obvious missing capability is externalized whitelist handling, but the same gap also blocks sender-aware context routing.
Ingress-to-dispatch flow lacks a configurable external rules pipelineto Ingress-to-dispatch flow lacks a configurable external rules pipeline for whitelist and context routingAdditional note on documentation drift:
The current README presents the top-level flow as:
Ingress (IMAP) -> Dispatch (OpenClaw) -> Callback -> Egress (SMTP reply)See
README.md:3-7.But the detailed processing flow in
requirements.md:66-87already models multiple pre-dispatch steps inside ingress, and the feature gap discussed in this issue is specifically about making that stage explicit and configurable for external rules.So this issue should also include documentation work:
README.mdso the flow no longer implies a directIngress -> DispatchjumpValidation: Issue confirmed
Issue #5 đúng — hiện tại
processMessagegộp anti-loop, whitelist, idempotency vào một block cứng, không có extension point cho operator-defined rules.Full scope proposal
Tôi đề nghị chia thành 4 thành phần:
1. Internal vs External rules separation
2. External rules pipeline
internal/rules/package với interfaceRulevàRuleResultWhitelistRule(move from hardcoded),RejectRule(blocklist)3. Per-email context for dispatch
RuleResultcó thể attach metadata (routing hints, instructions, context)DispatchContext(JSON) để persist rule output4. Documentation
Ingress → Safety Checks → External Rules → Apply Context → Save → DispatchFiles to change
internal/rules/(engine, whitelist rule, reject rule)internal/mail/imap.go(extract rules from processMessage)internal/config/config.go(rule config)internal/database/models.go(dispatch_context field)internal/ai_client/client.go(pass context to dispatch)README.md,requirements.mddocs/adr/0002-external-rules-pipeline.mdRisks
Nếu duyệt scope này, tôi sẽ bắt đầu Phase 2.