People ask us what Digitorn is for. The honest answer is "applications". Not just chatbots, not just coding agents, not just RAG. The runtime is generic. Anything that can be expressed as a loop of LLM decisions plus tool calls fits the model, and the model is one config file.
To make that concrete, here are ten very different apps, each one a real shape we've built or seen built on the platform. Every entry shows the YAML skeleton. The full source for each lives in the Hub.
api_key field on each brain: for readability. To deploy any of them, add config: { api_key: "{{env.ANTHROPIC_API_KEY}}" } (or the equivalent for your provider) to the brain block. The compiler enforces this; a missing credential source is a hard error.
The hub at the centre is app.yaml. The orbits are categories of work the runtime handles natively (developer tools, live apps, knowledge work, messaging, background jobs). Pick any one, write fifty lines, deploy.
A coding agent that behaves like Claude Code
The flagship use case. A coordinator on Sonnet that plans, edits files, runs tests, and dispatches search work to a Haiku-powered explorer. We documented the full architecture in the Claude Code clone post, but the kernel of the YAML is small.
1agents:2 - id: coordinator3 brain: { provider: anthropic, model: claude-sonnet-4-6 }4 delegate_to: [explorer]5 - id: explorer6 modules: [{filesystem: [read, grep, glob]}, shell]7 brain: { provider: anthropic, model: claude-haiku-4-5 }89tools:10 modules:11 filesystem: {} # read-before-edit guard is built-in12 shell: {}Install: digitorn install hub://digitorn/digitorn-code. Around 60% cheaper than running Sonnet on every turn (cost analysis).
A live React sandbox where the agent edits in front of you
The agent writes JSX into a workspace, the runtime serves it as a live preview, and the user sees the UI rebuild as edits land. No build step in your YAML. No sync logic. The workspace module handles file mirroring, hot reload, and per-file approval.
1agents:2 - id: builder3 modules: [workspace]4 brain: { provider: anthropic, model: claude-sonnet-4-6 }5 system_prompt: "Build the requested UI as a single src/App.tsx."67tools:8 modules:9 preview: {} # required: workspace publishes mutations through preview10 workspace:11 config:12 render_mode: react13 entry_file: src/App.tsx14 lint: trueInstall: digitorn install hub://digitorn/digitorn-react-sandbox. Open the chat, ask for a dashboard. Watch it appear next to the conversation.
A research agent that cites its sources
Half the value of a research bot is not making things up. The shape that holds up: one coordinator that plans and writes, one or two researchers that fetch sources, one fact-checker on zero temperature that verifies claims before the writer ships the answer.
1agents:2 - id: coordinator3 brain: { provider: anthropic, model: claude-sonnet-4-6 }4 delegate_to: [researcher, fact_checker]5 - id: researcher6 modules: [{web: [search, fetch]}, memory]7 brain: { provider: deepseek, model: deepseek-chat, temperature: 0.2 }8 - id: fact_checker9 modules: [{web: [search]}]10 brain: { provider: deepseek, model: deepseek-chat, temperature: 0 }1112tools:13 modules:14 web: { config: { search_backend: duckduckgo } }15 memory: { config: { working_memory: true } }Install: digitorn install hub://digitorn/digitorn-deepresearch. Costs roughly a tenth of running everything on Sonnet, with citations the writer can't bypass.
A LaTeX writer that compiles in the workspace
workspace.render_mode: latex swaps the React renderer for a PDF preview. The agent edits .tex files, the runtime invokes the LaTeX toolchain and re-renders the PDF every time a write lands. Useful for paper drafts, technical docs, and anything that benefits from the typographical horsepower.
1agents:2 - id: writer3 modules: [workspace]4 brain: { provider: anthropic, model: claude-sonnet-4-6 }5 system_prompt: "Edit paper.tex. The build runs after every write."67tools:8 modules:9 preview: {} # required by workspace10 workspace:11 config:12 render_mode: latex13 entry_file: paper.tex14 sync_to_disk: truePair it with lsp for texlab diagnostics on every save and you get inline error feedback the same way you'd get TypeScript errors in a code editor.
A Slack copilot that lives in a thread
The slack channel adapter turns any agent into a bot you can @mention. It runs over Slack's Socket Mode (no public webhook URL needed), the user message becomes the goal, the agent answers in the channel.
1runtime:2 mode: background34agents:5 - id: helper6 modules: [{web: [search, fetch]}, channels]7 brain: { provider: anthropic, model: claude-haiku-4-5 }89tools:10 modules:11 channels:12 config:13 providers:14 slack_bot:15 adapter: slack16 config:17 bot_token: "{{secret.SLACK_BOT_TOKEN}}" # xoxb-...18 app_token: "{{secret.SLACK_APP_TOKEN}}" # xapp-...19 activation:20 message: "{{event.message}}"21 web: {}The bot needs Socket Mode enabled in your Slack app settings, plus app_mentions:read and chat:write scopes. The two tokens go in the credential vault (digitorn credentials create --provider slack_oauth); the agent never sees them.
A scheduled report that runs every Monday morning
Background triggers turn the agent into a worker that fires on a schedule, on a webhook, or on an event. The agent runs to completion, posts the result somewhere (Slack, email, S3), and exits. No always-on process. No cron job. The YAML is the schedule.
1runtime:2 mode: background3 entry_agent: reporter4 triggers:5 - id: weekly-summary6 type: cron7 schedule: "0 9 * * MON"8 message: "Generate the Monday digest."910agents:11 - id: reporter12 modules: [{web: [search, fetch]}, channels]13 brain: { provider: anthropic, model: claude-haiku-4-5 }1415tools:16 modules:17 web: {}18 channels: {}We use this internally for a "what shipped last week" digest. The agent reads our changelog, summarises, and posts to #engineering. The cron schedule lives next to the agent that uses it, which is the right place for it.
A pull-request triager that catches itself drifting
Webhooks are a cron's cousin. The runtime exposes an HTTP endpoint, a service like GitHub fires it on each new PR, and the agent runs against the diff. Add a behaviour rule to stop runaway loops and you have a triager that can't accidentally cost you a fortune on an unusual PR.
1runtime:2 mode: background3 entry_agent: triager4 triggers:5 - id: pr-opened6 type: http7 path: /hooks/github-pr8 method: POST9 message: "{{event.body.pull_request.title}}"10 hooks:11 - id: cap-tool-calls12 "on": tool_start13 condition: { type: tool_calls, threshold: 12 }14 action: { type: gate, reason: "Tool call ceiling reached." }1516agents:17 - id: triager18 modules: [{web: [search, fetch]}]19 brain: { provider: anthropic, model: claude-haiku-4-5 }20 system_prompt: "Read the PR diff. Tag risk areas. Be terse."2122security:23 behavior:24 profile: coding2526tools:27 modules:28 web: {}Twelve tool calls per PR is the ceiling. Past that, the runtime stops the agent and you decide whether to extend.
A documentation generator that updates with the code
Point it at a directory, give it the filesystem module, and let it read the source plus existing docs. It writes back into the workspace as Markdown, the workspace mirrors to disk, and your repo gets a doc PR you can review like any other change. The "did you read this file?" guard means you can trust the output.
1agents:2 - id: doc-writer3 modules: [filesystem, workspace]4 brain: { provider: anthropic, model: claude-sonnet-4-6 }5 system_prompt: |6 Read the source under src/. Update docs/ to match.7 One file at a time. Read before you write.89tools:10 modules:11 filesystem: {} # read-before-edit guard is built-in12 preview: {} # required by workspace13 workspace:14 config:15 render_mode: markdown16 entry_file: docs/index.md17 sync_to_disk: trueIt's a more forgiving cousin of the coding agent. Same primitives, narrower scope.
A slide builder that ships an interactive deck
render_mode: slides swaps the renderer for a fullscreen deck preview. The agent emits a tree of <Slide> blocks (or markdown the runtime parses into slides), the workspace serves the preview, and the user navigates with arrow keys. Same pattern as the React sandbox, different output target.
1agents:2 - id: presenter3 modules: [workspace]4 brain: { provider: anthropic, model: claude-sonnet-4-6 }5 system_prompt: |6 Build a deck for the requested topic. One idea per slide.7 Markdown only. No fluff.89tools:10 modules:11 preview: {} # required by workspace12 workspace:13 config:14 render_mode: slides15 entry_file: deck.mdUseful for kickoff decks, recap meetings, pitch drafts. It's surprising how much faster it is to refine a deck by chatting at it than by clicking through Keynote.
A voice agent that answers phone calls
Voice is a channel adapter, not a module. The runtime ships two voice backends today (Twilio ConversationRelay for hosted STT/TTS, generic WebSocket for bring-your-own); you pick one in the channel config and the rest of the agent is identical to any other.
1runtime:2 mode: background34agents:5 - id: phone6 modules: [{web: [search, fetch]}, channels]7 brain: { provider: anthropic, model: claude-haiku-4-5 }8 system_prompt: "Speak conversationally. Keep answers under 30 seconds."910tools:11 modules:12 web: {}13 channels:14 config:15 providers:16 phone_line:17 adapter: voice18 config:19 backend: twilio_cr # or "websocket"20 language: en21 welcome: "Hello, how can I help?"22 activation:23 message: "{{event.transcript}}"Latency is the trade-off worth knowing about. Round-trips below 800ms feel natural; above 1.5s feels broken. The Twilio backend handles STT/TTS server-side; the WebSocket backend lets you bring your own. Either way, the runtime never sees raw audio - the adapter passes transcripts in and replies out, so the agent's YAML stays the same shape as the chat-only version.
What ties them together
Ten apps. Different tools, different interfaces, different cadences. The shape is the same in every one: declare what the agent has access to, declare its brain, declare how it's triggered, write a system prompt. Everything else (orchestration, abort handling, hot reload, marketplace packaging, credentials, audit) is the runtime's job.
That's the bet behind the platform. Most of what people end up writing in a Python framework is plumbing the framework should have handled. Push the plumbing into the runtime, leave the user with a config file, and the time-to-app collapses.
If one of these shapes lines up with something you're building, the fastest way to start is to install the matching builtin and read its YAML. They all live on the Hub and are explicitly licensed for forking. Pick the one closest to your problem, copy it locally, edit until it does what you need.
1curl -sSL https://digitorn.ai/install | sh2digitorn install hub://digitorn/digitorn-deepresearch # or any other3digitorn dev chat <app-id>The runtime, the Hub, and the source for every builtin are open source on GitHub. If you build something interesting, push it to the Hub. That's how the catalogue grows.
Further reading
If you want to dig into specific patterns:
- The cost trick that makes multi-agent setups affordable: How we cut our coding agent's bill by 60%
- Why the platform is YAML-first in the first place: Why we chose YAML over Python
- The full architecture of the coding agent: How to build a Claude Code clone in YAML
- Foundations if you're new: What is an AI agent
One post a fortnight, in your inbox.
Engineering notes from the Digitorn team. No marketing, no launch announcements, no "10 prompts that will change your life". Just the things we write that we'd want to read.
We build the open-source AI agent runtime that runs on your own machine. YAML over Python, multi-agent by default, marketplace for sharing.
Keep reading
Ship your first AI agent in 5 minutes.
Open-source. Self-hosted. YAML-first. Bring your own LLM keys, agents run on your machine.