Ingress-to-dispatch flow lacks a configurable external rules pipeline for whitelist and context routing #5

Closed
opened 2026-04-27 18:44:40 +07:00 by codex · 2 comments
Collaborator

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.

## 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 routing 2026-04-27 18:45:25 +07:00
Author
Collaborator

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
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
Collaborator

Validation: Issue confirmed

Issue #5 đúng — hiện tại processMessage gộ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

  • Internal (bridge-owned): anti-loop, idempotency — luôn chạy, không configurable
  • External (operator-configurable): whitelist, sender routing, context selection

2. External rules pipeline

  • Tạo internal/rules/ package với interface RuleRuleResult
  • Mỗi rule nhận email context (sender, subject, headers) và trả về: accept/reject + metadata
  • Rules được cấu hình qua config/env, load khi start
  • Phase 1 rules: WhitelistRule (move from hardcoded), RejectRule (blocklist)

3. Per-email context for dispatch

  • RuleResult có thể attach metadata (routing hints, instructions, context)
  • Metadata được pass qua dispatch pipeline đến OpenClaw
  • Task model thêm field DispatchContext (JSON) để persist rule output

4. Documentation

  • Update README flow: Ingress → Safety Checks → External Rules → Apply Context → Save → Dispatch
  • Add ADR-0002: External rules pipeline architecture
  • Update requirements.md pipeline section

Files to change

  • New: internal/rules/ (engine, whitelist rule, reject rule)
  • Modify: internal/mail/imap.go (extract rules from processMessage)
  • Modify: internal/config/config.go (rule config)
  • Modify: internal/database/models.go (dispatch_context field)
  • Modify: internal/ai_client/client.go (pass context to dispatch)
  • Modify: README.md, requirements.md
  • New: docs/adr/0002-external-rules-pipeline.md

Risks

  • Phạm vi thay đổi rộng (4 packages), cần cẩn thận không break existing flow
  • Task model migration cần backward compatible

Nếu duyệt scope này, tôi sẽ bắt đầu Phase 2.

## Validation: Issue confirmed Issue #5 đúng — hiện tại `processMessage` gộ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 - **Internal (bridge-owned):** anti-loop, idempotency — luôn chạy, không configurable - **External (operator-configurable):** whitelist, sender routing, context selection ### 2. External rules pipeline - Tạo `internal/rules/` package với interface `Rule` và `RuleResult` - Mỗi rule nhận email context (sender, subject, headers) và trả về: accept/reject + metadata - Rules được cấu hình qua config/env, load khi start - Phase 1 rules: `WhitelistRule` (move from hardcoded), `RejectRule` (blocklist) ### 3. Per-email context for dispatch - `RuleResult` có thể attach metadata (routing hints, instructions, context) - Metadata được pass qua dispatch pipeline đến OpenClaw - Task model thêm field `DispatchContext` (JSON) để persist rule output ### 4. Documentation - Update README flow: `Ingress → Safety Checks → External Rules → Apply Context → Save → Dispatch` - Add ADR-0002: External rules pipeline architecture - Update requirements.md pipeline section ### Files to change - New: `internal/rules/` (engine, whitelist rule, reject rule) - Modify: `internal/mail/imap.go` (extract rules from processMessage) - Modify: `internal/config/config.go` (rule config) - Modify: `internal/database/models.go` (dispatch_context field) - Modify: `internal/ai_client/client.go` (pass context to dispatch) - Modify: `README.md`, `requirements.md` - New: `docs/adr/0002-external-rules-pipeline.md` ### Risks - Phạm vi thay đổi rộng (4 packages), cần cẩn thận không break existing flow - Task model migration cần backward compatible Nếu duyệt scope này, tôi sẽ bắt đầu Phase 2.
claudecode was assigned by thuanle 2026-04-28 06:18:20 +07:00
Sign in to join this conversation.
No labels
2 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: thuanle/claw-email#5