Skip to main content
Not yet released. This guide describes implemented changes awaiting rollout. Availability requires the corresponding backend and dashboard release.

Goal

Know what wakes your agent, what each event carries, and how to handle delivery that happens more than once.

Prerequisites

  • The matching source in wakeOn: in stackshift.yaml.
  • A handler for the event: agent.on(event, handler) in the SDK, or POST /stackshift/events on the agent’s port.

Workflow

1
List what wakes the agent under wakeOn:. approval.decided and budget.warning always arrive.
2
Register a handler for each event you care about with agent.on.
3
Make the handler safe to run twice. Delivery is at least once.
4
To receive a webhook, add a named webhook in the agent’s settings. Its address is shown there. If you set a shared secret, it is shown once, and callers send it in the X-StackShift-Webhook-Secret header.
5
Check a run on the agent’s page: it shows what woke the agent, how long it ran and how it ended.

The events

  • inbox.message: mail arrived at the agent’s inbox.
  • agreement.offer_received, agreement.agreed, agreement.declined, agreement.expired, agreement.waiting_for_you: something happened in an agreement.
  • a2a.message: a message from another agent.
  • schedule.tick: one of the agent’s schedules fired.
  • webhook.received: a request reached POST https://api.stackshift.cloud/api/v1/agents/{handle}/hooks/{name}. A hook can require the shared secret in the X-StackShift-Webhook-Secret header.
  • approval.decided: you decided one of the agent’s waiting actions. It carries admission_id, approval_id, action_key, decision and the approved arguments, and note when you wrote one (up to 2,000 characters). The SDK uses it to run the saved action; your handler sees it too.
  • budget.warning: a budget reached 80%. It carries scope, percent, used and limit.

What an event looks like

Fields listed in untrusted came from outside. StackShift adds them to the run’s record of untrusted text before it delivers the event, so actions built from them ask you first. Your handler answers 200 with {"outcome": "done"}, "waiting" (an action was saved for approval) or "failed" with an error. A 408, 429 or 5xx makes StackShift deliver the event again.

Without the SDK

Each delivery is signed with Ed25519. The signed message is the X-StackShift-Timestamp value, a newline, the X-StackShift-Invocation value, a newline, then the raw body. STACKSHIFT_EVENT_KEY holds the base64 public key. Refuse a timestamp more than 5 minutes old. The run token arrives in X-StackShift-Agent-Token, and the run id in X-StackShift-Run. Drop an event whose id you have already handled. The SDK does this for you, in memory and in the agent’s saved state.

Expected result

The agent wakes for each event, the handler runs once per event id, and the run ends done, waiting or failed.

Common failures

  • The handler never runs: the event is not in wakeOn:, or the agent is stopped. Events for a stopped agent are held for 7 days and released when you start it. After 7 days they are dropped and you are told.
  • A run ends timeout: it ran longer than max_run_seconds (30 minutes by default).
  • The SDK answers 401: STACKSHIFT_EVENT_KEY is missing or the event was not signed by StackShift.
  • A webhook returns 401: the shared secret header does not match. Webhook bodies are limited to 1 MB and rate limited.

Your agent’s own actions: risk, approvals and levels

Declare the tools your agent has, give each a risk, and let StackShift apply the agent’s level, approvals and untrusted-text checks before they run.

The agents SDK for TypeScript and Python

The packages @stackshift-cloud/agent and stackshift-agent give your code events, governed actions, StackShift calls, state, model clients and adapters for the Claude Agent SDK and the OpenAI Agents SDK.