●CONFERENCE — Code w/ Claude, the annual developer conference, kicked off June 22 with keynotes, sessions, and workshops●LIMITS — Claude Code rate limits doubled and Opus API limits rose, making it easier to build reliably at scale●DESIGN — Claude Design updates add design-system alignment, tighter Claude Code sync, and direct canvas editing●SANDBOX — Claude Managed Agents now run in your own sandbox and connect to private MCP servers●MODEL — Claude Fable 5 offers a 1M-token context, always-on adaptive thinking, and 128K output●LINEUP — Opus 4.8, Sonnet 4.6, and Haiku 4.5 lead the lineup; pick the right one per task●CONFERENCE — Code w/ Claude, the annual developer conference, kicked off June 22 with keynotes, sessions, and workshops●LIMITS — Claude Code rate limits doubled and Opus API limits rose, making it easier to build reliably at scale●DESIGN — Claude Design updates add design-system alignment, tighter Claude Code sync, and direct canvas editing●SANDBOX — Claude Managed Agents now run in your own sandbox and connect to private MCP servers●MODEL — Claude Fable 5 offers a 1M-token context, always-on adaptive thinking, and 128K output●LINEUP — Opus 4.8, Sonnet 4.6, and Haiku 4.5 lead the lineup; pick the right one per task
I Watched an Agent Try to Fix a File It Had Already Fixed — Stale Shallow Clones and Refreshing Before You Decide
An unattended agent tried to re-fix a file it had already fixed. The cause was a days-old shallow clone it kept reading. Here is how to detect that staleness numerically and re-clone only before decisions.
I was reading the logs of a pipeline that runs unattended when I stopped. The agent was trying, with exactly the same intent, to fix something it had already fixed the day before. A diff was being produced, yet nothing new landed on the remote. Nothing failed, either. It was simply redoing work that had already been put to bed.
The cause was unglamorous. A shallow clone I kept under /tmp to make runs faster had quietly gone stale over several days. The agent read that old tree, concluded "this still needs fixing," and calmly started a second pass.
As an indie developer who touches several repositories on a fixed schedule every day, I have learned that this "silently aging clone" is a nastier opponent than it looks. Today I want to use that single incident to lay out a design that catches staleness as a number and re-clones only right before a decision.
It Tried to Fix a Place It Had Already Fixed
That day the agent was reusing the persistent clone, as usual. git pull --rebase had run, and the log showed no errors. Even so, the artifact it was about to generate was nearly identical to one published the day before.
A quick check on disk made the cause obvious. The persistent clone held 668 articles; re-fetching the remote showed 671. Three new pieces — added earlier by a different session — had never made it into the local tree. The HEAD commits disagreed, too. The agent never knew that "three of the 671 are new," so it kept judging from a 668-article world where the work "did not yet exist."
I had trusted pull completely at first, so for a while I looked in the wrong place. I suspected write permissions, then the network, and only at the end came back to the obvious truth: the tree I was reading was old.
"Can't Write" and "Is Old" Are Completely Different Failures
When you triage this kind of bug, the first thing worth separating is the failure class. They look alike, but the fixes are nothing alike.
Set user.email/name before commit; judge success by comparing local==remote SHA
Permission denied on write
Working dir owned by another user, disk full
Fall back to a writable path, free up space
A diff exists, yet the verdict is "nothing to do"
The clone you are reading is stale
Measure how far behind the remote you are before deciding, and re-clone if needed
This incident is the bottom row. The write path was healthy and permissions were fine. What was broken was the freshness of the read. No amount of "push says success but nothing landed" handling, or owner-mismatch fallback, reaches this failure. That is exactly why it deserves to be treated as its own distinct fault.
✦
Thank you for reading this far.
Continue Reading
What follows includes implementation code, benchmarks, and practical content we hope you'll find useful. This site runs without ads — server and development costs are supported entirely by members like you. If it's been helpful, we'd be truly grateful for your support.
WHAT YOU'LL LEARN
✦How to compare local HEAD against remote HEAD with git ls-remote and report exactly how many commits behind you are before pushing
✦Separating a write-failure from a stale-read failure, and adding a re-clone check that targets only the second one
✦Building an idempotent unattended pipeline that confirms the artifact already exists before generating, so it stops duplicating work
Secure payment via Stripe · Cancel anytime
✦
Unlock This Article
Get full access to the rest of this article. Buy once, read anytime. This site is ad-free — your support goes directly toward keeping it running.
Reusing a --depth 1 shallow clone for speed has a clear upside. It is far faster than a full clone every run, and light on disk. My own clone, built without node_modules, lands around 30MB, so the urge to reuse it is natural.
The problem is that a shallow clone is easy to mistake for current. There are several routes by which it goes old.
Another session or machine pushed first. When you distribute automation, a single repository has multiple writers. The remote moves while you sleep.
The pull did not run, or was swallowed. If a rebase conflict or a brief network hiccup leaves pull half-finished, downstream steps may keep running as if nothing happened.
A shallow history makes pull behavior hard to read. With almost no history locally, --depth 1 makes rebases misbehave more often than you would expect.
None of these throws a loud error. That is why it "ages in silence." And in unattended operation, there is no human present to doubt that silence.
See Staleness as a Number — Compare Local HEAD to Remote HEAD
The heart of the fix is to stop asking "did pull succeed?" and instead produce a number: "how many commits behind the remote is the tree I am reading right now?" Because git ls-remote fetches only a reference over the network, you can check the remote tip without touching your working tree.
Here is the naive version I wanted to get away from.
# Before: trust that pull succeeded, then proceed to decidecd "$WORK"git pull --rebase origin main # may not halt downstream even if it fails# now read content/ and conclude "not there yet" -> wrong call on an old tree
And here is the version that measures the gap before deciding. It reads the remote tip first and compares.
# After: before deciding, report the gap as a commit countcd "$WORK"LOCAL=$(git rev-parse HEAD)REMOTE=$(git ls-remote origin -h refs/heads/main | cut -f1)if [ "$LOCAL" != "$REMOTE" ]; then # count how far behind (a shallow history may not have enough to count) git fetch --depth 50 origin main 2>/dev/null BEHIND=$(git rev-list --count "HEAD..$REMOTE" 2>/dev/null || echo "unknown") echo "stale: local=$LOCAL remote=$REMOTE behind=$BEHIND"fi
The key point is that ls-remotechanges nothing in the working tree. You measure the freshness of a read without contaminating the read you are about to judge from. The moment LOCAL != REMOTE appears, you know mechanically that the current tree is no longer trustworthy as a basis for a decision.
Re-clone or Catch Up — Where the Decision Forks
Once you know the gap, the next question is how to close it. This is not one-size-fits-all; choose based on what the read drives.
Situation
Choice
Reason
The read drives a "generate or not" decision
Re-clone fresh
A fresh clone is more deterministic and easier to reason about than a shallow rebase
Small gap, and the write is a simple append
git fetch && reset --hard origin/main
Lines you up with the tip without paying re-clone cost
Multiple writers touch the same paths
Re-clone plus a pre-generation existence check
Catching up alone can miss the fact that someone else already fixed it
The rule I settled on is simple. If the read decides what to do next, re-clone without hesitation. For reads that only display or tally — things you can correct later if wrong — catching up is enough. Be strict about freshness only for reads that drive decisions. That keeps the re-clone count low while pulling the wrong-call seedlings out by the root.
You may also run into side issues, such as a /tmp shallow clone you cannot delete because it is owned by another user. When that happens, do not cling to it; cloning fresh into a different, writable path is the fastest move in the end. One re-clone resolves the freshness and the ownership problem together.
Idempotency Is What Stops Duplicate Work
Detecting freshness is only half of the machinery that prevents duplicate work. The other half is making generation itself idempotent — that is, "if it is already done, do nothing," confirmed against reality right before generating.
# before generating, confirm against reality whether the artifact existsTARGET="content/articles/en/${CAT}/${SLUG}.mdx"if [ -f "$TARGET" ]; then echo "skip: $SLUG already exists (avoid double generation)" exit 0fi# from here on, "truly not there yet" is guaranteed
It is modest, but it also stops the leaks that slip past freshness detection. Freshness detection prevents "starting to think on an old foundation"; the idempotency check prevents "building the same artifact twice." Their roles differ, so you only feel safe with both. Even my double-fix would have stopped at the last step — old tree or not — had this existence check sat in front of generation.
Wire It Into Operations — A Verdict Function and a Log
Finally, fold all of this into a single verdict. Because it runs unattended, always log the basis for the decision. Letting a human trace "why did it re-clone?" afterward is what makes unattended operation feel safe.
# refresh_if_stale: call before a decision. returns true when stale.refresh_if_stale() { local work="$1" remote_url="$2" cd "$work" || return 1 local local_sha remote_sha local_sha=$(git rev-parse HEAD) remote_sha=$(git ls-remote "$remote_url" -h refs/heads/main | cut -f1) if [ "$local_sha" = "$remote_sha" ]; then echo "[fresh] $(TZ=Asia/Tokyo date +%H:%M) local==remote ${local_sha:0:7}" return 1 fi echo "[stale] local=${local_sha:0:7} remote=${remote_sha:0:7} -> re-clone" return 0}# callerif refresh_if_stale "$WORK" "$REMOTE_URL"; then # re-clone only before a read that drives a decision rm -rf "$WORK" && git clone --depth 1 "$REMOTE_URL" "$WORK"fi
I spell out TZ=Asia/Tokyo to avoid an accident where the log timestamp drifts to UTC and overwrites the previous day's record. That, too, is something unattended operation taught me the hard way, and I have added it ever since. The verdict is only a few lines, but the design intent — deciding in advance where to doubt freshness — is what quietly heads off duplicate work and wrong calls.
As a next step, pick one of your running unattended jobs and write down where the "reads that drive decisions" are. Wrap just those in refresh_if_stale. Usually a single function closes off the whole path to a quiet, wrong decision. Thank you for reading.
Share
Thank You for Reading
Claude Lab is ad-free, supported entirely by members like you. We publish practical guides daily with implementation code, benchmarks, and production-ready patterns. If you've found it useful, we'd love to have you on board.