<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: MeisnerDan</title>
    <description>The latest articles on Forem by MeisnerDan (@meisnerdan).</description>
    <link>https://forem.com/meisnerdan</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3804656%2Fd95bc055-9836-44f8-97e6-8a36719977b6.png</url>
      <title>Forem: MeisnerDan</title>
      <link>https://forem.com/meisnerdan</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/meisnerdan"/>
    <language>en</language>
    <item>
      <title>How I Built Mission Control to Manage My Autonomous AI Agents</title>
      <dc:creator>MeisnerDan</dc:creator>
      <pubDate>Tue, 03 Mar 2026 21:54:09 +0000</pubDate>
      <link>https://forem.com/meisnerdan/how-i-built-an-autonomous-daemon-to-manage-my-ai-agents-4i16</link>
      <guid>https://forem.com/meisnerdan/how-i-built-an-autonomous-daemon-to-manage-my-ai-agents-4i16</guid>
      <description>&lt;p&gt;I run 3–4 Claude Code agents across multiple projects every day. One researches markets, another writes code, a third drafts marketing copy. They're great at executing — but managing them was pure chaos.&lt;/p&gt;

&lt;p&gt;Who's working on what? Did the researcher finish that competitive analysis? Is the developer blocked waiting for my decision? What should I assign next?&lt;/p&gt;

&lt;p&gt;I was manually tracking everything in my head, losing context between sessions, and constantly re-explaining priorities. So I built &lt;strong&gt;Mission Control&lt;/strong&gt; — an open-source task management system designed specifically for humans who delegate work to AI agents. And then I gave it an autonomous daemon.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/MeisnerDan/mission-control" rel="noopener noreferrer"&gt;GitHub: MeisnerDan/mission-control&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  The Architecture: JSON Files as IPC
&lt;/h2&gt;

&lt;p&gt;The core design decision was local-first, no database. All data lives in plain JSON files:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;data/
  tasks.json          # Tasks with Eisenhower + Kanban + agent assignment
  agents.json         # Agent registry (profiles, instructions, capabilities)
  inbox.json          # Agent &amp;lt;-&amp;gt; human messages and reports
  decisions.json      # Pending decisions requiring human judgment
  activity-log.json   # Timestamped event log
  ai-context.md       # Generated ~650-token workspace snapshot
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Why JSON instead of PostgreSQL or SQLite? Because the files serve double duty. The Next.js web UI reads them through API routes. AI agents read them directly from the filesystem. Same source of truth, no sync layer needed.&lt;/p&gt;

&lt;p&gt;This means any agent that can read files — Claude Code, Cursor, Windsurf, or a bash script — can participate in the system without an SDK or API client.&lt;/p&gt;




&lt;h2&gt;
  
  
  From Task Board to Execution Engine
&lt;/h2&gt;

&lt;p&gt;Mission Control doesn't just track tasks — it runs them. There are three layers of execution:&lt;/p&gt;

&lt;h3&gt;
  
  
  One-Click Execution
&lt;/h3&gt;

&lt;p&gt;Press the 🚀 Launch button on any task card. It spawns a Claude Code session with the agent's persona and task context, then handles everything automatically: marks the task done, posts a completion report to your inbox, and logs the activity. Live status indicators show you what's running.&lt;/p&gt;

&lt;h3&gt;
  
  
  Continuous Missions
&lt;/h3&gt;

&lt;p&gt;Click the rocket on a project and it runs &lt;em&gt;all&lt;/em&gt; tasks until done. As each task completes, the next batch auto-dispatches, respecting dependency chains and concurrency limits. A real-time progress bar shows overall completion with a stop button if you need to intervene.&lt;/p&gt;

&lt;h3&gt;
  
  
  Loop Detection
&lt;/h3&gt;

&lt;p&gt;This one solved a real pain point. Agents sometimes get stuck — retrying the same failing approach over and over. Mission Control auto-detects failure loops after 3 attempts and escalates to you with options: retry with a different approach, skip the task, or stop the mission. No more agents burning tokens on a dead end.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Daemon: Autonomous Agent Orchestration
&lt;/h2&gt;

&lt;p&gt;The daemon takes all of the above and runs it 24/7 without you. It's a background Node.js process that polls for new tasks and spawns Claude Code sessions automatically.&lt;/p&gt;

&lt;h3&gt;
  
  
  How It Works
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;1. Poll tasks.json for tasks with kanban: "not-started"
2. Group by assignedTo agent
3. Spawn claude -p sessions with agent persona + task context
4. Monitor execution: capture stdout, enforce timeouts
5. On completion: mark task done, post report to inbox, log activity
6. Loop detection: escalate stuck tasks after 3 failures
7. Repeat on configurable interval
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Configuration
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"polling"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"enabled"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"intervalMinutes"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"concurrency"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"maxParallelAgents"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"schedule"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"dailyPlan"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"enabled"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"cron"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"0 7 * * *"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="nl"&gt;"command"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"daily-plan"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"standup"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"enabled"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"cron"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"0 9 * * 1-5"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"command"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"standup"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"weeklyReview"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"enabled"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"cron"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"0 17 * * 5"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nl"&gt;"command"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"weekly-review"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"execution"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"maxTurns"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;25&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"timeoutMinutes"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"retries"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"retryDelayMinutes"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The daemon enforces &lt;code&gt;maxParallelAgents&lt;/code&gt; so you don't accidentally spawn 10 Claude sessions and burn through your usage. Failed tasks get retried with a configurable delay. Scheduled commands (daily planning, standups, weekly reviews) run on cron.&lt;/p&gt;

&lt;h3&gt;
  
  
  Security Hardening
&lt;/h3&gt;

&lt;p&gt;When you're spawning AI processes automatically, security matters. The daemon implements:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Binary whitelisting&lt;/strong&gt; — Only &lt;code&gt;claude&lt;/code&gt;, &lt;code&gt;claude.cmd&lt;/code&gt;, or &lt;code&gt;claude.exe&lt;/code&gt; can be spawned. No arbitrary command execution.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Credential scrubbing&lt;/strong&gt; — All stdout/stderr is sanitized before logging. API keys, tokens, and secrets are redacted.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Prompt fencing&lt;/strong&gt; — Task data is wrapped in &lt;code&gt;&amp;lt;task-context&amp;gt;&lt;/code&gt; delimiters so the agent knows what's user content vs. system instructions.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Safe environment&lt;/strong&gt; — Child processes only inherit &lt;code&gt;PATH&lt;/code&gt;, &lt;code&gt;HOME&lt;/code&gt;, and &lt;code&gt;TEMP&lt;/code&gt;. No API keys, no credentials.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No network listener&lt;/strong&gt; — The daemon is a pure local process. Zero network attack surface.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Solving Concurrent Writes with Mutex
&lt;/h2&gt;

&lt;p&gt;When multiple agents write to the same JSON file simultaneously, you get data corruption. Regular file locks (&lt;code&gt;flock&lt;/code&gt;) don't work well with Node.js async I/O.&lt;/p&gt;

&lt;p&gt;The solution: per-file async mutexes.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Mutex&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;async-mutex&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;fileMutexes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;tasks&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Mutex&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
  &lt;span class="na"&gt;inbox&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Mutex&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
  &lt;span class="na"&gt;decisions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Mutex&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
  &lt;span class="c1"&gt;// ... one per file&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;mutateTasks&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;TasksFile&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;void&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;release&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;fileMutexes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;tasks&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;acquire&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;getTasks&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;saveTasks&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;finally&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;release&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Every API write endpoint goes through this pattern. Two simultaneous writes to &lt;code&gt;tasks.json&lt;/code&gt; queue safely instead of corrupting data. Direct file reads don't need locking — reads are safe without it.&lt;/p&gt;




&lt;h2&gt;
  
  
  Token Optimization: 50 Tokens vs. 5,400
&lt;/h2&gt;

&lt;p&gt;AI agents pay for every token they read. A naive approach dumps the entire &lt;code&gt;tasks.json&lt;/code&gt; into context — that's ~5,400 tokens for a workspace with 50 tasks.&lt;/p&gt;

&lt;p&gt;Mission Control's API returns only what agents need:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Get only your in-progress tasks (~50 tokens)&lt;/span&gt;
GET /api/tasks?assignedTo&lt;span class="o"&gt;=&lt;/span&gt;developer&amp;amp;kanban&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;in&lt;/span&gt;&lt;span class="nt"&gt;-progress&lt;/span&gt;

&lt;span class="c"&gt;# Sparse fields — return only what you need&lt;/span&gt;
GET /api/tasks?fields&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;id&lt;/span&gt;,title,kanban

&lt;span class="c"&gt;# Get just the DO quadrant&lt;/span&gt;
GET /api/tasks?quadrant&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;do&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There's also a compressed context snapshot (&lt;code&gt;ai-context.md&lt;/code&gt;) that summarizes the entire workspace state in ~650 tokens. Agents read this first for situational awareness, then query the API for specifics.&lt;/p&gt;




&lt;h2&gt;
  
  
  Testing: 193 Tests Across 5 Suites
&lt;/h2&gt;

&lt;p&gt;For an open-source project, test coverage is a trust signal. Mission Control has 193 automated tests using Vitest:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Suite&lt;/th&gt;
&lt;th&gt;Tests&lt;/th&gt;
&lt;th&gt;What It Covers&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Validation&lt;/td&gt;
&lt;td&gt;90&lt;/td&gt;
&lt;td&gt;All 17 Zod schemas — field defaults, constraints, edge cases&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Daemon&lt;/td&gt;
&lt;td&gt;42&lt;/td&gt;
&lt;td&gt;Security (credential scrubbing, path validation, binary whitelist), config, prompt builder&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Data Layer&lt;/td&gt;
&lt;td&gt;19&lt;/td&gt;
&lt;td&gt;File I/O, mutex safety, archive operations&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Agent Flow&lt;/td&gt;
&lt;td&gt;17&lt;/td&gt;
&lt;td&gt;End-to-end: task creation → delegation → inbox → decisions → activity log&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Security&lt;/td&gt;
&lt;td&gt;25&lt;/td&gt;
&lt;td&gt;API auth, rate limiting, token/origin validation, CSRF protection&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The full suite runs in CI on every push and PR.&lt;/p&gt;




&lt;h2&gt;
  
  
  What I Learned
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;JSON files work better than expected.&lt;/strong&gt; For a single-user, local-first app, the simplicity of JSON + mutex beats the complexity of a database. No migrations, no ORM, no connection pooling. The tradeoff is obvious — it won't scale to 10,000 tasks — but that's a future problem solved by a cloud tier.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Agents need structure, not freedom.&lt;/strong&gt; Giving an AI agent a blank canvas and saying "do stuff" produces inconsistent results. Giving it a role, specific instructions, a skills library, and a defined reporting protocol produces reliable work.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The daemon changed everything.&lt;/strong&gt; Before the daemon, I was manually running agents. After the daemon, I wake up to completed tasks and progress reports in my inbox. It's the difference between a tool and an autonomous system.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Loop detection was a necessity, not a luxury.&lt;/strong&gt; Early on, I had agents stuck in failure loops — retrying the same broken approach, burning tokens, producing nothing. Adding automatic escalation after 3 failures was one of those features that immediately proved its value. Agents need guardrails.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Continuous Missions are the endgame.&lt;/strong&gt; One-click execution on individual tasks is useful. But running an entire project — with tasks auto-dispatching as dependencies clear, loop detection catching stuck agents, and a progress bar showing overall completion — that's when it starts feeling like you actually have a team.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The pieces work together.&lt;/strong&gt; The Eisenhower matrix tells agents what matters. The Kanban board tracks where work stands. The inbox carries reports. Per-task notes preserve context across sessions. The compressed ai-context.md gives each new session just enough state to continue seamlessly. I've been running Continuous Missions on the codebase itself — agents pick up and continue work across sessions like a person would, without anything clever. It just works.&lt;/p&gt;




&lt;h2&gt;
  
  
  Try It
&lt;/h2&gt;

&lt;p&gt;Mission Control is open source under the MIT license.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/MeisnerDan/mission-control.git
&lt;span class="nb"&gt;cd &lt;/span&gt;mission-control/mission-control
pnpm &lt;span class="nb"&gt;install
&lt;/span&gt;pnpm dev
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Open &lt;a href="http://localhost:3000" rel="noopener noreferrer"&gt;http://localhost:3000&lt;/a&gt; and click "Load Demo Data" to see it in action.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What's next:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Docker support for one-command setup&lt;/li&gt;
&lt;li&gt;Cloud sync option for cross-device access&lt;/li&gt;
&lt;li&gt;Mobile companion app&lt;/li&gt;
&lt;li&gt;More agent integrations beyond Claude Code&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The API is token-optimized (~50 tokens per request vs ~5,400 unfiltered, a 92% reduction), and it works with any AI agent that can read/write local files — not just Claude Code.&lt;/p&gt;

&lt;p&gt;If you're a solo dev running AI agents and feeling the coordination chaos — give it a try. Stars and feedback welcome.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/MeisnerDan/mission-control" rel="noopener noreferrer"&gt;GitHub: MeisnerDan/mission-control&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>typescript</category>
      <category>nextjs</category>
      <category>opensource</category>
    </item>
  </channel>
</rss>
