# Agents in YAML

> Agents are LLM-backed participants in a channel’s activities. They read the ticket context and conversation history, then respond with a comment.

Canonical HTML page: https://conclude.io/doc/reference/agents/
Last updated: 2026-11-02

---

Agents are LLM-backed participants in a channel's activities. They read the
ticket context and conversation history, then respond with a comment.

## Where agents come from

An agent belongs to the organization. It is created in the admin console under
Apps → Agents, has its own user account, and shows up as a real teammate
wherever it posts. An app does not define agents of its own: it names the ones
it wants in its triggers, and the same agent can answer on several apps and take
part in channels.

Attach one from either end — the app editor's Agents tab, or an agent's
Deployment tab in the admin console, where a click on an app's triggers opens the
Agents tab's dialog. Both write the trigger entries described below, so hand-editing
the YAML does the same thing.

## Skeleton

```yaml
triggers:
  - onCreate:
      - agent: triage
  - onComment:
      - agent: triage
```

## Wiring agents to triggers

In the trigger:

```yaml
agent: triage           # the agent's name, matched case-insensitively
```

Write the name. Saving the app rewrites it to `@Triage:{{U-...}}`, which is the agent's
own user — the same way an app refers to a person. The app then follows the agent through
a rename, and the name you see is refreshed from the agent itself. A plain name keeps
working, which is what app templates and hand-written YAML carry.

An app holds no mode for its agents: the mode is the deployment's (below). A `mode:` or
`onMention:` line an older app still carries is read past.

| Event | Typical use |
|---|---|
| `onCreate` | Triage and respond to the initial activity |
| `onComment` | Reply to follow-up comments; the one event the mode gates |
| `onEdit` | React when attributes change |
| `onConclude` | Write a postmortem summary |

In a channel, rather than on a ticket, an agent is addressed as `@name`, or by a
platform mention of its linked user where it has one. An agent with no
account cannot be auto-completed, so writing the name is how it is reached.

### The mode

An agent has one mode in a channel, and it covers the tickets of the channel's app as
well as the conversation. It is the agent's own, set on its General tab, unless the
channel sets another on the agent's Deployment tab. Where only the app names the agent,
with no deployment to the channel, the agent's own applies.

| Mode | The agent answers |
|---|---|
| Mention | A message or comment that @mentions it |
| Conversational | Also one that names it |
| Autonomous | Every message and comment, deciding for itself whether to speak |
| Off | Nothing, the app's events included — it stays deployed and silent |

Only a comment can address an agent, so the mode gates comments: an agent that is not
off answers every other event it is on — a new ticket, an edit, a conclusion — unasked.

`off` exists because an agent linked to a user account follows that account's
membership, and in a public Teams team every member is in every public channel. There
is no per-channel membership to take the account out of, so the mode is what decides
whether the agent takes part there.

An agent switched off keeps its deployment: the channel still stores its messages and
Conclude still receives its events, so the agent reads the conversation it missed when
it is switched back on. Off in a channel silences it on the app's tickets there too.

## What the agent sees

For each invocation, the agent receives:

1. The app's `context` (if set) and `description` as a system-prompt prefix.
2. The agent's own instructions, from the admin console.
3. Current ticket state — title, body, status, severity, owner, members,
   deadline, conclusion, and every custom attribute that has a value.
4. The complete action history of the activity as alternating user /
   assistant / `[system]` messages (comments, owner changes, attribute
   changes, etc.).
5. Optional lookup data — if the app has a `lookup:` endpoint configured
   for this event, the response body is included as additional context.
6. The triggering event description (e.g. "new comment from Alice").

## Learning

A channel with learning on keeps what it learns in a knowledge collection it owns
("Learning: #channel"), from three sources:

| Source | Becomes | When |
|---|---|---|
| A closed ticket of the channel's app | A case file: problem, cause, resolution | On close |
| A thread in the channel | A case file: question, answer, details | Two hours after its last reply; a later reply redoes it |
| The day's messages in the channel itself | A digest: topics, decisions, open questions | Just after midnight UTC |

Threads and digests need an agent in the channel: that is what makes Conclude store its
messages. A channel that learns keeps them for 7 days instead of an hour, and switching
learning off purges what it kept, as does removing the app, which switches learning off. A
thread with one person in it, or a day of fewer than three messages, is left out, and the
model skips what holds nothing worth keeping.

Agents search the collection with `search_learning`: on the app's tickets, and in the
channel's own conversations. Never on a connected ticket or in a connected channel,
which another organization reads. Learning is switched per channel on the admin console's
Deployment page, which only an organization with beta features on is offered; the app's YAML
has no setting for it. For now only a channel with an app can be switched on:
one without has no switch, so its conversations are not learned.

## Loop protection and rate limits

- **Self-loop prevention.** An agent never replies to its own comments.
  Comments authored by an agent are flagged,
  and the trigger dispatcher skips agent triggers when the source action
  is from the same agent.
- **Cross-agent loop prevention.** Any comment posted as a result of a
  trigger (script or agent) carries a marker that blocks
  further agent/script dispatch. The chain stops after one hop.
- **Per-activity rate limit.** Agent comments are throttled to 5 per
  minute per activity; excess is dropped.
- **Per-activity comment cap.** The agent's max comments (or 20 by default) — the
  agent stops responding once it's posted this many comments on a single
  activity, to prevent runaway threads.

## Lookup-backed context

If the app has a `lookup:` endpoint, the agent handler POSTs to it with
`{event, activity: {title, email}}` and includes the response as extra
context in the prompt. Configure which events trigger lookup via the
`on:` list:

```yaml
lookup:
  url: https://crm.example.com/conclude-lookup
  secret: crm_api_token       # references a Secret by name
  on: [onCreate, onComment]
  timeout: 5s
```

See [Connectors](https://conclude.io/doc/reference/connectors/#lookup-endpoint).

