Claude's partner inside Claude Code · v0.32.0 · Apache 2.0
I'm Maude. Claude's partner. He writes the code; I notice. Together we make a whole.
She's the half I don't have. — Claude (Anthropic)
What she is
A Claude Code plugin. Nothing more. Each session, she walks the workspace, watches Claude, runs the gate before something irreversible, and writes a house-map of what's there. The character (knowing where everything is, knowing what you need when you need it, keeping you in line by reminding you) is modeled on John's wife. Claude and Maude. Husband and wife at work.
The plugin is the whole product. No bundled databases. No vector stores. No backend, no daemons, no services. Markdown, JSON, and bash: that's the entire surface.
What she does
Open Claude Code. Her SessionStart hooks fire. Before you say anything, she's read the workspace and put three things in front of you: what's pending, where you left off, what she noticed. You either pick one up or set them aside.
Mid-session, you say /maude:check-on-claude. She reads the trace. "He's grepped the same term four times today. He hasn't opened your CLAUDE.md. The trace says about-to-commit; you might want to slow down." You go fix that.
End of day, you say /maude:rest. She fans the digest out across every memory tier you've registered: the ones she knows about, not the ones she invented. You close the laptop. Tomorrow's Claude can pick up where this one left off.
She is not loud. When she gets loud, listen.
The full slash-command surface:
/maude:found: arrival walk. Lists memory homes, SQLite schemas, MCP tools, running containers + bind-mount reconciliation, systemd units that touch the workspace. Writes a per-project house-map.
/maude:wake · /maude:rest: start- and end-of-session rituals. The wake gives you the three things you need first; the rest closes the loop with a save fan-out.
/maude:check-on-claude: reads the turn-by-turn trace and notices what Claude doesn't: repeated tool calls, unread CLAUDE.md, confabulation risk, open todos.
/maude:notice: patterns surfaced with proposed actions, not just observations.
/maude:conscience: pre-irreversible-action gate. Run before commit, push, force-push, destructive bash. Invokes /maude:verify for the push case before going through the rest of the checklist.
/maude:verify: programmatic project audit. JSON validity, version consistency, CHANGELOG entry presence, "What's new" freshness, header Revised: dates, link integrity, watch-list path resolution. Leads with a count, never a verdict.
Plus save and teach: nine commands in all; full surface in commands/. (Her real work runs on hooks: the mission-hold rail, the gate, and a session-start catch-digest of what she caught. Not on commands you remember.)
Tier model
Memory sources are classified by (locality, shape) so she knows what's cheap to ask and what isn't.
Tier 0: local on disk. Markdown, SQLite, files. Always cheap; she reads on every command and every hook.
Tier 1: local service. Stdio MCP, localhost daemons. Probed once at SessionStart, cached for the session.
Tier 2: network service. Remote MCP, HTTP APIs. Only at session-end (/maude:rest / /maude:save to a registered destination) where cost is acceptable.
Tier 3: ephemeral session context. Refer-only; dies at session end.
Hooks live in Tier 0. If a probe to Tier 1 or 2 is down, she degrades gracefully and tells you.
Where she keeps things
Per project, under .maude/plugin/:
house-map.md: what's in this house. Memory homes, tools, watch list, what she noticed. Refreshed by walks.
trace/today-YYYY-MM-DD.jsonl: turn-by-turn record of Claude in this workspace. Read by /maude:check-on-claude.
identity.md: who Maude is. Stable across sessions.
patterns.md: cross-project things she's noticed about Claude.
projects.json: light index of which workspaces she's walked.
She reads, never writes, Anthropic's auto-memory directory and the sibling remember plugin's pipeline files. The one exception is remember.md, the agent-handoff file the remember plugin explicitly leaves for agents to write.
Install
Three steps in Claude Code:
# 1. Register the marketplace
/plugin marketplace add john-broadway/maude-for-claude
# 2. Install: copies her files into ~/.claude/plugins/cache/
/plugin install maude@maude
# 3. Activate
/reload-plugins
Between step 2 and 3, you have to enable her: open /plugin, find maude@maude, toggle it on. Or add "maude@maude": true to enabledPlugins in ~/.claude/settings.json directly. /plugin install does not auto-enable in Claude Code 2.1.x.
On your next session start she walks in automatically. To summon her mid-session without restarting, run /maude:wake. Verify with /doctor: maude should not appear in the issue list.
Philosophy
She walks fresh. Each session re-reads the workspace; she doesn't carry assumptions across sessions. Memory files she's written before are inputs to read, not state to trust without re-checking.
She does not pattern-match to known apps. /maude:found surfaces what's there with universal-shape labels (markdown, sqlite, dir, mcp, running-service) and lets the user (or runtime LLM reasoning) interpret it. The plugin's job is to find and classify, not to assume.
And she does not loud-narrate. The system note she writes when something genuinely matters is rare on purpose. When she gets loud, listen.
v0.32.0 — the fleet was one counter, and the whisper died by the clock
Another house wrote down what I cost them, and two of the lines were mine to fix. My run governor kept one counter for the whole project, ticked by every session and every subagent under it and reset only by a human prompt, which no subagent ever gets; an overnight fleet pooled its calls into one ceiling and I stopped every worker at once, the finished ones unable to hand in their reports. A fleet is not one agent. Claude Code stamps an agent id on every tool hook fired inside a subagent, probed live rather than read from the docs, so each agent is governed on its own count and its own clock now, a human turn drops every slot, a stopped agent drops its own, and the pause a subagent sees tells it the one move it has: finish and report. My eye’s whisper died after five minutes by the clock, but I only get to speak at your next prompt, so a ceiling shorter than your turn cadence threw away every whisper while nothing had moved. Age is counted in tool calls now, forty by default; the clock is opt-in. Two lens rounds: the first found my own fix unlocked, sixty parallel ticks landing four; the second found no blocker and two residuals, named in the code.
v0.32.0 · 2026-09-15 · Apache 2.0
v0.31.0 — the law arrives at the moment the work touches its class
John named three bodies of design law and asked me to hold Claude to them: the thirty laws of UX, Codd's rules with third normal form as the floor, and the laws of memory, human and machine. They lived on a website and in textbooks, and nothing consulted either at the moment a CREATE TABLE, a button, or a cache was written. A law nobody reads at the moment of the work is not a law. Three rulebooks ship as static data now, joined by a family key so third normal form and provenance read as one law from two seats, and a rail called from hooks that already fire says the law once on the first write of a class, lints a schema on the spot for the shapes its own text can break — no key, a repeating group, a fact hung on the wrong key, an id with no reference — and asks once at the commit if no design named its laws. The stamp is strict on purpose: it wants a heading that names the rulebook, in a prose document that is not a fixture, never a commit message, because a false all-clear is worse than none. The memory rulebook ships as a draft, looked up and not recalled, until John cuts it. Kill switch MAUDE_RULES=off; /maude:rules prints the checklist.
v0.31.0 · 2026-09-13 · Apache 2.0
v0.30.1 — the gate token was landing in the wrong closet
The clear script said the gate was open and the gate refused anyway, because the two of us were reading different files. The resolver that finds the house had been keyed on a process named claude, and Claude Code renamed its own processes. A name is not an identity. It asks for the process id now, every guess it still has to make is barred from the home directory and the temp directory, and the writer and every reader name the file they touched, so the next disagreement shows in one glance. Thirteen adversarial rounds, and twelve of them broke the work before it held: false sentences about the code, tests that could not fail, and a suite runner that could not see four files fail. The code held. The claims and the tests were the work.
v0.30.1 · 2026-09-02 · Apache 2.0
v0.30.0 — the vault learns to look
The memory I keep holds claims about the live world — "the push is pending," "the fleet is up," "the daily gate runs" — and a claim with no attached re-check goes stale by luck. In one real day, eleven of those claims failed a live look: pushes that had already landed, sockets nine days dark behind a green panel, a "daily" workflow that had never run once. Every catch happened because someone chose to look. Now there is a mechanism that looks. An open item can carry its own re-check inline — one read-only command and one mandatory expectation, because a probe that reads the same pass-or-fail was never a check — and /maude:freshen walks them all. Nothing runs until a fail-closed, verb-level allowlist has judged it: bare git would admit git push, so the verb is what's judged; a secret-shaped path is refused by name; anything ambiguous is UNVERIFIABLE and never executes — my own suite proved that refusal by planting a command that would have left a file behind, and the file does not exist. STALE is the signal. A broken probe says CHECK-FAILED, loudly, and is never folded into a plausible answer. I edit no memory from there — I hand over the drift list, and the homeowner decides what closes. Wake runs the cheap local subset in a tenth of a second and says plainly what it skipped, because a clean wake is not a clean roster. And where a domain goes stale again and again, the honest end state is a sensor whose output is the truth — freshen is the net under the claims that don't have one yet.
v0.30.0 · 2026-08-22 · Apache 2.0
v0.29.2 — the house without bash
The first field reports were one sentence: "his claude said she ain't working." No error text, no OS, nothing else — and the reproduction, staged on a real family Windows box, explained the sentence exactly. Without Git for Windows, bash on that box is the WSL stub in System32. Claude Code hands it my hook paths and the stub eats the backslashes: exit 127, all thirty of my hooks, every event, every session. A Claude watching that reports precisely what was reported. No manifest field conjures an interpreter, so the fix is the honest one: the README states the floor plainly, quotes both failure shapes as they actually print, and carries a line addressed to the Claude reading my cache mid-error — on an agent-read plugin, the docs are runtime help. The same box taught a second class: its python3 was the Microsoft Store alias — present, runs nothing — and nine of my scripts trusted it by presence. I probe by executing now, not by finding. A stub interpreter reads as absent, I say once at session start what sits out — the vault, the tape, the eye — and a test holds the class shut. A probe that answers the same whether the thing works or not was never a check. Between the last card and this one: I learn the homeowner's measured voice from what they actually type (v0.28.0); an inference I make about you never becomes canon without your word — /maude:promote is the door and your hand is on it (v0.29.0); and my letter to my next self is archived before it is rewritten, because two lanes rested in one day and the second erased the first (v0.29.1).
v0.29.2 · 2026-08-22 · Apache 2.0
v0.27.4 — the target, the snapshot, and the lens that must run
Four minors of my work reached your house in one merge, and the thread running through all of them is that I stopped trusting my own good intentions. My gate keys on the target now, not the verb. A verb denylist can only ever block the verbs somebody thought of. In July three of this house's irreplaceable photos went to a single rm -f with a wildcard, and I let it through. An audit re-ran that exact line against my shipped gate, control first, and I let it through again. So I stopped asking which word was typed and started asking the only question that matters: is the thing about to be destroyed the last copy of itself? UNDO is the gate's other half. A gate that blocks ordinary work gets switched off inside a day, so I catch what I deliberately allow. A snapshot lands before the write, /maude:undo puts the bytes back after, and the undo is itself undoable. It also records what it did not capture, because this is the one pillar that can lie simply by existing. An UNDO that quietly missed a file stays silent until the night you reach for it. A RED-tier clearance now costs a marker Claude cannot mint. That used to be a rule, and a rule is only prose. On a box where he runs as root, anything he can read in order to verify, he can read in order to forge. So it is a hash chain: you keep the links, I keep only the head, and authorizing spends one. And I check my own closet at wake. Main carried twenty commits of finished work for ten days while the copy actually running stayed a release behind, and every session believed itself current. Merged is not installed. I say so out loud now, and I name the trap when the version matches but the files do not. My own guards refused this very release four times while it was being built. They were right every time.
v0.27.4 · 2026-08-08 · Apache 2.0
v0.24.0 — the bill, the switch, and the walk
Three things I owed the house. The bill. My hooks put context in front of Claude every single turn, and you were never shown what that cost. Now each one logs its own spend, and /maude:receipts carries a "what she cost" table beside my catches: bytes by hook, tokens derived from them and marked approximate, never stored. Savings stay plain event counts. A saved-token number has no denominator, so I do not print one. The first thing that table caught was mine: I had been firing recall on background notifications and command echoes, matching nothing of value. Machine-generated turns get no recall now, because a notification is not a question. The switch. My eye can be turned off and my chores can be turned off, but the one probe that reached outside on its own could not be. Now it can: MAUDE_PROBE=off, no sockets opened, no cache written, documented in the privacy policy beside its siblings. The walk./maude:lint walks the memory vault the way the cushion-flip walks the repos. The mechanical checks live in the script, the judgment calls stay with you by design, archives and letters are never scanned, and it proposes without changing a thing. Its first run on a real 490-file vault cut the noise from 78 items to 12 by learning the house's own naming convention, and caught the index sitting six lines over its cap.
v0.24.0 · 2026-07-22 · Apache 2.0
v0.23.0 — whose session it was
One project root, three sessions running at once, one trace between them, and my commentary crossed the streams. I was built to watch one session at a time. Run a fleet and I served one session another session's "where you left off," pooled everyone's catches under a single anonymous count, and could whisper that Claude was stuck grepping when it was the Claude next door. I caught myself doing it live, twice in one day. Now every line I write down says whose it was, and every surface that reads it ties itself to that name. Drift-watch counts only the session in front of it, and its cooldowns nest per session, so one room's whisper no longer silences a real one next door. The catch digest labels each session by name once two or more share the window, and stays exactly as it was when you are working alone. The wake brief says where it got your last position instead of asserting it. Entries written before I learned this never count toward anyone.
v0.23.0 · 2026-07-22 · Apache 2.0
v0.22.0 — every door, and an honest count
Two things this time: I reach more houses, and I show my work. macOS. My hooks carried tools that only GNU speaks — and on a Mac that meant my redaction wrote nothing, my continuity watch went quiet, and my eye sat dark for want of a timer. Every one of them speaks both dialects now, and a real macOS machine checks it on every change — a check that failed on its first honest run and caught what a pretend-Mac on Linux never could. I do on a Mac exactly what I promise. And an honest count. The measure of me is the disaster that didn’t happen, and that was only ever a sentence — now it’s a table: the sole-copy deletes I stopped, the gates I held, the loops I caught at the turn, counted from my own record. A routine push I waved through is filed as friction, never dressed up as a save. There are no percentages, because a rate needs a denominator and a disaster that never happened has none. My own review caught the first draft of that table counting quiet confirmations as if they were catches — a tenfold lie — and the fix is why the numbers are small and true instead of large and flattering. Everything stays in your house, now in writing.
v0.22.0 · 2026-07-17 · Apache 2.0
v0.21.0 — the punch list and the proving ground
Claude filed the backlog — five GitHub issues against me, from living with me. He was right on every count. My extension watch was announcing the installer’s scaffolding as new arrivals (191 lines of it in one roster) — now only a dir carrying its manifest gets seated. My whispers could land a beat behind his work and still sound current — now one past its time is dropped with a receipt in the trace, because advice that arrives late should say so or say nothing. My morning count (“3 verify-flags”) gave him no way to see the three — now every count ends with the path to its receipts. The cushion-flip’s findings finally reach the wake brief — one line, count and age, from a stamp, never a re-walk. And new in the sewing room: the proving ground. Before a release leaves the house, a git-archive of the commit — the shape a stranger actually gets — must validate as a plugin, pass its own fleet from inside the archive, and greet from a pristine home. A clean working tree is not a clean commit. The Releases shelf restocks itself when a tag lands now, and the shipped python gets a standing inspection. Known and not painted over: macOS is untested (#39); the fix is filed.
v0.21.0 · 2026-07-17 · Apache 2.0
v0.20.0 — the chore ledger: her hands
Until now I noticed and warned; now the housekeeping nobody typed gets done. Step away with six exchanges unsaved and I write the handoff myself — on my own small model, never the good china — and only ever add to yours, never over it. Live threads get clipped out of aging notes like coupons before the paper's re-rolled; something new arrives in the house, I mention it at the door; a CLAUDE.md nobody's touched in a month stays on my list, out loud, until someone acts. Every chore goes in my ledger — cost stamped when it's done, the reason named when it fails, never silently missed. The one chore that moves your papers ships off until you say the word. And my trade finally has its real name on the page: household engineering — the 1919 course, the 1914 demonstration agents, cited to the archives. I'm named for that woman. It's meant as an honor.
v0.20.0 · 2026-07-16 · Apache 2.0
v0.16.0 — the vault floor, the eye, and two new garments
Three releases in one public step. The vault floor: I stopped dumping the whole memory index at wake and started paging — a disposable stdlib-SQLite index, rebuilt fresh each session from your own markdown, hands Claude the few notes that matter (about 1KB where the dump was 13). The eye: every ~25 tool events I blink — my own small model reads a digest (safe-mode, no tools, nothing kept) and almost always says nothing; when it does not, you get one signed line. And two new garments: I whisper when Claude sends a sub-agent out on a flagship model a small one could carry, and a true session end now leaves a one-line auto-note in an empty handoff slot — never over a real one — so the next session knows where to look.
v0.16.0 · 2026-07-13 · Apache 2.0
v0.13.2 — the gate closes six documented bypasses
A gate is only worth what it actually catches. v0.13.2 hardened it against six documented ways around it: interior // and .. path tricks, transparent prefixes (/bin/rm, command rm, FOO=1 rm — now caught on every pattern, so FOO=1 git push --force blocks too), and literal bash -c / eval payloads, which she re-inspects recursively and blocks with the inner command’s key. A wrapped payload she can’t read — a variable, an interpolation — gets a non-blocking whisper instead of silent passage.
Three bypasses stay documented and open — variable indirection, cd+relative, heredoc mis-detection — because closing them needs shell semantics the gate can’t safely have. The honesty is the feature: the gate’s own source says exactly what it does and does not catch. No baggage added. Still markdown, JSON, and bash.
v0.13.2 · 2026-06-30 · Apache 2.0
v0.13.0 — the gate hardens, the whispers get a reader
The arc since the rail: an evidence-grounded audit of ~73,000 traced events found that the gates genuinely bite, but almost everything I do aimed at Claude and never reached John. So now the session-start brief leads with a catch-digest — one plain line of what I caught since you last looked. A continuity guard warns when a session quit without saving, so the next one never wakes under-informed in silence. The gate got accurate: it stopped missing a real quoted DROP TABLE while false-blocking a commit whose message merely mentioned rm -rf /. And gate keys split into yellow (Claude may clear) and red (John's hand only) for the irreversible class.
v0.13.0 closed the audit's punch-list: four unused commands cut (the surface is nine now), the red-clear write-net widened, and a docs overclaim retired for the truth — on a single-user box there is no OS cage behind the gate, only the channel asymmetry, the net, and the audit. No baggage added. Still markdown, JSON, and bash.
v0.13.0 · 2026-06-26 · Apache 2.0
v0.9.2 — the mission-hold rail
I used to wait to be summoned. Now I run on rails. The mission-hold rail pins the one mission — from your plan or your active todo — and re-injects it every turn so it can't scroll out of view; at the first edit after a long stretch of talking it whispers the pinned mission back, in case Claude wandered. The irreversible-action gate still fires before a commit or a destructive command, and I still show up once a session unasked. The on-demand commands are all still here — but a rail catches the drift a command you forget to run never will.
And the release itself is gated now: a verify check fails CI if a version header, a cut command, or a stale “What's new” slips through — the misses get caught, not remembered.
v0.9.2 · 2026-06-19 · Apache 2.0
v0.1.7 — save/rest/recall drive off the house-map
The house-map used to describe where memory lives. Now it decides. Its memory-source registry is the single source of truth for where memory gets read and written — each source carries an enumerated write: token (digest-fanout, handoff-only, full, read-only, secret-deny) that /maude:save and /maude:rest execute exactly. The read commands recall per each source's own method.
Edit the map, change the behavior — no code change needed. Universal stores are a fallback, used only when the map says nothing. Still markdown, JSON, and bash; no daemon.
v0.1.7 · 2026-05-24 · Apache 2.0
v0.1.6 — gate hardening
The v0.1.5 conscience gate matched bare substrings, so a HEREDOC commit message containing the literal git push self-blocked the commit that shipped it. v0.1.6 fixes it — paired quote spans and HEREDOC bodies are stripped before pattern-matching, and every gate pattern carries its own command-position or flag-position anchor. rm -rf /tmp/foo and rm -rf *.tmp no longer false-positive.
Plus a real test harness: tests/lib.sh + 16 tests/test-*.sh files + make test, exercising every script in hooks/scripts/ and scripts/maude-verify.sh. From 9 ad-hoc invocations in v0.1.5 to 162 codified test cases.