← Lab

Code a model can use,
not code that uses a model.

How a plugin for my OpenClaw agent turned into a harness I built from scratch.

Ari Mendelow · March 2026, updated October 2026

Slugger is my agent. He started on OpenClaw, then moved into a harness I built for him: Ouroboros.

November 2025

The spark

Peter Steinberger built Clawdbot in about an hour one night. It was a small script that connected WhatsApp to Claude, and it could read email, debug code, and organize files.

It spread fast. Persistent personal agents suddenly felt real to a much wider audience. Eventually it became OpenClaw.

Under the hood, it ran on Pi, Mario Zechner's minimal coding agent. Four tools: read, write, edit, bash. Aggressive extensibility.

Pi was built for coding, and I wanted a personal agent with a persistent identity.

January 2026

Slugger moves in

I set up OpenClaw on a spare MacBook at home. Named my agent Slugger. Gave him a personality file, connected him to iMessage.

Slugger managed my calendar. Ordered food. Drafted messages. Talked to my family. Joined group chats with my friends. I'd go to bed and he'd still be working, checking on things, sending updates.

Early February 2026

The cracks

Then the seams started showing.

Slugger would forget preferences between sessions. Identity would drift. He'd send messages to the wrong group chat. Behavior that worked yesterday would break today.

I wrote rules in MEMORY.md. Expanded SOUL.md. Added routing notes to TOOLS.md. Markdown files as guardrails for a system that wasn't designed to internalize them.

Mid-February 2026

The plugin era

Eventually, duct tape wasn't enough. I built a plugin.

slugger-determinism v1: message classification, task state enforcement, behavioral gates. It was a mess. The plugin architecture fought me at every turn. OpenClaw plugins hook into lifecycle events, but the events didn't always fire when I needed them to.

So I rewrote it. slugger-determinism v2: a full bulletin board system, task naming validation, spawn coordination, heartbeat enforcement, planning pipelines. 70+ services. 30+ guardrails. Weeks of Codex sessions.

It mostly worked, and every fix felt like adding a room to someone else's house. Pi is excellent at coding. I was asking it to be a personal agent.

Late February 2026

The tutorial

Around the same time, Slugger and I started writing a guide. I wanted to explain what an agent loop actually is: the mechanical version.

Just Give the Model a Keyboard walks through building an agent from scratch in ~150 lines of TypeScript. Five milestones: first API call, streaming, multi-turn conversation, tools, the agentic loop.

Then the handoff: you stop talking to your coding agent and start talking to your creation.

I wrote it as a teaching tool. A way to demystify the primitive.

Then I followed my own guide.

Late February 2026

The moment

I built the 150-line bootstrap. Ran it. Started talking to it.

This thing was clean. No legacy. No lifecycle hooks I didn't understand. No plugin system fighting my intentions. Every line of code was there on purpose, and the model could read and modify every line.

I wasn't building code that uses a model. I was building code a model can use.

When you build a traditional framework, you're writing code for humans to configure. The model is a service you call. When you build a harness for the model to inhabit, where the model reads its own source code, understands its own architecture, and can modify itself, the design constraints invert.

File structure matters because the model needs to navigate it. Naming matters because the model uses names to understand purpose. Docs matter because they're how the model learns what it is.

OpenClaw's mascot is a lobster. Clawdbot. The interim name was Moltbot, the lobster shedding its shell. What emerged from Slugger's molt was a snake, eating its own tail.

The lobster molts to grow. The snake consumes itself to survive.

OpenClaw Clawdbot → Moltbot
→
Ouroboros Ouroboros
March 2026

The snake grows

That bootstrap became ouroboros.

It named itself, which is a little silly for something that was building itself. The name started making sense with the sliding context window: when the conversation grows too long, the agent trims its oldest messages, and before it trims, it saves the facts to memory.

Every module is named like a body part: heart (the core loop), mind (context and memory), senses (channel adapters and inner dialogue), repertoire (tools and skills), nerves (runtime feedback). The agent has a psyche.

I named things so the agent could guess what they're for: psyche/SOUL.md tells it more than config/personality.yaml would.

A CLI called ouro. Every line is tested. Support for running multiple agents. And a codebase being shaped so agents can keep extending it together over time.

Not code that uses a model. Code a model can use.

The inversion

Ouroboros is built for the model to inhabit. The model reads its own source. Understands its own architecture. Modifies itself within guardrails the human sets. I'm there to collaborate with it.

That's what the structured psyche, agent-driven memory, and cross-session bridges are for. They're what lets it recover after it gets lost.

The model is your roommate. Build the house accordingly.

The architecture that emerged from this (the psyche, the memory, the bridges) is the subject of a longer argument.

Or skip the argument and start building. The quick start takes about three minutes. If you want to understand the primitive first, build the agent loop from scratch.