Core concepts

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 Approval entity.
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:

text
┌───── 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:00

The 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.

markdown
# 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 → succeeded or failed.
  • 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 failed or timed out straight 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 running long 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.