Skip to content
🎓 Find your path Subscribe

The Pivot to a Claude Code Custom Harness

Tier 3 · Everything Built 7 min read

In early April 2026, the OpenClaw spec document noted a persistent problem with the Telegram bridge and floated the idea of switching channels or pivoting the architecture. The pivot that actually happened wasn’t to a different messaging backend — it was to a different philosophy for what a harness should be.


OpenClaw was roughly 3,500 lines of custom TypeScript and Python building a runtime: a loop, a tool-dispatcher, a memory layer, a router. Every new capability meant extending that runtime. The Telegram bridge had been unreliable for months. The research loop worked, but the maintenance surface was growing faster than the capability surface.

Claude Code already solved the core problem: it provided a loop, tools, file access, and a way to communicate. Rather than continuing to build around it, the decision was to build on top of it — to make Claude Code the runtime and wrap it in the infrastructure the system actually needed.

That’s what “custom harness” means here. Not a new agent runtime; a set of conventions, files, and automation layers that make the existing runtime do exactly what the operator needs.


What “Wrapping Claude Code” Means Concretely

Section titled “What “Wrapping Claude Code” Means Concretely”

The first dated entries in the master CHANGELOG (2026-04-10 through 2026-04-16) show what this looked like in practice. No new runtime was written. Instead:

A claude process in tmux, under launchd. The always-on part of the system is a Claude Code session kept alive as a macOS LaunchAgent (com.jd.claude-telegram-daemon). The self-healer monitors it and kicks it back up if it falls over. When a Telegram message arrives, it routes to this session.

State in files, not conversation memory. The CLAUDE.md files — a global one at ~/.claude/CLAUDE.md and a project-level one at ~/agent-system/CLAUDE.md — give the agent its standing instructions, domain knowledge, and behavioral rules. These persist across session rotations (which happen when the context window fills, roughly at the 1M token limit). The agent reads them at the start of every session; its “memory” is the file system, not the chat history.

Per-project state: each project at ~/clawd/projects/<slug>/ carries a WORKPLAN.md, CHANGELOG.md, and LINKS.md. Per-domain state: each of the 8 domains has ~/clawd/domains/<domain>/state/*.yaml files. The master CHANGELOG at ~/clawd/CHANGELOG.md is the append-only log of everything that ships, auto-aggregated from per-project logs by daily-rollup.sh.

Cron jobs as the heartbeat. Rather than a custom event loop, the system uses the OS scheduler. By 2026-04-16, there were 8 domain heartbeats firing hourly, staggered at :03–:52 intervals. Today the count is roughly 155–160 jobs across approximately 87 scripts (the ARCHITECT-BRIEF index as of 2026-06-10). Each job is a script that reads state, takes an action, and writes results back to files.

Telegram via an inbound router. The bridge that OpenClaw couldn’t stabilize was replaced by a simpler architecture: an inbound router script (telegram-inbound-router.sh) intercepts messages, handles the command palette (/status, /tasks, /loops, etc.), and hands off to the Claude session. The session replies via the mcp__plugin_telegram_telegram__reply MCP tool. The CLAUDE.md rule is non-negotiable: every Telegram response must call the reply tool — text output alone never reaches the operator.


Three engineering rules emerged in this period that became load-bearing for everything after:

Files beat conversation memory. Any state that needs to outlive a session goes to a file. The agent reads it fresh on startup. This includes per-session task logs (~/agent-system/logs/tasks/YYYY-MM-DD.md), domain reports (state/report.md), and the master CHANGELOG. The rule is explicit in CLAUDE.md: “If I ask you to remember something across sessions, write it to a file.”

Instrument before you trust. The 2026-04-16 hardening pass installed the stale-cron alerter, the self-healer, the MCP health check, and the budget hard-stop. Not because the system was broken, but because you can’t trust what you can’t measure. The CHANGELOG entry from that day: “instrumentation that makes imperfection visible.”

Root-cause first, bandaids never. When something went wrong, the standing rule became: diagnose the root cause (five whys, not one), fix the process, backfill existing instances, add a regression guard, then patch the symptom. The symptom patch is often redundant by step 3. This rule is documented verbatim in CLAUDE.md and is treated as a core operating principle, not a suggestion.


Building a harness on top of Claude Code rather than a custom runtime means you inherit the constraints of the runtime: session rotation at ~1M tokens, the specific tool set, Claude’s rate limits, the billing model. You don’t get to design the loop from scratch.

What you gain: you don’t maintain a runtime. Claude Code handles the tool dispatch, the context management, the retry logic, the MCP server integration. The operator’s job narrows to: write good CLAUDE.md files, design the right file structures, wire the crons, and build the integrations Claude Code doesn’t provide natively (Telegram, voice, domain-specific MCP servers).

That’s the trade. Whether it’s worth it depends on how much of the value you were trying to build was in the runtime versus the application layer above it. For this system — where the value is in the domain knowledge, the orchestration rules, and the integrations — wrapping Claude Code was the right call.


Next: The File-Based Second-Brain Infrastructure — the specific file conventions, the append-only master CHANGELOG, and the rollup pipeline that make the system’s memory of itself possible.