Skip to content

Automations

Automations

Automations are background jobs — the work that should happen even when nobody is looking. Each is one default export at exactly src/automations/+<lower_snake_case>.ts ; the filename is the canonical automation ID. The directory is plural — a singular `automation/`, camel case, a missing + prefix, and nested files are rejected.

Definition

import { defineAutomation } from '@norbital-ai/bolt/authoring';
import { Effect } from 'effect';
import type { Api } from './$types.js';

export default defineAutomation(
  { schedule: '0 6 * * *' },
  {
    description: 'Counts every active site each morning.',
    // An automation's authority is its own: the policies it acts under, never its trigger's.
    policies: ['daily_sites_digest'],
    handler: (api: Api) =>
      Effect.gen(function* () {
        const sites = yield* api.db.query.sites.findMany({ limit: 250 });
        return { count: sites.length };
      })
  }
);

Save this declaration as src/automations/+daily_site_digest.ts .

Triggers

  • Schedule — cron execution after the automation is deployed; the schedule takes effect when the new build goes live
  • Collection event — background work triggered by collection changes
  • Manual — `{}` declares none; every automation remains manually runnable

Execution model

Author the business workflow, not a resident process. The host admits the handler into a one-shot worker with an uninterrupted CPU-span limit. Model and database facility waits retain its worker and capacity slot, pause active CPU metering, and resume inside the same invocation. More rows may continue later from a saved cursor. A successful dispatch records its worker CPU once; a dispatch that fails or is terminated before completion currently emits no compute observation. When an observation is due, metering fails closed if its outbox write cannot be made durable.

When to use an automation

  • Hooks — run inside the write’s own phases (before / after); an automation is a separate background run and cannot join the write that fires it
  • Remotes — request/response endpoints called directly by an app; an automation has no caller to answer
  • Automations — scheduled digests, compliance checks, retries, and any work that should run independent of a user action; use `api.infer` inside the handler when judgement is needed