@assistant in a channel to start a conversation, and every reply in that thread routes back to the same session, so the agent keeps its memory for the life of the thread.
It is the simplest end-to-end factory workflow — one agent, one trigger pair, no repository — and the best first install, because the output lands directly in front of the people evaluating it.
How it works
The example is the canonical demonstration of spawn vs. deliver routing on the same event, split by whether the thread already belongs to a session:
The moving parts:
- A fresh mention spawns and binds in one step. The spawn route’s
bind: { target: slack.thread }writes the thread binding as part of session creation, so the agent never has to “subscribe” manually. $.auto.attributionslists the sessions bound to the thread (for an addressed mention, filtered to the addressed agent).exists: falsemeans “no session of mine holds this thread yet” — spawn;exists: truemeans one does — deliver into it.- Every reply in a bound thread arrives as
chat.message.subscribedand delivers to the bound session viaattributedSessions, interrupting whatever the session was doing so the conversation feels live. - The inline
identity:block is what makes the agent a mentionable presence — display name,@assistanthandle, avatar — in the connected Slack workspace. See connections and identities.
This trigger pair is validated at apply time, not just convention: a chat deliver trigger routed by
attributedSessions must filter $.auto.authored: false (so the agent never loops on its own messages), and a spawn trigger sharing an event with such a deliver trigger must carry the mutually exclusive $.auto.attributions filters shown here. Configurations that break either rule fail to apply. See the trigger reference.Reference-only example
The full configuration
.auto/fragments/environments/agent-runtime.yaml
.auto/agents/assistant.yaml
Walkthrough
1
Someone mentions the agent
A teammate writes
@assistant can you summarize this thread?. Slack delivers the event; ingress resolves the mention to this agent and normalizes it to chat.message.mentioned. No session of this agent holds the thread, so $.auto.attributions is absent — the mention trigger matches.2
Spawn, bound to the thread
routing: spawn starts a session, and bind: { target: slack.thread } binds the thread to it at spawn. The event payload ({{message.text}}, {{chat.channelId}}, {{chat.threadId}}, author) arrives as the session’s first message.3
The agent replies in-thread
The agent calls
chat.send with provider slack, the triggering channel, and the triggering thread — falling back to the message timestamp as the new thread root when the mention wasn’t already in a thread. chat.send returns the threadId, so subsequent sends stay threaded.4
Replies keep the context
The teammate replies in the thread — no re-mention needed. The reply arrives as
chat.message.subscribed, now carrying $.auto.attributions for the bound session, so thread-reply delivers it straight into the running session via attributedSessions. The agent answers with its full conversational memory. $.auto.authored: false guarantees its own messages never echo back into it.5
Parallel threads, parallel sessions
A mention in a different thread has no attribution for this agent, so it spawns a second, independent session bound to that thread. Each conversation gets its own memory;
onUnmatched: drop means replies to a thread whose session has ended are dropped silently rather than resurrecting a context-free agent.Variations
- Make it an expert. The base agent is deliberately tool-poor. Add a read-only git mount of your repo and it answers codebase questions; add a docs MCP server (any
mcp_remotetool or hosted connection provider) and it cites your internal docs. Adjust thesystemPrompt’s hard limits to match whatever you grant. See tools. - Direct messages. DMs arrive as
chat.message.directand auto-subscribe their thread. Add that event key to the triggers to make the assistant answer DMs with the same spawn/deliver split. - Other chat providers. Slack, Discord, and Telegram share the same
chat.*event contract. Pointconnection:at the other workspace’s connection and adjust the$.chat.providerfilter — or drop the filter and let one assistant listen across providers. See Slack events and Telegram events. - A different persona. Rename the agent,
identity.displayName,identity.username, and the avatar asset — identity is entirely yours; the routing machinery doesn’t care. - Smoke test. After apply, mention the agent in a test channel, confirm the in-thread reply, then reply again and confirm it remembers the conversation. This doubles as the standard end-to-end check that events, sessions, and the Slack connection are all healthy.