Back to Blog
Claude MCP AI DevOps

Running an Autonomous Content Pipeline on a Raspberry Pi with Claude Code and MCP

A cron job on a Raspberry Pi wakes a headless Claude Code agent that drafts a post, opens a PR, and files it for review — behind a hard human-approval gate.

Running an Autonomous Content Pipeline on a Raspberry Pi with Claude Code and MCP

Every demo of an “autonomous agent” quietly assumes a human is watching — approving each tool call, nudging it back on track, catching the moment it confidently does something dumb. That’s not automation; that’s pair programming with extra steps. The interesting question is what an agent can do when nobody is watching — on a schedule, unattended, with real write access to your repo and your tools — without it going off the rails the first time the model is wrong.

We answered that question by building one. A Raspberry Pi on a shelf in our office runs a cron job that, every morning, wakes up a headless Claude Code agent, has it draft a blog post, fact-check it, open a pull request, and file a review card on our project board. Then it stops and waits for a human. This post you might be reading was produced by exactly that pipeline. Here’s how it’s wired, and — more importantly — the guardrails that make handing a model unattended write access something other than reckless.

The shape of it, in one sentence

A scheduled trigger runs a headless coding agent against a written runbook; the agent produces an artifact (a draft + PR) and a review task, then halts at a hard human-approval gate before anything ships.

That sentence contains every load-bearing decision. The schedule is cron. The agent is Claude Code in headless mode. The runbook is a Markdown file checked into the repo. The artifact is a normal GitHub PR. The review task lives on our internal project board, reached over MCP. And the gate is the rule that the agent may draft but never publish.

Why a Raspberry Pi, and not a Lambda

The honest answer is that the Pi was already there. It’s a device we manage anyway, it draws a couple of watts, and cron is the most boring, most reliable scheduler ever written. There’s no cold start, no 15-minute execution ceiling, no per-invocation billing to reason about — a drafting run can take several minutes of model time and nobody cares.

The trade-off is that a Pi is a single box you own and have to keep alive. If it’s off, the run is skipped. For a daily content job that’s completely fine — a missed day is a non-event. For anything with a real SLA you’d want redundancy or a managed scheduler, and we’d reach for one. But there’s a real lesson in not over-architecting the substrate: the agent doesn’t care what wakes it up, so use the cheapest thing that reliably does. (If you do run agents on a Pi, our notes on shrinking Raspberry Pi images with Docker make the box itself easy to reproduce.)

The cron entry is unremarkable on purpose:

# Draft a post every morning at 05:00
0 5 * * * cd /home/kenneth/keyq-web && /usr/local/bin/claude -p "$(cat content-ops/draft-run.md)" --output-format json >> /var/log/keyq-blog/draft.log 2>&1

Headless Claude Code is the engine

Claude Code has a non-interactive mode: pass -p (or --print) with a prompt and it runs the task to completion, emits the result to stdout, and exits — no REPL, no waiting on a human. That single flag is what turns an interactive assistant into something you can put behind cron. (The headless docs cover the full flag set.)

Two details matter for unattended runs:

  • --output-format json returns a structured payload that includes total_cost_usd and a per-model cost breakdown. We log it per run, so “what does this pipeline cost?” is answered by reading a file, not by squinting at a usage dashboard at the end of the month. Knowing the marginal cost of each run is what lets you decide, honestly, whether the automation earns its keep.
  • The prompt is the program. Rather than cram instructions into the cron line, the prompt is cat’d from a runbook file in the repo (draft-run.md). The agent’s entire behavior — which idea to pick, the word count, the anonymization rules, the exact PR and card format — is version-controlled Markdown. Tuning the pipeline is a normal commit with a normal diff and a normal git blame, not a sysadmin SSH’ing in to edit a script. The runbook is the contract.

That last point is the one we’d press hardest. The most maintainable “agent framework” we’ve found is a clearly written instruction file plus a model good enough to follow it. There’s no orchestration DAG to debug because the control flow lives in prose the agent reads top to bottom.

MCP gives the agent hands

A drafting agent that can only write text isn’t a pipeline — it has to act: open a PR, file a review task, link the two. Git and the GitHub CLI (gh pr create) cover the repo side. For our internal project board, the agent talks to it through an MCP server.

The Model Context Protocol is the now-standard way to give a model typed tools over a defined transport (stdio for a local subprocess, or Streamable HTTP for a remote, multi-client server). Instead of the agent screen-scraping a web UI or us hand-rolling a REST wrapper, the board exposes tools like create_card and move_card, and the agent calls them the same way it calls any other tool. If you want the build-it-yourself version, we walked through building an MCP server for remote device management end to end; the same shape applies to any system you want an agent to drive.

The board card is deliberately the center of gravity, not the PR. We call it “the desk”: the agent files a card in a QA / Review column with a summary, the PR link, and a one-line instruction — comment to request changes, or drag to Done to approve and publish. The reviewer lives in one place. The PR is just the merge mechanism the card points at. Each card and PR carry a hidden marker comment so the pipeline can always tell its own artifacts from a human’s, which matters the moment a second automated step starts reading the board.

The guardrails that make “unattended” safe

This is the part that’s actually load-bearing, and the part most “look, my agent did a thing!” demos skip. Giving a model write access to your repo on a timer is only sane if a wrong run is cheap and reversible. The guardrails:

  • A hard human gate, enforced by data, not discipline. Every draft is written with draft: true in its frontmatter, and the blog’s build hides anything marked draft. The agent is structurally incapable of publishing — the flag only flips to false in a separate publish step that runs after a human approves. The worst an off-day run can do is open a PR nobody merges.
  • Verify, don’t trust, the model’s facts. A model’s training has a cutoff and tech moves fast; the failure mode isn’t usually fabrication, it’s staleness — a version, default, or “best practice” that was true a year ago. So the runbook forces a fact-check pass: extract every checkable claim, verify the time-sensitive ones against current official docs, and either correct with a dated source or soften and flag for the reviewer rather than silently “fixing.” A verification trail goes in the PR body. (The links and version claims in this very post went through that pass.)
  • Anonymization is a rule, not a hope. The runbook forbids client-identifying detail outright — real names get generalized to “a streaming client” or “a recent AWS migration.” Encoding that as an explicit instruction, with named exclusions, is far more reliable than hoping the model exercises judgment.
  • One marker to tell self from human. Because the automation and the human owner post under the same account, author name is useless for telling them apart. A hidden marker line on every pipeline-authored comment is the only reliable signal — a small thing that prevents a feedback loop from mistaking its own output for instructions.

None of these are clever. They’re the same instincts you’d apply to any system with write access: make the blast radius small, make the dangerous action require a second actor, and don’t trust an input just because it looks confident.

What we’d tell you before you build one

A few honest trade-offs:

  • The gate stays. We’ve run this long enough to trust the mechanics completely and the editorial judgment not at all. The agent is excellent at producing a solid, on-format, fact-checked draft and terrible at knowing whether a topic is worth publishing. Removing the human approval would not be brave; it’d be a downgrade. The point of the automation isn’t to remove the human — it’s to move the human from “doing the work” to “approving the work.”
  • Watch the marginal cost. A daily run is cheap, but the cost is real and it scales with how much you fan out. Logging total_cost_usd per run kept us honest about that.
  • The runbook is never “done.” Most of our iteration has been tightening the prose instructions after a run did something technically-compliant but not what we meant. That’s the actual maintenance surface — and it’s a much nicer one than debugging orchestration code.

The reusable idea here isn’t “AI writes our blog.” It’s that a scheduled, headless agent + a written runbook + MCP tools + a hard approval gate is a general pattern for handing recurring, structured work to a model without babysitting it. Content is just our first instance of it. Triage, report generation, routine PR chores — anything that’s well-specified in prose and safe behind a review gate fits the same mold.

If you’d rather drive the box your agents run on from anywhere — kick off a run, tail the logs, manage the fleet without SSH gymnastics — that’s exactly what we built Slipstream for, and it’s how we operate the Pi behind this pipeline. (Managing remote servers from Claude Code shows that side of it.)


Sources / last verified 2026-06-23: