> ## Documentation Index
> Fetch the complete documentation index at: https://docs.auto.sh/llms.txt
> Use this file to discover all available pages before exploring further.

# Chat Assistant

> An @mentionable Slack agent with its own identity that holds context across a whole thread: mention it to start, reply to continue.

This example gives your team a conversational agent with its own Slack presence: mention `@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:

```mermaid theme={null}
flowchart TD
    A["chat.message.mentioned"] --> B{"Does this agent already<br/>hold the thread?<br/>($.auto.attributions)"}
    B -->|"exists: false"| C["spawn a new session,<br/>bound to the slack.thread"]
    B -->|"exists: true"| D["deliver into the bound<br/>session (attributedSessions)"]
    E["chat.message.subscribed<br/>(any reply in a bound thread)"] --> D
    C --> F["Reply in-thread<br/>with chat.send"]
    D --> F
```

| Trigger        | Events                                              | `where`                                                            | Routing                                    |
| -------------- | --------------------------------------------------- | ------------------------------------------------------------------ | ------------------------------------------ |
| `mention`      | `chat.message.mentioned`                            | `$.auto.attributions: { exists: false }`, `$.auto.authored: false` | `spawn` + `bind: { target: slack.thread }` |
| `thread-reply` | `chat.message.mentioned`, `chat.message.subscribed` | `$.auto.attributions: { exists: true }`, `$.auto.authored: false`  | `deliver`, `routeBy: attributedSessions`   |

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.attributions`** lists the sessions bound to the thread (for an addressed mention, filtered to the addressed agent). `exists: false` means "no session of mine holds this thread yet" — spawn; `exists: true` means one does — deliver into it.
* **Every reply in a bound thread** arrives as `chat.message.subscribed` and delivers to the bound session via `attributedSessions`, 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, `@assistant` handle, avatar — in the connected Slack workspace. See [connections and identities](/concepts/connections-and-identities).

<Note>
  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/triggers).
</Note>

## Reference-only example

<Warning>
  Chat Assistant is retired from the managed roster. This page remains a
  worked example of chat spawn/deliver attribution; there is no current
  managed entrypoint to import.
</Warning>

## The full configuration

```text theme={null}
.auto/
  agents/assistant.yaml
  assets/chatterbox.png
  fragments/environments/agent-runtime.yaml
```

```yaml .auto/fragments/environments/agent-runtime.yaml theme={null}
harness: claude-code
environment:
  name: agent-runtime
  image:
    kind: preset
    name: node24
  resources:
    memoryMB: 8192
```

```yaml .auto/agents/assistant.yaml theme={null}
name: assistant
model:
  provider: anthropic
  id: claude-sonnet-5
identity:
  displayName: Assistant
  username: assistant
  avatar:
    asset: .auto/assets/chatterbox.png
  description: The team's channel assistant - mention @assistant for quick answers, summaries, and drafts.
imports:
  - ../fragments/environments/agent-runtime.yaml
systemPrompt: |
  You are the team's conversational assistant. You exist to be quick and
  helpful: answer questions, summarize, draft, and keep things light in direct
  sessions and, when the chat tool is available, Slack.

  Conversation rules:
  - Reply through the current interaction surface. For Slack-triggered work,
    use chat.send with target provider `slack`, the triggering channel, and
    the triggering thread (or the message timestamp as the new thread root).
  - A Slack mention delivery binds its thread to this run so follow-up messages
    route back here and retain context.
  - Keep replies short — one to three sentences for most messages. Slack
    is a chat, not a blog. Use mrkdwn (<https://url|text> links) and at
    most one or two emoji.
  - Remember what was said earlier in the conversation and refer back to
    it.
  - Never reply to your own messages. If a message looks like it was not
    meant for you, stay quiet.

  Hard limits: do not edit files, run repository commands, or touch
  anything outside the chat tools. If a request is real engineering work,
  suggest the right workflow or person for it instead of attempting it.
initialPrompt: |
  Help with the request in this session. Answer directly unless Slack trigger
  context is present and the chat tool is available; in that case reply in the
  triggering thread already bound by mention delivery and keep the
  conversation there.
tools:
  auto:
    kind: local
    implementation: auto
  chat:
    kind: local
    implementation: chat
    auth:
      kind: connection
      provider: slack
      connection: slack
      optional: true
triggers:
  - name: mention
    event: chat.message.mentioned
    connection: slack
    optional: true
    where:
      $.chat.provider: slack
      $.auto.authored: false
      $.auto.attributions:
        exists: false
    routing:
      kind: spawn
      bind:
        target: slack.thread
  - name: thread-reply
    events:
      - chat.message.mentioned
      - chat.message.subscribed
    connection: slack
    optional: true
    where:
      $.chat.provider: slack
      $.auto.authored: false
      $.auto.attributions:
        exists: true
    message: |
      {{message.author.userName}} replied in your conversation:

      {{message.text}}

      Channel: {{chat.channelId}}
      Thread: {{chat.threadId}}

      Reply in that thread with chat.send and keep the running context of
      this conversation.
    routing:
      kind: deliver
      routeBy:
        kind: attributedSessions
      onUnmatched: drop
```

There is no mount and no GitHub tool: the agent's entire surface is the [chat tool](/runtime/chat-tools) plus the [auto tool](/runtime/auto-tools), which is what makes it safe to point at a whole workspace.

## Walkthrough

<Steps>
  <Step title="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.
  </Step>

  <Step title="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.
  </Step>

  <Step title="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.
  </Step>

  <Step title="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.
  </Step>

  <Step title="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.
  </Step>
</Steps>

## 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_remote` tool or hosted connection provider) and it cites your internal docs. Adjust the `systemPrompt`'s hard limits to match whatever you grant. See [tools](/reference/tools).
* **Direct messages.** DMs arrive as `chat.message.direct` and 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. Point `connection:` at the other workspace's connection and adjust the `$.chat.provider` filter — or drop the filter and let one assistant listen across providers. See [Slack events](/reference/events/slack) and [Telegram events](/reference/events/telegram).
* **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.
