External Triggers

External triggers let Holon agents wait for events from outside the runtime — for example, a CI pipeline completing, a GitHub webhook, or a timer firing. Every agent receives a default ingress callback URL at startup. The agent waits on it, and resumes when the external system delivers an event.

The trigger model

Holon treats external events as first-class runtime concepts. The model has three parts:

  1. Default ingress — Every agent receives a default ingress callback URL with a capability secret at startup.
  2. Wait on the trigger — The agent calls WaitFor with wake=external and the external object reference. The runtime records the wait and yields the turn.
  3. External delivery — When the external system POSTs to the callback URL, the runtime wakes the agent and delivers the payload.

Delivery modes

Triggers support two delivery modes:

ModeBehavior
enqueue_messageThe external payload is enqueued as a normal message into the agent's queue
wake_hintThe callback acts as a wake signal only; the agent resumes and checks the external state itself

Use enqueue_message when the external system carries the full event content (e.g., a webhook payload). Use wake_hint when the agent needs to actively poll or check the external state after being woken (e.g., a CI status check).

Callback endpoints

Every agent has a single default ingress capability created at startup. The default ingress is provisioned as either a wake_hint or enqueue_message mode callback URL, depending on how the agent is configured. A trigger always has one delivery mode and one trigger_url.

ModeURL patternEffect
wake_hint/callbacks/wake/:tokenWakes the agent from WaitFor(external)
enqueue_message/callbacks/enqueue/:tokenEnqueues a message (the POST body)

The callback token is a capability secret — treat it like a password. Anyone who knows the token can wake your agent or enqueue messages into it. Tokens are generated by the runtime, are cryptographically random, and are returned to the agent's execution environment context (not persisted to transcripts or logs by default).

Example: Wake callback

curl -X POST http://localhost:8787/callbacks/wake/CALLBACK_TOKEN

A minimal POST (even with an empty body) wakes the agent. The runtime validates the token and resumes the waiting agent.

Example: Enqueue callback

curl -X POST http://localhost:8787/callbacks/enqueue/CALLBACK_TOKEN \
  -H "Content-Type: application/json" \
  -d '{"text": "CI build #42 completed: success"}'

The payload is enqueued into the agent as a message. The agent processes it on its next turn.

The agent's WaitFor cycle

When an agent expects an external event:

  1. The agent uses its default ingress capability (exposed in the execution environment context)
  2. The agent calls WaitFor(wake=external, resource=<object>)
  3. The runtime records the wait, yields the turn, and the agent sleeps
  4. The external system delivers the event via the callback URL
  5. The runtime wakes the agent and resumes from the WaitFor point

The resource parameter in WaitFor identifies what the agent is waiting on (e.g., github:owner/repo#123 for a PR, or a URL for an HTTP endpoint). This is for the agent's own tracking; the runtime does not interpret it.

Security model

Callback tokens are capability secrets. The runtime stores only the hashed token, not the raw value — once a token is issued, the raw token is returned to the agent's execution context and is never persisted to logs or storage. Store it securely on the caller side.

Tokens can be revoked with CancelExternalTrigger. Revoking a trigger invalidates its URL immediately; future requests to that URL are rejected.

Reset callback token

The POST /control/agents/:agent_id/external-triggers/:id/reset-callback endpoint rotates the callback token for an existing trigger. The old token is invalidated immediately and a new token is returned. Use this when a token has been exposed or as a periodic security rotation.

Default ingress capability

Every agent has a default external ingress capability created at startup:

This default trigger is sufficient for most use cases. Use CreateExternalTrigger only when you need a different delivery mode than the default, or for compatibility diagnostics. Do not treat creating multiple triggers as the ordinary workflow.

Cancelling triggers

Revoke a trigger when it's no longer needed:

CancelExternalTrigger { external_trigger_id: "trigger_abc123" }

This invalidates the callback URLs immediately. Any future requests to those URLs will be rejected.

Agent stop auto-revocation

When an agent is stopped (holon agent stop), all of its external triggers are automatically revoked. This prevents orphaned callback URLs from remaining active after the agent is no longer running. If you restart the agent later, new triggers with fresh tokens are provisioned.

Integration patterns

CI/CD pipeline

Configure your CI system to POST to the wake callback on pipeline completion. The agent uses its default ingress, starts a build, waits on the trigger, and resumes when the build reports its status.

GitHub webhooks

Point a GitHub webhook at the enqueue callback. The agent receives repository events (issues, PRs, pushes) as enqueued messages and processes them on its next turn.

Scheduled timers

Holon's built-in Timer CLI command (holon timer --after-ms 60000) can deliver events through the callback system, allowing agents to sleep and wake on a schedule.

See also