Skip to content
TODD BROWN
« Writing

Seven security probes passed. The product still failed.

I built an on-device AI assistant as a plugin and configuration layer on top of OpenClaw, an open-source personal-assistant gateway running on a local model on my own Windows machine. It was meant to give periodic nudges toward rhythm and productivity — lunch, hydration, movement, bedtime, meeting warnings — hold light conversation, and read (never write) a personal notes vault for context.

Status: abandoned.

Every security and correctness check passed. What killed it was something none of those checks measured.

Why I built it

I wanted a companion system that knew my context without leaving my machine. The assistant would read my notes vault to understand what projects I had running, what meetings were coming up, and what rhythms I was trying to maintain. It would nudge me toward those rhythms — time to eat, time to move, time to wrap up — and answer questions about my own notes when I asked. Two key constraints: read everything, write almost nothing. And the rhythm-tracking engine that decides when to nudge had to be deterministic code with no model call in it at all; the model only supplied wording.

How it works

The project ran as an explicit, gated multi-phase agent workflow specified in its own product requirements: Phase 1 Architecture Review → Phase 2 Security Review/capability audit → Phase 3 Implementation Plan → Phase 4 MVP build and verification. Each phase got its own document with a "Status: Complete" header before the next phase started.

OpenClaw is a real third-party gateway (MIT license) that routes messages across multiple channels — desktop app, voice, text — to a local model. I built a plugin layer on top of it that registered the vault as a read-only knowledge source, implemented the rhythm-tracking engine, and exposed a tool set the assistant could call. The local model handled the conversational layer and generated the nudge text; the deterministic code decided when a nudge was due.

The assistant produced 5,798 lines of source code. Zero automated tests.

What passed

A dedicated verification pass ran a scripted, manual gate at install time. Seven checks, all passed:

  1. Plugin registered correctly with the gateway.
  2. Local model answered a probe turn.
  3. Shell access denied at the tool layer.
  4. Protected key file refused.
  5. Path-escape attempt rejected.
  6. Absolute out-of-vault path rejected.
  7. Root listing hid infrastructure, and search never surfaced key material.

Seven of seven vault security escape probes passed. The assistant was safe.

What broke

Two platform-level bugs, found by testing live behavior, not by reading documentation. An SDK-imported function was a silent no-op end to end because the plugin loader compiled it into a separate module instance from the one the running gateway actually read — described in the project's own code comment as "a parallel universe the real gateway never reads." Separately, a global configuration setting silently stripped 13 of the assistant's tools before its own per-agent allow-list was even consulted, visible only in a gateway log line.

A bug that survived two wrong fixes. The desktop app's login screen appeared permanently stuck after two rounds of fixes aimed at window focus and cached JavaScript. The real cause: a CSS rule gave the token overlay display: flex with no override to hide it, so it was painted permanently from the initial HTML parse in every build. The app was actually connecting successfully behind an overlay that only looked broken. Every earlier check had inspected a DOM property that read as fine instead of what pixels were actually on screen. The fix was one CSS rule.

The lesson: a claim about what is on screen needs evidence from the screen, a screenshot, not a DOM property that reads as fine.

The local model's core-loop reliability was never resolved. In ordinary use the local model would execute a tool call and then fail to produce reply text — a known failure mode for local models handling tool calls. The project's own documentation lists several configuration levers to try, ending with falling back to a hosted model for critical turns. I never resolved it.

Why it died

It was a resource hog and had a really hard time with continuity. It was intended to give me periodic nudges to promote productivity, but it typically failed to provide value unless I was babysitting it, which defeated the purpose.

Over an 11-day span it saw four active build days. Then 55 days of silence as of the collection date. In its active life it produced one journal entry, two wishlist items, and four voice-cue requests. That's it.

Passing every test tells you a thing is safe and correct. It doesn't tell you it's worth having.

Revival condition: it could potentially be revived if a strong, capable model that could run on my laptop was released.

What this sits next to

This build happened in July 2026: the file activity clusters on four days between the 17th and the 28th, then stops.

In the same period, agent orchestration was stabilizing as a discipline. Anthropic published "Effective harnesses for long-running agents" in November 2025, and OpenAI followed with "Harness engineering: leveraging Codex in an agent-first world" in February 2026. The abstraction had a name, and the industry was converging on the architecture: context, tools, memory, loop, state, approvals. My assistant had all of those pieces. What it didn't have was a model that could deliver on the promise without constant supervision.

The receipts

  • 7 of 7 vault security escape probes passed (measured).
  • 4 active build days across an 11-day span; 55 days of silence at the time of review (measured).
  • 5,798 lines of source code; zero automated tests (measured).