Documentation menu
Getting started
New in v2.0
Feature deep dives
Reference
Multi-source → multi-target routing
Multi-Source to Multi-Target Routing
A single task can watch any number of source chats and deliver to any number of targets, with the primary pair mirrored and forum topics addressable per target.
Verified against the checkout built for v2.2.4 · updated 20 Oct 2026
On this page
RoutingNew in v2.0
Lists instead of single values, with a sanctioned write path that keeps the legacy mirror in step.
Why lists, not one source per task
Duplicating a task per source was the old workaround: same cleaner, same filters, same footer, N times to maintain.
- One policy edit applies to every source and every target of that task.
- Statistics, queue depth and dead letters stay aggregated per task instead of scattered across clones.
- Adding a source or a target is a list mutation, not a new task with its own session and schedule.
- The primary source and primary target are derived from the lists — never configured twice.
The data model
A task carries source_chat_ids and target_chat_ids. The first entry is mirrored into the legacy scalar fields (source_chat_id, target_chat_id) by a single sanctioned write path, set_targets(), which accepts ids, titles, or both and always leaves the pair consistent.
Readers are defensive: when the mirror is empty — for example on a row written by an older release — the destination is resolved from the list itself. That is what makes the format backward compatible without a migration.
{
"name": "Desk feed → VIP + free tier",
"source_chat_ids": ["@desk_feed", "-1001695513745"],
"target_chat_ids": ["-1002000000001", "-1002000000002"],
"mode": "copy",
"priority": 10,
"content_policy": { "enabled": true, "remove_links": true }
}Per-target addressing
- Every target entry keeps its own title, so dashboards and the bot show a human name next to the numeric id.
- Forum topics are addressed per target with message_thread_id: a task can post to a topic in one supergroup and a plain channel in the same run.
- Copy mode drops the forward tag; direct forward keeps the native quote header. The mode is a task property, applied to every target.
- A target that rejects writes auto-disables that task instead of retrying forever.
Adding sources and targets from the CLI
# create a task with two sources and two targets in one shot
atf rules create --name "Desk feed" \
--source @desk_feed --source -1001695513745 \
--target -1002000000001 --target -1002000000002
# mutate the lists later
atf rules sources <task-id> list
atf rules sources <task-id> add @second_desk
atf rules sources <task-id> remove @desk_feed
# see the resolved route, including which target gets what
atf rules path <task-id>Frequently asked
Do I have to reconfigure targets after upgrading to v2.0?
No. Existing single-source and single-target tasks are read as a one-entry list, and the first list entry keeps mirroring into the legacy field. Nothing has to be migrated.
Can one target have different rules from another in the same task?
Yes — policy overrides exist per source and per target. An override is additive only: it can narrow what is forwarded or add a transform, but it can never relax the task policy.
What happens when the primary target is deleted but the list has other entries?
Resolution falls back to the list, so delivery continues to the remaining targets. The mirror is rewritten on the next write to the task.