Connect

Orbs

An orb is an inbound webhook that wakes an agent. CI fails, an issue opens, a monitor fires — and an agent is standing there.

Setting one up

AI Agents, pick the agent, open its Webhook tab, and create one. You get a URL. Then configure it:

SettingWhat it does
Providergeneric, github or stripe — which signature scheme is checked
Signing secretThe provider's secret. Write-only, stored in the vault.
InstructionsWhat the agent should do when this event arrives. This is the only instruction it is given.
Payload fieldsDot-paths to narrow the body to. Empty passes the whole body, truncated.
ThreadA new conversation per delivery, or all deliveries into one thread
Rate limitAccepted deliveries per hour. Defaults to 60.

An orb without a signing secret is badged Unsigned in the list, because the URL is then the only thing authenticating the caller — treat it as a secret.

What happens to a delivery

In order, and every step fails closed:

  1. Size. Bodies above 1 MB are rejected. An unauthenticated route must not accept a 50 MB body just because the global upload limit allows one.
  2. Signature. Verified per provider. Every verifier returns false on any failure — a malformed header, a missing secret, a stale timestamp, a one-byte body change. A provider configured with no secret returns a clear error, not a degradation to "unsigned, probably fine".
  3. Permission check. An agent running at yolo will not run from an unsigned orb. The real bound on a successful injection is not the fence around the payload — it is the permission mode the agent runs at, and an unauthenticated HTTP request must not reach a runtime with full host access.
  4. Rate cap. Checked before the deduplication claim, so a throttled delivery does not consume its idempotency slot and cause the provider's legitimate retry an hour later to be dropped as a duplicate. Only accepted deliveries count toward the cap, so an orb over its limit can recover.
  5. Deduplication. Keyed on the provider's own delivery id, which makes it exact rather than heuristic. GitHub does not timestamp its signature, so for GitHub this dedupe is the replay guard.
  6. Dispatch. The agent is woken with a composed message.

Every delivery is logged — accepted or rejected, with the reason — so a webhook that is not firing can be diagnosed from the app.

The payload is untrusted

A webhook body is attacker-controlled text. The composed message has two halves, and the boundary between them is the point of the design:

Narrowing the payload to the handful of fields you actually need is the single most effective thing you can do here.

Signature schemes

ProviderChecked
githubHMAC over the raw body, compared in constant time; delivery-id dedupe doubles as the replay guard
stripeSigned timestamp plus HMAC, within a 300-second tolerance — Stripe's own documented default
genericagensis's own scheme, for anything you control

A provider is only listed once its verifier exists and is exercised by tests, because an unimplemented provider in that list would be a provider that silently accepted anything.