---
title: "Triggers — schedule future work"
description: "Start a Workflow or fresh Session on a schedule or document condition, inspect occurrences, and recover safely from conflicts or unknown outcomes."
---

# Triggers — schedule future work

A Project Trigger starts a **published Workflow or a fresh Session** when a time or document condition is met. Use it for repeated reviews, a one-time future task, or work that begins when a Shared Document reaches an agreed state. It never adds a turn to an existing Session. Existing-Session follow-up is a separate [Session](/en/docs/sessions) feature; immediate reusable work uses [Workflow run](/en/docs/workflows).

## Access and target preparation

Use an active Project. Viewers can inspect content; creating and managing automation needs collaborator/admin authority. For an agent-created Trigger, the agent's current human owner must also be an active Project collaborator/admin. For a Session target, choose an active collaborator/admin agent. The execution owner's runtime and selected agent configuration must be available when work starts. Scheduling does not grant repository, tool, or production permissions.

In WebUI, open the Project's **Triggers** and choose **New trigger**, or use **When** while preparing a supported fresh Session/Workflow request. Choose the target, schedule, timezone, and input, check the preview, and save. The Triggers list and detail show the next occurrence, history, and permitted management actions. Open the started Session or Run to inspect the work itself.

The following CLI operations are for an agent in a running aachat Session with Project access. **Every `chat trigger` command requires `--project <team>/<project>`**; cwd does not select it. Check the returned `project` before using a result. Replace placeholders with actual names and IDs.

```bash
chat trigger list --project <team>/<project>
chat workflow list --project <team>/<project>
chat workflow show greeting --project <team>/<project>
chat project members <team>/<project> --runtime-profiles
```

Follow every `next_command` from `list` until it is `null` before deciding that matching automation does not exist. Use the exact published Workflow slug or exact active agent name. The CLI resolves them; do not substitute their internal UUIDs.

## Create a weekday Workflow Trigger

First create and publish `greeting` using the [Workflow guide](/en/docs/workflows), or select another existing Workflow and adjust its input to the schema returned by `show`. Save this complete input as `trigger.json` outside the Workflow Bundle. Update the dates to a future range before using the example:

```json
{
  "name": "Weekday greeting",
  "description": "Generate a greeting on weekday mornings.",
  "schedule": {
    "kind": "calendar",
    "time": "09:00:00",
    "days": ["mon", "tue", "wed", "thu", "fri"],
    "timezone": "Asia/Singapore",
    "starts_on": "2026-09-07",
    "ends_on": "2026-12-31"
  },
  "target": {
    "kind": "workflow",
    "workflow": "greeting",
    "input": {"reader": "Alex"}
  }
}
```

Preview just the schedule, then create once:

```bash
jq '{schedule}' trigger.json | chat trigger preview --project <team>/<project> --stdin
chat trigger create --project <team>/<project> --stdin < trigger.json
chat trigger show <trigger-id> --project <team>/<project>
```

`preview` returns the server's canonical schedule and next three time occurrences without creating automation. Check local time, timezone, and dates. `create` creates a live Trigger, so its conditions can begin dispatching work. Record its ID, inspect `show`, and check occurrence history after it fires. An accepted occurrence means a target was started, not that its work succeeded.

The name must be 1–120 characters after trimming; an optional description is limited to 1,000 characters. Workflow `input` is checked against the current published input schema at creation/edit and again at dispatch. Publishing an incompatible input contract can automatically pause existing Triggers. A Trigger targets the published Workflow; unlike a parent Workflow Revision's pinned child, it does not freeze the published pointer at creation.

## Start a fresh Session instead

Replace the complete input's `target` with a Session target. Replace the illustrative member with a real Project member. `workspace_repo`, when present, must be the Project repository or Team default repository; otherwise omit it to use the effective configured repository:

```json
{
  "kind": "session",
  "agent": "reviewer.yourname",
  "prompt": "Review the Project's latest results and record the next decision.",
  "launch": {
    "runtime_kind": "codex-acp",
    "config_overrides": []
  },
  "workspace_repo": "owner/repository",
  "working_branch": "main"
}
```

`prompt` is the non-empty work request and is limited to 100,000 bytes. `launch`, `workspace_repo`, and `working_branch` are optional. With no `launch`, the server resolves the agent default. Use only Runtime kinds and typed config options advertised by `chat project members <team>/<project> --runtime-profiles`. For an advertised ID option, an override has the shape `{"id":"mode","value":{"type":"id","value":"agent-full-access"}}`; do not copy an option unless that agent exposes it. An empty override list selects no custom options. `working_branch` requires a configured Project or Team repository. Update the Project/Team repository settings before selecting a different repository; omit `workspace_repo` when the effective configured repository is suitable. Omit `working_branch` when neither repository exists. A named working branch is a repository selection, not permission to push directly to it.

## Schedule reference

These are individual `schedule` objects, not complete create requests. UTC timestamps end in `Z`; use a valid IANA timezone. Replace the example dates before they expire.

```json
{"kind":"once","at":"2026-09-07T01:00:00Z","timezone":"Asia/Singapore"}
```

```json
{"kind":"calendar","time":"09:00:00","days":["mon"],"timezone":"Asia/Singapore","starts_on":"2026-09-07","ends_on":"2026-12-31"}
```

```json
{"kind":"interval","every_seconds":3600,"starts_at":"2026-09-07T01:00:00Z","ends_at":"2026-09-30T01:00:00Z","timezone":"Asia/Singapore"}
```

| Kind | Meaning and constraints |
|---|---|
| `once` | One future UTC `at`; timezone supplies the local context. |
| `calendar` | Local `HH:MM:SS`, one or more distinct weekdays `mon`–`sun`, and local `starts_on`. Optional `ends_on` is inclusive. |
| `interval` | A UTC cadence of at least 300 seconds (5 minutes). `starts_at` is optional and defaults to acceptance time; `ends_at` is required and inclusive. |
| `document_match` | A same-Project frontmatter condition; no time preview and no Run now. |

Calendar schedules follow the timezone's daylight-saving rules. An ambiguous repeated local time fires once at the earlier instant; a nonexistent local time advances one second at a time, for up to four hours, to the first valid time. Always inspect the server preview around timezone transitions. An interval is elapsed seconds, not “the same local clock time every day.” These limits are different from existing-Session follow-up limits.

## Start when a document matches

Use this `schedule` in a complete create input with a prepared target:

```json
{"kind":"document_match","on":"reviews/release","match":{"status":"approved","ready":true}}
```

It watches `docs/reviews/release.md` in this Project. A matching [Shared Document](/en/docs/shared-documents) could have this frontmatter:

```yaml
---
title: Release review
status: approved
ready: true
---
```

`on` is the exact `kind/doc_id`, not a file path or a document in another Project. `match` must contain at least one field. Values are exact strings, numbers, or booleans; multiple fields are ANDed. `true` is a boolean, while `"true"` is a different string. Arrays, objects, and null are not match values.

A document condition can match immediately when created or revalidated. It dispatches at most once, rather than on every subsequent save. Saving the watched document evaluates the condition; `run` is not supported for document conditions. To arm it again after completion, submit a complete edit with a new document condition.

## Manage an existing Trigger

Read `show` before changing a Trigger. Its `state_version` can advance on either mutation or dispatch. Never hard-code a version or reuse an old one. `show` also returns `edit_input`, a complete reusable object containing the current version. When it is non-null, save it, change the desired fields while retaining the observed version, then submit the full replacement:

```bash
chat trigger show <trigger-id> --project <team>/<project> > trigger-state.json
jq '.edit_input' trigger-state.json > trigger-edit.json
```

```bash
chat trigger edit <trigger-id> --project <team>/<project> --stdin < trigger-edit.json
```

Make the intended changes to `trigger-edit.json` between those commands. `edit` is replacement, not a partial patch. Preview a changed time schedule before submission. If the target is unavailable, `edit_input` is null: select a new target and construct the complete name, schedule, target, optional description, and latest `state_version` yourself. An older server during a CLI/server version transition can also leave the target unavailable without reusable edit input; do not substitute a UUID. In returned Session edit input, preserve `working_branch: ""` when keeping the accepted repository default, or the non-empty value for the accepted named branch.

| Operation | CLI | Expected effect |
|---|---|---|
| Inspect page | `chat trigger list --project <team>/<project> [--cursor <cursor>] [--limit 50]` | States, next times, last outcomes; follow `next_command`. |
| Inspect one | `chat trigger show <trigger-id> --project <team>/<project> [--cursor <cursor>] [--limit 50]` | State/version, actions, recent occurrences; follow `next_occurrences_command` for older history. |
| Preview | `chat trigger preview --project <team>/<project> --stdin` | Read-only schedule preview from `{"schedule": ...}`. |
| Create | `chat trigger create --project <team>/<project> --stdin` | A new live Trigger. |
| Replace | `chat trigger edit <trigger-id> --project <team>/<project> --stdin` | Full replacement with `state_version` in JSON. |
| Run now | `chat trigger run <trigger-id> --state-version <version> --project <team>/<project>` | One ordinary occurrence for the observed active time Trigger; schedule unchanged. |
| Pause | `chat trigger pause <trigger-id> --state-version <version> --project <team>/<project>` | Stop future dispatches. |
| Resume | `chat trigger resume <trigger-id> --state-version <version> --project <team>/<project>` | Resume a manually paused Trigger when offered. |
| Delete | `chat trigger delete <trigger-id> --state-version <version> --project <team>/<project>` | Remove future dispatches and preserve history. |

Square brackets mean optional arguments. List/history limits accept 1–100. Pause and delete never cancel or delete an already-started Session or Workflow Run. Manage that target separately when needed and authorized.

## Read outcomes and avoid duplicate work

A Trigger is `active`, `paused`, or `completed`. An occurrence is `accepted`, `skipped`, or `failed`. For `accepted`, follow its `workflow_run_id` or `session_id` and current target state. `run` returns the occurrence synchronously, but does not wait for the target's result. It advances `state_version` without changing `next_scheduled_for` or the recurring schedule.

| Occurrence or condition | What happens / what to do |
|---|---|
| Previous accepted target still active | The occurrence is skipped with `previous_run_active`; it is not queued. Inspect the previous target. |
| Previous Workflow Run is in `attention_required` | The next occurrence supersedes and cancels it, then starts new work with `previous_run_superseded`. Retry a stalled Run before that next occurrence if it must continue. Do not manually cancel it merely to unblock the Trigger. |
| Scheduler returns after downtime | Older due occurrences are skipped as `superseded_during_downtime`; only the newest due occurrence can start. |
| Dispatch fails | The Trigger pauses; inspect `occurrence.reason` and `pause_message`, repair the cause, and revalidate with a complete edit. |

A paused/completed Trigger or a document condition cannot be run now. A changed revision or dispatch already in progress conflicts before another target is started. Follow the returned action rather than forcing the request.

## Recover a conflict, pause, or unknown result

For a version conflict, run the exact Project-scoped `show` command returned by the error and decide again using the refreshed state. Do not merely replace the version in an old request without checking what changed.

**Create is non-idempotent.** If its structured error says the outcome is unknown, do not send the create JSON again. Follow the returned read-only `list` command through all pages and reconcile whether the Trigger already exists. If `run` has an unknown outcome, do not retry it; use the returned `show` command and occurrence history to find whether work started. If evidence still cannot establish the outcome, keep it unresolved rather than creating duplicate work. This differs from [Workflow completion](/en/docs/workflows), which permits retrying the exact same completion payload after transport uncertainty.

Manual pauses and automatic pauses have different recovery paths:

| State / reason | Recovery |
|---|---|
| Manually paused document condition | Resume directly when offered. |
| Manually paused time schedule | `show` checks for a future occurrence and offers resume only if one exists. Otherwise provide a complete future replacement. An edit preserves a manual pause: read the latest version with `show`, then use the offered `resume`. If that read fails, `show` fails instead of guessing. |
| `input_contract_invalid` | Match the current published Workflow input schema, then submit a complete edit. |
| `target_unavailable` | Restore or select an available Workflow/agent, then submit a complete edit. |
| `permission_revoked` | Restore the required authority and revalidate with an edit. If the creator is no longer owned by its execution owner, the old Trigger cannot be repaired: create a new one under the current owner. |
| `project_inactive` | Restore the Project to a state that permits work, then revalidate with an edit. |
| `completed` | Reactivate only by editing to a future time schedule or a new document condition. |

The server rechecks Project, creator, execution-owner relation, target, and Runtime authority at mutation and dispatch. A valid preview or an earlier successful occurrence is not a guarantee that later work will run. Read the started target's results and use the [Workflow recovery procedure](/en/docs/workflows) or [Session guide](/en/docs/sessions) for the execution itself.
