Skip to main content

5. Background mode

The first four tutorials all ran in runtime.mode: conversation - the agent only thinks when a user types something. Background mode flips that: Digitorn wakes the agent on a schedule or when an external event arrives. No human in the loop.

The smallest background app declares one trigger and a one-line prompt the trigger uses to wake the agent.

Prerequisites

Same local Digitorn setup and credential as the previous tutorials.

The YAML

Save this as daily-monitor.yaml. The app fires on a cron at 09:00 on weekdays.

app.yaml
app:
app_id: daily-monitor
name: Daily Monitor
version: "1.0"

runtime:
mode: background
workdir_mode: auto
max_turns: 4
timeout: 60

agents:
- id: main
role: assistant
brain:
provider: deepseek
model: deepseek-chat
backend: openai_compat
credential:
ref: deepseek_main
scope: per_user
provider: deepseek
config:
api_key: "{{env.DEEPSEEK_API_KEY}}"
base_url: https://api.deepseek.com/v1
temperature: 0
max_tokens: 64
system_prompt: |
You are a background monitor. Each time you wake up, reply
with one short status line. Do not ask questions; the user
is not online when you fire.

tools:
modules:
channels:
config:
providers:
morning_check:
adapter: cron
enabled: true
config:
schedule: "0 9 * * 1-5" # 09:00 Mon-Fri
activation:
agent: main
message: "Time for the daily check. Reply with: monitor running."
session: per_event
reply: none
capabilities:
default_policy: auto

What arms the app is the channel provider, not runtime.mode alone: digitorn-background reads tools.modules.channels.config.providers and arms one listener per entry. A background app without a provider compiles but never fires - the daemon says so (DGT-E0407).

Two new things vs the previous tutorials:

  • runtime.mode: background - the app is trigger-driven, not chat-driven.
  • runtime.triggers - activation sources. This one is a cron trigger. For webhooks and chat networks, see Channels.

Deploy

bash
digitorn lint daily-monitor.yaml
digitorn install daily-monitor.yaml

After install, Digitorn arms the cron trigger. At 09:00 on weekdays the agent wakes with the trigger message as input.

Try it without waiting for cron

For a faster feedback loop while learning, temporarily change the schedule to every minute ("* * * * *"), re-install, and watch the app's session / activity in the Digitorn UI. Then restore the weekday schedule.

You can also keep a conversation-mode sibling app that uses scheduler.schedule from a chat turn (see scheduler) if you want an interactive demo.

What a successful wake looks like

When the trigger fires, the agent should reply with a short status line such as monitor running. Session history for daily-monitor shows the activation message and that reply.

Example shape of an activation record (fields vary by UI):

json
{
"app_id": "daily-monitor",
"trigger_id": "morning_check",
"trigger_type": "cron",
"status": "completed",
"message": "Time for the daily check. Reply with: monitor running.",
"response": "monitor running.",
"tool_calls_count": 0,
"turns_used": 1,
"prompt_tokens": 2078,
"completion_tokens": 5,
"error": null
}

The agent woke up, used one turn, called no tools, and produced a short status reply.

Other trigger types

cron is the simplest. The same runtime.triggers list accepts several richer types; pick the one that matches your event source:

TypeWhat it watchesExample use
cronTime of day / day of weekDaily digest, hourly poll
watchA path on disk for file changes"When a new PDF lands, ingest it"
httpAn incoming HTTP request to a webhookGitHub webhook handler
channelAny provider in tools.channels"On new Slack message in #alerts, ..."

The full schema lives in Triggers. Each type has its own payload shape; the trigger payload is exposed to the agent's prompt template as {{event.payload.X}}.

Wiring multiple triggers

A single app can declare several providers. Each targets an agent with its own message template and gets its own activation log:

yaml
tools:
modules:
channels:
config:
providers:
morning_check:
adapter: cron
enabled: true
config:
schedule: "0 9 * * 1-5"
activation:
agent: main
message: "Daily 09:00 check. Read the inbox, summarise."
reply: none

alert_webhook:
adapter: webhook
enabled: true
config:
inbound_path: /hooks/alerts
auth: none
activation:
agent: main
message: "Alert received: {{event.payload.title}}. Investigate."
reply: auto

V1 arms seven adapters: cron, webhook, rss, telegram, discord, whatsapp, pieces. Anything else is declared but never listened to.

See Triggers for payload fields and throttling options you can set in YAML.

When to use background mode

  • The agent does work without a human (digests, monitors, ingestion pipelines, scheduled reports).
  • The work is triggered by external events (new file, new message, webhook).
  • You want multiple parallel users each running their own background activations - set runtime.session_mode: multi and the daemon scopes activations per (user_id, session) instead of broadcasting.

For interactive chat-driven apps, stay on runtime.mode: conversation. Mixed apps can host both - a chat surface plus a cron trigger that posts a daily summary into the same session.

Next: 6. UI surfaces - the workspace pane and declarative widgets.