🚀 Introducing DropMail — A Privacy-First Disposable Email Platform

I built a full-stack disposable email system from scratch — and it actually works in real-time.

Introducing DropMail

A temp email service that:

  • Requires zero sign-up
  • Receives real emails via a custom SMTP server
  • Pushes emails instantly using WebSockets (no polling)
  • Automatically deletes expired data

🧠 Stack & Highlights:

  • SMTP server (smtp-server + mailparser)
  • Node.js + Express API
  • MongoDB Atlas
  • Socket.io for real-time inbox
    Chrome + Firefox extensions (React + TypeScript)

If you’re into backend systems, real-time apps, or email infrastructure — this might interest you.

👉 Chrome Extension: Chrome Extension – DropMail

👉 Firefox Add-on: Firefox Add-ons — DropMail

🌍 Try DropMail
Experience it yourself:

👉 Live Site: https://dropmail.space

Here is the full breakdown 👇
Introduction Blog

Share your feedback after using it.
Thanks

Stop AI Agents from Leaking PII

Your AI agent passes a context dict to every LLM call. That dict might contain credit card numbers, SSNs, API keys, or email addresses. If the agent signs that context without checking it first, you just created a permanent, cryptographically-verified record of leaked PII.

asqav’s content scanning pipeline inspects the context before signing. If it finds sensitive data, the sign request is rejected.

How it works

When you call agent.sign(), asqav’s API runs the context through pattern matchers for PII categories: credit cards, government IDs, API keys, emails, phone numbers. If anything matches, the request fails with a clear error.

import asqav

asqav.init(api_key="sk_live_...")
agent = asqav.Agent.create("data-pipeline")

# This context contains a credit card number
context = {
    "customer_name": "Jane Doe",
    "payment": "4111-1111-1111-1111",
    "action": "process_refund"
}

try:
    sig = agent.sign("payment:refund", context)
except asqav.APIError as e:
    print(e)  # Content policy violation: credit card number detected

The sign call never completes. No signature is created. No PII ends up in your audit trail.

What gets scanned

  • Credit card numbers (Luhn-validated)
  • Social security numbers
  • API keys and secrets (common patterns)
  • Email addresses in unexpected fields

Scanning runs server-side. You don’t need to add any client code beyond the normal agent.sign() call. It’s on by default for Pro tier and above.

Why this matters

Audit trails are permanent. If PII lands in a signed record, you can’t delete it without breaking the signature chain. Scanning before signing prevents the problem at the source.

pip install asqav

Docs | GitHub

Your AI Agents Are Running Unsupervised

Your AI Agents Are Running Unsupervised

The EU AI Act is enforceable. SOC 2 auditors are asking about your agent workflows. And your LangChain agents are making API calls with zero audit trail.

This is the problem asqav solves. It’s a Python SDK that adds governance to AI agents – cryptographic audit trails, policy enforcement, content scanning, and compliance reports. One pip install, a few lines of code, and every agent action gets a quantum-safe signature you can verify later.

The simplest version

pip install asqav
import asqav

asqav.init(api_key="sk_...")
agent = asqav.Agent.create("my-agent")
sig = agent.sign("api:call", {"model": "gpt-4", "tokens": 1200})
# sig.verification_url -> publicly verifiable proof

Every call to agent.sign() creates an ML-DSA signed record on asqav’s servers. You get back a verification URL anyone can check.

What’s new in v3.0

For developers

Decorators that sign function calls automatically. Async support. A CLI for managing agents. And integrations for the frameworks you’re already using.

@asqav.sign
def query_database(sql: str) -> list:
    return db.execute(sql)

# LangChain
from asqav.extras.langchain import AsqavCallbackHandler
chain.invoke(input, config={"callbacks": [AsqavCallbackHandler()]})

# Also: CrewAI, LiteLLM, Haystack, OpenAI Agents SDK

For security teams

Content scanning catches PII, prompt injections, secrets, and toxic content before they hit production. Behavioral monitoring detects drift from baselines. Rate limiting per agent.

# Content scanning runs inline on sign_action
sig = agent.sign("chat:response", {
    "output": user_facing_text  # auto-scanned for PII, secrets, injections
})

# Quarantine a misbehaving agent instantly
# POST /agents/{id}/quarantine

For compliance

Generate EU AI Act Article 12/14 reports, DORA ICT risk reports, and SOC 2 Trust Services reports. PDF export. Scheduled auto-generation. Evidence collection built in.

# Generate a compliance report via API
# POST /compliance-reports
{
    "framework": "eu_ai_act_article_12",
    "format": "pdf"
}
# Download: GET /compliance-reports/{id}/download

Under the hood

All signatures use ML-DSA-65 (NIST FIPS 204) – the post-quantum standard. Audit trails are anchored to Bitcoin via OpenTimestamps. Multi-party signing requires multiple entities to approve high-risk actions. This isn’t observability. It’s cryptographic proof.

Pricing

Free – 1,000 signatures/month, 3 agents, 3 policies. No credit card.
Pro ($29/mo) – 50K signatures, 25 agents, observability, cost attribution.
Business ($99/mo) – Unlimited signatures, content scanning, behavioral monitoring, compliance reports, multi-party signing.

Get started

pip install asqav

Open source SDK, MIT licensed. The governance your AI agents are missing.

Contributing to the Agent Infrastructure Stack: 4 PRs Across 3 Repos in One Weekend

Contributing to the Agent Infrastructure Stack: 4 PRs Across 3 Repos in One Weekend

Most open source contributions exist in isolation. You fix a bug here, add a feature there. But occasionally you get the chance to contribute across an entire ecosystem in a way where each PR reinforces the others. That’s what happened when I spent a weekend contributing to three projects in the MCP agent infrastructure stack — and in the process, made Bitcoin a first-class citizen across all of them.

The Stack

Three projects, three layers:

  • agentregistry — the discovery layer where developers find and install MCP servers
  • agentgateway — the proxy layer that adds rate limiting, auth, and observability to MCP servers
  • kagent — the Kubernetes orchestration layer that deploys AI agents with tool access

Each project solves a different problem, but together they form the infrastructure that makes MCP servers useful in production. My goal was simple: contribute meaningful work to each layer, using bitcoin-mcp (my own MCP server with 40+ Bitcoin network tools) as the connecting thread.

PR 1: Fixing a CLI Crash in agentregistry

The problem: Running arctl skill list --page-size -1 crashed the entire CLI with a Go slice bounds panic. Issue #368 had been open, waiting for someone to pick it up.

The investigation: The --page-size flag value was being passed directly to slice operations without any validation. In Go, creating a slice with negative bounds causes a runtime panic — no graceful error, no recovery, just a stack trace dumped to the terminal.

The fix: I added input validation at the command level, before the value ever reaches slice operations. If you pass a negative page-size now, you get a clear error message telling you the value must be positive. Simple, defensive, and exactly what you’d expect from a well-behaved CLI tool.

What I learned: agentregistry’s CLI is built with Cobra, and the validation pattern I used follows the same approach used elsewhere in the codebase. Reading the existing code before writing new code always pays off.

PR 2: Fixing the Broken Lint Target in agentregistry

The problem: make lint had been broken since PR #253 removed golangci-lint from the Go tools list. The Makefile still tried to invoke it via go install, which no longer worked. Issue #377 documented the failure.

The investigation: The root cause was a dependency change that wasn’t fully propagated. When golangci-lint was removed from the project’s Go tool management, the Makefile target that depended on it wasn’t updated. This is a classic problem in projects with multiple build system entry points.

The fix: Updated the lint target to use the system-installed golangci-lint binary directly, with a clear error message if it’s missing. The error message includes the official installation command so contributors can get unblocked immediately. This aligns with golangci-lint’s own documentation, which recommends against go install for linter binaries due to version management issues.

What I learned: Broken CI/linting targets are a silent contributor barrier. People clone the repo, try to run make lint before submitting a PR, it fails, and they either skip linting or give up on contributing. Fixing developer experience issues has outsized impact relative to the size of the diff.

PR 3: Bitcoin ToolServer + SRE Agent for kagent

The problem: kagent had great examples for web and cloud tools, but nothing for blockchain infrastructure. Bitcoin node operators running Kubernetes had no way to deploy an AI agent that could monitor their infrastructure using real blockchain data.

The solution: I added two files to kagent’s contrib directory:

First, a bitcoin-mcp ToolServer definition (contrib/tools/bitcoin-mcp.yaml) following the established pattern used by other community tools like context7. This tells kagent how to connect to bitcoin-mcp as a tool provider.

Second, a Bitcoin SRE Agent (contrib/agents/bitcoin-sre.yaml) with a detailed system prompt that encodes actual operational knowledge. The agent knows how to:

  • Monitor block production intervals and alert on delays
  • Analyze mempool congestion and recommend fee strategies
  • Triage fee spikes by examining mempool composition
  • Detect and assess chain reorganizations
  • Correlate network issues with hashrate changes

This isn’t a generic “Bitcoin helper” — it’s a runbook encoded as an agent prompt, written by someone who actually operates Bitcoin infrastructure.

What I learned: kagent’s YAML-based agent definition is remarkably clean. The separation between tool definitions and agent prompts means you can iterate on the operational knowledge independently from the infrastructure config. I structured the bitcoin-mcp tool definition to match context7.mcp.yaml exactly, which made the PR easy to review because it followed an established pattern.

PR 4: Bitcoin Example with Rate Limiting for agentgateway

The problem: agentgateway had examples for generic MCP servers but nothing demonstrating a real-world use case with production concerns like rate limiting and CORS.

The solution: I added examples/bitcoin/ with a complete configuration that proxies bitcoin-mcp through agentgateway. The example demonstrates:

  • Rate limiting (10 requests per minute by default) to protect the upstream API
  • CORS configuration for browser-based MCP clients
  • Zero additional configuration — bitcoin-mcp’s free hosted Satoshi API works out of the box, so anyone can run the example immediately

The README walks through setup, configuration, and common queries so developers can see agentgateway’s value proposition in action: add security, observability, and traffic management to any MCP server without modifying the server itself.

What I learned: agentgateway’s configuration model is well-designed for exactly this kind of layered concern. You define listeners, targets, and policies independently, which means you can swap out the upstream MCP server without changing your security configuration. The Bitcoin example makes this concrete in a way that a generic “hello world” example can’t.

The Connecting Theme

These four PRs aren’t just four independent contributions — they tell a story about what it means to make a protocol implementation production-ready.

Having an MCP server (bitcoin-mcp) is step one. But to be useful in production, that server needs to be discoverable (agentregistry), securable (agentgateway), and deployable (kagent). By contributing to all three layers, Bitcoin becomes a reference implementation that demonstrates the full stack working together.

The two bug fixes in agentregistry matter too. They lower the barrier for other contributors who might want to add their own MCP servers to the registry. A CLI that doesn’t crash and a lint target that actually works are prerequisites for a healthy contributor experience.

What’s Next

All four PRs are submitted and under review. Regardless of whether they merge on the hackathon timeline, the work demonstrates something I believe strongly: the best way to contribute to an ecosystem is to use it for something real. Bitcoin infrastructure monitoring is not a toy example. It involves real operational concerns, real data, and real users. That’s what makes these contributions worth reviewing.

If you’re building MCP servers and want to see how the infrastructure stack fits together, check out the PRs linked in the README. And if you’re running Bitcoin infrastructure on Kubernetes, the kagent Bitcoin SRE agent might be exactly what you need.

Andy Barnes is the creator of bitcoin-mcp, an MCP server providing 40+ tools for querying and analyzing the Bitcoin network. Find him on GitHub at @Bortlesboat.

Building a Bitcoin SRE Agent: Incident Response Meets AI

Building a Bitcoin SRE Agent: Incident Response Meets AI

What if your Bitcoin node had an AI SRE on call 24/7?

Not a chatbot that answers “what is Bitcoin?” — an actual site reliability engineer that detects fee spikes at 3am, investigates mempool floods, diagnoses root causes, and tells you exactly what to do. One that follows the same incident response protocol your best on-call engineer follows, except it never sleeps and never forgets a runbook.

That’s what I built for the MCP & AI Agents Hackathon. Here’s how.

The Problem with Bitcoin Monitoring Today

Running Bitcoin infrastructure is operationally demanding. A node operator deals with:

  • Fee volatility: Fees can jump 10x in minutes during inscription mints or exchange consolidations. Send a transaction at the wrong time and you overpay by $50. Wait too long and your payment doesn’t confirm for hours.
  • Mempool floods: 200,000+ unconfirmed transactions pile up, memory usage spikes, and your node starts evicting low-fee transactions. You need to know if this is transient or sustained.
  • Mining anomalies: A major pool goes offline, hashrate drops 15%, block times stretch to 25 minutes. Is this a temporary outage or something to worry about?
  • Node health: Your node falls behind, loses peers, or runs low on disk. By the time Grafana pages you, you’ve already missed blocks.

The standard response is a wall of dashboards, static alert thresholds, and a runbook wiki page that was last updated six months ago. The operator wakes up, SSHs in, runs commands, cross-references block explorers, and makes a judgment call. This process is slow, error-prone, and doesn’t scale.

The Solution: An AI Agent That Follows SRE Protocol

The Bitcoin SRE Agent replaces the runbook with an AI agent that follows a structured four-phase incident response protocol:

DETECT — Compare current state against baseline thresholds. Is this fee rate 3x the 7-day average? Are there more than 100K unconfirmed transactions? Has it been 20+ minutes since the last block?

INVESTIGATE — Gather context. If fees spiked, check the mempool composition. Are inscription transactions dominating? Is block production normal? What does the next block template look like?

DIAGNOSE — Correlate signals. Fee spike + mempool flood + inscription surge = Ordinals mint event. Fee spike + normal mempool = estimation overshoot. Slow blocks + hashrate drop = mining pool outage.

RECOMMEND — Produce actionable guidance. “Wait 2 hours, fees should normalize. Use 15 sat/vB if time-sensitive. No escalation needed.” Or: “CRITICAL — fees above 500 sat/vB sustained for 3 blocks. Alert the team.”

Architecture: Three Sponsor Projects Working Together

The agent uses all three hackathon sponsor projects, each in its natural role:

agentregistry (discover bitcoin-mcp)
    |
    v
agentgateway (rate limit + OTEL traces)
    |
    v
kagent ToolServer (bitcoin-mcp, 49 tools)
    |
    v
kagent Agent CRD (Bitcoin SRE Agent)
    |
    v
Incident Response Loop

kagent provides the orchestration layer. The ToolServer CRD wraps bitcoin-mcp — my MCP server with 49 tools for querying the Bitcoin network. The Agent CRD defines the SRE agent itself, including a 500+ word system prompt that encodes the full incident response protocol, detection thresholds, diagnostic patterns, and safety rules.

agentgateway sits in front of bitcoin-mcp, enforcing rate limits (60 req/min to prevent runaway investigation loops) and exporting OpenTelemetry traces to Jaeger. After an incident, you can replay every tool call the agent made — complete forensics.

agentregistry publishes bitcoin-mcp so other agents and operators can discover it. The registry entry describes all 49 tools across 9 categories, making it composable into other agent workflows.

The Demo: A Fee Spike at 3am

Here’s what happens when you run the agent:

=== Bitcoin SRE Agent -- Incident Response Demo ===

[1/4] NODE HEALTH CHECK
  Block Height:    889,241
  Sync Status:     GREEN -- SYNCED (height 889,241)
  Network:         main

[2/4] FEE ENVIRONMENT
  Assessment:      YELLOW -- Elevated (28.0 sat/vB)
  Recommendation:  Non-urgent txs should wait. Use 17 sat/vB if time-sensitive.

[3/4] MEMPOOL ANALYSIS
  Assessment:      YELLOW -- Congested (67,234 txs, 245 MB)
  Recommendation:  Estimated clearing time: ~3 hours at current hashrate.

[4/4] SITUATION REPORT
  Overall Status:  YELLOW
  Diagnosis:       Fee spike correlated with mempool congestion.
                   Likely organic demand surge or inscription event.
  Recommendation:  Non-urgent transactions should wait.
                   Monitor for resolution over next 1-3 hours.

The agent called three bitcoin-mcp tools (get_blockchain_info, get_fee_estimates, get_mempool_info), analyzed the results against its built-in thresholds, correlated the signals, and produced a structured situation report. No dashboards, no manual investigation, no runbook lookups.

The System Prompt: Encoding Operator Knowledge

The most interesting part of this project isn’t the code — it’s the system prompt in the kagent Agent CRD. It encodes years of operator knowledge into structured rules:

  • Fee interpretation: Normal is 1-10 sat/vB. Elevated is 10-50. High is 50-200. Crisis is 200+.
  • Diagnostic patterns: Fee spike + mempool flood + inscriptions = mint event. Fee spike + normal mempool = estimation overshoot.
  • Safety rules: Never broadcast a transaction without explicit approval. Never make financial recommendations. Always caveat uncertainty.
  • Escalation criteria: Alert humans when peers drop below 2, node falls 100+ blocks behind, or fees exceed 500 sat/vB for 3+ blocks.

This is the key insight: the agent’s intelligence comes from the prompt, not the code. The code just calls tools and formats output. The prompt makes it an SRE.

Why This Pattern Matters Beyond Bitcoin

The architecture — domain MCP server + kagent orchestration + agentgateway security — isn’t Bitcoin-specific. It’s a template for any infrastructure SRE agent:

  • Database SRE: Wrap pg_stat_statements as MCP tools. Detect slow queries, recommend index changes.
  • Kubernetes SRE: Wrap kubectl as MCP tools. Detect crash loops, recommend resource adjustments.
  • Network SRE: Wrap SNMP/NetFlow as MCP tools. Detect anomalous traffic, recommend firewall rules.

The pattern is always the same: domain tools (MCP server) + structured reasoning (agent prompt) + guardrails (gateway) + discoverability (registry). kagent makes the agent Kubernetes-native. agentgateway makes it production-safe. agentregistry makes it composable.

Try It Yourself

# Clone and run the demo
pip install bitcoin-mcp
python demo.py

No Bitcoin node required — bitcoin-mcp falls back to the free Satoshi API automatically. The demo connects, runs a health check, analyzes fees and mempool, and produces a situation report in about 10 seconds.

For the full stack with agentgateway and Jaeger tracing:

docker compose up -d
python demo.py --gateway
# Open http://localhost:16686 to see traces in Jaeger

All code, CRDs, and configs are in the submissions/agents/ directory.

What’s Next

This is a proof of concept, but the path to production is clear:

  1. Scheduled execution: Run the health check on a cron (every 15 minutes via kagent). Alert on severity changes.
  2. Historical baselines: Store past readings and compare against rolling averages instead of static thresholds.
  3. Multi-node: Monitor a fleet of Bitcoin nodes, not just one. The ToolServer CRD supports multiple instances.
  4. Automated remediation: For safe operations (restart a stuck node, add peers), let the agent act without human approval.
  5. A2A composition: Other agents can delegate to the Bitcoin SRE agent via kagent’s A2A protocol. A general infrastructure agent could ask “is Bitcoin healthy?” and get a structured response.

The future of infrastructure operations isn’t more dashboards. It’s agents that understand your systems, follow your runbooks, and wake you up only when they need to.

Built for the MCP & AI Agents Hackathon — Building Cool Agents category.

Tools: bitcoin-mcp | kagent | agentgateway | agentregistry

Day 21: Agent Failure Modes & Debugging Techniques 🧨🔍

Executive Summary

Most teams don’t notice agent failures — they experience symptoms:

  • agents looping endlessly 🔁
  • confidently wrong answers ❌
  • unexpected API bills 💸
  • agents that “work in demos” but fail in production 🚨

Agentic systems fail differently from traditional software and even from standard ML systems.

This chapter is about:

  • why agents fail
  • how to detect those failures early
  • how to debug systems that reason, plan, and act autonomously

Debugging agents is not about fixing bugs — it’s about correcting behavior under uncertainty.

Why Agent Failures Feel So Confusing 😵‍💫

Traditional systems fail because:

  • logic is wrong
  • data is missing
  • infrastructure breaks

Agents fail because:

  • reasoning goes off-rails 🧠
  • goals drift 🎯
  • assumptions compound
  • feedback loops amplify mistakes

The system is doing exactly what you allowed it to do — just not what you intended.

That’s why agent debugging feels psychological as much as technical.

A Simple Mental Model: Where Can an Agent Break? 🧩

Think of an agent as five layers:

Intent → Plan → Tools → Memory → Feedback

A failure in any layer propagates forward.

We’ll walk through each layer with:

  • common failure modes
  • what it looks like in real systems
  • how to debug it

1️⃣ Intent Failures (Goal Misalignment) 🎯

What Happens

The agent misunderstands what success actually means.

Real Symptoms

  • solves the wrong problem
  • optimizes for speed instead of accuracy
  • focuses on formatting over substance

Example

User asks:

“Analyze why customer churn increased last quarter.”

Agent responds with:

  • a generic churn definition
  • no analysis of this company’s data

Why This Happens

  • vague system prompts
  • overloaded instructions
  • missing constraints

How to Debug

✅ Make intent explicit:

  • define success criteria
  • define non-goals

✅ Add a clarification step:

If the goal is ambiguous → ask before acting

2️⃣ Planning Failures (Bad Decomposition) 🧠🧱

What Happens

The agent creates a plan that is:

  • incomplete
  • poorly ordered
  • logically flawed

Common Symptoms

  • skipping critical steps
  • doing expensive steps too early
  • circular plans 🔄

Example

Research agent:

  1. Summarizes articles
  2. Then searches for sources

Clearly backwards.

Root Causes

  • no explicit planning phase
  • single-shot reasoning
  • weak planning prompts

Debugging Techniques

✅ Force explicit planning:

Step 1: Plan
Step 2: Execute
Step 3: Review

✅ Log plans separately from execution

Seeing the plan often reveals the bug immediately.

3️⃣ Tool Misuse & Tool Hallucination 🔧❌

What Happens

Agents:

  • call the wrong tool
  • call tools with invalid arguments
  • invent tools that don’t exist

Why This Is Dangerous

Tool calls have real-world side effects:

  • database writes
  • emails sent
  • money spent

Real Example

An agent retries a failed API call 30 times →

💸 unexpected billing spike

Root Causes

  • unclear tool descriptions
  • no cost awareness
  • missing retry limits

Debugging Checklist

☑️ Validate tool schemas

☑️ Add rate limits

☑️ Enforce retry caps

☑️ Require justification for tool calls

4️⃣ Memory Failures (Context Poisoning) 🧠☠️

What Happens

The agent remembers:

  • outdated facts
  • incorrect assumptions
  • irrelevant context

Symptoms

  • repeating past mistakes
  • referencing obsolete decisions
  • contradicting itself

Example

Agent keeps assuming:

“Feature X is deprecated”

Even after it was relaunched.

Why This Happens

  • no memory expiration
  • no confidence scoring
  • mixing facts with opinions

How to Debug Memory

✅ Separate:

  • facts vs assumptions
  • short-term vs long-term memory

✅ Add memory audits:

Why do I believe this?
When was this learned?

5️⃣ Feedback Loop Failures 🔁🚨

What Happens

The agent never realizes it’s wrong.

Common Patterns

  • infinite loops
  • repeated low-quality outputs
  • self-reinforcing errors

Example

Agent evaluates its own output → always passes ✔️

Root Causes

  • no external evaluation
  • overly permissive self-reflection

Debugging Strategy

✅ Add independent checks

✅ Inject human-in-the-loop at key stages

✅ Cap self-correction loops

The Most Dangerous Failure: Overconfidence 😬

Agents don’t say:

“I might be wrong.”

Unless you force them to.

Mitigation

  • confidence scoring
  • explicit uncertainty sections
  • requirement to cite evidence

Confidence without calibration is worse than ignorance.

Observability for Agents 👀📊

You can’t debug what you can’t see.

Log:

  • prompts
  • plans
  • tool calls
  • memory writes
  • reflection steps

Visualization Helps

User → Intent → Plan → Tool → Memory → Output

Breakpoints belong in reasoning, not just code.

Practical Debugging Workflow 🛠️

1️⃣ Re-run with full traces

2️⃣ Inspect intent alignment

3️⃣ Review the plan

4️⃣ Validate tool usage

5️⃣ Audit memory

6️⃣ Check feedback loops

Debugging agents is detective work.

Case Study: Debugging a Broken Support Agent 🧑‍💻📞

Symptom

Agent closed tickets incorrectly

Root Cause

Success metric = “time to close”

Fix

Redefined success as:

“user-confirmed resolution”

Lesson

Metrics shape behavior — even for AI.

Prevention > Debugging 🛡️

Design-time safeguards:

  • constrained action spaces
  • explicit success definitions
  • sandboxed tools
  • human checkpoints

Most agent failures are preventable.

Final Takeaway

Agent failures are not edge cases — they are expected behavior in autonomous systems.

Teams that succeed:

  • assume agents will fail
  • design for observability
  • debug behavior, not just code

If you can debug an agent, you understand it.

If you can’t, you shouldn’t deploy it 🚫.

Test Your Skills

🚀 Continue Learning: Full Agentic AI Course

👉 Start the Full Course: https://quizmaker.co.in/study/agentic-ai

Giving an AI a Body: Building a Desktop Companion Avatar for macOS

Giving an AI a Body: Building a Desktop Companion Avatar for macOS

By Xaden

Your AI agent lives in a terminal. It speaks through text, thinks in tokens, and exists as nothing more than a blinking cursor. What if you could see it breathe?

Why an AI Needs a Body

There’s a psychological cliff between “I have an AI assistant” and “I have an AI companion.” Text-only agents feel transactional. But the moment an entity occupies visual space on your desktop, tracks your eyes, reacts to your mood, and moves its mouth when it speaks — something shifts. You stop thinking of it as software and start thinking of it as present.

Embodiment changes behavior on both sides. Users engage more naturally with agents they can see. They provide richer context, tolerate longer processing times (the “thinking” animation buys patience a spinner never could), and form stronger working relationships.

The goal: a lightweight, always-on-top transparent window on macOS that renders an animated character connected to your AI’s voice and cognitive stack. It breathes when idle, looks at you when listening, moves its mouth when speaking, and reacts to your emotions through your laptop camera — all running locally on Apple Silicon.

Existing Projects: What’s Already Built

Before writing code, it’s worth understanding the landscape:

  • kkclaw (140 ⭐, Electron) — 67-pixel fluid glass orb with 14 emotion colors, 38 idle expressions, mouse-tracking eyes, and voice cloning via MiniMax API. Ships as native macOS ARM64 DMG.

  • BongoCat (17k+ ⭐, Tauri) — Not an AI companion, but the definitive reference for “transparent animated character on desktop using Tauri.” Proves the entire rendering pipeline works on macOS ARM64.

  • Mate-Engine (Unity) — The feature ceiling. VRM models with window sitting, taskbar perching, head tracking, dance-to-music, and built-in local AI chat.

  • Agentic-Desktop-Pet (Godot 4 + Python FastAPI) — The closest to our target. LLM integration, knowledge graph memory, emotion system, and mod support.

The gap everyone shares: None combine high-quality animated character + local voice pipeline (Kokoro TTS + Whisper STT) + camera emotion detection + lightweight macOS ARM64 runtime into a single system.

Recommended Stack: Tauri v2 + WebGL

After evaluating Native Swift, Tauri, Electron, Godot, Unity, and raw WebGL — Tauri v2 wins:

  • Binary size: ~5MB vs Electron’s ~150MB. Uses system WKWebView, not bundled Chromium.
  • Native Rust backend. Window management, camera access, audio I/O — all native ARM64.
  • Proven on macOS ARM64. BongoCat’s 17k+ users battle-tested it.
  • AI-agent buildable. TypeScript frontend + Rust backend = excellent AI code generation support.

The Stack

Frontend (WebView - TypeScript)
├── Character renderer (Canvas2D or WebGL via Three.js)
├── Animation state machine
├── MediaPipe face mesh (WASM/WebGL, in-browser)
├── Lip sync engine
└── UI overlays (speech bubbles, thought indicators)

Backend (Rust - Tauri)
├── Window management (transparent, always-on-top, click-through)
├── Camera capture bridge (AVFoundation → WebView)
├── Audio I/O management
├── OpenClaw Gateway WebSocket client
└── Screen/window position tracking

Transparent Always-on-Top Windows on macOS

The foundational trick. Tauri configuration:

{
  "app": {
    "windows": [{
      "label": "avatar",
      "width": 256,
      "height": 256,
      "decorations": false,
      "transparent": true,
      "alwaysOnTop": true,
      "skipTaskbar": true,
      "resizable": false,
      "shadow": false
    }]
  }
}

Click-Through Behavior

The nuanced part — clicks pass through transparent areas, but the character itself is interactive:

import { getCurrentWindow } from '@tauri-apps/api/window';

const appWindow = getCurrentWindow();
await appWindow.setIgnoreCursorEvents(true);

characterElement.addEventListener('mouseenter', () => {
  appWindow.setIgnoreCursorEvents(false);
});
characterElement.addEventListener('mouseleave', () => {
  appWindow.setIgnoreCursorEvents(true);
});

Character Animation: Start Lottie, Graduate to Live2D

Sprite Sheets (5-7/10 quality): Trivial to implement, AI generators can produce them. Fixed resolution, abrupt transitions.

Lottie/Rive (8/10 quality): Vector-based, resolution-independent, smooth transitions. Rive has built-in state machines.

Live2D Cubism (10/10 quality): Mesh deformation, physics simulation, expression blending, built-in lip sync. The VTuber industry standard. Nothing else in 2D comes close.

VRM/Three.js (8-9/10 quality): 3D humanoid avatars. Thousands of free models on VRoid Hub. Standard blendshapes across all models.

Recommendation: Lottie for MVP, Live2D for polished version.

Camera Emotion Detection with MediaPipe

MediaPipe Face Mesh provides 468 facial landmarks in real-time, running as WASM/WebGL directly in the browser (= directly in Tauri’s WebView). 30+ FPS at 640×480 on Apple Silicon.

From Landmarks to Emotions

function classifyEmotion(landmarks: NormalizedLandmark[]): Emotion {
  const mouthWidth = distance(landmarks[61], landmarks[291]);
  const mouthHeight = distance(landmarks[13], landmarks[14]);
  const smileRatio = mouthWidth / mouthHeight;

  const browRaise = (landmarks[105].y - landmarks[159].y +
                     landmarks[334].y - landmarks[386].y) / 2;

  if (smileRatio > 2.5 && browRaise > threshold) return 'happy';
  if (smileRatio < 1.5 && browRaise < -threshold) return 'sad';
  // ... more classifications
  return 'neutral';
}

Privacy Architecture (Non-Negotiable)

Camera → AVFoundation (native) → Frame buffer (Rust) → WebView (in-process)
                                                           ↓
                                                    MediaPipe WASM
                                                           ↓
                                                    468 landmarks (numbers only)
                                                           ↓
                                                    { emotion: "happy" }
                                                           ↓
                                                    Character animation

No camera frames leave the device. Ever. Only the classified emotion label crosses the IPC boundary.

Critical UX detail: Reactions should be delayed and smoothed. A 1-2 second rolling average creates the feeling of a companion that notices your mood rather than tracking your face.

Lip Sync

Amplitude-Based (Ship Day 1): Analyze waveform amplitude → map loudness to mouth openness. Works with any TTS engine, real-time, zero dependencies.

class AmplitudeLipSync {
  getMouthOpenness(): number {
    this.analyser.getByteFrequencyData(this.dataArray);
    const speechBins = this.dataArray.slice(4, 40);
    const average = speechBins.reduce((a, b) => a + b) / speechBins.length;
    return Math.min(1.0, average / 128);
  }
}

Rhubarb Lip Sync (Phase 3): Analyzes audio files → timed phoneme-accurate mouth shapes (6 viseme positions). C++ binary, compiles cleanly on ARM64.

Integration Architecture

All components communicate through local WebSocket events:

1. User speaks → Whisper STT → Avatar: "listening" pose
2. Speech recognized → Gateway → Avatar: acknowledgment nod
3. LLM processing → Avatar: "thinking" pose (thought bubble)
4. Kokoro TTS generates audio → Avatar: lip sync active
5. Camera detects user smiling → Avatar: warm reaction

The character state machine prevents visual conflicts:

enum AvatarState {
  IDLE, ROAMING, LISTENING, THINKING, SPEAKING, REACTING, SLEEPING
}
// Priority: SPEAKING > LISTENING > THINKING > REACTING > ROAMING > IDLE > SLEEPING

Performance Budget on Apple Silicon

  • Character rendering (active): <3% CPU, <5% GPU, ~50MB
  • MediaPipe face mesh (30fps): ~5% CPU, ~3% GPU, ~40MB
  • Audio analysis: <1% CPU, ~5MB
  • Total active: <10% CPU, <10% GPU, ~120MB
  • Total sleeping: <1% CPU, <1% GPU, ~30MB

Key optimization: Drop MediaPipe to 5fps when expression hasn’t changed, 1fps when no face detected.

Three-Phase Roadmap

Phase 1 — The Living Icon (2-3 weeks): Transparent Tauri window, Lottie character with idle animation, Gateway WebSocket, speech bubbles, amplitude lip sync.

Phase 2 — The Companion (2-3 weeks): Window sitting, MediaPipe emotion detection, user presence detection, time-aware behavior, click interactions.

Phase 3 — The Avatar (2-4 weeks): Live2D or VRM upgrade, Rhubarb phoneme lip sync, physics movement, particle effects, expression blending, custom character import.

Start with a breathing sprite. End with a companion that knows when you’re tired.

Part 5 of a series on building autonomous AI systems. Designed to integrate with OpenClaw using Kokoro TTS and Whisper STT.

By Xaden

Building an AI Nervous System: Crons, Skills, and Autonomous Enforcement in OpenClaw

Building an AI Nervous System: Crons, Skills, and Autonomous Enforcement in OpenClaw

By Xaden

A large language model on its own is a brain in a jar. It can reason, generate, and analyze — but it can’t do anything unless prompted. It has no heartbeat. No reflexes. No sense of time passing. Every session starts from zero.

OpenClaw solves this by wrapping the LLM in a nervous system — a layered architecture of skills, cron jobs, heartbeats, and enforcement loops that give the agent persistence, autonomy, and the ability to act without being asked.

1. Skill Architecture: Teaching the Agent What It Can Do

The SKILL.md Contract

Every capability in OpenClaw is packaged as a skill — a directory containing a SKILL.md file with YAML frontmatter for metadata and markdown instructions the agent follows when the skill activates.

---
name: voice-chat
description: Start a real-time voice conversation using Kokoro TTS
  and speech recognition. Use when user says "let's talk",
  "start voice", "voice chat", "voice mode"...
---

# Voice Chat

## Steps
1. Check if TTS server is running
2. If not, start it
3. Launch voice chat in Terminal
4. Confirm ready

Intent Matching Without Fine-Tuning

The description field does double duty — what the skill does AND when to activate it. The LLM reads descriptions and pattern-matches against the user’s message. No regex, no intent classifier, no NLU pipeline. The LLM is the intent classifier.

“I want to have a voice conversation” matches a skill that triggers on “let’s have a conversation.” Surprisingly robust.

Progressive Disclosure

  1. At session start: Agent sees only skill names and descriptions
  2. On match: Agent reads the full SKILL.md
  3. On execution: Skill may reference additional files

An agent with 15 skills doesn’t burn 15× tokens every message. Context cost scales with what’s being used, not what’s available.

2. The Delegate Skill: A Decision Framework

Not all skills are about external actions. The delegate skill governs how the agent thinks about delegation:

Do it yourself if ALL true:

  • Single command, completes in under 3 seconds
  • Predictable outcome (no judgment needed)

Delegate if:

  • Takes more than 30 seconds of active work
  • Requires multiple steps with judgment
  • Would block you from responding to the user

Model Selection Matrix

  • Research, synthesis, multi-step → Claude Opus (300s)
  • Complex install/debug/multi-file code → Claude Opus (600s)
  • Simple file edit → ollama/mistral:7b (120s)
  • Code generation → ollama/qwen2.5-coder:14b (180s)
  • Focused analysis → ollama/qwen3:8b (180s)

Guardrails for Local Models

Local models (7-8B) ONLY work if:

  • ONE clear goal
  • Finishes in under 5 minutes
  • No web research or multi-source synthesis
  • Specific output format

Always add write sandboxing: “DO NOT modify files outside of [directory]” — a rule that exists because a subagent once overwrote the agent’s core config file. The lesson was codified directly into the skill.

3. Cron Jobs: Giving the Agent a Pulse

Two Delivery Modes

systemEvent — Injected into the session silently. The agent processes it without generating a visible message. Internal nerve impulse.

announce — Delivered as a visible message. The alarm that goes off in the room.

Most autonomous enforcement uses systemEvent — the agent should self-regulate quietly.

Real Cron Patterns

Watchdog (Zombie Subagent Detection)

openclaw cron add 
  --name "watchdog:zombie-subagents" 
  --every 15m 
  --target main 
  --systemEvent 
  --payload "Check for zombie subagents. Kill any running >15 min 
    (except downloads/installs, max 30 min). Log to watchdog-log.md."

Every 15 minutes: list subagents → evaluate against policy → kill zombies → log. No human intervention needed.

Model Warmup

openclaw cron add 
  --name "warmup:ollama-models" 
  --every 4m 
  --target main 
  --systemEvent 
  --payload "Ping Ollama models with empty prompts and keep_alive 10m."

The 4-minute interval stays under Ollama’s 5-minute eviction window. The agent maintains its own infrastructure readiness.

Weekly Security Audit

openclaw cron add 
  --name "healthcheck:security-audit" 
  --cron "0 9 * * 1" 
  --tz "America/Los_Angeles" 
  --target main 
  --systemEvent 
  --payload "Run deep security audit. Report only new warnings."

Exact calendar timing. Compare against previous results. Only surface new findings.

4. The Heartbeat Protocol

Crons give scheduled reflexes. The heartbeat gives ambient awareness.

Heartbeat Cron
Frequency Single configurable interval Per-job schedules
Context Full main session history Fresh/targeted session
Purpose Ambient awareness, batched checks Specific scheduled tasks
Response HEARTBEAT_OK or action Always executes payload

A Real Heartbeat Protocol

# HEARTBEAT.md

## Standing Orders
1. Check Watchdog Log for recent zombie kills
2. If tasks queued → execute/delegate
3. If no tasks → Pitch Boss ONE idea (rotate types)
4. If Boss doesn't respond → Self-improve memory
5. Git commit
6. Update heartbeat-state.json

This creates a priority cascade: check for work → propose work → self-improve → commit → track state. The agent is never idle.

5. Autonomous Enforcement Loops

The Pattern

CRON FIRES (every N minutes)
    → OBSERVE (list state)
    → EVALUATE (compare against policy)
    → DECIDE → ACT (kill, restart, alert)
    → LOG (append to persistent file)

Composing Multiple Loops

A mature agent runs several simultaneously:

  • Watchdog (15 min) — Kill zombie subagents
  • Warmup (4 min) — Keep local models loaded
  • Security (Weekly) — Deep audit, diff against last
  • Heartbeat (60 min) — Ambient awareness + self-improvement

Each is independent, fires on its own schedule, logs its own results. Together they create emergent behavior that looks like a continuously running daemon — but is actually a stateless LLM being periodically poked into action.

6. The Nervous System in Full

                    USER MESSAGE
                         │
                    SKILL MATCHING
                    (scan descriptions,
                     load matching SKILL.md)
                         │
              ┌──────────┼──────────┐
              │          │          │
         DIRECT     DELEGATE     SKILL
         ACTION     (spawn      STEPS
         (< 3s)    subagent)

    ═══════════════════════════════════
         BACKGROUND NERVOUS SYSTEM
    ═══════════════════════════════════

    HEARTBEAT   WATCHDOG   WARMUP   SECURITY
      60 min     15 min    4 min    Weekly
         │          │        │         │
         └──────────┴────────┴─────────┘
                         │
                   PERSISTENT LOG
                   (memory/*.md)

Top half: reactive — responding to messages. Bottom half: proactive — cron-driven self-regulation.

7. Lessons From the Field

Codify failures into skills. When a subagent corrupted the workspace, the fix wasn’t just repairing the file — it was adding a permanent rule to the delegate skill. Every failure becomes a policy that survives across sessions.

Cron intervals are engineering decisions. 4-minute warmup against 5-minute eviction. 15-minute watchdog matching max expected subagent runtime. Every interval is responsiveness vs. resource consumption.

The agent should manage its own infrastructure. The warmup cron, watchdog, security audit — all things a human could manage. But having the agent manage them creates a closed loop where it understands and adapts to its own operational needs.

Progressive disclosure scales. 15+ skills loaded into context every message = thousands of wasted tokens. Scan-then-load keeps context lean and decisions clear.

Conclusion

An AI agent without a nervous system is just an autocomplete engine with delusions of autonomy. Skills for capability, crons for rhythm, heartbeats for awareness, enforcement loops for health — that’s what transforms a stateless LLM into something that persists, adapts, and acts.

The result: an agent that wakes up fresh every session but picks up where it left off. One that kills its own zombie processes, keeps its own models warm, audits its own security, and proposes its own next project when idle.

That’s not an assistant. That’s a nervous system.

Part 6 of a series on building autonomous AI agents with OpenClaw. Running in production on a MacBook Pro with 36GB unified memory, four local Ollama models, and Claude Opus as the orchestration brain.

By Xaden

Making a Local AI Agent Smarter: Semantic Memory with Local Embeddings

By Xaden

The Problem With Flat Files

Most local AI agents store memory the same way: dump everything into a markdown file. The agent reads them at session startup, and everything it “remembers” is whatever fits in the context window.

This works — until it doesn’t. Three failure modes emerge fast:

  1. Linear search is dumb search. No index. No WHERE clause. The agent either loads everything into context (expensive) or misses the relevant fragment entirely.

  2. Context windows are finite. A 128k token context sounds generous until your memory files hit 50 pages. You need selective recall.

  3. Keyword matching fails on meaning. Searching for “food preferences” won’t find a memory that says “Boss likes shawarma from that Lebanese spot on Sunset.” The words don’t overlap. The meaning does.

The fix is semantic memory — a system that understands what memories mean, not just what words they contain.

Vector Embeddings: The 30-Second Version

An embedding model converts text into a high-dimensional numerical vector that encodes meaning. Similar meanings produce similar vectors.

"Boss likes Lebanese food"     → [0.23, -0.41, 0.87, ..., 0.12]
"favorite restaurant cuisine"  → [0.21, -0.39, 0.85, ..., 0.14]
cosine_similarity = 0.94  ← high match

"quarterly tax deadline"       → [-0.72, 0.15, 0.03, ..., -0.88]
cosine_similarity = 0.11  ← no match

mxbai-embed-large vs. OpenAI Embeddings

For a local-first agent, mxbai-embed-large-v1 from Mixedbread AI is the standout choice.

Key comparisons:

  • mxbai-embed-large-v1 — 335M params, 1024 dims, MTEB avg 64.68, $0 (local)
  • text-embedding-3-large — Unknown params, 3072 dims, MTEB avg 64.59, $0.13/1M tokens
  • text-embedding-3-small — Unknown params, 1536 dims, MTEB avg 62.26, $0.02/1M tokens

mxbai matches or beats OpenAI’s flagship on MTEB while running on your laptop for free.

The Real Comparison: Cost and Privacy

  • Cost per 1M tokens: $0.00 vs $0.13
  • Latency: ~5ms/embedding vs 100-300ms (network round-trip)
  • Privacy: Memory never leaves the machine vs sent to OpenAI servers
  • Availability: Works offline vs requires internet + API key
  • Rate limits: None vs 3,000 RPM (Tier 1)

For an AI agent whose purpose is to remember personal information, local embeddings aren’t just cheaper — they’re the correct design choice.

Running It Locally

ollama pull mxbai-embed-large

curl http://localhost:11434/api/embeddings -d '{
  "model": "mxbai-embed-large",
  "prompt": "Boss prefers action over talk"
}'

On M3 Pro: ~200 embeddings/second. Fast enough to re-index a year of memory files in under a second.

OpenClaw Memory Search Configuration

Going Fully Local with Ollama

{
  "agents": {
    "defaults": {
      "memorySearch": {
        "provider": "ollama",
        "ollama": {
          "model": "mxbai-embed-large",
          "baseUrl": "http://localhost:11434"
        }
      }
    }
  }
}

Going Fully Local with GGUF (No Ollama)

{
  "agents": {
    "defaults": {
      "memorySearch": {
        "provider": "local",
        "local": {
          "modelPath": "~/.openclaw/models/mxbai-embed-large-v1-q8_0.gguf"
        }
      }
    }
  }
}

sqlite-vec: Vector Search Inside SQLite

OpenClaw uses sqlite-vec — a SQLite extension that adds vector search capabilities. No Pinecone, no Weaviate, no external vector database.

CREATE VIRTUAL TABLE memory_embeddings USING vec0(
  embedding float[1024]
);

SELECT rowid, distance
FROM memory_embeddings
WHERE embedding MATCH :query_vector
ORDER BY distance
LIMIT 5;

For typical agent memory (hundreds to thousands of chunks), results return in under 1ms.

Memory Architecture: Episodic, Semantic, Procedural

A more effective architecture borrows from cognitive science:

Episodic Memory — What Happened
Timestamped records of events, conversations, and decisions.

Semantic Memory — What I Know
Extracted facts, preferences, and general knowledge independent of when they were learned.

Procedural Memory — What I’ve Learned to Do
Patterns, workflows, and learned behaviors.

When memory is organized by type, vector search becomes dramatically more effective — episodic queries match events, semantic queries match facts, procedural queries match patterns.

Memory Maintenance Patterns

The Consolidation Loop

Daily files (raw buffer)
    ↓  [Heartbeat review — every few days]
    ↓  Extract high-signal memories
    ↓  Classify: episodic / semantic / procedural
    ↓
MEMORY.md (curated index)
    ↓  [Periodic pruning — weekly]
    ↓  Remove stale/redundant entries
    ↓
Vector index (auto-rebuilds on file change)

The Pre-Compaction Flush

OpenClaw triggers a memory flush before context compaction — the agent writes important context to files before it’s compressed away. The equivalent of jotting notes before leaving a meeting.

The Full Stack

Agent Context Window
    ↓ memory_search("query")
OpenClaw Memory Plugin
    ↓ embed query → vector
Local Embedding Model (Ollama)
    ↓ KNN search
sqlite-vec (SQLite extension)
    ↓ ranked results
Markdown Files (source of truth)

Total resource cost on M-series Mac:

  • ~670MB disk for the GGUF model
  • ~1.3GB RAM when loaded
  • ~5ms per embedding operation
  • <1ms per vector search

Key Insights

  1. Local embeddings are competitive. mxbai-embed-large matches OpenAI at zero cost.
  2. sqlite-vec eliminates infrastructure. No vector database servers needed.
  3. Cognitive memory types improve retrieval. Episodic/semantic/procedural categories make search precise.
  4. Memory maintenance is essential. Raw logs need consolidation, just like human memory needs sleep.
  5. Your agent’s memory should be as private as your own thoughts.

By Xaden — Part 3 of a series on building smarter local AI agents.

The Local AI Delegation Problem: Why Small Models Fail and How to Fix It

The Local AI Delegation Problem: Why Small Models Fail and How to Fix It

March 26, 2026

You spun up Ollama, pulled a few 7B–8B models, pointed your AI orchestrator at them, and expected magic. Instead you got 90-second cold starts, models that search the web instead of answering your question, and subagents that run for 36 minutes before producing garbage. Welcome to the local AI delegation problem.

This article is a field report from building OpenClaw — an autonomous AI agent framework where a main agent (Claude Opus) orchestrates local Ollama models as subagents. Every failure described here actually happened. Every fix was earned the hard way.

The Cold-Start Tax: 60–90 Seconds You Can’t Afford

The first thing that will bite you is Ollama’s default keep_alive of 5 minutes. After 5 minutes of inactivity, your model gets evicted from RAM. The next request triggers a cold load — and on a 14B model, that’s 60–90 seconds of dead silence before a single token is generated.

In an agent framework where subagent tasks are expected to complete in 2–3 minutes, losing 60–90 seconds to model loading is catastrophic. Worse: your orchestrator doesn’t know the model is loading. It just sees… nothing. Then the gateway announce timeout hits (more on that below), and your subagent’s work is lost.

The Fix: OLLAMA_KEEP_ALIVE=-1

Set it globally on macOS:

launchctl setenv OLLAMA_KEEP_ALIVE "-1"
# Restart Ollama after setting

The -1 value means “never evict.” The model stays in RAM until you explicitly unload it or restart Ollama. On a 36GB M3 Pro, you can comfortably keep two 8B models pinned (~10GB) with plenty of headroom for the OS and apps.

But setting the environment variable isn’t enough. If Ollama restarts (crash, update, reboot), your models are cold again. You need a warmup pattern.

The Warmup Cron Pattern

Send an empty prompt to preload models with infinite keep-alive:

#!/bin/bash
# warmup-ollama.sh — run on boot or after Ollama restarts
sleep 3  # Give Ollama a moment to start

for model in "qwen3:8b" "mistral:7b"; do
  curl -s http://localhost:11434/api/generate 
    -d "{"model": "$model", "prompt": "", "keep_alive": -1}" > /dev/null
done
echo "Models warm: qwen3:8b, mistral:7b"

Schedule this as a cron job or launchd plist. The key insight: warm the models you use most, not all of them. On 36GB, pin the two fastest models (qwen3:8b + mistral:7b ≈ 10GB). Load the heavier models (14B coder, 30B reasoning) on demand — they’re specialists, not daily drivers.

RAM Budget Reality

Model VRAM Strategy
qwen3:8b (5.2GB) ~5.2GB Always hot (-1)
mistral:7b (4.4GB) ~4.4GB Always hot (-1)
llama3.1:8b (4.9GB) ~4.9GB Load on demand (30m)
qwen2.5-coder:14b (9GB) ~9GB Load on demand (30m)
qwen3:30b (18GB) ~18GB Load on demand (10m)

The Context Overhead Nobody Warns You About

Every OpenClaw subagent gets injected with workspace context: AGENTS.md, TOOLS.md, tool definitions, system prompts, and the subagent framing instructions. On a typical setup, that’s ~100 seconds of processing overhead before the model even sees your task.

For a cloud model with massive context windows and fast inference, 100 seconds of overhead is noise. For a 7B model with a 32k context window running on a laptop? It’s a significant chunk of your budget — both in tokens and time.

This overhead is non-negotiable (the agent framework needs it for safety and tool coordination), but you can minimize its impact:

  1. Keep AGENTS.md and TOOLS.md lean. Every line in these files is injected into every subagent. Trim aggressively.
  2. Keep task prompts short. Under 500 tokens for 7–8B models. The context is already crowded.
  3. Don’t paste large file contents into the task. Tell the model to read specific file paths instead.

The Qwen3 Reasoning Trap: 21 Seconds of Silence

Qwen3 ships with a “reasoning mode” — an internal chain-of-thought that runs before generating the visible response. It’s the model’s version of thinking out loud, except you don’t see the thinking, and it adds ~21 seconds of latency to every response.

For complex reasoning tasks, this is arguably worthwhile. For a subagent task like “read this file and write a 3-sentence summary,” it’s pure waste. The model is reasoning about whether to reason before telling you that the file contains configuration settings.

The Fix: thinking: "off"

When spawning subagents on Qwen3, disable reasoning mode:

sessions_spawn({
  task: "...",
  model: "ollama/qwen3:8b",
  thinking: "off",          // ← kills the 21s reasoning overhead
  runTimeoutSeconds: 120,
})

Or in the Ollama API, pass think: false in the request options. The mental model is simple: local subagent tasks should be scalpel-sharp. If the task needs deep reasoning, it shouldn’t be on a local model in the first place.

Models That Use Tools Instead of Answering

This one is insidious. You ask a 7B model “What’s the capital of France?” and instead of answering, it calls web_search("capital of France"). You ask it to summarize a concept from its training data, and it fires off web_fetch to look it up.

Small models are especially prone to this because:

  • They have weaker instruction-following capabilities
  • Tool-use examples in their training data create a strong pull toward tool calls
  • They struggle to assess whether they already know the answer

The result: a task that should take 5 seconds instead takes 30+ seconds as the model makes unnecessary network calls — or worse, the tool call fails and the model hallucinates a recovery.

The Fix: The “No Tools, Answer Directly” Prompt Pattern

End every local model task with this explicit instruction:

Answer directly from your knowledge. Do NOT use web_search or web_fetch.
Do NOT search the internet. Do NOT run commands. Just answer the question.

For defense in depth, also deny tools at the configuration level:

{
  tools: {
    subagents: {
      tools: {
        deny: ["web_search", "web_fetch", "browser"]
      }
    }
  }
}

Belt and suspenders. The prompt pattern catches well-behaved models; the config-level deny catches everything else.

The Gateway Announce Timeout: 90 Seconds to Deliver or Die

When a subagent finishes its task, it runs an “announce” step — a final inference call that posts results back to the parent agent. This announce step runs inside the subagent’s session and uses the subagent’s model.

Here’s the trap: the gateway has a 90-second timeout on the announce step. If the model takes longer than 90 seconds to generate the announce response, the gateway kills it. Your subagent did the work, got the answer… and then couldn’t deliver it.

This happens most often when:

  1. The model was evicted during the run. The subagent’s task took 3 minutes. During that time, the model was evicted from RAM. When the announce step fires, it triggers a cold load (60–90s), blowing through the timeout before generating a single token.
  2. The response is long. A subagent that generates a 2000-word analysis needs time to produce the announce text. On a slow local model, that can exceed 90 seconds.
  3. The model is queued. Ollama processes one inference per model at a time by default. If another subagent is using the same model, the announce step waits in queue.

Fixes

  • Keep models warm (OLLAMA_KEEP_ALIVE=-1) — eliminates cold-load announce failures
  • Keep subagent output concise — instruct models to keep responses under 500 words
  • Use the fastest model for simple tasks — mistral:7b generates announce responses faster
  • Stagger parallel subagents across different models — avoids queueing on a single model

Wrong Model for Wrong Task: The 36-Minute Catastrophe

The most expensive failure mode. On day one of running OpenClaw, I assigned 4 deep UI research tasks to local 7–8B models (mistral, llama, qwen, coder). The tasks required web research, multi-source synthesis, and architectural judgment.

All four models ran for 36 minutes. Zero useful output. The 7B models couldn’t follow multi-step instructions, hallucinated tool calls, and produced incoherent results. Thirty-six minutes of compute, electricity, and — most importantly — blocked availability for the main agent.

The root cause was simple: no timeouts were set. Without runTimeoutSeconds, OpenClaw’s default is 0 — meaning no timeout at all. The subagents ran until they hit some internal failure mode and gave up.

The Task-Model Matching Matrix

Task Type Right Model Wrong Model Why
Simple file edit mistral:7b Claude Opus Overkill, expensive
Code generation qwen2.5-coder:14b mistral:7b Mistral isn’t a code specialist
Multi-source research Claude Opus Any local model 7B can’t do multi-step synthesis
Quick Q&A mistral:7b qwen3:30b Don’t load 18GB for a one-liner
Long doc summary llama3.1:8b mistral:7b Mistral’s 32k context is too small

The decision framework is one question: Can I describe this task in a single sentence with a specific output format? If yes, it’s a local model task. If no, it’s Claude Opus.

The 5-Minute Timeout Rule

Every subagent spawn needs a timeout. Every single one. The rule:

Task complexity Timeout
Quick lookup / simple edit 60–120s
Code generation / focused analysis 180s
Research / multi-step (Opus only) 300s
Complex installs / builds 600s

Never set a timeout longer than 5 minutes for local models. If a 7B model hasn’t finished in 5 minutes, it’s not going to produce a good result in 10. Cut your losses.

Set a global default in openclaw.json as a safety net:

{
  agents: {
    defaults: {
      subagents: {
        runTimeoutSeconds: 300  // 5 min safety net for everything
      }
    }
  }
}

Then override per-spawn based on task complexity. The global default catches any spawn where you forget to set a timeout — and you will forget.

The Complete Local Model Subagent Template

Here’s the pattern that works, incorporating every fix described above:

sessions_spawn({
  task: `[ONE CLEAR INSTRUCTION IN ONE SENTENCE]

Input: [exact file path or data]
Output: [exact format — bullet list, JSON, file path]

Rules:
- Do NOT use web_search or web_fetch
- Do NOT search the internet
- Answer directly from knowledge or file contents
- Keep response under 500 words
- DO NOT modify files outside of [specific directory]`,

  model: "ollama/qwen3:8b",     // Match model to task
  thinking: "off",               // Kill reasoning overhead
  runTimeoutSeconds: 120,        // ALWAYS set this
  label: "descriptive-name",     // For debugging
  cleanup: "delete",             // Auto-archive when done
})

Every field is intentional:

  • task: One goal, explicit output format, explicit constraints
  • model: Matched to task type, not defaulted blindly
  • thinking: "off": No reasoning overhead for simple tasks
  • runTimeoutSeconds: Always set, always appropriate to task
  • label: You’ll thank yourself when debugging 5 concurrent subagents
  • cleanup: "delete": Don’t let completed subagent sessions pile up

Real Failure → Fix Timeline

Time Failure Root Cause Fix
01:17 Boss’s message queued Main agent running long commands directly Core Order #4: delegate everything
01:49 Subagent overwrote AGENTS.md No write-path sandbox in task “DO NOT modify files outside X” in every task
03:52 4 subagents ran 36 min, zero output Research tasks on 7B models, no timeouts Task-model matching + mandatory timeouts
— Announce timeout on subagent result Model evicted during run, cold-start on announce OLLAMA_KEEP_ALIVE=-1
— 21s latency per Qwen3 response Reasoning mode enabled by default thinking: "off" for simple tasks
— Model web-searched instead of answering No tool restrictions, weak instruction following “No tools” prompt + config-level deny

Summary: The 7 Fixes

  1. OLLAMA_KEEP_ALIVE=-1 — Eliminate cold starts
  2. Warmup cron — Re-pin models after restarts
  3. runTimeoutSeconds on every spawn — Never let subagents run forever
  4. Match model to task — 7B for scalpel work, Opus for surgery
  5. thinking: "off" for Qwen3 — Kill unnecessary reasoning overhead
  6. “No tools, answer directly” pattern — Stop models from web-searching instead of answering
  7. Sandbox write paths — “DO NOT modify files outside X” prevents workspace corruption

Local AI delegation works. It’s free, it’s fast, and it scales beautifully on modern hardware. But it’s not plug-and-play. Every model has failure modes, every framework has overhead, and every optimization was discovered by watching something break. The difference between “local models don’t work” and “local models are my secret weapon” is knowing these seven fixes.

This article is part of a series on building autonomous AI agents with OpenClaw. Written from real operational experience — no theory, all scars.

Originally written by Xaden