---
sidebar_position: 1
title: Triggering programmatically
---

# Triggering programmatically

The CLI is the public surface for triggering agents. CI runners, cron hosts, webhook handlers — all of them shell out to the same command:

```bash
zibby agent trigger <uuid>
zibby agent trigger <uuid> -p ticket=BUG-123
zibby agent trigger <uuid> --input '{"ticket":"BUG-123","priority":"high"}'
zibby agent trigger <uuid> --input-file payload.json
```

Auth: set `ZIBBY_API_KEY` in the environment, or run `zibby login` once on a workstation. Either works; the CLI picks up whichever is available.

The flag surface is identical to `zibby agent run` (local) — same `-p / --input / --input-file`, plus `--idempotency-key` for the cloud-only dedup case below. Flip the verb and the same call shape goes from local to remote.

### Input precedence

When more than one input source is provided, they merge with this **precedence (highest → lowest)**:

1. `-p key=value` (repeatable) — wins over everything; great for shell-friendly tweaks on top of a base payload
2. `--input '<json>'` — full JSON payload as a string
3. `--input-file path.json` — full JSON/YAML payload from a file (lowest precedence)

This means the common pattern of "load a base payload from disk, override a few keys for this run" works without manual merging:

```bash
zibby agent trigger <uuid> --input-file payload.json -p priority=urgent
```

## CI / cron

Anywhere you can shell out, call the CLI. Don't hand-roll an HTTP client — you'll just rebuild what the CLI already does (project lookup from UUID, idempotency, quota error messages, retries).

### GitHub Actions

```yaml
- name: Trigger Zibby agent
  run: |
    npm i -g @zibby/cli
    zibby agent trigger $WORKFLOW_UUID -p sha=$GITHUB_SHA -p pr=$PR_NUMBER
  env:
    WORKFLOW_UUID: 2b1ea07f-3ede-4bfd-a51d-431f0bab008e
    ZIBBY_API_KEY: ${{ secrets.ZIBBY_API_KEY }}
```

### Cron (any provider)

GitHub Actions schedule, Vercel Cron, EventBridge with a Lambda runner, fly.io machines — all the same pattern:

```yaml
on:
  schedule:
    - cron: '0 9 * * 1'   # every Monday 9am UTC
jobs:
  triage:
    runs-on: ubuntu-latest
    steps:
      - run: npm i -g @zibby/cli
      - run: zibby agent trigger $UUID --input '{"weekly":true}'
        env:
          UUID: ${{ vars.WORKFLOW_UUID }}
          ZIBBY_API_KEY: ${{ secrets.ZIBBY_API_KEY }}
```

### Webhook handlers

Inside a Node/Python/Go server processing an inbound webhook (Stripe, GitHub, Linear), spawn the CLI from your handler. You inherit all of its behavior — auth, error handling, idempotency — and don't write any of it yourself.

```js
import { execFileSync } from 'node:child_process';

app.post('/webhook', (req, res) => {
  if (!verifySignature(req)) return res.status(401).end();

  try {
    execFileSync('zibby', [
      'agent', 'trigger', process.env.WORKFLOW_UUID,
      '--input', JSON.stringify(req.body),
      '--idempotency-key', req.headers['x-event-id'],
    ], { env: process.env, stdio: 'pipe' });
    res.status(202).end();
  } catch (err) {
    res.status(502).end();
  }
});
```

If your runtime can't spawn a Node CLI (constrained Lambda layers, edge runtimes, non-Node servers without child_process), open an issue — that's the case worth a real SDK, not a documented HTTP surface.

## Idempotency

Pass an idempotency key to deduplicate triggers within a 24-hour window:

```bash
zibby agent trigger <uuid> \
  -p ticket=BUG-123 \
  --idempotency-key webhook-2026-05-02-event-7
```

Same key + same input within 24h returns the original `jobId` instead of starting a new run. Use the inbound event's ID (`X-Event-Id`, Stripe's `event.id`, GitHub's delivery ID) — that way a retry from the source automatically dedupes.

## Tailing the result

After triggering, the CLI prints the `jobId`. To watch the execution:

```bash
zibby agent logs <uuid> -t
```

See [`agent logs` in the CLI Reference](../cli-reference#agent-logs).

## Per-agent env vars

If your agent needs credentials or config that's specific to it (different `ANTHROPIC_API_KEY` per agent, an agent-only `DATABASE_URL`, etc.), set them via the env-var API — see [Per-agent env vars](./env-vars). They get injected into the Fargate task at trigger time and override anything set on the project record.

## Quotas

Per-project quota:
- Concurrent executions
- Total executions per day
- Per-execution wall-clock cap (default: 30 min)

Hit a quota and the trigger errors out with a readable message + retry hint. The CLI surfaces these directly; if you're shelling out from CI, the non-zero exit + stderr is enough to fail the job and have your retry logic kick in.
