nextv1.4.0
Reference

Inbound triggers

The trigger fields in policy.yaml and the POST /api/triggers contract for starting a chain from a schedule or a webhook.

A trigger files a work item from an event instead of kraft item create. There are two kinds, a cron entry in policy.yaml and an HTTP call. Both always file the item paused, exactly like manual intake: an agent can't start work from a trigger any more than from your own kraft item create. To set one up, see Schedule or webhook work.

Cron entries

Each entry in the triggers: list of policy.yaml has these fields:

FieldRequiredMeaning
cronyesFive fields: minute, hour, day of month, month, day of week (0 is Sunday). Each field is * or a comma-separated list of integers. Ranges (1-5) and steps (*/15) aren't supported.
repoyesPath of a repo you connected with kraft repo connect.
chainyesA chain template id from templates/chains/.
titleyesThe work item's title.
descriptionnoThe work item's description. Defaults to "".

Kraft evaluates the schedule in UTC, not in the server's local time zone. It checks once a minute, and a minute missed while the server is down isn't backfilled. The poller runs for the life of the server, so a trigger you add later fires without a restart. kraft admin reload rereads policy.yaml.

Kraft skips an entry, logs a warning naming the reason, and still fires the other entries due in the same tick, when:

  • the repo is not connected (the warning names kraft repo connect);
  • the chain id is unknown;
  • the template library is invalid.

POST /api/triggers

The HTTP twin of a cron entry, for anything that can fire a webhook and can't wait for the next minute tick. The request body is JSON:

FieldRequiredMeaning
titleyesThe work item's title.
repoyesPath of a connected repo.
chain_templatenoA chain template id. Defaults to the repo's default_chain_template, else default.
descriptionnoThe work item's description. Defaults to "".

The chain field is chain in policy.yaml and chain_template in the HTTP body.

CallerAuthentication
The machine running Kraft, while it is bound to loopbackNone.
Any caller after a non-loopback bind, the same machine includedThe trigger token in $KRAFT_HOME/run/trigger-token, sent as Authorization: Bearer <token>. The MCP bearer token in $KRAFT_HOME/run/mcp-token or a browser session cookie also works. See Remote access.
StatusMeaning
201The item was filed. The body is the work item as JSON: id is the new item's id and status is paused.
401Kraft is bound off loopback, and the request has no valid bearer token or session.
403A remote caller while no password is set, or a browser request from a disallowed Host or another site.
422The body is not valid: repo or title is missing, or a field has the wrong type.
422The repo is not connected. The message names kraft repo connect.
422The repo path no longer exists.
422chain_template names no chain, or that chain does not resolve.
422The title is longer than 500 characters.
422repos.yaml cannot be read, or the repo's policy or steering is invalid. The message names the problem.
502Filing failed after the checks passed. The message starts intake failed:.
503policy.yaml or the template library is invalid, so Kraft refuses all new work. kraft admin doctor names the file.

See HTTP API for the rest of the API.

{"id": "<work-item-id>", "title": "Nightly dependency check", "status": "paused", "...": "..."}
Give CI and webhook senders the trigger token. It passes the login check on POST /api/triggers only, so its holder can file paused work and nothing else. The MCP bearer token passes it on every route, so whoever holds that one can also start, approve and cancel work and change settings. To rotate either, see The bearer token.
Copyright © 2026