<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>MumbleKey Blog</title><description>Fred Chu on AI agent engineering, one-person-company automation, and cycle-based trading.</description><link>https://blog.mumblekey.com/</link><language>en</language><item><title>CLAUDE.md Is a Score: Running a One-Person Company as an AI Conductor</title><link>https://blog.mumblekey.com/en/posts/claude-md-as-score/</link><guid isPermaLink="true">https://blog.mumblekey.com/en/posts/claude-md-as-score/</guid><description>I don&apos;t have employees, and I don&apos;t pay for a pile of SaaS. I restructured my work into a system of AI agents: two Macs, one rule file that keeps growing, and four agent roles that each stay in their lane. Here&apos;s the architecture and the traps I hit.</description><pubDate>Mon, 06 Jul 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;In an interview, Reid Hoffman said:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&amp;quot;I&apos;m more of a conductor than I am a violin player or a piano player.&amp;quot;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;That line stuck with me. When most people say &amp;quot;I&apos;m using AI,&amp;quot; they mean they&apos;re using it to speed up a step: translate a bit faster, autocomplete code a bit faster. That&apos;s not where the real dividing line is. The line is whether you &lt;strong&gt;restructure the work itself into something an AI can take over&lt;/strong&gt;. This post is how I do that, and what the system has grown into after a year.&lt;/p&gt;
&lt;h2&gt;Two Machines, Two Roles&lt;/h2&gt;
&lt;p&gt;My system runs on two Macs:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;MacBook Pro (M1 Max)&lt;/strong&gt;: the interactive workhorse. This is where I talk to Claude Code, build things, and make decisions.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Mac mini (M1, 8GB)&lt;/strong&gt;: unattended. It runs scheduled jobs — pulling liquidity indicators every Monday morning, sweeping the health of my cron jobs daily, updating futures price levels before the open, and pushing anything anomalous straight to Discord.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Each machine has its own Claude Code agent (I call them Pro CC and Mini CC), and they hand off work state through a shared handoff note. While I sleep, Mini CC is working; when I sit down at my desk, Pro CC picks up where the last session left off from the handoff summary.&lt;/p&gt;
&lt;h2&gt;&lt;a href=&quot;http://CLAUDE.md&quot;&gt;CLAUDE.md&lt;/a&gt; Is a Score&lt;/h2&gt;
&lt;p&gt;A conductor doesn&apos;t play the violin, but there&apos;s a full score on the stand. My score is a Markdown file called &lt;code&gt;CLAUDE.md&lt;/code&gt; — loaded automatically at the start of every session, defining what this agent can do, where it has tripped before, and how to avoid tripping again.&lt;/p&gt;
&lt;p&gt;The point isn&apos;t writing rules. The point is &lt;strong&gt;making the rules grow&lt;/strong&gt;. Every time I hit a trap, the lesson gets written back into the system:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-markdown&quot;&gt;## F-0. Git Discipline (hard rule, added after the pack-swallowing incident)

- Forbidden: `git add -A`, `git add .` — always use an explicit pathspec
- Reason: the cloud-sync tool hardlinks .git/objects/pack/*.pack
  into the worktree, so a blanket add swallows the pack and makes
  the repo balloon exponentially (this repo once hit 2.0TB)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This rule came out of a real incident: a cloud-sync tool got into a fight with git, and the repo ballooned to 2TB. After I fixed it, the lesson became a hard rule, and no agent session repeats the mistake. The longer I use it, the better the system understands me — and that&apos;s worth more than any model upgrade.&lt;/p&gt;
&lt;h2&gt;Memory in Three Layers&lt;/h2&gt;
&lt;p&gt;A single giant file blows up your token budget, so memory is layered by reusability:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Episodic memory&lt;/strong&gt;: dated session logs, for tracing &amp;quot;what happened that day&amp;quot;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Semantic memory&lt;/strong&gt;: knowledge reusable across sessions, organized by topic&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Hard rules&lt;/strong&gt;: constraints that hold no matter the context&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Once episodic memory piles up enough, it gets distilled into semantic memory; semantic memory then condenses upward into wiki articles. Add lazy loading (a session only reads the core-identity file at startup, and loads other modules on demand), and token consumption drops about 70% compared to one big file.&lt;/p&gt;
&lt;h2&gt;Four Roles, Each With a Boundary&lt;/h2&gt;
&lt;p&gt;When I was building an iPhone keyboard app, I split the agent into four roles: PM analyzes requirements and writes the spec, Designer produces the mockups, Engineer implements, QA reviews and gatekeeps. The key is that &lt;strong&gt;the boundaries are locked in by policy&lt;/strong&gt;: the PM never touches code, only the Engineer can commit, QA blocks the release.&lt;/p&gt;
&lt;p&gt;This isn&apos;t a role-playing game. The boundaries exist for the same reason they do on a human team: the person who wrote the code shouldn&apos;t sign off on their own code. One of the iron laws in my verification discipline is &amp;quot;the author never verifies their own work&amp;quot; — an implementer&apos;s output only counts once another independent agent, or I myself, has run it against real input.&lt;/p&gt;
&lt;h2&gt;What This System Actually Produces&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Commercial output&lt;/strong&gt;: a client&apos;s video subtitles, squeezed from 2-3 hours of manual correction per video down to 15-30 minutes of automation (that pipeline deserves its own post, which &lt;a href=&quot;/en/posts/subtitle-pipeline-3h-to-30min/&quot;&gt;I&apos;ve already written&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Daily productivity&lt;/strong&gt;: calendar, reminders, email summaries, daily planning — all of it Claude Code gluing native Apple apps together, zero SaaS subscriptions&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Investment infrastructure&lt;/strong&gt;: brokerage API integrations, position-anomaly scans, options positioning snapshots, all running on schedule&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;No employees, no SaaS purchases. The marginal cost of the system is my monthly Claude subscription.&lt;/p&gt;
&lt;h2&gt;If You Want to Start&lt;/h2&gt;
&lt;p&gt;You don&apos;t have to build it all at once. The order I&apos;d suggest:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Write a minimal &lt;code&gt;CLAUDE.md&lt;/code&gt; first: who you are, where your projects live, and what must never happen&lt;/li&gt;
&lt;li&gt;Every time the AI screws up, write the lesson back in (this step is where the compounding comes from)&lt;/li&gt;
&lt;li&gt;Once the file gets big, split it into layers: rules, memory, wiki&lt;/li&gt;
&lt;li&gt;Multiple machines and multiple roles come last&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;There&apos;s one more line from that Hoffman interview: &amp;quot;Even most people who say &apos;Oh yeah I&apos;m using AI&apos; are not using it seriously enough.&amp;quot; Using it seriously doesn&apos;t mean writing prettier prompts. It means being willing to tear your work down and rebuild its structure.&lt;/p&gt;
</content:encoded><category>ai-agents</category><category>claude-code</category><category>one-person-company</category></item><item><title>I Gave My Blog Both an MCP Server and a CLI, Then Measured the Tokens</title><link>https://blog.mumblekey.com/en/posts/mcp-and-cli-for-my-blog/</link><guid isPermaLink="true">https://blog.mumblekey.com/en/posts/mcp-and-cli-for-my-blog/</guid><description>&apos;MCP is dead, CLIs are cheaper&apos; takes are everywhere. Why not both? I built both paths for this blog, mostly for fun, and measured the same task over each. The conclusion is more boring than the takes — but it has numbers.</description><pubDate>Mon, 06 Jul 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;There&apos;s a running debate in the agent world: &lt;strong&gt;MCP servers are too expensive; agents should just use CLIs&lt;/strong&gt;. The evidence looks damning — someone measured an enterprise API&apos;s MCP integration burning ~145,000 tokens on a task that a CLI pipeline finished in just over 4,000, a 35x gap. Another evaluation ran the same model through GitHub tasks and found the MCP path cost 6x more and took 5x longer.&lt;/p&gt;
&lt;p&gt;My reaction was the meme kid shrugging: why not both? This blog happens to be an ideal test bench — static content, read-only, bilingual pairs — so I &lt;strong&gt;built both paths&lt;/strong&gt;, mostly for fun, and measured them.&lt;/p&gt;
&lt;h2&gt;The Result, Up Front&lt;/h2&gt;
&lt;p&gt;Same task — &amp;quot;find the post about the subtitle pipeline, then read the whole thing&amp;quot; — three ways:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Path&lt;/th&gt;
&lt;th&gt;Steps&lt;/th&gt;
&lt;th&gt;Total bytes&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;MCP (&lt;code&gt;/mcp&lt;/code&gt; endpoint)&lt;/td&gt;
&lt;td&gt;initialize + tools/list + search + get_post&lt;/td&gt;
&lt;td&gt;11,893&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;CLI (&lt;code&gt;npx&lt;/code&gt; command)&lt;/td&gt;
&lt;td&gt;help + search + get&lt;/td&gt;
&lt;td&gt;6,373&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Plain HTTP&lt;/td&gt;
&lt;td&gt;llms.txt + post .md&lt;/td&gt;
&lt;td&gt;7,532&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;(Baseline) scraping the HTML&lt;/td&gt;
&lt;td&gt;one page, before extraction&lt;/td&gt;
&lt;td&gt;15,178&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;The CLI is about 46% cheaper than MCP. Same direction as the hot takes, but &lt;strong&gt;an order of magnitude less dramatic&lt;/strong&gt; — the 35x horror stories come from enterprise APIs with dozens of tools and bloated schemas. My MCP server has two tools with 1,339 bytes of schema, total. MCP&apos;s cost problem is a tool-surface problem, not original sin in the protocol.&lt;/p&gt;
&lt;p&gt;The genuinely interesting numbers are the other two.&lt;/p&gt;
&lt;h2&gt;Finding 1: JSON-in-JSON Is a Hidden Tax&lt;/h2&gt;
&lt;p&gt;For the search step, MCP returned 5,960 bytes; the CLI returned 1,840 — 3.2x. Same content, so where&apos;s the difference? MCP tool results are a JSON string escaped inside a JSON-RPC envelope: every quote becomes &lt;code&gt;\&amp;quot;&lt;/code&gt;, every newline becomes &lt;code&gt;\n&lt;/code&gt;. The CLI prints plain text and skips the tax entirely.&lt;/p&gt;
&lt;h2&gt;Finding 2: The Biggest Lever Isn&apos;t the Protocol At All&lt;/h2&gt;
&lt;p&gt;The Markdown version of a post is 4,439 bytes. The HTML of the same post is 15,178 — &lt;strong&gt;3.4x&lt;/strong&gt;. Simply serving clean Markdown matters more than the MCP-vs-CLI choice. On this blog, append &lt;code&gt;.md&lt;/code&gt; to any post URL, or hit the original URL with a header:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;curl -H &amp;quot;Accept: text/markdown&amp;quot; \
  https://blog.mumblekey.com/en/posts/mcp-and-cli-for-my-blog/
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The response carries an &lt;code&gt;x-markdown-tokens&lt;/code&gt; header so an agent can check the cost before swallowing the content.&lt;/p&gt;
&lt;h2&gt;So Why Build the MCP Server At All?&lt;/h2&gt;
&lt;p&gt;&amp;quot;Both&amp;quot; isn&apos;t stubbornness — the two paths genuinely serve different scenarios, which I only fully appreciated after building them:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;CLI is the inner loop&lt;/strong&gt;: your agent, your machine, you can install things. Cheaper tokens, composable with pipes. Correct choice, no argument.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;MCP is the outer loop&lt;/strong&gt;: a &lt;strong&gt;reader&apos;s&lt;/strong&gt; agent runs on the reader&apos;s machine, and you can&apos;t ask strangers to &lt;code&gt;npm install&lt;/code&gt; anything first. One &lt;code&gt;claude mcp add&lt;/code&gt; and the protocol handles discovery and invocation — something a CLI structurally cannot do safely over the internet.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;So the answer isn&apos;t either/or:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;# You&apos;re a reader who wants your Claude to query my posts (outer loop)
claude mcp add --transport http blog https://blog.mumblekey.com/mcp

# You&apos;re an agent engineer who wants the cheapest path (inner loop)
npx github:fredchu/mumblekey-blog search &amp;quot;subtitle&amp;quot; --lang en
npx github:fredchu/mumblekey-blog get subtitle-pipeline-3h-to-30min
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Both paths read the same &lt;code&gt;search-index.json&lt;/code&gt; generated at build time. The MCP server is a hand-rolled stateless JSON-RPC handler on a Cloudflare Worker at the edge — about two hundred lines, zero servers to babysit.&lt;/p&gt;
&lt;h2&gt;Implementation Notes (If You Want to Copy This)&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Build the Markdown twin first&lt;/strong&gt; — it&apos;s the foundation both paths (and every crawler) benefit from. On a static site, emitting a &lt;code&gt;.md&lt;/code&gt; per page at build time is nearly free&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Keep the MCP surface tiny&lt;/strong&gt; — a read-only site needs two tools (search, get). Every extra tool adds per-session schema cost; that&apos;s where the 35x disasters come from&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;You don&apos;t need to publish to npm&lt;/strong&gt; — add a &lt;code&gt;bin&lt;/code&gt; field to &lt;code&gt;package.json&lt;/code&gt; and &lt;code&gt;npx github:user/repo&lt;/code&gt; just works&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Measure your own numbers&lt;/strong&gt; — bytes are one &lt;code&gt;curl | wc -c&lt;/code&gt; away, and they&apos;re more honest than quoting someone else&apos;s benchmark. Every number in this post was measured that way; token estimates assume roughly 4 bytes per token&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The takes say &amp;quot;MCP is dead.&amp;quot; My data says: MCP isn&apos;t dead — it just keeps getting shoved into scenarios it was never good at. A blog happens to have both scenarios. So: both. Picking is for kids.&lt;/p&gt;
</content:encoded><category>ai-agents</category><category>mcp</category><category>claude-code</category></item><item><title>From 3 Hours to 30 Minutes: My Automated Chinese Subtitle Pipeline</title><link>https://blog.mumblekey.com/en/posts/subtitle-pipeline-3h-to-30min/</link><guid isPermaLink="true">https://blog.mumblekey.com/en/posts/subtitle-pipeline-3h-to-30min/</guid><description>A subtitle production line running on Apple Silicon — local ASR, on-screen term extraction, LLM correction, and a fail-safe quality gate. This post covers the architecture, the term-learning loop, and three lessons that took it from &quot;it runs&quot; to &quot;it&apos;s reliable.&quot;</description><pubDate>Mon, 06 Jul 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;I make video subtitles for a finance-education creator. A two-hour video used to take 2-3 hours of manual correction; the same work now takes 15-30 minutes — the pipeline runs on its own and I spot-check the result. This post is how I built that production line, and the three lessons that took it from &amp;quot;it runs&amp;quot; to &amp;quot;it&apos;s reliable.&amp;quot;&lt;/p&gt;
&lt;h2&gt;What the Production Line Looks Like&lt;/h2&gt;
&lt;p&gt;The whole pipeline is triggered by a single skill inside Claude Code, running six stages in sequence:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;Download (yt-dlp)
  → On-screen term extraction (OCR / VLM caption, one frame every 60s)
  → ASR (Breeze ASR 25, local inference on Apple Silicon)
  → Preprocessing (sentence-boundary cleanup, mid-word comma repair)
  → LLM correction (dispatch subagents per segment, inject the glossary + on-screen context)
  → Postprocessing (split overlong captions, quality gate, SRT output)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;ASR runs locally the whole way; only the correction stage uses a cloud model. The hard part of finance content isn&apos;t speech recognition itself — it&apos;s the &lt;strong&gt;proper nouns&lt;/strong&gt;: ticker symbols, ETFs, indicator abbreviations, the speaker&apos;s pet phrases. When ASR mishears a company name or shatters &amp;quot;MA30&amp;quot; into fragments, a general-purpose model can&apos;t fix those well. It takes domain knowledge.&lt;/p&gt;
&lt;h2&gt;The Glossary Is Alive&lt;/h2&gt;
&lt;p&gt;The core of the system isn&apos;t any single model — it&apos;s a &lt;strong&gt;glossary that learns&lt;/strong&gt;:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;After each video is corrected, a term-learning pass runs, turning &amp;quot;ASR mistake → correct term&amp;quot; into mechanical substitution rules&lt;/li&gt;
&lt;li&gt;The next video&apos;s ASR output passes through this batch of rules before it goes into LLM correction&lt;/li&gt;
&lt;li&gt;On-screen slide text (extracted by OCR) adds the new terms for that episode&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;I quantified the effect once: processing 8 videos in a row, the first learning round added 16 substitution rules, and the automatic corrections on the same video jumped from 0 to 58. After the second round, the correction volume reported by the LLM correction subagent dropped noticeably — because the cheap mistakes were already being eaten upstream by the mechanical rules.&lt;/p&gt;
&lt;h2&gt;Lesson 1: Verify the Values, Not Just the Absence of Errors&lt;/h2&gt;
&lt;p&gt;Once, a correction subagent &amp;quot;over-merged&amp;quot; 300 captions down to 110, producing overlong captions of 10-29 seconds each. The verification at the time only checked &amp;quot;the file exists and the format is valid,&amp;quot; so it let them straight through.&lt;/p&gt;
&lt;p&gt;The fix was to change verification to &lt;strong&gt;check the numbers&lt;/strong&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;ratio = corrected_count / original_count
if ratio &amp;lt; 0.55:
    fail()          # too few entries left — must be over-merging
if ratio &amp;lt; 0.80 and longest_entry_sec &amp;gt; 15:
    fail()          # entry-ratio plus duration symptom, double confirmation
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The thresholds aren&apos;t guesses — they were calibrated against 88 segments from 10 historical videos (zero false positives). The entry ratio alone isn&apos;t enough: passages where the speaker talks in fragments are naturally low-ratio, so you have to pair it with the &amp;quot;longest entry duration&amp;quot; symptom to judge.&lt;/p&gt;
&lt;h2&gt;Lesson 2: Always Parse Subagent Output Defensively&lt;/h2&gt;
&lt;p&gt;An LLM subagent will occasionally write its reasoning into the output (&amp;quot;[reads fine, no change]&amp;quot;), or leak the XML tags of a tool call. Worse, the postprocessing split logic will &lt;strong&gt;amplify a single point of contamination into multiple spread-out ones&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;The fail-safe has three layers: the prompt explicitly lists the forbidden output patterns, a strip before merging, and another strip after postprocessing. The principle is a single sentence: &lt;strong&gt;cleanup must happen before slicing — you can&apos;t trust the subagent to police itself&lt;/strong&gt;.&lt;/p&gt;
&lt;h2&gt;Lesson 3: Resource Conflicts Need Orchestration, Not Prayer&lt;/h2&gt;
&lt;p&gt;A 32GB M1 Max can&apos;t run two large models inferring at the same time. After the 20GB vision model finishes, the framework keeps the model resident in memory for a few minutes — start ASR during that window and you OOM outright. The fix is crude but effective: as soon as the caption stage finishes, explicitly issue &lt;code&gt;ollama stop&lt;/code&gt;, then start the next stage. Small models (the 1.5GB ASR plus the 5GB auxiliary ASR) can actually run in parallel without worry — at worst they contend for the GPU and slow down, but they won&apos;t crash.&lt;/p&gt;
&lt;h2&gt;Three Designs Worth Stealing&lt;/h2&gt;
&lt;p&gt;If you&apos;re going to build something similar, the parts I think are most worth stealing:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Keep every intermediate artifact.&lt;/strong&gt; Save the output of every stage. Calibrating the quality gate&apos;s thresholds, and rebuilding after an incident, both rely on this stash of historical data.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Mechanical rules eat the cheap errors, the LLM eats the hard ones.&lt;/strong&gt; Once you layer it this way, the expensive model only handles the parts that genuinely need understanding.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Calibrate the gate on real data.&lt;/strong&gt; Compute the fail-safe thresholds from historical output, don&apos;t guess them.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;This pipeline&apos;s skill is already open-sourced, alongside its sister skill (turning a recording into an article that stays faithful to the original words) — both are on my GitHub.&lt;/p&gt;
</content:encoded><category>asr</category><category>automation</category><category>claude-code</category></item></channel></rss>