Skip to content

Automations

Run an agent on a schedule, or whenever another tool calls a URL. Every run is an ordinary PiCode agent session: it shows in the sidebar, the dashboard counts its cost, and its result lands in the Inbox.

  • Where: user menu → Automations, or Ctrl+K → Automations.
  • Not this: not a snippet you send by hand, and not a cron job on the host.

Video: schedules, webhooks, and the inbox — the screens are the real app.

Create one

  1. Create automation.
  2. Name it. The agent that runs it takes the same name.
  3. What it doesStart a new run (a fresh session each time on the automation's own agent, in the workspace you pick) or Message an agent
  4. Prompt — what the agent should do each time.
  5. Schedule — one or more rules. Each is Hourly, Daily, Weekdays or Weekly at a time, or Custom for a cron line (minute hour day month weekday), with an optional label and its own switch. Add a schedule for "weekdays at 09:00 and Saturday at noon" or "every 30 minutes in business hours, plus a nightly summary". Times are in your browser's time zone, saved with the rule.
  6. Webhook — turn on to get a URL other tools can POST to.
  7. Limits — max cost per run, max runs per hour/day/week.

Run now on the list or the detail page tries it immediately, even when the automation is switched off.

Describe it instead

With an agent open, type /automate followed by what you want, for example /automate every weekday at 9, summarize what changed since yesterday. The agent reads the repository and drafts the name, prompt, schedule and limits; the editor opens pre-filled with a "Drafted by …" line. Review, adjust, Create. If the agent answers without a config, the editor still opens with your description as the prompt. Bare /automate asks for the description first.

Templates

Suggested on the Automations page lists ready-made jobs any agent can run on a local repository: morning brief, nightly tests, docs drift, outdated dependencies, stale branches, changelog draft, vulnerability audit. Filter by category, click one, and the editor opens filled in. In the editor, Start from template… does the same for an automation you are already writing. Templates never push, commit or delete anything; they report.

Webhook

After saving, the detail page shows the URL and the secret once. Send the secret as a header:

bash
curl -X POST https://localhost:8445/api/automations/<id>/fire \
  -H "Authorization: Bearer <secret>" \
  -d '{"anything": "the agent should know"}'

The body (up to 64 KB, any format) is appended to the prompt as text. A wrong secret answers 401; Regenerate secret replaces it.

The detail page shows the URL to use. On a laptop it is your server's own (https://localhost:8445/...); with a public URL set (Preferences → Server) it is that name; behind a gateway (a shared or public box) it is https://<box>/-/hook/<your user>/<id>, which needs no login — the secret is the credential, and the gateway only routes.

Recipes

GitHub Actions — after a deploy, or on a schedule GitHub keeps:

yaml
- name: Tell PiCode
  run: |
    curl -fsS -X POST "${{ secrets.PICODE_HOOK_URL }}" \
      -H "Authorization: Bearer ${{ secrets.PICODE_HOOK_SECRET }}" \
      -H "Content-Type: application/json" \
      -d "{\"repo\":\"${{ github.repository }}\",\"sha\":\"${{ github.sha }}\",\"ref\":\"${{ github.ref }}\"}"

Sentry — Settings → Integrations → Webhooks; paste the URL with the secret in it as a query is not supported, so use an internal integration with a custom header Authorization: Bearer <secret>. The event JSON lands in the prompt; ask the automation to "summarize the Sentry event and open a fix branch".

Any cron on another machine:

0 7 * * 1-5  curl -fsS -X POST https://box/-/hook/alice/<id> -H "Authorization: Bearer <secret>" -d "weekday morning"

Slack slash command / Zapier / n8n — anything that can POST with a header works the same way; the body is free text for the agent.

Notify a channel when a run ends

Every run lands in the Inbox. To hear about it somewhere else, give the automation a Notify URL: a Slack incoming webhook (https://hooks.slack.com/services/…), a Discord webhook with /slack appended, a Teams incoming webhook, or any endpoint that accepts JSON. When a run ends PiCode POSTs one message — ✅/❌, the automation's name, the cost, a link back to it, and the agent's final message (clipped at 1500 characters) — in the Slack shape:

json
{"text": "✅ *Nightly tests* ran · $0.12 · <https://box/#/automations/a1|Open in PiCode>\nAll green.",
 "blocks": [{"type":"section","text":{"type":"mrkdwn","text":"…"}}]}

A failed delivery is retried once after five seconds and then recorded as an automation.notify event with the error; the run itself is not affected.

Messaging an agent

Message an agent sends the prompt to one of your own agents instead of starting a new one. If the agent is closed, PiCode starts it on its session, delivers the prompt, waits for the answer and closes it again; open the agent later and the exchange is in its history. If the agent is already open in PiCode, the prompt arrives as a follow-up and the agent stays open. An agent open in a terminal is skipped: nothing can type into it safely.

What a run can end as

ResultMeaning
DoneThe agent finished. Its final message is the Inbox item.
Skipped · busyThe previous run was still going. Runs never overlap.
Skipped · rate capThe runs-per-window limit was reached.
Skipped · agent in terminalThe agent is open in a terminal, where messages are not delivered automatically.
Failed · cost capSpending passed the limit; the run was stopped.
Failed · pi missingpi is not installed or not on PATH.
Failed · daemon restartedPiCode restarted mid-run. The next scheduled run starts fresh.

Timing

Schedules run only while PiCode is running (the machine is on). Each schedule fires a few minutes after its slot — a fixed offset per schedule, never more than half the interval — so many "daily at 09:00" automations do not hit your provider at the same second. If PiCode was down when a slot passed, each missed schedule runs once when it comes back. Two schedules of one automation due in the same minute run one after the other; the second is skipped as busy if the first is still going. Changing a schedule's time starts it over: it waits for its next slot rather than catching up. The Runs table names the schedule that fired each run.