> ## 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.

# Identity

> The agent identity block: display name, username, avatar assets under .auto/assets/, how inline identities compile to resources, and @mention presence in chat providers.

The `identity` block gives an agent a face: a display name, a handle, an avatar, and a short description. Wherever the agent shows up — Slack messages, Telegram chats, Discord mentions, GitHub attribution, the auto UI — this one declaration is the source of those pixels and strings. Declare it inline on the agent; the compiler turns it into a standalone `identity` resource for you.

```yaml .auto/agents/ship-digest.yaml theme={null}
name: ship-digest
identity:
  displayName: Ship Digest
  username: ship-digest
  avatar:
    asset: .auto/assets/ship-digest.png
  description:
    Auto's daily shipped-code digest — summarizes merged work, flags
    follow-ups, and links the full report.
```

## Field reference

`identity` is optional. It takes either an inline object (the usual form) or a string naming an existing identity resource. The inline object is strict — unknown keys fail apply — and must carry **at least one** field.

<ParamField path="identity.displayName" type="string">
  Human-facing name, trimmed, 1–80 characters. Used as the app name for a dedicated Slack app and as the per-message sender name for workspace-bot sends.
</ParamField>

<ParamField path="identity.username" type="string">
  Handle-style name, trimmed, 1–80 characters. This is the agent's **mention alias** in chat providers (see [@mention presence](#mention-presence-in-chat-providers)) and the bot user's display name on a dedicated Slack app. When absent, the alias falls back to the agent's resource name.
</ParamField>

<ParamField path="identity.avatar" type="object">
  The agent's image, referenced from a file checked into the repo:

  * `asset` (required) — a relative path under `.auto/assets/` ending in `.png`, `.jpg`, or `.jpeg`. Absolute paths, Windows drive paths, and `..` segments are rejected.
  * `sha256` (optional) — the content hash of the stored asset bytes, 64 lowercase hex characters.

  When the apply carries the asset's bytes, the server derives the hash itself and overwrites any declared value. A declared hash **without** a local file resolves an already-stored or built-in catalog avatar — managed templates reference their baked-in avatars this way — but can never attach arbitrary bytes. A missing file is only an error when there is no hash to resolve.
</ParamField>

<ParamField path="identity.description" type="string">
  One-line purpose statement, trimmed, non-empty. The limit is **140 characters as Slack counts them** for an app's short description — Slack measures the JSON-escaped form, so a non-ASCII character like an em dash costs 6, an emoji costs 12, and `"`, `\`, `/` cost 2 each. auto enforces the same arithmetic at apply time so any accepted description renders untruncated everywhere it is realized. Also applied as the long and short description of a dedicated Telegram bot.
</ParamField>

### Avatar asset constraints

Apply validates the image bytes, not just the path. The asset must be:

| Constraint | Value                |
| ---------- | -------------------- |
| Format     | PNG or JPEG          |
| Size       | 1 byte – 2 MiB       |
| Shape      | Exactly square       |
| Dimensions | 512–2000 px per side |

The pixel bounds match the strictest provider surface — Slack app icons must be squares between 512×512 and 2000×2000 — so any accepted avatar can be realized on every provider without a rejection at connect time.

Stored avatars are served content-addressed at `/api/v1/avatars/<sha256>`: a changed image always means a changed URL, which is what keeps aggressively-cached provider surfaces (Slack caches `icon_url` hard) from showing a stale face.

## How identities compile to resources

Identities are **inline-only** in `.auto/` authoring. Standalone identity files under `.auto/identities/` are rejected at apply with an error telling you to move the block onto the owning agent.

The compiler splits the inline object out of the agent document and emits a generated `identity` resource; the agent's stored spec keeps only the resource **name**. An inline identity with no `name` of its own inherits the agent's name, so `ship-digest` above produces `identity/ship-digest` alongside `agent/ship-digest`.

Two consequences of that model:

* **Sharing by name.** `identity: reviewer` (a string) points the agent at an identity resource by name — for example one generated from another agent file. Most agents just declare inline.
* **Dedupe across files.** When two files generate an identity with the same name, the contents must be identical; differing content fails the apply with a "Conflicting generated resource" error rather than letting one file silently win.

During [import merge](/reference/imports-and-fragments), `identity` behaves like other record fields: inline objects deep-merge across imports (your document's fields win over an imported fragment's), and a string name overrides an inherited object outright — and vice versa.

## Where the identity is used

### Chat messages

An agent posting to Slack sends with its declared identity even before any dedicated app exists: the shared workspace bot applies per-message overrides — the sender name is `displayName` (falling back to `username`) and the icon is the avatar's public URL. A realized dedicated Slack app posts under its own bot user instead. Identity machinery is deliberately non-fatal: any failure to resolve the identity or a dedicated bot token falls back to the plain workspace bot rather than dropping the message.

### @mention presence in chat providers

Every chat provider resolves agent-addressed mentions through the same **canonical alias**: the identity `username`, falling back to the agent's resource name, matched case-insensitively.

* **Slack** — mention the shared Auto app with a delimiter and alias: `@auto.ship-digest summarize today`. Delimiters `.`, `:`, `/`, and `-` all work, and a space after the mention is tolerated (Slack inserts one). A dedicated per-agent app is @mentioned directly by its own bot user.
* **Discord** — mention the Auto application the same way: `@Auto.ship-digest …` with the same delimiter set.
* A **bare `@auto`** (or an unknown alias) falls back to the single connected agent when exactly one exists, otherwise to an `onboarding` agent, otherwise to a help reply listing the addressable aliases.

An alias only resolves for agents that declare a `chat.message.mentioned` trigger on that connection — addressing is opt-in through [triggers](/reference/triggers), not a side effect of having an identity. A message whose only mentions are humans stays inert.

### Dedicated provider presence

Applying an agent never calls a provider API. Instead, apply computes the agent's *desired* presence — which provider connections it reaches — and stores it; realizing that presence as a dedicated app or bot is a separate, explicit connect step.

Desired presence is inferred from two sources: provider-origin triggers (what makes the agent addressable), and — only when the agent declares an `identity` — the connections reachable through its chat tools, so an outbound-only agent like a cron digest can still carry its own persona. Providers with per-agent presence are Slack, Discord, and Telegram; a GitHub or Linear connection never yields a per-agent bot. Slack and Telegram presence are realizable as dedicated apps today.

What connecting does per provider:

* **Slack** — creates a dedicated per-agent Slack app from a manifest (app name from `displayName`, bot handle from `username`, description from `description`, marked always-online), then installs it into the workspace through an authorization you approve. Creating apps requires a one-time Slack **app-config token** per workspace, which auto rotates from then on.
* **Telegram** — produces a bot-creation deep link with a suggested username; once you confirm the new bot in Telegram, auto provisions the persona automatically and keeps its profile (name, descriptions, photo) in sync with the identity on later connects.

Reconnecting an already-realized identity reruns the install authorization — the repair path for a stranded bot token or for picking up newly added scopes. Stored app credentials are reused, so no duplicate app is ever created.

<Note>
  Slack exposes no API for app icons, so a dedicated app's icon is uploaded by hand in the app's Display Information settings. auto records the hash of the applied image — later connects with the same avatar stay silent, and a changed avatar surfaces the upload step again until the new image is recorded.
</Note>

An apply that drops a trigger or chat tool removes unrealized desired-presence rows, but **realized** presence (a created Slack app, a live Telegram bot) is preserved — tearing down a real bot is a deliberate lifecycle step, never an apply side effect.

## A complete example

Adapted from a production agent — a scheduled digest whose only provider surface is outbound Slack posts, carrying a full persona:

```yaml .auto/agents/ship-digest.yaml theme={null}
name: ship-digest
harness: claude-code
environment:
  name: digest-runtime
  image:
    kind: preset
    name: node24
identity:
  displayName: Ship Digest
  username: ship-digest
  avatar:
    asset: .auto/assets/ship-digest.png
  description:
    Auto's daily shipped-code digest — summarizes merged work, flags
    follow-ups, and links the full report.
tools:
  chat:
    kind: local
    implementation: chat
    auth:
      kind: connection
      provider: slack
      connection: slack
triggers:
  - kind: heartbeat
    cron: "0 8 * * 1-5"
    timezone: America/Los_Angeles
    routing:
      kind: spawn
```

Because the agent declares an `identity` and reaches a Slack connection through its chat tool, apply records a desired Slack presence; its posts immediately carry the Ship Digest name and avatar via the workspace bot, and connecting the agent upgrades that to a dedicated `@ship-digest` Slack app when you want one.

## Related pages

* [Agent file](/reference/agent-file) — every other field on the agent
* [Connections and identities](/concepts/connections-and-identities) — the connection model identities realize against
* [Slack events](/reference/events/slack) — the `chat.message.*` events mention routing produces
