One night in April I almost found out my laptop was the only copy of six months of work.

I'd been running Claude as a daily coding partner for months. Dozens of small projects. A few big ones. Cloudflare Workers, Pages sites, data pipelines, command-line utilities. Claude wrote a lot of the code. Claude also, in the way these things go, ran most of the git commands. I'd say "deploy this," and Claude would handle the plumbing: commit, push, wrangler deploy, verify the live URL, done. It felt smooth.

That evening I shipped a small change to a project called leadgen and something looked off in the terminal output. I poked around. Ran git remote -v in the project directory. No output. I was standing inside code I had been deploying to production for weeks, and it lived in exactly one place on Earth: my laptop's SSD.

Then I checked the other projects in the same folder. Same story, six more times.

I spent the next ninety minutes doing git forensics and the next five sessions building tooling so this specific failure mode could never happen again. Here's what I learned, what I built, and why I think everyone running Claude as a serious coding partner should be thinking about this.


What Claude will actually do to your git

Claude is extraordinarily good at writing code. It is less good at the thing senior developers do instinctively, which is pause and verify the state of the world before acting on it.

If you tell Claude to deploy, Claude deploys. It doesn't first run git status, check that the working tree is clean, confirm the remote exists, verify the origin URL points where you think it points, and check that your last commit is reflected upstream. Those are the habits a ten-year veteran has internalized so deeply they happen automatically. Claude doesn't have those habits. Claude has the ability to run any of those checks when asked — but the default is forward motion. Ship the thing. You asked me to ship it.

Layer on top of that a more structural problem: Claude has no persistent state between sessions. Every new conversation starts cold. If last week's Claude properly initialized a project with a remote and pushed it, this week's Claude has no memory of that. This week's Claude will happily create a new project, start writing code, and deploy it — without checking whether a remote exists, because nothing in its context tells it that's a thing to check.

So what actually happened on my machine, over a period of maybe three months, was this:

None of that is Claude being malicious. None of it is Claude being bad at code. It's Claude being helpful and forward-moving in a domain where correctness requires you to be skeptical and backward-checking.


The full inventory of sins

Here's the complete picture I pieced together over the next few weeks:

Missing remotes. Seven projects with no origin configured. Every one of them had been deployed to production. Total amount of unique, unrecoverable work if my SSD had died: call it two months of dense output.

Misconfigured origins. One project was worse than missing — it had an origin, but pointing at the wrong repository. This is more dangerous than no remote at all, because git push succeeds and you think you're backed up. You're not.

Hardcoded tokens. Sixteen scripts across the codebase with GitHub PATs inlined. Every one of them would have been a security issue if any of those files leaked to a public repo or a pastebin.

Tokens lingering in .git/config. Three different project .git/config files still contained credentials from earlier authentication attempts. Not dangerous in the same way as leaked source, but not something you want sitting around either.

Orphan branches. A handful of experimental branches (cowork/node2-setup, cowork/wire-v2) that were started for specific experiments and never cleaned up. Not harmful. Just clutter.

Ambiguous default branch. Twenty-two projects on master, because that's what git init defaults to and Claude never normalized to main. GitHub defaults to main now. Most CI and deploy configs don't care, but it's the kind of inconsistency that bites you later when something does care.

Accidental child-repo staging. Because the workspace parent directory contains individual project directories that are themselves git repositories, running git add . from the workspace root would sometimes try to stage entire child-repo contents as submodule-adjacent chaos. Fixing this required a specific .gitignore negation pattern.

None of these are complex problems. Every single one is the kind of thing a careful developer would catch at the moment it happened. But they accumulated, quietly, because Claude was doing the git and Claude's default is motion.


What I built in response

I sat down after the near-miss and designed a response. The principle I landed on: cleanup tooling beats cleanup sessions. If my assistant is going to drift, the audit has to run at the moment of drift, not on a weekly calendar reminder. By the time you get to the weekly review, the drift is three days old and you've forgotten why it happened.

Four pieces.

A one-shot init script. tools\new_project.ps1 <name> "<description>" creates the directory if it doesn't exist, runs git init, writes a starter README and .gitignore, makes the initial commit, creates the GitHub repository via API, adds the remote, pushes, and appends an entry to the project registry. Takes twenty seconds. Removes every excuse for skipping the init ceremony, because the ceremony is now one command.

A trigger rule. No project gets wrangler deploy run against it until it's properly configured: .git present, origin set correctly, initial commit pushed, registered in Projects.md. If those conditions can't be met in the current session, the deploy waits. This is the rule that prevents the exact failure mode that caused the April night — the "deploy first, back up later" ordering that turned out to be "deploy first, back up never."

A hygiene audit. tools\project_hygiene.ps1 runs at every session start, before any deploy, and on demand. It walks every project directory, reports any that lack .git, any with misconfigured origins, any with unpushed commits, any with uncommitted working-tree changes. RED for critical issues (no source control, wrong remote). YELLOW for unsafe-but-not-catastrophic (unpushed work, orphan config). Clean runs are silent; dirty runs interrupt whatever we were doing.

A secrets policy. One file on disk — .secrets.json — holds every credential. Nothing is inlined into scripts. Scripts read from the file at runtime. This turned sixteen time bombs into one door with a lock on it. And the lock is just a .gitignore entry, which is less elegant than what a real enterprise setup would do, but it's the simplest thing that works and it survives contact with reality.

The last piece isn't tooling, it's behavioral: I asked Claude to watch for specific intent phrases during normal conversation. When I say things like "let's build a worker" or "spin up a new Pages project" or "give it a D1," Claude is supposed to pause and check whether the project exists, whether it has a remote, whether the remote points at the right place — before doing anything. If everything's clean, proceed. If something's off, raise it. The trigger list lives in the session startup protocol. It's imperfect and will miss cases, but it catches the common paths.


What the discipline caught later

The real test of a discipline is what it catches after you stop paying attention to it.

The PAT footprint scrub. A few weeks after the initial cleanup, I ran the hygiene audit and it flagged three separate .git/config files that still contained GitHub token fragments. I had thought this was cleaned up. It wasn't. A ten-minute scrub removed them. The audit found the drift because the audit runs every session, not because I remembered to look.

The orphan duplicate. A second leadgen/ directory appeared in the workspace. I don't know exactly how — probably a half-initialized attempt to scaffold something that got aborted mid-flow. The hygiene audit saw it, flagged it, and refused to proceed with the deploy I was about to run. Without the audit, I would have eventually deployed whatever state that duplicate directory was in, and the resulting confusion would have cost me hours to untangle.

Both of these are exactly the kind of mysterious-bug-three-weeks-later the tooling exists to prevent. Neither cost me anything beyond a few minutes.


What's still open, deliberately

Not everything got fixed, and this part matters.

Twenty-two projects are still on master instead of main. Renaming a default branch sounds trivial — it isn't, once you have wrangler configs, CI workflows, deploy webhooks, and documentation all referring to the old name. The audit flags them YELLOW, I've accepted the YELLOW, and until there's a concrete reason to fix it, I leave it.

A couple of experimental branches are still open. They're either going to be merged soon or retired soon, and rushing either decision would be worse than the slight clutter of them sitting there.

The reason I'm mentioning this: scope discipline matters as much as cleanup discipline. "Everything must be pristine" is its own failure mode. You spend every session cleaning instead of building. The right bar is "no RED, YELLOW is acknowledged, move on."


The meta lesson

If you take one thing away from this: your AI coding assistant will drift, and the drift is invisible by default.

Claude isn't bad at git. It's actually very competent at git commands. What it's not good at is the specific shape of your discipline — your naming conventions, your deploy protocols, your secret-handling rules, your preference for main over master, your policy on what constitutes a "real" project versus a throwaway experiment. None of that is in Claude's training data in a way that's specific to you.

You can encode that discipline in two places. You can encode it in your own head and hope you catch every drift event in real time. Or you can encode it in tooling that runs automatically at known checkpoints. The first approach does not scale past about one project. The second approach scales indefinitely and gets sharper every time it catches something new.

The night I lost ninety minutes to git forensics was the moment I decided this was worth taking seriously. The months since have been a steady drip of small catches by the audit — none individually significant, all of them cumulatively pointing at a maintenance load that would have manifested, eventually, as an actual data loss event.


The bigger pattern

This story is really about one corner of a much larger problem: the integration tax of working with AI.

Git and GitHub and the PAT and the .gitignore and the secrets file are each a separate protocol. A human integrates them mentally, over years, through repeated exposure. An AI doesn't. An AI sees each one as an independent request and optimizes for the immediate task, not for the coherent whole.

Every tool in your workflow has this property. Your calendar. Your email. Your CRM. Your analytics. Your deploy pipeline. Your observability stack. For each one, there's a specific set of habits and guardrails you've built up that keep the thing sane. Your AI doesn't know any of them unless you encode them somewhere it can see.

The response pattern generalizes. Figure out the drift vectors. Build tooling that catches them at the moment of drift, not on a calendar. Write the tooling assuming the AI is helpful-by-default and will take the path of least resistance. Don't assume the AI will learn your discipline just because you've mentioned it a few times — it won't, and the gap will show up as mysterious bugs three weeks later.

Eventually the patterns across tools start to resemble each other. The secrets file for git looks suspiciously like the secrets file for the API integrations, which looks like the secrets file for the deploy pipeline. At some point the right move is to lift the whole pattern up a level — a general-purpose discipline layer sitting between the AI and your tools. That's where my work is heading next. For now, though, the specific cabinet for the specific tool is the right granularity, because you can actually ship it.

If Claude is driving your git, build the cabinet. Tonight, if you can. The version of you that had to do six months of forensics on a bad April evening will thank the version of you that spent an hour writing a hygiene script.


Frank Kurka is the creator of TQL (The Question Layer), MemoryOS, and the Glass Bead Game development paradigm. He has been building software for 45+ years and writes weekly at fkxx.substack.com.