Workflow Trigger Reference¶
This page is a consolidated quick-reference for all workflow trigger types. For full documentation on each type, follow the links in each section.
Trigger Type Comparison¶
| Trigger | When it fires | Repeats? | Requires public endpoint? | CLI support? | YAML support? |
|---|---|---|---|---|---|
github_issues |
New or updated GitHub issues matching filters | Yes - polls continuously | No | Yes | Yes |
github_pull_requests |
New or updated GitHub PRs matching filters | Yes - polls continuously | No | Yes | Yes |
linear_issues |
New or updated Linear issues matching filters | Yes - polls continuously | No | Yes | Yes |
cron |
On a recurring cron schedule | Yes - indefinitely | No | Yes | Yes |
delay |
Once at a specific datetime | No - auto-disables | No | Yes | Yes |
agent_lifecycle |
When the agent connects, disconnects, or clears context | Yes | No | No - API only | No - API only |
dispatch_result |
When another workflow dispatch completes | Yes | No | No - API only | No - API only |
webhook |
On inbound HTTP POST to a dedicated endpoint | Yes | Yes (or tunnel) | Yes | Yes |
agent_idle |
When the agent has been idle for a configured duration | Yes - repeats on each idle period | No | Yes | Yes |
composite |
When sub-triggers fire (AND/OR logic) | Yes | Depends on sub-triggers | No - API only | No - API only |
queue |
When a task is available in a named internal queue | Yes - polls continuously | No | Yes | Yes |
manual |
Only when explicitly triggered via CLI or API | On demand | No | Yes | Yes |
When to Use Each Trigger¶
github_issues / github_pull_requests¶
Use when:
- You want an agent to react to GitHub issues or PRs automatically
- You are behind a firewall or don't want to expose a public endpoint
- Latency of up to
poll_interval_secsis acceptable (default: 60 s)
Do not use when:
- You need sub-second latency (use
webhookinstead) - The trigger source is not GitHub
linear_issues¶
Use when:
- You want an agent to react to Linear issues automatically
- You manage engineering work in Linear and want agent-driven triage, assignment, or resolution
- You are behind a firewall or don't want to expose a public endpoint
- Latency of up to
poll_interval_secsis acceptable (default: 60 s)
Do not use when:
- You need sub-second latency (use
webhookinstead) - The trigger source is not Linear
cron¶
Use when:
- You need a recurring scheduled task (daily report, hourly health check, weekly audit)
- The schedule is fixed and known in advance
Do not use when:
- The task should run exactly once (use
delayinstead) - The task is triggered by an external event
delay¶
Use when:
- You need a one-shot task at a specific future time (scheduled deployment, maintenance window)
- You want a "run this exactly once at time X" guarantee
Do not use when:
- You need a recurring schedule (use
croninstead)
agent_lifecycle¶
Use when:
- You need to bootstrap an agent every time it connects (
session_start) - You need to clean up or archive state when an agent disconnects (
session_end) - You need to re-inject context after a
/clearcommand (context_clear)
dispatch_result¶
Use when:
- You want to chain workflows into a pipeline (lint → test → deploy)
- A downstream step should only start after an upstream step completes
Do not use when:
- You want parallel execution (each workflow must have its own trigger)
agent_idle¶
Use when:
- You want to run background tasks when an agent has no work to do
- You need periodic health checks or maintenance that only run during idle periods
- You want to implement a "keep alive" or background monitoring pattern
Do not use when:
- You need a fixed schedule (use
croninstead) - You want the task to run regardless of agent activity
composite¶
Use when:
- You need to combine multiple trigger conditions with AND/OR logic
- A workflow should only fire when multiple conditions are met simultaneously (AND mode)
- A workflow should fire when any one of several conditions is met (OR mode)
Do not use when:
- A single trigger type is sufficient
- You need
webhookormanualas a sub-trigger (not supported in composites)
queue¶
Use when:
- You want a producer/consumer pattern where external systems or other agents push work items
- You need priority-based task ordering
- You want to decouple task production from task consumption
- Multiple producers need to feed a single agent workflow
Do not use when:
- The trigger source is a known external system (use polling or webhook triggers instead)
- You need immediate dispatch without queuing
webhook¶
Use when:
- You need near-real-time reaction to external events (GitHub, CI, monitoring)
- You can expose a public HTTPS endpoint (or use a tunnel like ngrok)
Do not use when:
- You are behind a firewall with no public endpoint (use polling instead)
manual¶
Use when:
- You want an on-demand workflow that fires only when you tell it to
- You need an override or emergency path for any workflow type
- You are integrating with a CI pipeline (
curl POST /workflows/{id}/trigger)
Configuration Quick Reference¶
JSON (REST API)¶
All trigger types use the trigger_config field with a "type" discriminant:
{ "type": "github_issues", "owner": "myorg", "repo": "myrepo", "labels": ["agent"], "state": "open" }
{ "type": "github_pull_requests", "owner": "myorg", "repo": "myrepo", "labels": [], "state": "open" }
{ "type": "linear_issues", "team_key": "ENG", "status": ["Triage"], "labels": ["bug"] }
{ "type": "cron", "expression": "0 9 * * MON-FRI" }
{ "type": "delay", "run_at": "2026-04-01T09:00:00Z" }
{ "type": "agent_lifecycle", "event": "session_start" }
{ "type": "dispatch_result", "source_workflow_id": "<UUID>", "status": "completed" }
{ "type": "agent_idle", "idle_seconds": 30 }
{ "type": "composite", "mode": "or", "triggers": [{ "type": "cron", "expression": "0 9 * * *" }, { "type": "agent_lifecycle", "event": "session_start" }] }
{ "type": "queue", "queue_name": "work-items", "poll_interval_secs": 5, "visibility_timeout_secs": 300 }
{ "type": "webhook", "secret": "my-hmac-secret" }
{ "type": "manual" }
YAML (.agentd/ templates)¶
# GitHub Issues
source:
type: github_issues
owner: myorg
repo: myrepo
labels: [agent]
state: open
# GitHub Pull Requests
source:
type: github_pull_requests
owner: myorg
repo: myrepo
state: open
# Linear Issues
source:
type: linear_issues
team_key: ENG
status: [Triage]
labels: [bug]
# project: Backend # optional
# assignee: alice@example.com # optional
# Cron
source:
type: cron
expression: "0 9 * * MON-FRI"
# Delay (one-shot)
source:
type: delay
run_at: "2026-04-01T09:00:00Z"
# Agent Idle
source:
type: agent_idle
idle_seconds: 30
# Queue
source:
type: queue
queue_name: work-items
poll_interval_secs: 5 # optional, default 5
visibility_timeout_secs: 300 # optional, default 300
# Webhook
source:
type: webhook
secret: "my-hmac-secret" # optional
# Manual
source:
type: manual
Note
agent_lifecycle, dispatch_result, and composite are not available in YAML templates. Create them via the REST API.
CLI (create-workflow)¶
# GitHub Issues (default trigger type)
agent orchestrator create-workflow --name wf --agent-name agent \
--owner myorg --repo myrepo --labels "bug,agent"
# GitHub Pull Requests
agent orchestrator create-workflow --name wf --agent-name agent \
--trigger-type github-pull-requests \
--owner myorg --repo myrepo
# Cron
agent orchestrator create-workflow --name wf --agent-name agent \
--trigger-type cron \
--cron-expression "0 9 * * MON-FRI" \
--prompt-template "Daily task at {{fire_time}}"
# Delay
agent orchestrator create-workflow --name wf --agent-name agent \
--trigger-type delay \
--run-at "2026-04-01T09:00:00Z" \
--prompt-template "Scheduled task: {{run_at}}"
# Agent Idle
agent orchestrator create-workflow --name wf --agent-name agent \
--trigger-type agent-idle \
--idle-seconds 30 \
--prompt-template "Agent idle for {{idle_seconds}}s. Run background check."
# Queue
agent orchestrator create-workflow --name wf --agent-name agent \
--trigger-type queue \
--queue-name work-items \
--queue-poll-interval 5 \
--queue-visibility-timeout 300 \
--prompt-template "Process: {{title}}\n{{body}}"
# Webhook
agent orchestrator create-workflow --name wf --agent-name agent \
--trigger-type webhook \
--webhook-secret "$(openssl rand -hex 32)" \
--prompt-template "Webhook: {{title}}\n{{body}}"
# Manual
agent orchestrator create-workflow --name wf --agent-name agent \
--trigger-type manual \
--prompt-template "{{title}}\n\n{{body}}"
Template Variables by Trigger Type¶
Universal variables (all trigger types)¶
| Variable | Description |
|---|---|
{{title}} |
Task title |
{{body}} |
Task body / description |
{{url}} |
Source URL (empty for non-GitHub triggers) |
{{labels}} |
Comma-separated label names (empty for non-GitHub triggers) |
{{assignee}} |
Assignee login (empty for non-GitHub triggers) |
{{source_id}} |
Deduplication identifier (format varies by trigger type) |
{{metadata}} |
All metadata as key: value lines |
github_issues / github_pull_requests¶
| Variable | Description |
|---|---|
{{title}} |
Issue or PR title |
{{body}} |
Issue or PR body (markdown) |
{{url}} |
GitHub HTML URL |
{{labels}} |
Comma-separated label names |
{{assignee}} |
Assignee login |
{{source_id}} |
Issue or PR number (string) |
linear_issues¶
| Variable | Description | Example |
|---|---|---|
{{title}} |
Issue title | "Fix login timeout" |
{{body}} |
Issue description (markdown) | Full markdown content |
{{identifier}} |
Linear issue identifier | ENG-123 |
{{state}} |
Issue state name | Todo, In Progress |
{{priority}} |
Priority level (0 = none, 1 = urgent, 2 = high, 3 = medium, 4 = low) | 2 |
{{team}} |
Linear team key | ENG |
{{team_name}} |
Linear team display name | Engineering |
{{project}} |
Linear project name (empty if unset) | Backend |
{{assignee}} |
Assignee display name (empty if unassigned) | Alice Example |
{{labels}} |
Comma-separated label names | "bug, urgent" |
{{url}} |
Linear issue URL | https://linear.app/myorg/issue/ENG-123 |
{{linear_id}} |
Internal Linear UUID | abc-uuid-... |
{{source_id}} |
Linear issue identifier (e.g. ENG-123) |
ENG-123 |
cron¶
| Variable | Description | Example |
|---|---|---|
{{fire_time}} |
RFC 3339 timestamp when the cron fired | 2026-04-01T09:00:00Z |
{{cron_expression}} |
The expression that fired | 0 9 * * MON-FRI |
{{source_id}} |
cron:<fire_time> |
cron:2026-04-01T09:00:00Z |
delay¶
| Variable | Description | Example |
|---|---|---|
{{run_at}} |
RFC 3339 scheduled datetime | 2026-04-01T09:00:00Z |
{{workflow_id}} |
UUID of the workflow | 550e8400-... |
{{source_id}} |
delay:<workflow_id> |
delay:550e8400-... |
agent_lifecycle¶
| Variable | Description | Example |
|---|---|---|
{{event_type}} |
Lifecycle event name | session_start |
{{agent_id}} |
UUID of the agent | 550e8400-... |
{{timestamp}} |
RFC 3339 event timestamp | 2026-04-01T09:00:00Z |
{{source_id}} |
event:<event_type>:<agent_id>:<timestamp> |
dispatch_result¶
| Variable | Description | Example |
|---|---|---|
{{source_workflow_id}} |
UUID of the workflow that completed | a1b2c3d4-... |
{{dispatch_id}} |
UUID of the dispatch record | b2c3d4e5-... |
{{status}} |
Completion status | completed |
{{timestamp}} |
RFC 3339 completion timestamp | 2026-04-01T09:05:00Z |
{{source_id}} |
event:dispatch:<dispatch_id>:<timestamp> |
webhook¶
| Variable | Description | Example |
|---|---|---|
{{title}} |
Parsed title or "Webhook payload" |
"Fix login bug" |
{{body}} |
Issue/PR body or raw payload | |
{{url}} |
GitHub HTML URL (empty for generic payloads) | |
{{delivery_id}} |
From X-GitHub-Delivery or auto-generated UUID |
abc-123 |
{{timestamp}} |
RFC 3339 receive time | 2026-04-01T09:00:00Z |
{{github_event}} |
GitHub event type (GitHub requests only) | issues |
{{action}} |
GitHub action (issues/pull_request only) | opened |
{{issue_number}} |
Issue number (issues events only) | 42 |
{{pr_number}} |
PR number (pull_request events only) | 99 |
{{source_id}} |
webhook:<delivery_id>:<timestamp> |
agent_idle¶
| Variable | Description | Example |
|---|---|---|
{{agent_id}} |
UUID of the idle agent | 550e8400-... |
{{idle_seconds}} |
Configured idle timeout | 30 |
{{timestamp}} |
RFC 3339 timestamp when idle fired | 2026-04-01T09:00:00Z |
{{source_id}} |
idle:<unix_timestamp> |
idle:1751234567 |
composite¶
| Variable | Description | Example |
|---|---|---|
{{source_id}} |
composite:or:<sub-source-id> or composite:and:<id1>,<id2>,... |
|
{{composite_sub_source_ids}} |
Comma-joined sub-source IDs (AND mode) | cron:...,event:... |
In addition, all template variables from the sub-trigger that fired are available. In AND mode, variables from all sub-triggers are merged.
queue¶
| Variable | Description | Example |
|---|---|---|
{{title}} |
Task title from the queue item | "Process report" |
{{body}} |
Task body from the queue item | |
{{queue_name}} |
Name of the queue | work-items |
{{queue_task_id}} |
Internal UUID of the queue task | abc-uuid-... |
{{queue_priority}} |
Priority value assigned at push time | 10 |
{{source_id}} |
Queue task source ID |
manual¶
| Variable | Description |
|---|---|
{{title}} |
From request title field (default: "Manual trigger") |
{{body}} |
From request body field (default: empty) |
{{source_id}} |
manual:<uuid> - random per trigger call |
{{<key>}} |
Any key from the request metadata object |
Performance Considerations¶
| Aspect | Polling (github_issues, github_pull_requests) |
Polling (linear_issues) |
Schedule (cron, delay) |
Event (agent_lifecycle, dispatch_result, agent_idle) |
Webhook | Queue | Composite | Manual |
|---|---|---|---|---|---|---|---|---|
| Latency | Up to poll_interval_secs (default 60 s) |
Up to poll_interval_secs (default 60 s) |
Zero - wakes exactly at fire time | Near-zero - in-process event bus | Sub-second | Up to poll_interval_secs (default 5 s) |
Depends on sub-triggers | Immediate |
| External API calls | Yes - GitHub API per poll | Yes - Linear API per poll | None | None | One inbound HTTP request per event | None | Depends on sub-triggers | None |
| Missed events on restart | No - deduplication by issue/PR number | No - deduplication by issue identifier (e.g. ENG-123) |
No - dedup by fire time / workflow ID | Yes - events not stored | Depends on sender retry policy | No - tasks persist in database | Depends on sub-triggers | N/A |
| Network requirements | Outbound to GitHub | Outbound to Linear | None | None | Inbound HTTP (public endpoint or tunnel) | None | Depends on sub-triggers | None |
| Rate limits | GitHub API rate limits apply | Linear API rate limits apply | None | None | Depends on sender volume | None | Depends on sub-triggers | None |
Polling vs. webhooks for GitHub¶
| Scenario | Recommendation |
|---|---|
| Behind a firewall, no public endpoint | Use github_issues / github_pull_requests polling |
| Need sub-second latency | Use webhook |
| Network unreliable | Use polling - catches up automatically on next poll |
| High-volume GitHub events | Use webhook - polling may miss events between polls |
Triggering Any Workflow On Demand¶
Any workflow, regardless of trigger type, can be dispatched immediately via:
# CLI
agent orchestrator trigger-workflow <WORKFLOW_ID> \
--title "Ad-hoc run" \
--body "Description of what to do"
# API
curl -X POST http://127.0.0.1:17006/workflows/<ID>/trigger \
-H "Content-Type: application/json" \
-d '{"title": "Ad-hoc run", "body": "Description", "metadata": {"key": "value"}}'
This bypasses the workflow's normal trigger strategy and dispatches immediately. See Manual Triggers for full details on bypass trigger semantics and response codes.
Troubleshooting¶
Workflow is enabled but not firing¶
- Check the trigger config -
agent orchestrator get-workflow <ID>shows the activetrigger_config. - Check dispatch history -
agent orchestrator workflow-history <ID>shows recent dispatches. A new entry should appear after each firing. - Check agent connectivity -
agent orchestrator get-agent <AGENT_ID>must showstatus: running. Workflows skip dispatch if the agent is not connected. - Check logs - the orchestrator logs at
INFOlevel for each trigger event and dispatch attempt.
Cron workflow not firing at the expected time¶
- All cron expressions are evaluated in UTC. Convert your local time to UTC.
- Validate your expression with an external tool like crontab.guru.
- Check that
enabled: true- a disabled workflow's runner is not started and the cron strategy is never executed.
Delay workflow fired immediately (not at scheduled time)¶
run_atis in the past. Ifrun_athas already passed when the runner starts, the delay trigger fires immediately. Verify the datetime and recreate the workflow with a futurerun_at.
Webhook returning 404¶
- The workflow UUID in the URL must match exactly.
- The workflow must be
enabled: true- a disabled workflow's runner is not started, so the webhook channel does not exist. - Verify with
agent orchestrator get-workflow <ID>.
Webhook returning 401¶
- HMAC signature mismatch. Verify that the secret in the trigger config matches the secret configured in your external system (e.g., GitHub webhook settings).
- Ensure the request body is not modified in transit (e.g., by a proxy that re-formats JSON).
dispatch_result workflow not chaining¶
- The
source_workflow_idmust exactly match the upstream workflow's UUID. - The upstream workflow must complete (not just dispatch) -
dispatch_resultfires onDispatchCompleted, which is published after the agent finishes. - Check that
statusin the trigger config matches the upstream's actual completion status (completedvsfailed).
Agent idle workflow not firing¶
- The agent must have completed at least one dispatch before the idle timer starts. The timer resets on each
DispatchCompletedevent. - Verify
idle_secondsis set to a reasonable value - too short may cause rapid re-firing, too long may never trigger during a session. - Events are not stored - if the orchestrator restarts, the idle timer resets.
Composite AND trigger never fires¶
- Verify
correlation_window_secsis long enough for all sub-triggers to fire within the window (default: 60 seconds). - Check that all sub-triggers are configured correctly and producing tasks individually.
webhookandmanualcannot be used as sub-triggers inside a composite.
Queue workflow not consuming tasks¶
- Verify the
queue_namein the trigger config matches the name used inPOST /queues/{name}/push. - Check that the workflow is enabled and the agent is connected.
- Monitor queue depth with
agent orchestrator queue-stats <name>.
Agent lifecycle workflow not firing on session_start¶
- The workflow must be created and enabled before the agent connects. If the agent was already connected when the workflow was created, the
session_startevent has already fired and will not be re-delivered. - Events are not stored - a missed event cannot be replayed.
Full Documentation¶
| Topic | Page |
|---|---|
| TriggerStrategy trait and architecture | Trigger Strategies |
| Cron and delay triggers | Schedule Triggers |
| Agent lifecycle and dispatch result triggers | Event-Driven Triggers |
| Webhook trigger and GitHub setup | Webhook Triggers |
| Linear trigger setup and filter options | Linear Triggers |
| Composite triggers (AND/OR logic) | Composite Triggers |
| Queue-based trigger and producer/consumer patterns | Queue Trigger |
| Manual trigger and on-demand dispatch | Manual Triggers |
| YAML template schema | Templates |
Migration from source_config |
Migration Guide |