Skip to content

Bots, Agents, Triggers

Mate’s configuration model has three building blocks: Bots, Agents, and Triggers. Understanding how they interact is the key to configuring Mate well.

A bot is a GitLab user whose Personal Access Token (PAT) you have registered with Mate. When an event fires, the bot is the actor: it clones the repository, posts comments, and takes actions in GitLab under that user’s identity.

You register a bot by providing its PAT in the tenant configuration. Mate derives the username automatically by calling the GitLab API — you do not configure the username yourself. Each PAT you register appears as a distinct bot with a distinct GitLab identity.

Bots are intentionally minimal. They carry no behavior — only an identity and credentials. To change what a bot does, you configure an agent.

An agent is a named configuration bundle that describes how a job should run:

  • Which LLM backend (claude-code is the primary backend in v1)
  • Which model (model: field, e.g. anthropic/claude-sonnet-4-6)
  • The system prompt
  • The authority profile — which GitLab operations the job may perform
  • Optional image and environment overrides

Agents have arbitrary names. An agent only runs when a trigger explicitly names it — there is no implicit “default persona” that runs when no trigger matches. If a GitLab event matches no trigger, no job is dispatched.

Additional agents with other names are allowed and are used to describe specialized behavior (a strict code reviewer, a junior fixer, a security auditor) without creating additional GitLab users.

A trigger binds a GitLab event to an agent. When the event fires, Mate evaluates the trigger list in order and fires the first matching trigger.

Each trigger specifies:

  • on: — the event type (issue_assigned, mr_opened, label_applied, etc.)
  • agent: — which agent’s configuration drives the job
  • Optional if: conditions — narrow the trigger to specific assignees, branches, labels, changed paths, or MR properties
  • Optional deny: — subtract specific authorities from the effective permission set for this trigger

See the configuration reference for the full list of event types and if: matcher vocabulary.

The most important thing to internalize: the GitLab actor and the effective configuration are chosen independently.

WhatChosen byHow
Actor — whose PAT mints the tokens, whose username appears in commentsThe GitLab eventThe assigned bot or the mentioned bot
Effective config — model, system prompt, permissionsThe matched triggerThe trigger’s agent: field. If no trigger matches, no job is dispatched.

A trigger override lets you decouple persona from identity. For example: you assign junior to an issue, but a trigger routes that assignment to the bot1 agent’s configuration — junior’s PAT acts, bot1’s model and prompt drive the behavior.

Configuration lives in two places that share the same schema:

  • Tenant YAML — edited in the console. Tenant-wide defaults. Only this layer may declare bots:.
  • .mate.yml at the repository root — per-repo overrides, versioned with the code.

The two are merged on every webhook. Repo-level config may extend or narrow agents but cannot escalate authorities beyond the tenant-level cap. See Tenant configuration for the full merge rules.

This example uses two bots and three agents across tenant and repo config to show the model in practice.

Tenant config:

version: 1
bots:
- master_token: plain:<bot1-PAT> # username "bot1" — derived from GitLab
- master_token: plain:<junior-PAT> # username "junior"
agents:
bot1:
backend: claude-code
model: anthropic/claude-sonnet-4-6
system_prompt: |
You are a senior engineer. Think carefully before making changes.
permissions: [read, comment, push_branch, open_mr]
junior:
backend: claude-code
model: anthropic/claude-haiku-4-5
system_prompt: |
You are a junior engineer. Implement the described task
with the smallest reasonable change.
permissions: [read, comment, push_branch, open_mr]
triggers:
- on: mr_assigned
if: { assignee: junior }
agent: bot1 # junior assigned → bot1's config runs
- on: issue_assigned
agent: bot1 # any issue assignment → bot1's config runs
policies:
cooldown: 5m
concurrency: 2

Repo .mate.yml (for one specific repository):

version: 1
agents:
code-reviewer:
extends: bot1
model: anthropic/claude-opus-4-7
system_prompt: |
You are a strict code reviewer. Comment only on real issues.
permissions: [read, comment]
triggers:
- on: mr_opened
agent: code-reviewer

What happens for each event:

EventAssigned toActorEffective agentModelPermissions
MR opened(anyone)bot1 (via code-reviewer extends: bot1)code-revieweropusread, comment
MR assignedjuniorjuniorbot1sonnetread, comment, push_branch, open_mr
MR assignedbot1(no matching trigger)no dispatch
Issue assignedbot1bot1bot1sonnetread, comment, push_branch, open_mr

Repo triggers are evaluated first (repo list is prepended to the tenant list). The mr_opened trigger in .mate.yml matches before any tenant trigger for that event.

The permissions: field on an agent lists which GitLab operations the job may perform. Explicit deny: at the trigger or tenant level subtracts from that set.

AuthorityWhat it allows
readRead issues, MRs, files, pipelines, project metadata
commentPost comments on issues and MRs
push_branchCreate and push a branch
push_mr_branchPush to an existing MR’s source branch
open_mrCreate a merge request
mergeMerge a merge request
close_issueClose an issue
update_issueEdit issue title, description, labels, state
touch_ciRetry or cancel a pipeline

approve_mr is intentionally not a grantable authority. An agent can never approve a merge request — that action is reserved for human reviewers.