---
title: Scheduled runs
description: BrainyShorts keeps the schedule, targets, and history. A runner on your own machine does the research and generation when a run is due.
sidebar:
  label: Scheduled runs
  icon: calendar-clock
---

An automation is a skill that runs on a schedule. BrainyShorts stores what should happen (skill version, cron, targets, publish mode). A runner you control decides when to wake your agent and does the actual work. BrainyShorts never calls a model and never hands your agent a social platform token.

## How a run works

1. **Create the automation**

    An agent connected over [MCP](/mcp) loads a skill with `brainy_get_skill`, registers the machine with `brainy_register_executor`, and calls `brainy_create_automation`. BrainyShorts validates it, stores revision 1, and returns an install manifest.

2. **The runner syncs**

    `brainy-shorts-runner tick` calls `GET /api/agent/automations/sync`, installs new revisions, removes paused or deleted ones, and acknowledges each applied revision with `POST /api/agent/automations/{id}/ack`. Idle ticks never invoke a model.

3. **A run starts**

    When the cron is due, the runner calls `POST /api/agent/automations/{id}/start` with the idempotency key `<automation_id>:<revision>:<scheduled_for>`. BrainyShorts checks the automation is still enabled and current, then returns a `ba_run_...` token that is valid for 6 hours and bound to that single run.

4. **Your agent does the work**

    The runner launches your agent with `BRAINY_RUN_TOKEN` in its environment. The agent posts progress to `/api/agent/runs/{id}/events` and uploads media through `/api/agent/runs/{id}/media/uploads`.

5. **The run completes**

    The agent calls `POST /api/agent/runs/{id}/complete-local`, or `/fail`. BrainyShorts then creates a draft, or publishes when the automation's publication mode is `auto`.

## Automation settings

| Setting | Values |
| --- | --- |
| Publication mode | `draft` (default) or `auto` |
| Schedule | cron expression plus an IANA timezone |
| Missed runs | `skip`, `run_once`, or `catch_up` |
| Skill | id and pinned version, see [Skills](/skills) |

Turning on `auto` is a separate decision from creating the automation. Pausing or disconnecting an account takes effect immediately, because every run start and completion is checked on the server.

## Runner

The reference runner `brainy-shorts-runner` currently ships inside the BrainyShorts repository rather than on npm. It needs Node 20 or newer and uses the `codex` adapter.

```bash
cd runner && npm install && npm link
export BRAINY_API_KEY="ba_sk_..."
brainy-shorts-runner install ./automation.json
brainy-shorts-runner tick <executor-id>     # run this from cron or launchd every minute
```

| Command | What it does |
| --- | --- |
| `install <file or ->` | Install a manifest and acknowledge its revision |
| `list` | Installed manifests |
| `remove <automation-id>` | Uninstall one |
| `sync <executor-id>` | Pull desired revisions |
| `run` | Start due runs, using no network when nothing is due |
| `tick <executor-id>` | `sync` followed by `run`, which is the normal scheduler command |

Any process that speaks the HTTP endpoints below can act as a runner, so you can write your own in any language.

## Runner endpoints

All of these live under `https://www.brainyshorts.com/api/agent`. The first three take an API key; the rest take the run token.

| Method | Path | Auth |
| --- | --- | --- |
| `POST` | `/executors` | API key |
| `GET` | `/automations/sync` | API key |
| `POST` | `/automations/{id}/ack`, `/automations/{id}/start` | API key |
| `GET` | `/runs/{id}` | run token |
| `POST` | `/runs/{id}/events` | run token |
| `POST`, `PATCH` | `/runs/{id}/media/uploads` | run token |
| `POST` | `/runs/{id}/direct-upload`, `GET /runs/{id}/direct-upload/status` | run token |
| `POST` | `/runs/{id}/complete-local`, `/runs/{id}/fail` | run token |

`direct-upload` returns a provider upload session so TikTok and YouTube video bytes go straight from your machine to the platform, up to 64 MiB. A YouTube handoff also needs the parent runner's API key in `x-brainy-runner-key`, so only the trusted runner process, not the spawned agent, can stage a YouTube upload. Instagram, LinkedIn, and X use managed media instead.

## Legacy claim queue

Automations created before `local_push` use a pull queue. A runner claims work with an API key, then renews, completes, skips, or fails it with the returned `claim_token`:

`POST /api/agent/runs/claim` → `/runs/{id}/renew` → `/runs/{id}/complete` | `/skip` | `/fail`

The queue still works for existing Instagram automations. Create new automations over MCP.
