Examples
Complete app YAML sketches. Prefer tool names from
YAML building blocks. Top-level blocks:
app, runtime, agents, tools, security, ui, dev, flow,
plus optional templates / requirements / docs / ...
channels: lives under tools: (not top-level).
1 · Minimal chat
The simplest possible conversational app - LLM + filesystem read access.
app:
app_id: chat-assistant
name: Chat Assistant
description: Interactive conversation with tool access.
runtime:
mode: conversation
agents:
- id: assistant
role: assistant
brain:
provider: deepseek
model: deepseek-chat
backend: openai_compat
config:
api_key: "{{secret.DEEPSEEK_API_KEY}}"
base_url: https://api.deepseek.com/v1
system_prompt: |
Tu es un assistant intelligent et amical. Tu réponds en français.
Utilise les outils disponibles quand c'est pertinent.
tools:
modules:
filesystem: {}
capabilities:
default_policy: auto
ui:
greeting: "Bienvenue ! Je suis ton assistant Digitorn."
2 · One-shot task
Process a single input and return; the agent loop exits as soon as the LLM produces text without calling any tool.
app:
app_id: hello-oneshot
name: Hello One-Shot
runtime:
mode: one_shot
input:
type: text
description: A question or message
output:
type: text
agents:
- id: assistant
role: assistant
brain:
provider: deepseek
model: deepseek-chat
backend: openai_compat
config: {api_key: "{{secret.DEEPSEEK_API_KEY}}"}
system_prompt: "Be concise and helpful. Use tools when relevant."
tools:
modules:
filesystem:
constraints:
allowed_actions: [read, glob, grep]
capabilities:
default_policy: auto
digitorn install hello-oneshot.yaml
digitorn chat hello-oneshot
Type Say hello in 3 languages as your message.
3 · Smart chat with context management
Conversation mode with automatic context compaction
(summarize strategy + auto_compact: true).
app:
app_id: smart-chat
name: Smart Chat
runtime:
mode: conversation
max_turns: 40
timeout: 1200
agents:
- id: assistant
role: assistant
brain:
provider: deepseek
model: deepseek-chat
backend: openai_compat
config: {api_key: "{{secret.DEEPSEEK_API_KEY}}"}
context:
max_tokens: 80000
output_reserved: 1000
strategy: summarize # truncate | summarize
keep_recent: 20 # last N messages always kept verbatim
compression_trigger: 0.9 # compact when usage > 90 %
summary_max_tokens: 5120
auto_compact: true
system_prompt: |
Tu es un assistant intelligent. Réponds en français.
Limite-toi à 3-5 appels d'outils maximum par question.
Si un outil échoue, explique l'erreur, ne ré-essaie pas en boucle.
tools:
modules:
filesystem:
constraints:
allowed_actions: [read, glob, grep, write]
capabilities:
default_policy: auto
ui:
greeting: "Salut ! Assistant avec gestion automatique du contexte."
4 · Local LLM (Ollama, no native tools)
Local model, tool definitions injected in the system prompt since the model doesn't support native function calling.
app:
app_id: ollama-chat
name: Ollama Chat
runtime:
mode: conversation
max_turns: 10
timeout: 300
agents:
- id: assistant
role: assistant
brain:
provider: ollama
model: qwen2.5:14b-instruct-q4_K_M
backend: openai_compat
config: {base_url: http://localhost:11434/v1}
context:
max_tokens: 8000
strategy: truncate
keep_recent: 6
compression_trigger: 0.6
auto_compact: true
system_prompt: "Tu es un assistant local. Limite-toi à 3-5 appels d'outils max."
tools:
modules:
filesystem:
constraints:
allowed_actions: [read, glob, grep]
capabilities:
default_policy: auto
ui:
greeting: "Assistant local prêt."
Local-LLM tips: timeout: 300 (or higher) - local
models are slower than cloud APIs.
5 · Context-management stress test
Aggressive compression_trigger so the compaction code path
fires within a few turns. Includes a runtime.hooks: entry
that logs token pressure on every turn.
app:
app_id: context-test
name: Context Management Test
runtime:
mode: conversation
max_turns: 50
timeout: 120
hooks:
- id: pressure_log
"on": turn_start
condition: {type: always}
action:
type: log
message: "Turn {turn}: ~{tokens} tokens, {messages} messages"
cooldown: 0
agents:
- id: assistant
role: assistant
brain:
provider: deepseek
model: deepseek-chat
backend: openai_compat
config: {api_key: "{{secret.DEEPSEEK_API_KEY}}"}
context:
max_tokens: 0 # 0 = use provider default
output_reserved: 4096
strategy: summarize
keep_recent: 6
compression_trigger: 0.15 # very aggressive
summary_max_tokens: 512
auto_compact: true
system_prompt: "Réponds en français. Sois détaillé pour générer du contenu."
tools:
modules:
filesystem:
constraints:
allowed_actions: [read, glob, grep]
capabilities:
default_policy: auto
6 · Smart chat with summary brain
Same as example 3 but the summary brain is a small local model - keeps the main conversation on the cloud LLM while compaction runs locally for free.
agents:
- id: assistant
role: assistant
brain:
provider: deepseek
model: deepseek-chat
backend: openai_compat
config: {api_key: "{{secret.DEEPSEEK_API_KEY}}"}
context:
max_tokens: 80000
strategy: summarize
keep_recent: 10
compression_trigger: 0.75
summary_max_tokens: 1024
auto_compact: true
summary_brain:
provider: ollama
model: qwen2.5:3b
backend: openai_compat
config: {base_url: http://localhost:11434/v1}
system_prompt: "Réponds en français."
7 · Secure read-only analyst
Read-only filesystem + database access, with explicit
grant: / deny: and max_risk_level: low. Demonstrates
the security model in Security.
app:
app_id: secure-analyst
name: Secure Analyst
runtime:
mode: conversation
workdir: "{{env.PWD}}"
agents:
- id: analyst
role: assistant
brain:
provider: deepseek
model: deepseek-chat
backend: openai_compat
config: {api_key: "{{secret.DEEPSEEK_API_KEY}}"}
system_prompt: |
You are a data analyst with read-only access.
Never attempt to modify files or execute write queries.
tools:
modules:
filesystem:
constraints:
allowed_actions: [read, glob, grep]
database:
config:
databases:
- name: main
kind: postgres
dsn: "{{secret.ANALYST_DATABASE_URL}}"
security:
mode: read_only
constraints:
allowed_actions: [query]
capabilities:
default_policy: auto
max_risk_level: low
grant:
- {module: filesystem, actions: [read, glob, grep]}
- {module: database, actions: [query]}
deny:
- {module: filesystem, actions: [write, edit], reason: "Read-only mode"}
- {module: database, actions: [disconnect], reason: "Only query allowed"}
ui:
greeting: "Data analyst ready. I can read files and query databases."
dev:
variables:
workspace: "{{env.PWD}}"
8 · Multi-agent (coordinator + worker)
Two agents. The coordinator delegates with
agent(agent="worker", task="...", wait=true). delegate_to on the
coordinator is required, not optional: it both builds the automatic
"Available specialists" prompt block and is the actual runtime
authorization list - a coordinator can only spawn an id that's in
its own delegate_to, even with agent_spawn granted and worker
a real agent in the file. See Multi-agent.
app:
app_id: multi-agent
name: Multi-Agent
runtime:
mode: conversation
entry_agent: coordinator
max_turns: 30
workdir: "{{env.PWD}}"
agents:
- id: coordinator
role: coordinator
delegate_to:
- id: worker
instructions: "Delegate here for any task the user asks to have done."
brain:
provider: deepseek
model: deepseek-chat
backend: openai_compat
config: {api_key: "{{secret.DEEPSEEK_API_KEY}}"}
system_prompt: "Orchestrate via the agent tool (agent + task params)."
- id: worker
role: specialist
specialty: "Executes the delegated task"
brain:
provider: groq
model: llama-3.3-70b-versatile
backend: openai_compat
config:
api_key: "{{secret.GROQ_API_KEY}}"
base_url: https://api.groq.com/openai/v1
system_prompt: "Execute the delegated task."
tools:
modules:
filesystem:
constraints:
allowed_actions: [read, glob, grep]
agent_spawn: {}
capabilities:
default_policy: auto
grant:
- module: agent_spawn
- module: filesystem
ui:
greeting: "Multi-agent system ready."
See Multi-agent for real agent modes
(agent/task, batch agents, wait, list, cancel). There
is no reassign tool param in this build.
9 · Background mode with channel providers
A daemon app that sweeps an inbox folder every 10 minutes and emits an hourly summary. Digitorn has no file watcher: polling on a cron is how you pick up new files today. See Channels for the adapters that arm.
app:
app_id: csv-watcher
name: CSV Watcher
runtime:
mode: background
max_turns: 10
timeout: 60
workdir: "{{env.PWD}}"
agents:
- id: analyst
role: assistant
brain:
provider: deepseek
model: deepseek-chat
backend: openai_compat
config: {api_key: "{{secret.DEEPSEEK_API_KEY}}"}
system_prompt: |
When activated, glob the inbox for CSV files, read the ones
you have not summarised yet, and report what they contain.
tools:
modules:
filesystem:
constraints:
allowed_actions: [read, glob, grep]
channels:
config:
providers:
inbox_sweep:
adapter: cron
enabled: true
config:
schedule: "*/10 * * * *"
activation:
agent: analyst
message: "Sweep {{workspace}}/inbox/ for new CSV files and analyse them."
reply: none
hourly_report:
adapter: cron
enabled: true
config:
schedule: "0 * * * *"
activation:
agent: analyst
message: "Generate an hourly summary of {{workspace}}/inbox/."
reply: none
capabilities:
default_policy: auto
dev:
variables:
workspace: "{{env.PWD}}"
Background mode requires at least one channel provider. The agent is activated each time a provider fires with the activation's
messageas input. For multi-user routing, set the provider'sactivation.session(per_eventdefault, or a template like{{event.payload.user_id}}to group one user's events into a recurring session) - see Background Sessions.
10 · Parallel execution + background tasks
A polyvalent assistant showing the auto-injected execution
primitives (run_parallel, background_run) - no YAML
config needed for those.
app:
app_id: smart-chat
name: Smart Chat
runtime:
mode: conversation
max_turns: 200
timeout: 1200
workdir: "{{env.PWD}}"
agents:
- id: assistant
role: assistant
brain:
provider: openai
model: gpt-4o-mini
backend: openai_compat
config: {api_key: "{{secret.OPENAI_API_KEY}}"}
context:
max_tokens: 128000
output_reserved: 2000
strategy: summarize
keep_recent: 20
compression_trigger: 0.85
auto_compact: true
system_prompt: |
Tu disposes de primitives d'exécution :
- run_parallel : actions indépendantes en parallèle
- background_run : tâches longues non bloquantes
Utilise run_parallel pour les actions indépendantes.
Utilise background_run pour les téléchargements et opérations lentes.
tools:
modules:
filesystem:
constraints:
allowed_actions: [read, glob, grep, write]
bash:
constraints:
allowed_actions: [run]
http:
constraints:
allowed_actions: [request, download, upload]
database:
config:
databases:
- name: test_db
kind: postgres
dsn: "{{secret.TEST_DATABASE_URL}}"
security:
mode: read_write
constraints:
allowed_actions: [connect, query, disconnect]
capabilities:
default_policy: approve
ui:
greeting: "Assistant polyvalent : exécution parallèle + tâches background."
dev:
variables:
workspace: "{{env.PWD}}"
Key takeaways:
- Modules such as filesystem, bash, http, database can load together.
- Execution primitives:
run_parallelandbackground_run(one tool, several modes - status / result / cancel / list / wait) come from auto-loadedcontext_builder. default_policy: approvemakes tool calls ask for confirmation by default when configured that way.
11 · Monitoring bot - cron + http
A background-oriented monitor. A cron channel provider wakes it
every 5 minutes; the agent itself calls http.request both for the
health check and to post the alert to Slack.
app:
app_id: monitoring-bot
name: Monitoring Bot
runtime:
mode: background
entry_agent: monitor
max_turns: 200
timeout: 3600
workdir: "{{env.PWD}}"
agents:
- id: monitor
role: assistant
brain:
provider: openai
model: gpt-4o-mini
backend: openai_compat
config: {api_key: "{{secret.OPENAI_API_KEY}}"}
system_prompt: |
You are a monitoring agent. Each wake-up: use http.request to
check the monitored endpoints. On a failure, use http.request
again to POST a Slack message to {{secret.SLACK_WEBHOOK_URL}}
({"text": "..."} JSON body). Use memory.remember for durable
notes across wake-ups.
tools:
modules:
http: {}
filesystem:
constraints:
allowed_actions: [read, glob, grep]
memory: {}
channels:
config:
providers:
cron_health:
adapter: cron
enabled: true
config:
schedule: "*/5 * * * *"
activation:
agent: monitor
message: "Run a health check on all monitored endpoints."
reply: none
capabilities:
default_policy: auto
grant:
- module: http
- module: filesystem
- module: memory
ui:
greeting: |
Monitoring bot prêt. Je peux surveiller et alerter Slack.
Que veux-tu surveiller ?
Key takeaways:
- The
cronchannel provider is what actually wakes this app -runtime:alone does not arm anything. - The agent posts to
{{secret.SLACK_WEBHOOK_URL}}itself viahttp.request, the same tool it uses for the health check. scheduler.scheduleis a different mechanism, for scheduling a wake-up from inside a live agent turn (e.g. "check back on this in an hour") - see scheduler. It is not needed here since thecronprovider already covers the recurring wake-up.
12 · MCP - multiple external servers
An agent connected to three MCP servers (Slack, GitHub, Brave Search). Each server declares its OS sandbox permissions.
app:
app_id: mcp-multi
name: MCP Multi-Server Agent
runtime:
mode: conversation
max_turns: 200
agents:
- id: assistant
role: assistant
brain:
provider: openai
model: gpt-4o
backend: openai_compat
config: {api_key: "{{secret.OPENAI_API_KEY}}"}
context:
max_tokens: 128000
strategy: summarize
keep_recent: 20
auto_compact: true
system_prompt: |
You are connected to Slack, GitHub, and Brave Search via MCP.
Use search_tools to discover virtual MCP tools.
tools:
modules:
filesystem:
constraints:
allowed_actions: [read, glob, grep]
mcp:
config:
servers:
slack:
transport: stdio
command: npx
args: ["-y", "@modelcontextprotocol/server-slack"]
env:
SLACK_BOT_TOKEN: "{{secret.SLACK_BOT_TOKEN}}"
sandbox:
permissions: [process.exec, net.http]
allowed_hosts: [slack.com, api.slack.com]
github:
transport: stdio
command: npx
args: ["-y", "@modelcontextprotocol/server-github"]
env:
GITHUB_PERSONAL_ACCESS_TOKEN: "{{secret.GITHUB_PAT}}"
sandbox:
permissions: [process.exec, net.http]
allowed_hosts: [api.github.com, github.com]
brave:
transport: stdio
command: npx
args: ["-y", "@modelcontextprotocol/server-brave-search"]
env:
BRAVE_API_KEY: "{{secret.BRAVE_API_KEY}}"
sandbox:
permissions: [process.exec, net.http]
allowed_hosts: [api.search.brave.com]
capabilities:
default_policy: auto
grant:
- module: mcp
- module: filesystem
# Tighten with allowed tool name patterns in your deploy if needed.
ui:
greeting: "3 serveurs MCP connectés : Slack, GitHub, Brave."
Key takeaways:
- Virtual MCP tools are exposed as
mcp_<server>__<tool>names under themcpmodule (not as separate compile-time modules). - Per-server sandbox with
permissions(+allowed_hostswhen needed) is mandatory for inline server blocks (deny-by-default). Catalog shorthandid: {}can omit it. search_toolsfinds MCP tools the same way it finds native ones.
13 · MCP with OAuth2 - Google Calendar (SSE transport)
OAuth2 with PKCE for per-user authorization. SSE transport injects the bearer token via HTTP header.
app:
app_id: mcp-oauth-demo
name: Calendar Assistant
runtime:
mode: conversation
agents:
- id: assistant
role: assistant
brain:
provider: openai
model: gpt-4o
backend: openai_compat
config: {api_key: "{{secret.OPENAI_API_KEY}}"}
system_prompt: |
Tu as accès au Google Calendar et à Slack.
Si un outil requiert une autorisation OAuth, présente le lien.
tools:
modules:
mcp:
config:
servers:
google_calendar:
transport: sse
url: http://localhost:3000/sse
auth:
type: oauth2
provider: google
client_id: "{{secret.GOOGLE_CLIENT_ID}}"
client_secret: "{{secret.GOOGLE_CLIENT_SECRET}}"
scopes:
- https://www.googleapis.com/auth/calendar.readonly
- https://www.googleapis.com/auth/calendar.events
sandbox:
permissions: [net.http]
allowed_hosts: [www.googleapis.com, oauth2.googleapis.com]
slack:
transport: stdio
command: npx
args: ["-y", "@anthropic/mcp-server-slack"]
env:
SLACK_TOKEN: "{{secret.SLACK_BOT_TOKEN}}"
sandbox:
permissions: [process.exec, net.http]
allowed_hosts: [slack.com]
capabilities:
grant:
# Virtual MCP tools are namespaced under the mcp module at
# runtime (e.g. mcp_google_calendar__list_events). Grant the
# mcp module; tighten with tool-name patterns in production.
- module: mcp
ui:
greeting: "Assistant Calendar + Slack prêt."
Key takeaways:
- OAuth2 + PKCE for SSE / HTTP transports - token sent in
Authorization: Bearer ...header. - Mixed auth models - Google = OAuth2, Slack = static bot token via the credentials vault.
mcp_google_calendar/mcp_slackare runtime namespaces for virtual tools undermcp, not modules declared separately.- Auto-refresh - the OAuth refresh loop renews tokens within 10 min of expiry (credentials.md).
requires_oauthflow - when the user hasn't yet authorised, the tool result carries anauth_urlthe agent surfaces.
14 · MCP with OAuth2 - Notion (stdio + env_token_var)
stdio transport injects the OAuth token as an environment variable and restarts the subprocess when the token refreshes.
app:
app_id: notion-agent
name: Notion Agent
runtime:
mode: conversation
max_turns: 200
timeout: 1200
workdir: "{{env.PWD}}"
agents:
- id: assistant
role: assistant
brain:
provider: openai
model: gpt-4o-mini
backend: openai_compat
config: {api_key: "{{secret.OPENAI_API_KEY}}"}
context:
max_tokens: 128000
strategy: summarize
keep_recent: 20
auto_compact: true
system_prompt: |
Tu es connecté au workspace Notion de l'utilisateur.
Tu peux rechercher, lire et modifier ses pages et bases de données.
tools:
modules:
mcp:
config:
servers:
notion:
transport: stdio
command: mcp-notion
args: []
auth:
type: oauth2
provider: notion
client_id: "{{secret.NOTION_CLIENT_ID}}"
client_secret: "{{secret.NOTION_CLIENT_SECRET}}"
env_token_var: NOTION_API_KEY # token injected as env var
redirect_uri: http://localhost:8913/callback
sandbox:
permissions: [process.exec, net.http]
allowed_hosts: [api.notion.com]
capabilities:
default_policy: approve
ui:
greeting: |
Agent Notion prêt ! Première connexion : tu dois autoriser l'accès
à ton workspace Notion (1 clic).
Key takeaways:
env_token_var: NOTION_API_KEY- the field that bridges OAuth2 tokens into stdio MCP servers. The daemon restarts the subprocess when the token refreshes.- Notion provider - pre-configured in the credentials catalog (Basic auth for token exchange, JSON body - not form-encoded).
- Local OAuth callback - in standalone mode, a temporary
HTTP server on the configured
redirect_uriport handles the callback and opens the browser automatically. - User-scoped sharing - the user must select the pages / databases to share at authorisation time. Skipping that step yields an empty workspace; modify later in Notion → Settings → My connections.
Cross-references
- Block-by-block YAML reference: App Configuration
- Agents + brains + sub-agent dispatch (
Agenttool, 7 modes): Agents - Background activation + session modes: Channels, Background Sessions
- Channels (cron, webhook, telegram, discord, whatsapp, rss, connector): Channels
- Security model + capabilities resolution: Security
- Credentials vault, OAuth flow, encryption: credentials.md
- Behavior engine (declarative rules + classifier): Behavior Engine
- Calling third-party HTTP APIs from an app: External APIs