Skip to main content
An automation is a stored prompt that belongs to one project and runs when any of its triggers fires. Each run is a normal Capy thread: the agent gets your prompt, the triggering event as context, and a machine to work on. You write the prompt once; the trigger decides when it runs. Create automations on the Automations page in the app, or ask Capy to create and manage them for you in a thread; the agent has the full set of automation tools.

Manage automations through the API

The public API lets an integration create and inspect automations, then pause, resume, delete, or restore them. Edit and manual-run controls remain in the app and agent tools. Create an automation with the same trigger and run configuration used by the app. It starts enabled unless you send "enabled": false; requestId is the caller-stable idempotency key, so retries converge on the same automation:
The create response is the stored automation. When its triggers include incoming_webhook, the first successful response also carries webhookUrl; save it immediately because retries and later reads never return that credential. If that response is lost, delete the original by its returned or listed id and create a replacement with a new requestId. List every automation your API-key principal can access, or narrow the page to one project:
The cursor-paginated response includes each automation’s prompt, triggers, run configuration, run-as identity, enabled state, run count, and last-triggered time. It never includes incoming-webhook secrets or stored file references. Pause and resume by id:
Delete an automation when it should no longer appear in lists, or restore it later by the id retained from an earlier response:
Every mutation returns the updated automation, including its deleted state. A service-user key with read_only access can only list; creating or changing state requires read_write or admin. Project allowlists apply to every automation operation, and an inaccessible id returns the same 404 as an unknown id. See Common flows for a script-friendly sequence and the generated API reference for complete request and response schemas.

Triggers

An automation has 1 to 20 triggers, OR’d together: any one of them firing starts at most one run per event. At most one each of schedule, incoming webhook, and on-demand. Each trigger can also carry additional conditions: repositories, branches, authors, and labels for GitHub; channels, authors, and text filters for Slack; substring and regex filters for webhooks. A condition matches when the event matches any of its listed values.

Schedules

Schedules are five-field cron and a IANA timezone, validated at save. The floor is one run per five minutes. DST follows wall-clock semantics in your timezone: a local time that doesn’t exist (spring forward) fires once at the next valid instant, and a local time that happens twice (fall back) fires once. If the scheduler falls behind, missed occurrences coalesce into a single run rather than a backlog.

Slack bursts

A burst of Slack messages becomes a single run. Each matched message extends a sliding window (1–300 seconds, default 10); the group closes when the window elapses, a different author posts, or the burst hits its bounds (20 messages, 100 KB). The run gets the joined messages in order. The agent’s normal reply channel writes to the run’s thread. If you want the automation to post in Slack, say so in the prompt and Capy will use an explicit Slack message tool.

The run-when gate

Trigger conditions are exact filters. For fuzzy conditions like “only when the message is a bug report”, add a run_when sentence to an event trigger. A fast model checks each matching event against it before the run starts. You are not billed for the fast model check.

Thread mode

thread_mode decides where runs land:
  • new: every run starts a fresh thread. The default, and right for independent jobs like a nightly check.
  • single: the automation owns one standing thread, and every run delivers its event into it. The thread keeps its machine and its context across runs, so it’s right for accumulating work like triaging a channel.

Who the automation runs as

Every automation stores one explicit run-as principal, and every run executes as it: the person who saved the automation, or a service user an admin selected. The triggering actor (the Slack author, the GitHub sender) is never the principal; they appear only inside the event context.
  • Eligibility is re-verified on every run: live user, live membership, live service-user state, project access.
  • If the principal is offboarded (user removed, service user disabled), the run fails naming the check that failed, and the automation is disabled with a visible reason. Re-enabling requires picking an eligible principal.
  • Commits attribute to the principal: a human’s runs commit as their interactive threads do; a service user’s runs commit under its display name with Capy’s bot address.
  • Model rights are the principal’s: a pinned model the principal can’t use fails at save, and rights lost later fail the run visibly, never a silent substitution.
Default to a service user for anything long-lived. Service users survive offboarding; automations running as a departed teammate stop. Any project member can run any automation in the project, enabled or disabled. Triggering executes the stored prompt as written; it changes nothing.

The webhook trigger

An incoming-webhook automation gets a URL of the form:
The URL itself is the credential: there is no signature scheme and no Authorization header. Treat it like a password: it’s generated server-side, shown once at creation or rotation, and stored only as a digest. Rotation is an immediate cutover; the old URL stops working in the same instant the new one is shown.
  • Idempotency-Key deduplicates: retries with the same key start one run. Without it, every delivery is distinct.
  • Bodies are capped at 256 KB (413 above that), and the first 8,000 characters reach the agent as context.
  • Responses: 202 with accepted, duplicate, or no-match in the body (a body your trigger’s filters reject is a valid delivery that starts no run; don’t retry it); 404 for an unknown or disabled automation, deliberately indistinguishable; 500 means retry.
The body is untrusted event context, never instructions. The agent reads it as data under the standing prompt; a payload that says “ignore your instructions” doesn’t.

Limits

max_runs_per_day is an opt-in daily cap counting runs admitted across all triggers. An over-cap event records a skipped run naming the cap, so throttling is visible in run history, never silent. Unset means no cap.

Examples

  • Nightly dependency check. Schedule 0 3 * * *, prompt: audit dependencies for security advisories and open a PR bumping anything vulnerable.
  • Follow-up on every merged PR. GitHub pull_request_merged, prompt: check the merged change for docs that now lie and fix them.
  • CI failure fixer. GitHub workflow_run with conclusion failure on your main branch, prompt: read the failing job, fix the cause, open a PR.
  • Slack support triage. Slack messages in #support with a run_when of “the message reports a bug”, single thread mode, prompt: reproduce, file the issue, link it back.
  • Deploy-failure investigation. Incoming webhook from your deploy pipeline, prompt: read the payload, find the regressing commit, report with evidence.