Local First, Public When Ready: A Git Setup for AI-Assisted Work

4 minute read Published: 2026-09-04

This entire blog network — the one you're reading right now — is built by working alongside an AI agent (Claude Code) on a home server, and it's the first real post to go out of that setup. Before writing about anything else, it felt right to write about the plumbing that makes the rest possible, because it's a pattern I think more people doing AI-assisted work should know about: two git remotes, not one.

The problem with "just push to GitHub"

If you're using an AI coding agent for anything beyond a single throwaway script, you generate a lot of git history you don't actually want anyone to see. Half-finished experiments. A theme patch that took nine tries to get right. Notes-to-self committed at 2am. Normally that's fine — you work on a branch, squash it, nobody's the wiser.

But GitHub Pages breaks that assumption in a specific, easy-to-miss way: the repo that serves your live site is the same repo you'd normally treat as a scratch pad. There's no private branch to hide behind. Every commit to the branch GitHub Pages builds from is, functionally, a live publish. If your workflow involves an agent iterating in public view — patching a broken theme, restructuring config, trying three different approaches to a build script — that iteration either has to happen somewhere else, or it happens live.

The fix: a private remote for the mess, a public one for the result

The setup that's worked for me is boring in the best way:

# inside a repo meant to eventually go public
git remote add origin ssh://git@my-local-server:222/me/project.git
git remote add github git@github.com:me/project.git

# work, iterate, commit as much garbage as you want
git push origin main

# only when something is actually ready
git push github main

That's the entire trick. Nothing clever, no tooling required — just a discipline about which remote gets which commits, enforced by the fact that one of them physically cannot be reached from outside your house.

The practical rule that falls out of this: draft and iterate privately, publish deliberately. For this blog network specifically, that means content and scaffolding get built and reviewed against the local server first, and only get pushed to each site's public GitHub Pages repo once it's actually ready to be live — because for a Pages repo, "pushed" and "published" are the same event.

Why this matters more once an agent is involved

The part that surprised me is how much more valuable this becomes once an AI agent is doing a meaningful share of the work, for two reasons:

1. Agents fail loudly and iteratively, and that's fine when nobody's watching. Getting an old, unmaintained Zola theme working again after a major templating-engine upgrade took real trial and error — patch a template, rebuild, read the error, patch again, repeat. That's completely normal agentic work. It's just not something that needs to live forever in a public commit log on the repo your visitors are looking at.

2. Agents need memory, and that memory shouldn't be public by default. This is the part I didn't expect going in. Two tools do the heavy lifting here:

Neither of those needs to be public, and honestly, most of it probably shouldn't be — it's internal reasoning, false starts, and the occasional embarrassing typo in a note to myself. But it needs to persist, reliably, across sessions that might be weeks apart. A private git remote is a perfectly good database for that, and it means the agent's memory survives right alongside the code, backed up the same way, without ever touching a public host.

The takeaway

If you're doing any kind of AI-assisted work — blogging, code, research notes, doesn't matter — and you haven't set up a private git remote alongside your public one, it's a genuinely small amount of setup (an evening, tops, if you self-host something like Gitea or Forgejo) for a real, ongoing benefit: your agent gets a place to fail, remember, and iterate freely, and your public repos only ever show the parts you meant to publish.

Content is content, and I'd rather ship a little rough and iterate than sit on something polishing it forever — but "rough" and "public" don't have to be the same thing anymore than "in progress" and "shipped" do. Two remotes gets you both.