Digitorn
Digitorn
All posts
showcase

10 apps you can ship in 50 lines of YAML

A walkthrough of ten very different apps, all built declaratively on Digitorn. Coding agents, live React sandboxes, Slack bots, cron reporters, voice copilots. Same runtime, same shape, no Python.

DDigitornMay 3, 20269 min read

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.

Note
The skeletons below omit the 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.
ONE FILEapp.yamlCoding agentdeveloper{ }Live Reactlive-app?Research botknowledgeΣLaTeX writerdocumentSlack copilotmessagingCron reporterbackgroundPR triagerdeveloperDoc generatorknowledgeSlide builderlive-appVoice agentmessaging
Ten kinds of app, one runtime, one config file each. Different modules, different brains, same shape.

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.

YAML
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.

YAML
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: true

Install: 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.

YAML
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.

Tip
The pattern of "premium model writes, cheap model researches and verifies" is the same trick the cost article walks through. It generalises beyond research: any task with a "produce final answer for a human" step plus several "filter and verify" steps maps to it.

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.

YAML
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: true

Pair 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.

YAML
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.

YAML
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.

YAML
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.

YAML
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: true

It'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.

YAML
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.md

Useful 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.

YAML
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.

Bash
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:

#showcase#tutorial#yaml#apps#self-hosted
ShareLinkedIn
Newsletter

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.

One-click unsubscribe. We never share your address. Powered by our own infrastructure, not a tracker.
D
The Digitorn team

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

Try it now

Ship your first AI agent in 5 minutes.

Open-source. Self-hosted. YAML-first. Bring your own LLM keys, agents run on your machine.