🛡️ Warning · ⚙️ Architecture · 🧠 Prompt Engineering · ☁️ Hybrid Models · 📊 Dashboard · 🧩 MCP · 🗣️ Voice · 🚀 Quick Start
Warden is an AI agent with the same access as your user account. It executes shell commands, moves your mouse and types on your keyboard, drives your real browser with your real logged-in sessions and saved passwords, reads and sends your email, and can edit and restart its own source code. There is no sandbox and no container. A model mistake, a prompt injection from a web page it visits, or an email it reads can do anything you can do at a terminal.
This is the warning the dashboard shows on first launch. It is not a joke and it is not boilerplate. Do not run Warden on a machine you care about unless you have read the code, understood the risks, and accepted that you are handing a language model the keys to your computer.
Now that that's out of the way — I'm currently running it on my laptop and my desktop, just rawdogging the system, and it has been solid. sudo prompts pop up graphically (polkit catches them), and in practice it doesn't stray out of its workspace unless it's actively searching for files or the like. Is this stupid in theory? Yes, absolutely. Does it work in practice? So far, yes — for now. Just back things up from time to time, in case.
Warden is a personal AI assistant that lives on your desktop. It runs local models through Ollama for fast, private tasks, and reaches out to cloud models for heavy lifting — all within a single conversation. It connects to your real browser, controls your desktop, manages your email and calendar, and talks to you through whatever channel you prefer.
A single LLM — the orchestrator — runs the show. It's the only thing you talk to, and it's deliberately small: a 12B Gemma 4 model (gemma4:latest) running locally on Ollama. It doesn't write your reports, doesn't browse the web, doesn't run shell commands. It reads your message, works out what you actually want, hands a clean brief to the right specialist, and then babysits that specialist until the job is done — cutting loose the ones that go sideways and re-briefing the ones that fail. A 12B model supervising a frontier model, and it doesn't fuck up.
You → Orchestrator (small, local) → Atlas (large, cloud) → result → Orchestrator → You
→ Iris (email/calendar)
→ Dexter (scheduling)
→ Byte (projects)
→ Artemis (audit)
→ The Council (deliberation)
💡 The orchestrator never touches the internet directly. It doesn't browse, search, or fetch URLs. It delegates. That separation lets the orchestrator stay small and local while the internet-connected agents run on the biggest models available.
This is the counterintuitive part: the orchestrator is the cheapest model in the stack, and that's by design. Its job isn't generation, it's classification and composition. Every turn it answers a small set of questions: what does the user want, which specialist owns it, what does that specialist need to know to start cold, and is anything I'm currently babysitting going sideways? None of that needs a frontier model. A 12B Gemma 4 nails it — locally, in well under a second per turn, on hardware you already own — so the thing you talk to most carries no per-turn cloud cost.
The expensive generation lives one layer down, in the specialists. Atlas and Artemis default to a large cloud model; the three Council seats each run their own model. The orchestrator stays out of that. It states what needs to happen and stops — it never prescribes how (no URLs, no search queries, no "go to X then click Y"), because it can't even see the specialists' tools. That discipline is exactly what lets a 12B model supervise a frontier one without getting in the way: it can't micromanage what it can't see, so it doesn't try.
Delegation is not fire-and-forget. When the orchestrator hands work to Atlas, Atlas runs in the background — the orchestrator gets a job ID back immediately and stays free to handle your next message. While those jobs run, the orchestrator supervises them on a fixed 45-second monitor tick. On every tick it receives a synthetic status line for each running job — elapsed time, tool-call count, what the job last did and how many seconds ago — and makes one of three calls:
- Progressing → leave it alone and wait for the next tick.
- Stuck, looping, or doing the wrong thing → call
stop_agentwith the job's ID and tell you, in one sentence, what it stopped and why. - Finished → the result lands in an inbox.
The inbox is the backbone of the async model. Finished jobs drop their full output there, and at the end of each turn the orchestrator drains it, digests what actually matters in its own voice, and chains any follow-up work the results call for. If a job failed, the failure routes back to the orchestrator automatically — it reads the full output, works out what went wrong, and re-delegates with a reworked brief (a different approach, a corrected URL, a missing detail — whatever the output showed was broken). You only hear about a failure if it can't be recovered; after the same task has failed the same way twice, the orchestrator stops retrying and tells you instead. Urgent results can even interrupt a turn mid-flight, so a finished job you're waiting on never sits behind whatever else happens to be running.
The net effect: you ask once, and the orchestrator owns the outcome — prompting the specialists, supervising them, cutting off the ones that drift, and correcting course until the job is done or it's genuinely stuck.
You have one conversation, with one assistant. Atlas, Iris, Dexter, and the rest never see your messages and never speak to you — the orchestrator is the only voice in the chat. It works out what you actually need, composes a self-contained brief for the right specialist, and reports back in its own words when the work is done.
Your raw message never reaches a specialist. "hey can you set the volume to like fifty percent" goes in; "Set the system volume to 50 percent" is what gets delegated. Every request is rewritten into a precise, self-contained brief — typos, slang, and missing context resolved — so the executing model starts from a clean statement of the goal instead of guessing at your phrasing.
Each sub-agent has its own system prompt, its own toolset, and its own model. They don't share context — the orchestrator composes a self-contained task string with everything the sub-agent needs.
| Agent | Model | Tools | Role |
|---|---|---|---|
| Atlas | Local or cloud | Shell, browser (DOM control), desktop, files, web search/fetch, documents | Execution — anything that touches the internet or runs commands. |
| Iris | Local or cloud (local recommended) | Email, calendar, contacts, todos | Personal information management. |
| Dexter | Local or cloud (local recommended) | create / list / pause / resume / cancel / update scheduled tasks (cron, interval, once) | Scheduling — builds perfect schedule entries and never executes them. |
| Byte | Local or cloud (local recommended) | Projects, deliverables, blockers, work tasks, time tracking | Work management. |
| Artemis | Local or cloud | Read-only file access | Critical review — audits conversations and decisions. |
| The Council | 3×, local or cloud | Read-only file access | Three independent seats (Skeptic, Pragmatist, Synthesist) deliberate in parallel on high-stakes decisions. |
🎛️ Every agent's model is picked in the dashboard — local Ollama or cloud, your call. Local and cloud run through the same Ollama pipeline, so switching an agent between them needs no code or infrastructure change. Iris, Dexter, and Byte are light, structured-task agents — run them on a local model (granite is plenty) and save cloud spend for Atlas and the Council.
Dexter is the scheduling agent. Its entire job is to create and manage schedule entries — it never executes them.
The orchestrator owns the intent; Dexter owns the timing. When something needs to happen later, the orchestrator gives Dexter a prompt (what to run) and a when (the timing intent). Dexter's sole job is to translate that into one flawless schedule entry and hand it to the scheduler. Nothing more.
What Dexter does:
- Picks the right
schedule_type—cron(recurring at specific times),interval(every N ms), oronce(a single future timestamp) — and writes theschedule_valuein its exact format. - Does the time arithmetic in your local timezone, walking the offset digit by digit and verifying computed-time minus now equals the requested interval before committing.
- Stores the prompt verbatim — at fire time that prompt is injected into the running chat as a message from "Scheduler", and the orchestrator runs it like any other message, with full context and all its tools. Dexter set up the schedule; the orchestrator does the work.
- Manages the lifecycle of existing entries — list, pause, resume, cancel, update.
What Dexter does not do:
- It does not execute the scheduled task. Ever. It writes the entry and stops.
- It does not gather data or do research — if a scheduled prompt needs facts (a price, a status, a number), the orchestrator delegates that to Atlas first and hands Dexter the result to bake into the prompt.
- It does not diagnose why a task did or didn't fire — that's Artemis's job. Dexter only touches the entry if it needs fixing or recreating.
- It does not own todos, calendar events, or contacts — those are Iris. A todo is a list item; a reminder that fires at a time is Dexter.
Model: basic structured output — a small local model (granite) is plenty. The reliability lives in the prompt and the format validation, not in a big model.
The schedule-value format is where scheduling breaks in every system that has one, so Dexter is built to be obsessive about it: it validates the cron expression, rejects malformed intervals and timestamps, refuses timezone suffixes on once, and double-checks its own offset math. The point is that the entry is correct the first time, every time, on a model that costs nothing to run.
🔥 The agent-runner is a persistent child process — no Docker, no containers, no cold starts between messages. It stays warm for hours (configurable
IDLE_TIMEOUT), keeping MCP servers connected and skills loaded. Follow-up messages route over IPC in milliseconds.
This is the feature that makes Warden work. The system prompt isn't a paragraph of vibes — it's a carefully engineered control surface that has been iterated on extensively.
The orchestrator is trained to state WHAT, never HOW. It doesn't see the sub-agents' tools. It can't prescribe URLs, search queries, or step-by-step instructions. The system prompt explicitly forbids it:
"Atlas is the internet model. It runs on a larger, more capable model than you. Never tell Atlas how to use the internet — no URLs, no search queries, no 'go to X then click Y.' Give it the goal and the facts, and stop."
This is reinforced at three layers: the orchestrator's system prompt, the Atlas tool description (what the orchestrator sees when deciding to call it), and Atlas's own system prompt (which tells it to ignore prescribed steps).
Warden ships with 258 expert prompt patterns from the Fabric library. Every turn, the user's message is keyword-extracted and the top 5 most relevant patterns are injected into the system prompt by name and description. The orchestrator loads the full pattern on demand and bakes its framing into the Atlas task brief — giving the larger model the structure it needs without the orchestrator micromanaging the execution.
Warden is built to host many tools at once — the core set plus anything you add via skills and MCP servers — so the tool surface had to scale without bloating every prompt. Not all 30+ tools go into every turn. Keywords from the conversation are extracted and tools are ranked by relevance; the core routing tools (sub-agents, Read, Bash) are always included, and everything else is surfaced only when relevant. This keeps the context window lean, the model focused, and the system futureproof — add a new tool and it's available without rethinking the prompt.
The tool loop has multiple circuit breakers to prevent common failure modes:
- Intent-without-action detection — if the model keeps saying "I'll do X" without actually calling tools, it gets nudged (capped at 2 nudges)
- Circling detection — consecutive useless rounds (no tool calls, no output) trigger a forced no-tools round to extract an answer
- Degenerate output filter — word-mash / garbled output from misconfigured models is detected and suppressed
- Verifier sub-agent — after effectful work (file writes, edits), a verifier pass confirms the changes
The orchestrator writes directly to MEMORY.md, TODO.md, and HEARTBEAT.md — no delegation needed. These files are loaded into context every turn.
HEARTBEAT.md holds standing instructions the agent executes on schedule via the task scheduler — no prompt from you required. Edit it from the dashboard's Heartbeat panel (or let the agent edit it itself) and the instructions run automatically, giving the agent persistent autonomous behavior between conversations.
Long conversations are compacted by a Mercury summarization layer. Older turns are condensed into memory notes, keeping the active context window focused on what matters.
The agent can modify its own source. A built-in self-edit skill constrains edits to src/ and container/agent-runner/src/, runs npm run build, gates on a successful compile, tells you what's changing, then restarts the service with systemctl --user restart warden. It refuses to touch dist/, configs, or the systemd unit, and never restarts on a failed build — so the agent can ship its own fixes without you opening a terminal.
Warden is built for hybrid operation from the ground up. Different tasks need different models, and you shouldn't have to choose one and stick with it.
Every model selection in the dashboard is per-role:
| Role | Typical Model | Why |
|---|---|---|
| Orchestrator | Local (gemma, granite) | Fast, cheap, always available. Only routes and supervises. |
| Atlas | Cloud (deepseek, glm) | Heavy lifting — internet access, shell, browser, complex reasoning. |
| Iris / Dexter / Byte | Local (recommended) | Light, structured tasks. Run them local; save cloud for Atlas and the Council. |
| Council seats | Cloud (3 different models) | Diverse perspectives for deliberation. |
| Sub-agent tools | Configurable | Tool-calling sub-agents can use a different model. |
All of this is configured from the dashboard's Settings panel — assistant name, model per role, Ollama URL, and automation settings:
There is no separate infrastructure for cloud models. Ollama serves both local models (on your machine) and cloud models (remote Ollama-compatible endpoints) through the same HTTP API — so every agent can be flipped between local and cloud from the dashboard with no code or infrastructure change. You're just picking a model id. The credential proxy (port 3001) sits in front of it all so the agent never sees real API keys:
- Validates the auth token
- Looks up and decrypts the user's API key
- Forwards local models directly to
localhost:11434 - Translates to the cloud endpoint's format and injects the real key only at the proxy layer
The agent-runner speaks Ollama's native HTTP API. The credential proxy (port 3001) routes every request based on the target model:
- Local models → forwarded directly to
localhost:11434 - Cloud models →
ollama-translate.tstranslates the request format as needed for Ollama cloud endpoints, injects the real API key
The agent doesn't know or care whether the model is local or cloud. Same format, same tools, same conversation. You pick the model per role in the dashboard and the proxy handles the rest.
Local and cloud models use separate session directories (.ollama/ vs .claude/) to prevent context contamination. Switching models mid-conversation doesn't lose history.
Warden connects to your actual Chrome via Playwright and the Chrome DevTools Protocol (port 9222). Your real profile — cookies, sessions, saved passwords, extensions — everything is intact.
The browser tools operate on DOM accessibility snapshots, not screenshots. Each element gets a [ref=e12] identifier. The agent clicks, types, and navigates by ref — fast, precise, and cheap. Screenshots exist only for visual verification of end states.
Chrome runs as a persistent process with its own watchdog. It survives agent restarts. Sign into Google once; the profile persists forever.
Warden controls your actual desktop — mouse movement, keystrokes, window management. Wayland via ydotool, X11 via xdotool. It discovers your display environment automatically, even when started from systemd with no DISPLAY set.
A full PWA at http://localhost:3200. It includes:
| 💬 Chat | Main conversation interface | 🗂️ Projects |
| 📁 Files | Browse, upload, download, manage | 🔒 Vault |
| 🔑 API Keys | Provider credentials | ⏰ Scheduled Tasks |
| 💓 Heartbeat | Standing instructions on schedule | ⏰ Alarms |
| ⚡ Actions | One-touch prompt buttons | 📱 SMS |
| 🎤 Talk | Voice transcription | |
| 📅 Calendar | CalDAV synced with Kontact | 🔗 Accounts |
| 🧩 Skills & MCP | Hot-pluggable capabilities | 📈 Agent Activity |
| 📜 Process Logs | Live log tail |
One-touch prompt buttons for the things you do all the time — setup, review, write, research. Press a button instead of typing the same prompt again; each action fires a pre-written prompt into the conversation.
An agent system is only as good as the requests you give it, so Warden teaches you how to use it. On first launch the dashboard opens a How to Use Warden guide that leads with the one thing new users need to hear — this is not a chatbot — then walks the whole system: the agent roster and what each specialist actually does, how to convene the Council on a decision, how to delegate to Atlas (including parallel delegations in a single turn), the skills system, and what kinds of asks work best.
Behind the modal sits a full help site with in-depth pages. The flagship, not-a-chatbot, puts chatbot-style asks and agent-style asks side by side — "tell me about microservices" gets you conversation; "read src/auth.ts and tell me if there's a timing-safe comparison missing" gets you tools run, files read, verdicts returned — then distills the principles that make requests land: be specific about the target, parallelize independent asks, read BLOCKED messages instead of retrying blindly, and watch the verbose bar to see what Warden is doing right now.
Model Context Protocol servers give agents real capabilities without touching core code:
| Server | Capability |
|---|---|
| Filesystem | Read, write, edit, search, manage files |
| Fetch | Retrieve web content |
| Shell | Execute commands in a live PTY |
| Memory | Persistent knowledge graph |
| SQLite | Query and manage databases |
| Time | Timezone-aware scheduling |
| Plasma | KDE Plasma D-Bus (notifications, clipboard, windows) |
MCP servers are configured in data/mcp-servers.json and can be toggled from the dashboard.
One conversation, many doors. All channels merge into a single chat:
| Channel | How |
|---|---|
| 🌐 Web Dashboard | PWA at http://localhost:3200 |
| Bot via grammy | |
| Baileys (no third-party API) | |
| 💜 Slack | Bot integration |
Message from WhatsApp, continue on Telegram, check the dashboard — same context, same memory.
| Layer | Technology |
|---|---|
| Runtime | Node.js 20+ with TypeScript |
| Database | SQLite via better-sqlite3 |
| Browser | Playwright (playwright-core) over CDP, driving your real Chrome — DOM interaction (navigate, click, type, read, screenshot, evaluate JS) |
| Desktop | xdotool + spectacle — coordinate input, screenshots |
| Terminal | Live PTY shell (tmux warden-shell) |
| LLM | Ollama (local + cloud) |
| LLM Routing | Credential proxy with format translation for cloud endpoints |
| Messaging | grammy (Telegram), Baileys (WhatsApp), Slack SDK |
| IMAP via imapflow, SMTP via nodemailer | |
| Calendar/Contacts | CalDAV/CardDAV via Radicale, synced with KDE Kontact |
| Voice | Whisper (STT), Kokoro (TTS) |
| Logging | Pino |
| Process | Single Node.js process, agent-runner as persistent child |
All LLM communication is raw HTTP fetch to Ollama. No vendor SDKs. You control the model.
git clone <your-repo-url> warden
cd warden
bash install.sh📦 The installer handles dependencies, TypeScript build, directory setup, and systemd service registration. Requires Node.js 20+ and Ollama.
# Service control (Linux)
systemctl --user start warden
systemctl --user kill warden # fast stop
systemctl --user start warden # restart
# Dashboard
open http://localhost:3200voice/ is a voice-first desktop companion that turns Warden into a talk-to-it assistant. Press a button (or a global hotkey), speak, and the reply is spoken back. Speech-to-text (Whisper) and text-to-speech (Kokoro) run locally on your machine — your voice never leaves it. All reasoning, tools, and memory stay on the Warden server; the app is just ears, eyes, and a mouth.
- 🎤 Local STT (Whisper) + TTS (Kokoro) — your voice never leaves the machine.
- 👻 Hologram UI that reflects state (idle / listening / thinking / speaking).
- 📸 Vision: capture a photo, describe a scene, read text (OCR), find objects.
- ⌛ Timer: "take a break for 10 minutes".
- 🔗 Talks to your existing Warden session — no new login.
See voice/README.md for install and usage. Copy voice/config/settings.example.yaml to voice/config/settings.yaml (or run python setup.py) — settings.yaml holds your local server URL, user id, and an optional Cloudflare token, so it's gitignored and never committed.
All settings live in data/env/env:
ASSISTANT_NAME=Warden
TZ=America/Vancouver
IDLE_TIMEOUT=14400000 # 4h warm-runner window
OLLAMA_URL=http://127.0.0.1:11434
OLLAMA_CHAT_MODEL=glm-5.2:cloud
TELEGRAM_BOT_TOKEN= # from @BotFather🎚️ Model selection is per-role via the dashboard — orchestrator, Atlas, sub-agents, and council seats can all use different models.
Most AI assistants live in the cloud. They see what you type, not what you see. They run on someone else's hardware, with someone else's model, under someone else's terms.
Warden runs on your machine. It uses your browser, your desktop, your files, your email. It works with local models through Ollama, so your data never leaves your hardware unless you choose to send it. And when you need more power, it reaches out to cloud models — all within the same conversation, with the same memory.
It is not a demo. It is a real assistant with browser automation, desktop control, voice, email, calendar, multi-channel messaging, a plugin ecosystem, an agent architecture that can reason about your work and audit its own decisions, and a prompt engineering surface that has been battle-tested across hundreds of hours of real use.
Warden stole fire from the gods. This one runs on your laptop.
MIT — see LICENSE for the full text.










