arizuko › howto › Asymmetric channels
asymmetric channels
A folder can read messages from a channel and never reply there. The agent reads every message that arrives, and it replies only on the channel that you select. Use this when one source gives a lot of context, for example a busy WhatsApp group or a mailing list, and another channel holds the conversation.
The target fragment decides whether a message starts a turn
The target of a route can end with a #mode fragment. The fragment decides what routd does after it stores the message in the folder:
| target | effect |
|---|---|
folder | store under folder and start a turn; the default |
folder#observe | store under folder and start no turn; the agent sees the message in the history at its next turn |
One folder can have two routes with two effects. The ACL of the agent applies to the folder, so the agent can read every observed message. The mode only decides when routd starts the agent. It does not change what the agent can see.
Two routes to one folder make a channel read-only
Add two routes to the same folder, one in each mode:
seq match target
10 platform=<reply-platform> room=<your-room> myfolder
20 platform=<ingest-platform> room=<src-room> myfolder#observe
- Select the channel that answers. This is the channel where the user talks, for example a phone chat, a team Slack or a Telegram DM. Its route has no fragment.
- Select the channels that only give context. Give each one a route to the same folder with
#observe. - Put the answering route first. A lower
seqcomes first, and the first match wins. So a route for one chat must come before an observe route with a wider pattern. - Change the context window if necessary. The answering turn adds the last
OBSERVE_WINDOW_MESSAGESobserved messages to the prompt, default 10, up toOBSERVE_WINDOW_CHARScharacters, default 4000. For a busy source, increase the values for the instance, or for one route in theobserve_window_messagesandobserve_window_charsfields of the route.
A mention-only channel uses the same two routes
One channel can answer only on a mention and observe the other messages. The first route matches the mentions, and the second route observes the rest of the same channel:
seq match target
10 chat_jid=slack:T012ABCD/channel/C0HJKL456 verb=mention team
20 chat_jid=slack:T012ABCD/channel/C0HJKL456 team#observe
A reply to a bot message also has verb=mention, so a reply starts a turn too. After the agent replies, the thread is engaged, and the next messages in it start turns without a mention. Engagement explains the time window.
Telegram answers, and WhatsApp only gives context
seq match target
10 platform=telegram room=group/5229089286 rhias/nemo
20 platform=whatsapp room=120363012345678901@g.us rhias/nemo#observe
The team talks on Telegram. The messages of the WhatsApp group go into the rhias/nemo folder as <observed> entries, and the agent never replies on WhatsApp. When a WhatsApp message is important, the agent posts to Telegram with a one-line source note.
The reality product uses this setup as a case study. This page gives the general recipe.
A rule in CLAUDE.md adds a second layer
The route mode is the enforcement: routd never starts a turn for an observed message. If you also want a rule that the agent itself reads, add it to the CLAUDE.md of the folder:
## Channels
Reply on Telegram only. Never call `send` with a WhatsApp chatJid.
Observed WhatsApp posts give context; the response goes on Telegram.
With the route mode in place, the rule changes nothing. It documents the intent.
Many observe routes can feed one folder
Many channels can feed one folder, and one channel answers:
- Read a Slack workspace, a Discord server and a partner Telegram group. Reply only in one Telegram DM.
- Read support email into a folder, and reply only on Slack.
- Copy the feed of a Discord server into a folder that already serves a personal Telegram chat. The user then has one inbox.
The limit is on the folder, not on the channel. Any number of #observe routes can go to one folder. Each route is one more row in the table.
Four pages give the details
- routing modes
- All target fragments.
- schema reference
- The fields of a route, also the
observe_window_*overrides. - OBSERVE_WINDOW_MESSAGES and OBSERVE_WINDOW_CHARS
- The defaults for the instance.
- reality product
- The Nemo deployment.