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

# Entry handlers

> Every way an agent can be started: the entry types, each handler's configuration fields, and the variables a handler injects for prompts

An agent's entry decides how a run starts. This page lists every entry type, the configuration fields of each entry handler, and the variables a handler makes available to prompts. Values are taken from the running binary; `servflowai resource handler describe --all` prints the same catalog.

## Entry types

| Dashboard label                                 | `entry.type` | `handlerConfig.type` | Needs a path | Replies to                                           |
| ----------------------------------------------- | ------------ | -------------------- | ------------ | ---------------------------------------------------- |
| Trigger — run manually or on a schedule         | `trigger`    | —                    | No           | Nobody. The reply is logged.                         |
| Webhook — a plain HTTP request starts the agent | `handler`    | empty                | Yes          | The HTTP caller.                                     |
| GitHub webhook                                  | `handler`    | `github_webhook`     | Yes          | The pull request or issue, when `respond_to` allows. |
| Telegram bot                                    | `handler`    | `telegram_webhook`   | Yes          | The chat the message came from.                      |
| Discord bot                                     | `handler`    | `discord_gateway`    | No           | The channel the message came from.                   |

### Trigger

A trigger entry has one field.

| Key    | Type   | Required | Default | Description                                                                                                                              |
| ------ | ------ | -------- | ------- | ---------------------------------------------------------------------------------------------------------------------------------------- |
| `cron` | string | No       | empty   | Cron expression with an optional seconds field, or a descriptor such as `@hourly`. Empty means the agent only runs when started by hand. |

### Webhook

A webhook entry answers `POST` requests on its path. The method is fixed. No handler wraps the request, so nothing is authenticated and nothing is read from it in advance. Prompts read the request with the `body`, `param`, and `header` template functions. `body` reads a field from a JSON body and requires `Content-Type: application/json`. The response body is the agent's final reply.

## Entry handlers

An entry handler wraps the whole run. On the way in it authenticates the delivery and parses it into variables. On the way out it delivers the agent's reply to the sender. Each handler needs an integration of a specific type, created before the agent.

Variables are read in a prompt as `{{ .<namespace>.<key> }}`, for example `{{ .github.comment_body }}`.

A handler marked as a listener dials its sender and holds the connection open. It has no path.

### github\_webhook

Runs on a delivery from a GitHub App: an issue or pull request comment, a review comment, a push. The agent's answer is posted back to the pull request or issue that started the run when `respond_to` says so.

Namespace: `github`. Needs a path. Integration type: `github_app`.

**Configuration**

| Key                 | Label                       | Type        | Required | Default                                      | Description                                                                                                                             |
| ------------------- | --------------------------- | ----------- | -------- | -------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------- |
| `integration`       | GitHub App                  | integration | Yes      | —                                            | The App whose deliveries this entry answers, and whose identity it replies as. Its webhook secret authenticates every delivery.         |
| `events`            | Events                      | string list | No       | every event the App is subscribed to         | `X-GitHub-Event` names this entry accepts, such as `issue_comment`, `pull_request`, `pull_request_review_comment`, `issues`, `push`.    |
| `actions`           | Actions                     | string list | No       | any action                                   | Delivery actions this entry accepts, such as `opened`, `created`, `synchronize`.                                                        |
| `trigger_text`      | Trigger text                | string      | No       | the App's own handle                         | What a comment has to say to be talking to this agent. Set it to be summoned by something other than the App's name, such as `/review`. |
| `respond_to`        | Respond to                  | string list | No       | never posts; the answer only reaches the log | Which kinds of delivery get the agent's answer posted back. Values: `pull_request`, `issue`.                                            |
| `update_pr_comment` | Update the previous comment | boolean     | No       | `false`                                      | Edit the comment this config last left on the pull request instead of posting another one underneath it.                                |

**Variables**

| Key               | Type    | Description                                                               |
| ----------------- | ------- | ------------------------------------------------------------------------- |
| `event`           | string  | The `X-GitHub-Event` the delivery carried.                                |
| `action`          | string  | The delivery's action, such as `opened` or `synchronize`.                 |
| `delivery`        | string  | GitHub's delivery id, for matching a run to a webhook redelivery.         |
| `repo`            | string  | The repository's full name, `owner/name`.                                 |
| `installation_id` | number  | The App installation this delivery is for. A `github_post` step needs it. |
| `is_pr`           | boolean | Whether the delivery is about a pull request.                             |
| `pr_number`       | number  | The pull request or issue number.                                         |
| `is_comment`      | boolean | Whether the delivery is a comment.                                        |
| `comment_body`    | string  | The comment's text.                                                       |
| `sender_login`    | string  | Who caused the delivery.                                                  |
| `sender_is_bot`   | boolean | Whether the sender is a bot account.                                      |
| `comment_app_id`  | number  | The App a comment was written through, when GitHub says.                  |
| `app_slug`        | string  | This App's slug, as GitHub reports it.                                    |
| `trigger_text`    | string  | What a comment had to name to reach this agent.                           |

### telegram\_webhook

Runs on a message delivered by the Telegram Bot API, and sends the agent's answer back to the chat it came from. Each chat keeps its own conversation thread.

Namespace: `telegram`. Needs a path. Integration type: `telegram_bot`.

**Configuration**

| Key               | Label                | Type        | Required | Default                            | Description                                                                                                                                                                   |
| ----------------- | -------------------- | ----------- | -------- | ---------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `integration`     | Telegram bot         | integration | Yes      | —                                  | The bot this entry receives as and answers as. Its secret token authenticates every delivery.                                                                                 |
| `chat_types`      | Chat types           | string list | No       | all three                          | The kinds of chat this agent answers in. Values: `private`, `group`, `supergroup`.                                                                                            |
| `allowed_chats`   | Allowed chats        | string list | No       | any chat                           | Chat ids or `@usernames` this agent answers. Anything else is ignored.                                                                                                        |
| `require_mention` | Required mention     | string      | No       | no mention required                | The text a group message must contain to run the agent, such as `@mybot`. Group chats only. In a private chat every message is addressed to the bot already.                  |
| `ignore_bots`     | Ignore bots          | boolean     | No       | `false`                            | Ignore messages sent by other bots.                                                                                                                                           |
| `commands`        | Commands             | string list | No       | every message runs the agent       | Slash commands this agent answers, such as `/ask`. A message that is not one of them is ignored.                                                                              |
| `typing`          | Typing indicator     | boolean     | No       | `true`                             | Show "typing…" in the chat for the length of the run.                                                                                                                         |
| `reply_in_thread` | Reply to the message | boolean     | No       | on in groups, off in private chats | Quote the message that asked, rather than answering the chat.                                                                                                                 |
| `parse_mode`      | Parse mode           | string      | No       | plain text                         | How Telegram renders the answer. Values: `MarkdownV2`, `HTML`. Leave it unset unless the agent is told to write that markup. One unescaped character costs the whole message. |

**Variables**

| Key             | Type    | Description                                               |
| --------------- | ------- | --------------------------------------------------------- |
| `text`          | string  | The message text.                                         |
| `chat_id`       | number  | The chat the message arrived in.                          |
| `chat_type`     | string  | `private`, `group`, or `supergroup`.                      |
| `chat_title`    | string  | The group's title, empty in a private chat.               |
| `chat_username` | string  | The chat's `@username`, when it has one.                  |
| `message_id`    | number  | The message's id.                                         |
| `update_id`     | number  | Telegram's update id.                                     |
| `user_id`       | number  | Who sent the message.                                     |
| `username`      | string  | The sender's `@username`.                                 |
| `first_name`    | string  | The sender's first name.                                  |
| `is_bot`        | boolean | Whether the sender is a bot.                              |
| `is_command`    | boolean | Whether the message starts with a `/command`.             |
| `command`       | string  | The command name, without the slash.                      |
| `args`          | string  | Everything after the command.                             |
| `reply_to_text` | string  | The text of the message this one replies to.              |
| `thread_id`     | number  | The forum topic this message belongs to, `0` outside one. |

### discord\_gateway

Holds a websocket open to Discord and runs on the messages it hears, answering in the channel that asked. It is a listener, so it has no path. The bot needs the MESSAGE CONTENT intent enabled in the Discord developer portal.

Namespace: `discord`. No path. Integration type: `discord`.

**Configuration**

| Key                | Label             | Type        | Required | Default                      | Description                                                                                                                                                                                                                         |
| ------------------ | ----------------- | ----------- | -------- | ---------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `integration`      | Discord bot       | integration | Yes      | —                            | The bot this entry connects and answers as.                                                                                                                                                                                         |
| `chat_types`       | Chat types        | string list | No       | all three                    | Where a message may arrive from. A thread is its own place, not a property of the channel it hangs under. Values: `guild`, `dm`, `thread`.                                                                                          |
| `allowed_guilds`   | Allowed servers   | string list | No       | any server                   | Guild ids this agent answers in.                                                                                                                                                                                                    |
| `allowed_channels` | Allowed channels  | string list | No       | any channel                  | Channel ids this agent answers in.                                                                                                                                                                                                  |
| `require_mention`  | Require a mention | boolean     | No       | `false`                      | Run only when the message mentions the bot.                                                                                                                                                                                         |
| `ignore_bots`      | Ignore bots       | boolean     | No       | `true`                       | Ignore messages sent by other bots.                                                                                                                                                                                                 |
| `commands`         | Commands          | string list | No       | every message runs the agent | Commands this agent answers, written without the `!` prefix a message carries.                                                                                                                                                      |
| `typing`           | Typing indicator  | boolean     | No       | `true`                       | Show the typing indicator in the channel for the length of the run.                                                                                                                                                                 |
| `super_user`       | Super user        | string      | No       | none                         | The Discord user this agent treats as its operator, as a user id or an `@username`. Sets `is_super_user` on each run. An id is the safer of the two. A username can be changed, and a released one can be claimed by somebody else. |

**Variables**

| Key                 | Type    | Description                                               |
| ------------------- | ------- | --------------------------------------------------------- |
| `content`           | string  | The message text, with the bot's own mention stripped.    |
| `channel_id`        | string  | The channel the message arrived in.                       |
| `parent_channel_id` | string  | The channel a thread hangs under, empty outside a thread. |
| `guild_id`          | string  | The server, empty in a DM.                                |
| `chat_type`         | string  | `guild`, `dm`, or `thread`.                               |
| `message_id`        | string  | The message's id.                                         |
| `author_id`         | string  | Who sent the message.                                     |
| `username`          | string  | The sender's username.                                    |
| `display_name`      | string  | The sender's nickname in this server, or their username.  |
| `is_bot`            | boolean | Whether the sender is a bot.                              |
| `is_super_user`     | boolean | Whether the sender is the configured super user.          |
| `mentions_me`       | boolean | Whether the message mentions the bot.                     |
| `is_command`        | boolean | Whether the message starts with a `!command`.             |
| `command`           | string  | The command name, without the prefix.                     |
| `args`              | string  | Everything after the command.                             |
| `reply_to_text`     | string  | The text of the message this one replies to.              |
| `reply_to_author`   | string  | Who wrote the message this one replies to.                |
| `message_link`      | string  | A link to the message.                                    |

## Declaring an entry in a config

In an agent config, the entry is the `entry` object. `start` names the first sub-agent or context group to run.

```yaml theme={null}
entry:
  type: handler
  handlerConfig:
    type: github_webhook
    path: /hooks/pull-request
    config:
      integration: my-github-app
      events: [pull_request]
      actions: [opened, synchronize]
      respond_to: [pull_request]
  start: agent.review
```

A webhook entry leaves `handlerConfig.type` empty and `config` out. A trigger entry replaces `handlerConfig` with `trigger`:

```yaml theme={null}
entry:
  type: trigger
  trigger:
    cron: "0 9 * * 1-5"
  start: agent.digest
```

## Related

<CardGroup cols={2}>
  <Card title="Create an agent" icon="robot" href="/guides/create-an-agent">
    Set the entry in the dashboard while building an agent.
  </Card>

  <Card title="Dynamic content" icon="code" href="/references/concepts/dynamic-content">
    The template functions a webhook entry reads the request with.
  </Card>
</CardGroup>
