Wintermolt: The Everything-Agent in 3 MB
Part of Agent Harness Field Guide.
Zig 0.15 • 3 MB Binary • 6 Backends • 16 Tools • MIT
A single native binary with zero runtime that ships 6 AI backends, 16 built-in tools, cron scheduling, Tailscale mesh networking, camera vision, browser automation, MCP bidirectional support, chat bridges to 4 platforms, and a macOS menu bar app.
(Alright, ad over. Back to the serious technical analysis.)
What is Wintermolt?
Wintermolt is an autonomous AI agent CLI written entirely in Zig 0.15. It compiles to a single 3 MB native binary with only two external dependencies — libcurl for HTTPS and sqlite3 for persistence — both pre-installed on macOS and most Linux distributions. Unlike every other agent in this set, it has zero runtime: no Node.js, no Python, no Electron, no virtual environments.
The project ships ~18,400 lines of Zig across 51 source files, plus two prebuilt Zig static libraries (libforagent.a and libforlearn.a) from sibling projects. The codebase is organized into clean modules: agent core, API clients, tools, MCP, chat/web/menubar bridges, and a canvas renderer.
📌
Key differentiator
Wintermolt is the only agent in this entire set that cross-compiles to any platform Zig supports — ARM boards like Jetson and Raspberry Pi included — with a single build command: zig build -Dtarget=aarch64-linux-gnu.
Architecture overview
| Module | Files | Lines | What it does |
|---|---|---|---|
src/main.zig |
1 | 1,202 | Entry point, REPL, 7 execution modes |
src/agent/ |
13 | 5,226 | Core agent: loop, tools, config, history, storage, scheduler, RAG, skills, subagents, router |
src/api/ |
7 | 2,460 | Multi-backend AI clients (Ollama, Claude, OpenAI, DeepSeek, Qwen, Gemini) |
src/tools/ |
14 | 4,521 | 16+ built-in tools: bash, file I/O, grep, glob, HTTP, search, camera, browser, Tailscale, canvas |
src/mcp/ |
4 | 1,001 | MCP client + server (bidirectional) |
src/chat/bridge.zig |
1 | 278 | Chat platform IPC (Discord, Telegram, Slack, WhatsApp) |
src/web/bridge.zig |
1 | 1,062 | Web UI WebSocket bridge with streaming |
src/menubar/bridge.zig |
1 | 314 | macOS native menu bar Swift sidecar IPC |
src/gateway/bridge.zig |
1 | 213 | OpenAI-compatible API gateway |
The agentic loop
The core loop lives in src/agent/loop.zig (~646 lines). The AgentLoop struct runs a prompt → tools → observe → repeat cycle with up to 25 tool iterations per turn:
- User message added to history with approximate token counting (
approx_tokens += text.len / 3) - RAG indexing — fire-and-forget
rag.indexMessage()for Pinecone semantic memory - Tool relevance filtering — keyword-matches user text against trigger lists to select extended tools (
tools.getRelevantDefinitions()) - API call — streams to the primary backend with live terminal output via callback
- Response parsing:
.end_turn,.max_tokens,.stop_sequence,.tool_use, or.unknown - Tool execution —
executeTools()iterates over tool_use content blocks - Results fed back as user-role messages (required by the API pattern)
- Context overflowhistory.emergencyCompact() (drops to 40% budget) and retries
The sendToBackend method implements automatic fallback: if the primary backend fails, it tries Ollama first (local, no rate limits), then OpenAI.
📌
Key file
src/agent/loop.zig — AgentLoop struct, processInput() at line 182, sendToBackend() at line 294
6 AI backends — one binary
All backends share a unified protocol.Message / protocol.Response wire type in src/api/protocol.zig (~281 lines). The dispatch happens in loop.zig's switchBackend:
| Backend | Protocol | Streaming | Auth | Default Model |
|---|---|---|---|---|
| Ollama | NDJSON | Yes, line-by-line | None (local) | qwen3:0.6b |
| Claude | SSE (Anthropic) | Yes, event-driven | X-Api-Key |
claude-sonnet-4-20250514 |
| OpenAI | SSE (OpenAI) | Yes | Bearer token | gpt-4o-mini |
| DeepSeek | SSE (OpenAI-compatible) | Yes | Bearer | deepseek-chat |
| Qwen | SSE (OpenAI-compatible) | Yes | Bearer | qwen-plus |
| Gemini | SSE (OpenAI-compatible) | Yes | Bearer | gemini-2.0-flash |
The DeepSeekClient struct is effectively a universal OpenAI-compatible client — it's reused for OpenAI, DeepSeek, Qwen, Gemini, and the custom forAI endpoint by simply overriding the api_url field.
Three hand-written streaming parsers handle the wire formats: sse.zig (~461 lines) for Anthropic SSE, openai_sse.zig (~287 lines) for OpenAI SSE, and ndjson.zig (~250 lines) for Ollama NDJSON. Each is an incremental character-by-character parser with no streaming library dependency.
The 16 built-in tools
Tool dispatch lives in src/agent/tools.zig (~717 lines) with a three-layer architecture:
- Layer 1 — Built-in tools hardcoded in the
executeTooldispatch chain - Layer 2 — Runtime skills loaded from
skill.jsonmanifests - Layer 3 — MCP remote tools from external MCP servers (prefixed like
filesystem__read_file)
| Tool | What it does |
|---|---|
bash | Shell execution with safety checks (pattern-matches against rm -rf /, dd if=, etc.) |
file_read | Read any file (text or images via multimodal) |
file_write | Create or overwrite files |
file_edit | Surgical find-and-replace editing |
glob | Recursive file search by pattern |
grep | Content search with regex |
http_request | HTTP GET/POST/PUT/DELETE to any URL |
web_search | DuckDuckGo search (no API key) |
camera_capture | Camera snapshots, screenshots, OAK-D depth |
image_process | Format conversion (BMP, PNG via sips/ffmpeg) |
browser_control | Full Chrome automation via DevTools Protocol (~895 lines) |
memory_search | Semantic search over conversation history (Pinecone RAG) |
schedule | Cron jobs — schedule recurring commands |
tailscale | Mesh VPN — query peers, devices, connectivity |
canvas_update | A2UI — render rich UI surfaces in terminal or web |
harness_create | CLI-Anything — generate agent wrappers for any software |
The bash tool includes automatic API key redaction — it scans for 12 secret patterns (sk-ant-, sk-proj-, xoxb-, ghp_, AIza, etc.) before returning output to the AI context.
Cron scheduler
src/agent/scheduler.zig (~756 lines) implements a SQLite-persisted job scheduler with three schedule types:
every— repeat interval ("5m","1h","30s")at— daily at time ("09:00","14:30")cron— standard cron expression ("*/5 * * * *")
The tickScheduler() is called from the REPL loop on every iteration. It queries due jobs, executes each via the bash tool, and updates last_run/next_run. Jobs are auto-disabled after max_retries consecutive failures.
No other agent in this set has a built-in cron scheduler.
MCP: both client and server
Wintermolt is one of only two agents in this set that implements MCP bidirectionally (Crush is the other).
As server (src/mcp/server.zig, ~214 lines): Exposes 20+ Wintermolt tools via JSON-RPC 2.0 over stdio. Supports initialize, tools/list, tools/call, resources/list, prompts/list, ping.
As client (src/mcp/client.zig, ~421 lines): Loads external MCP servers from ~/.wintermolt/mcp.json, spawns each as a child process with stdin/stdout pipes, runs the 3-step MCP handshake, and prefixes all discovered tool names with "servername__" (e.g., filesystem__read_file).
Chat bridges
All bridges follow the same sidecar IPC pattern: Zig spawns a child process (TypeScript/Swift), communicates via JSON lines over stdin/stdout pipes. No sockets, no HTTP servers, no shared memory — clean process boundaries.
| Bridge | Sidecar | What it does |
|---|---|---|
| Chat | TypeScript | Discord, Telegram, Slack, WhatsApp — multi-platform bot |
| Web | TypeScript | WebSocket UI at localhost:3000 with token-by-token streaming |
| Menu Bar | Swift | macOS native NSStatusBar app (~270 lines, no Electron) |
| Gateway | TypeScript | Exposes OpenAI-compatible /v1/chat/completions API |
The chat bridge uses a 7-tier priority binding system in src/agent/router.zig (~585 lines): peer → parent_peer → guild_role → guild → team → account → channel.
Memory and RAG
Tier 1 — SQLite (src/agent/storage.zig, ~793 lines): ~/.wintermolt/history.db with conversations and messages tables. All public methods are designed for catch-and-ignore — storage failures never break the agentic loop.
Tier 2 — Pinecone RAG (src/agent/rag.zig, ~577 lines): Vector database for semantic search with auto-embedding via Pinecone's integrated inference. Every user and assistant message is indexed fire-and-forget. Namespaced by user session (web mode) or domain (knowledge bases).
Skills system
Two-layer skill system:
- Comptime catalog (
src/agent/skills.zig, 158 lines): 14 built-inSkillEntrystructs — zero allocation, zero I/O, pure string literals. - Runtime plugins (
src/agent/skill_loader.zig, ~367 lines): Scans./skills/,~/.wintermolt/skills/, and~/.wintermolt/plugins/*/skills/. Each skill gets its owntool_schema, optionalbackend/modelpreferences, and a handler type (bash,mcp,script, orprompt).
The project ships 79 skill definitions across 11 domains: Zortran Core, Fortran Kernels, Zig Systems, Physics/Simulation, AI/ML Kernels, Cybersecurity, Synthetic Data, Agent Architecture, Audio/Music, 3D/VFX, and Engineering.
Unique engineering decisions
No @cImport pattern
All C interop uses explicit extern fn declarations (~12 curl functions, ~15 sqlite functions). No header file parsing, no platform-specific header dependency. Keeps the binary small and cross-compilation clean.
Hand-written streaming parsers
Three SSE/NDJSON parsers, each ~250–460 lines of incremental character-by-character processing. No streaming library dependency. Each handles escape sequences, nested objects, partial chunks across curl callbacks.
Docker sandbox mode
Optional sandboxed bash via Docker: read-only CWD mount, no network, memory/CPU limits, timeout enforcement. Falls back to host execution if Docker is unavailable.
Subagent system
Parent-child spawning with depth limiting (max depth 3, max concurrent 4). Each subagent gets its own AgentLoop with independent history and config. Callback-based design avoids circular dependencies.
Camera + vision built-in
Captures from cameras (imagesnap on macOS, ffmpeg on Linux, OAK-D depth). Object detection via local LLaVA model. Base64-encoded images flow through the agentic loop as vision content blocks.
Browser automation
Full Chrome DevTools Protocol integration (~895 lines). List tabs, navigate, click elements, type text, evaluate JS, screenshot, and snapshot page content.
7 execution modes
| Mode | Command | Description |
|---|---|---|
| REPL | wintermolt | Interactive terminal session |
| Single-shot | wintermolt -e "prompt" | Run one prompt, print result, exit |
| Setup | wintermolt --setup | Interactive API key + model wizard |
| Chat | wintermolt --chat | Multi-platform messaging bot |
| Web | wintermolt --web | Browser UI at localhost:3000 |
| Menu Bar | wintermolt --menubar | macOS native status bar app |
| MCP Server | wintermolt --mcp-server | Expose tools via JSON-RPC 2.0 |
Strengths
- Binary footprint — 3 MB vs 200–500 MB for Node.js/Electron agents
- Zero runtime — no npm, pip, venv, node_modules, or Docker required
- Cross-compilation — one command targets ARM, x86_64, macOS, Linux
- Feature breadth — no other single agent has cron + Tailscale + camera + browser + MCP + chat bridges
- Secrets redaction — automatic API key scrubbing from bash output (12 patterns)
- Fallback chain — primary backend failure auto-falls back to Ollama then OpenAI
- Clean process boundaries — all sidecars use JSON-lines over stdio, no sockets
Tradeoffs
⚠️
Where Wintermolt gives things up
- TypeScript sidecars — while the core is pure Zig, the chat, web, and gateway bridges require TypeScript runtimes. The core binary doesn't need them, but full functionality does.
- Prebuilt libraries —
libforagent.aandlibforlearn.aare distributed as prebuilt Zig archives, not built from source in-tree. - Bash safety is pattern-based — unlike Neovate's quote-aware pipeline parser or Claude's tree-sitter AST analysis, Wintermolt's bash guards use regex pattern matching.
- Less polished than Claude Code — the feature surface is enormous, but the UX polish of productized agents like Claude Code or Crush is not quite there yet.
- Harder to audit — 18,400 lines of Zig is compact for what it does, but the breadth of features (cron, Tailscale, camera, browser, chat, MCP, RAG) means there's a lot to verify.
Key files to read
📌
Core runtime
src/agent/loop.zig (agentic loop, 646 lines), src/agent/tools.zig (tool dispatch, 717 lines), src/agent/config.zig (multi-backend config, 461 lines), src/agent/storage.zig (SQLite persistence, 793 lines)
API clients
src/api/ollama.zig (NDJSON streaming, 484 lines), src/api/deepseek.zig (universal OpenAI-compatible, 373 lines), src/api/sse.zig (Anthropic SSE parser, 461 lines)
Unique features
src/agent/scheduler.zig (cron jobs, 756 lines), src/tools/browser.zig (CDP automation, 895 lines), src/tools/camera.zig (vision, 482 lines), src/tools/tailscale.zig (mesh VPN, 160 lines), src/agent/rag.zig (Pinecone RAG, 577 lines)
MCP and bridges
src/mcp/client.zig (MCP client, 421 lines), src/mcp/server.zig (MCP server, 214 lines), src/web/bridge.zig (WebSocket bridge, 1,062 lines), src/menubar/bridge.zig (macOS menu bar, 314 lines)
Verdict
Best designed, if you value a portable binary
Wintermolt is the only agent here that can be cross-compiled to ARM boards, embedded devices, or any Zig target. The no-runtime philosophy is carried through every module — explicit extern fn declarations, hand-written parsers, and JSON-lines IPC for all sidecars.
Most ambitious feature set
No other agent in this set combines a coding CLI, cron scheduler, Tailscale mesh query, camera vision, browser automation, MCP bidirectional, multi-platform chat bot, macOS menu bar app, and an OpenAI-compatible gateway — all in one 3 MB binary.