Notify with Actions¶
Mails, web requests and Matrix or Slack messages on evaluation and build events, e.g. a mail to the team on every failed build.
Requirements:
- A task, see First Project
- Email configured on the server, for mail actions only
- A Matrix access token or a Slack webhook URL, for chat actions only
1. Add the Action¶
Open Actions -> New Action on the task and pick a type.
| Type | Fields |
|---|---|
Recipients, comma-separated email addresses or team:<name>. Optional Subject Template |
|
| Webhook | URL. Optional Token, shown once after saving |
| Matrix | Homeserver, Room ID, Access Token |
| Slack | Webhook URL |
Mail is available only with email configured on the server.
A team:<name> recipient is a team granted with users on the project. Its verified members get the mail.
services.gradient.state.tasks.web-app.actions = [
{
name = "notify-ops";
type = "send_mail";
events = [ "evaluation.failed" "build.failed" ];
config.recipients = [ "ops@example.com" ];
}
{
name = "chat-hook";
type = "send_web_request";
events = [ "evaluation.completed" "evaluation.failed" ];
config = {
url = "https://hooks.example.com/gradient";
token_file = "/run/secrets/chat-hook-token";
};
}
{
name = "ops-room";
type = "send_matrix_message";
events = [ "evaluation.failed" "build.failed" ];
config = {
homeserver = "https://matrix.example.org";
room_id = "!abc123:example.org";
access_token_file = "/run/secrets/ops-room-token";
};
}
{
name = "ops-channel";
type = "send_slack_message";
events = [ "evaluation.failed" ];
config.webhook_url_file = "/run/secrets/ops-channel-webhook";
}
];
2. Pick the Events¶
An action without events never fires. The events most actions need are in the table below.
| Event | Trigger |
|---|---|
evaluation.completed |
Every build of the evaluation succeeded |
evaluation.failed |
The evaluation failed |
build.failed |
One build failed |
evaluation.action_required |
A pull request from a fork is waiting for maintainer approval |
The full list is in the events reference.
Mail¶
- Subject placeholders:
{event},{task},{project},{id},{status}. - Default subject:
[Gradient] {event}: {task}. - Body: the message line, the event, the time and a link to the evaluation log.
Web Request¶
Each delivery is a POST with a JSON body. Receivers are reading the content field.
{
"event": "build.failed",
"at": "2026-09-26T12:00:00.123Z",
"content": { "build_id": "...", "evaluation_id": "...", "task": "...", "project": "...", "status": 4 }
}
| Header | Value |
|---|---|
X-Gradient-Event |
The event name |
Authorization |
Bearer <token>, with a token only |
X-Gradient-Signature |
sha256=<HMAC-SHA256 of the body, with the token as key>, with a token only |
Receivers can check the signature and reject requests that did not come from Gradient.
Matrix and Slack¶
Both actions are posting one line per event, with a link to the evaluation log.
| Part | Content |
|---|---|
web/app |
Project and task |
hello-2.12.1 |
Derivation, on build events only |
failed |
Status, taken from the event name |
3f9c2ab |
Short commit hash |
- Gradient will retry rate limits (
429) and server errors (5xx). - Other HTTP errors are ending the delivery as failed, listed under Deliveries.
- The access token and the webhook URL are stored encrypted and never returned by the UI or the API.
Matrix Access Token¶
- A dedicated bot account is the safest choice. The bot must have joined the room.
- Encrypted rooms are not supported.
- The Room ID is under room settings -> Advanced, in the form
!abc123:example.org. Rooms of version 12 and later have IDs without the server part, like!abc123. Room aliases like#ops:example.orgare rejected.
A password login can return the access token of the bot account.
curl -s -X POST https://matrix.example.org/_matrix/client/v3/login \
-d '{"type":"m.login.password","identifier":{"type":"m.id.user","user":"gradient-bot"},"password":"<password>"}' \
| jq -r .access_token
Slack Webhook URL¶
- Slack apps with Incoming Webhooks enabled issue one URL per channel, under Add New Webhook to Workspace.
- The URL is in the form
https://hooks.slack.com/services/T.../B.../....
Git Status¶
The Git Status action can post one check per step on each commit and pull request. The Git host guides cover its setup.
| Check | State |
|---|---|
gradient/<task>: Approval |
Only for pull requests from forks, pending until maintainer approval |
gradient/<task>: Evaluation |
Pending while the evaluation is active, then success or failure. Failure once any entry point failed to evaluate, while the other builds continue |
gradient/<task>: Build <entry point> |
One per entry point: pending, running, then success or failure. Entry points that failed to evaluate show failure without a build |
Evaluations started with /gradient run <wildcard> report as gradient/<task>: Evaluation: <wildcard> next to the default checks.
Test can check the integration's access to the repository without posting a status.
Verify Deployment¶
- A click on Test in the action row can send a sample event, marked
"synthetic": truefor the receiver. - The Deliveries view of the action row can list every request with status, duration, request and response body.
Troubleshooting¶
| Symptom | Fix |
|---|---|
| Mail missing from the type list | Configure email on the server |
Delivery showing connection refused |
The URL is unreachable from the server |
| No deliveries | The action is inactive, or none of the events fired yet |
Matrix delivery showing 403 |
The bot left the room, or the access token was revoked |
Slack delivery showing 403 or 404 |
The webhook was removed in Slack |
Next Steps¶
- Update Flake Inputs: pull requests that bump
flake.lock - Connect GitHub: commit statuses with the Git Status action
- Projects and Tasks: triggers and actions