Routines & Runs
A Routine is a scheduled, recurring piece of AI work. Cron expression, markdown brief, on/off switch. Every execution becomes a Run with captured logs you can read line by line.
Where they live
Routines have their own section in the nav, under AI → Routines. That list is company-wide: every routine, every employee, one page. Filter it by the AI Employee a routine is assigned to, or by health — Active, Paused, Needs attention.
Clicking a routine opens its detail page: Overview, Brief, Runs, and Settings. Each AI employee still links to their own slice of that list — same page, filtered to them.
Anatomy
- name
- What humans call this routine.
- cron
- A standard 5-field cron expression. Rendered as a human-readable schedule next to the input field.
- body
- Markdown brief — what the employee should do when this fires. Stored on
Routine.body. - enabled
- Boolean. Disabling pauses the schedule without losing the row.
- approvalRequired
- Optional. If true, the runner records the intended action and blocks it on a human ✓ via the
Approvalentity. - model
- Optional. Which of the employee's AI Models this routine runs on. Defaults to Inherit — whichever model is active for the employee. See Picking a model.
- timeoutSec
- Hard timeout in seconds. The runner aborts the in-process agent after this long and marks the Run
timeout. Defaults to 60 minutes and is editable per routine (10s – 6h) from the routine editor — raise it for long jobs, lower it to fail fast.
Scheduling
Routines use node-cron, the standard 5-field syntax:
┌───── minute (0 - 59)
│ ┌─── hour (0 - 23)
│ │ ┌─ day of month (1 - 31)
│ │ │ ┌─ month (1 - 12)
│ │ │ │ ┌─ day of week (0 - 6, Sunday = 0)
│ │ │ │ │
0 9 * * 1-5 → weekdays at 09:00
*/15 * * * * → every 15 minutes
0 17 * * 5 → Fridays at 17:00The editor previews the cron in plain English next to the field, so you can sanity-check before saving.
The brief
The body is markdown the model reads at run time. Keep it short and verb-first. Reference a Skill by name if the playbook already exists; otherwise describe the desired outcome.
# Morning brief
Every weekday at 09:00, post a 5-bullet summary of:
1. Stripe revenue for the last 24h (call `reconcile-stripe-payouts`)
2. New customer signups (Postgres connection "prod-read")
3. Open PRs assigned to humans (GitHub connection "main")
4. Anything new in #alerts since yesterday
5. One sentence of your own opinion about the day
Post it to the #morning channel.Picking a model
An employee can hold several AI Models and keeps one active. By default a routine runs on that active model — the Model field in the routine editor reads Inherit, and the routine follows the employee whenever you switch their brain.
Pick a specific model instead to pin it. The routine then always runs on that model regardless of which one is active. This is how you put a noisy hourly digest on a cheap local endpoint while the employee's chat stays on a frontier model — or the reverse, pinning the weekly board report to your strongest model.
- You can only pin a model that belongs to that employee. Register it on the employee's Models tab first.
- A pin only affects this routine's Runs. Chat with the employee always uses the active model.
- Remove a pinned model and its routines quietly revert to Inherit rather than breaking. The run log names the model it used and whether it was pinned or inherited.
Runs
Every cron tick — and every manual trigger — creates a Run row. The runner runs the in-process agent in the employee's directory and stores the agent transcript — the model's messages and tool trace, not captured CLI stdout — on Run.logContent (capped at 256 KB; longer logs are head-truncated with a notice).
A routine's full run history lives on its Runs tab — every Run, scheduled or manual, with the log viewer.
- Status moves
queued → running → succeededorfailed. - The Run detail view streams the transcript over WebSocket while it's running, then renders the full transcript when it's done.
- Manual Runs from the "Run now" button live in the same table as scheduled Runs.
- Retry a Run that
failedortimed outstraight from its run history. It re-triggers the routine immediately, outside the schedule, and opens the live log for the new Run.
Failures are easy to notice: the Home page shows a Failed routines panel for anything that broke in the last 24 hours, and every Journal entry for a Run links straight to that routine's run history — where the Retry button is one click away. Once you've looked at a failure, hit the ✕ on its row to dismiss it — the run stays in the routine's history, but it drops off the panel (and out of the System Health failed-runs count) so it stops nagging the whole team.
System Health
Settings → System Health (also a card on the Home page) rolls up everything that might be quietly broken for the company, over a 24-hour window:
- Failed and stuck runs — failures, timeouts, and runs still
runninglong after their timeout (orphaned by a restart). - Skipped runs and employees missing an AI model — routines that never actually ran because no model was connected.
- Approvals waiting too long, email delivery failures, and integration connections in an error/expired state.
Every row deep-links to where you fix it — the routine's run history, the employee's model settings, the approvals inbox, or the relevant settings page. It is read-only and computed live from existing data, so there is nothing to configure.
Approvals
Some routines should not auto-fire. Flip approvalRequired on and the runner stops the moment the routine would take a sensitive action — paying a Lightning invoice, sending an email, hitting a third-party API. The action is recorded as an Approval row; a human clicks ✓ in the inbox and the call is replayed.
Built-in approval kinds
routine— the whole Run is gated.lightning_payment— auto-issued when a payment exceeds the per-connection cap. See the Integrations page.