Proactiveness

Formations that reach out, not just respond

By default a formation only answers when spoken to. The proactive: block lets it initiate contact: deliver notifications, run periodic heartbeats, and address users on the channel they last used. Everything here is inert until configured.

Channels are transformers

A channel is a named reference to a trigger transformer, so outbound delivery reuses the same template substitution, auth, and retry machinery, with a single webhook fallback when every channel fails.

Bundled dormant templates ship for slack, telegram, discord, and email (real platform payload shapes, no URLs, inert until referenced, shadowed by a formation-local transformers/ file). Email emits a constructed message object (from/to/subject/body/headers) to your bridge webhook; SMTP/SES wiring stays your side.

Each channel accepts only two keys: transformer (required) and an optional url (an http(s) URL or a ${{ secrets.* }} template) that overrides the transformer's own endpoint.

proactive:
  channels:
    slack:
      transformer: slack
      url: "${{ secrets.SLACK_WEBHOOK }}"
  default_channel: slack        # a channel name or "webhook"

Routing precedence

Outbound delivery resolves in this order: explicit channel(s) → user preference → formation default (default_channel) → webhook. The reserved targets last, preferred, and webhook and multi-channel arrays are supported. Per-user channel state (preferred channel, addressing context, last channel, timezone) is kept in memory with write-through persistence and exposed via:

Endpoint Purpose
POST /v1/notifications Send a notification through the routing chain
GET /v1/users/{id}/channels Read a user's channel state
PUT /v1/users/{id}/channels Update a user's channel state

Inbound chat and triggers record which channel a user last spoke on, so "reply where they are" works.

Heartbeat

A heartbeat rides the existing scheduler through a periodic-task extension point: interval gating, active hours (fixed or user-timezone, overnight ranges, weekend flags), and a fresh session per run with full failure isolation.

proactive:
  heartbeat:
    enabled: true                # default true when the block is present
    interval: "30m"              # <N>s / <N>m / <N>h (optional "every " prefix)
    target: "last"               # last | preferred | webhook | <channel>
    active_hours:                # optional; absent means always active
      start: "08:00"
      end: "20:00"
      timezone: "user"           # IANA name, or "user" for per-user tz
      weekends: true             # false suppresses Saturday/Sunday
    instruction: "..."           # optional extra prompt content
    sop: my-heartbeat            # optional SOP name for the base prompt

A heartbeat enabled with no sop: / instruction: falls back to a bundled default SOP (check due jobs and recent context, reach out only when warranted, otherwise emit HEARTBEAT_OK). The HEARTBEAT_OK sentinel suppresses delivery and is detected even when synthesis layers wrap it - scoped to heartbeat sessions, so a normal chat that mentions it is untouched.

Soul documents

The overlord's persona can live in a SOUL.md / soul.md next to formation.yaml, auto-discovered as the default persona. Precedence: SOUL.md

soul.md > inline overlord.soul > built-in default. Agents stay single-file: an agent's character lives in its system_message.

Slash commands

An opt-in commands: block maps /command to SOPs by explicit invocation (no LLM round-trip for unknown commands). Nine fully deterministic built-in commands are active whenever the block is enabled:

Command Purpose
/setup Guided per-user setup flow derived from the formation's own config
/jobs List/pause/resume/cancel/logs for the caller's scheduled jobs
/identity Link/unlink identifiers (cross-user protected)
/channels Read/write channel state (/channels test sends a real notification)
/preferences Read/write per-user preferences
/reset Clear the current session buffer
/help List available commands
/status Read formation status
/learnings Review, apply, or dismiss pending self-tuning lessons

Formation-defined commands shadow built-ins (author control wins), and a commands.builtin: map disables individual built-ins.

commands:
  enabled: true
  aliases:
    tasks: jobs
  builtin:
    reset: false

The feature is inert when commands: is absent. With the block present, enabled defaults to true.

Learn More


Home Docs SDKs
Star on GitHub