CLAUDE LABJP
DEFAULT — Sonnet 5 is now the default model for Pro, Team Standard, and Enterprise seats, with a native 1M-token context window and adaptive thinking on by defaultREWIND — The /rewind command can now restore a conversation after /clear. At a checkpoint you choose whether to roll back the code, the conversation, or bothORGDEFAULT — Organization default models are supported. When you have not picked a model yourself, /model shows it as Org default or Role defaultATTACH — File attachments in chat are now clickable. Cmd or Ctrl-click reveals the file in Finder or ExplorerBASH — Bash mode gained live file path autocomplete, and auto mode now spells out the reason when it declines an actionEXPIRE — The claim window for the $100 promotional credit closed on August 2. Credits already claimed expire September 17, so any evaluation run needs to sit inside that windowDEFAULT — Sonnet 5 is now the default model for Pro, Team Standard, and Enterprise seats, with a native 1M-token context window and adaptive thinking on by defaultREWIND — The /rewind command can now restore a conversation after /clear. At a checkpoint you choose whether to roll back the code, the conversation, or bothORGDEFAULT — Organization default models are supported. When you have not picked a model yourself, /model shows it as Org default or Role defaultATTACH — File attachments in chat are now clickable. Cmd or Ctrl-click reveals the file in Finder or ExplorerBASH — Bash mode gained live file path autocomplete, and auto mode now spells out the reason when it declines an actionEXPIRE — The claim window for the $100 promotional credit closed on August 2. Credits already claimed expire September 17, so any evaluation run needs to sit inside that window
Articles/Claude Code
Claude Code/2026-08-03Advanced

Existence Checks Pass, Writes Fail — Probing Capabilities Before an Unattended Run

A directory existing and a directory being writable are two different facts. Measured results from five broken-environment cases, and a capability-probe preflight for unattended Claude Code runs.

Claude Code208Automation42Scheduled RunsError Handling6Operations15

Premium Article

I opened the log first thing in the morning and found the run had stopped on line one.

It had been running the same way for months. Not a character of the code had changed. What changed was the environment underneath it: the working directory had quietly become owned by a different user, and writes to it were no longer permitted.

What actually bothered me was what came next. There was a check at the top of the script. Does the directory exist? If not, create it. If so, use it. I had written that shape for years without questioning it.

That check passed cleanly that morning. The directory existed.

It just could not be written to.

Existing Is Not the Same as Being Usable

I reproduced the state locally first — a directory whose owner keeps read and execute but loses write.

mkdir locked && chmod 500 locked
 
mkdir -p locked; echo "mkdir -p exit=$?"
echo "-d test: $([ -d locked ] && echo true || echo false)"
echo "-w test: $([ -w locked ] && echo true || echo false)"
touch locked/x 2>/dev/null; echo "touch exit=$?"

The output:

mkdir -p exit=0
-d test: true
-w test: false
touch exit=1

The zero from mkdir -p is the part that surprised me. It does not mean "created and ready." It means "already there, nothing to do." That is correct by the POSIX definition. But anyone who writes mkdir -p "$DIR" && cd "$DIR" reads that zero as a guarantee about the next step.

[ -d ] has the same shape. It is a question about existence, and I had been leaning on it as a question about permission. You do not get answers to questions you never asked.

That gap is precisely where the run broke.

Measuring Existence Checks Against Capability Probes

So I split verification into two styles and compared them.

The first is the existence check I had always written: os.path.isdir, os.path.exists, the presence of a .git directory. The second is a capability probe — perform the operation you are about to perform, once, at the smallest possible scale. If you plan to write, write. If you plan to delete, delete. If you plan to use git, run git rev-parse through it.

I built five environments that break in different ways: a directory that exists but rejects writes, a path that is a file where a directory was expected, a dangling symlink, a directory containing a .git entry that is not a repository, and a genuinely read-only mount.

Here is what came back.

CaseExistence checkCapability probe
Exists but not writableOKNG
File where a directory was expectedNGNG
Dangling symlinkNGNG
Has .git but is not a repositoryOKNG
Read-only mountOKNG

Three of five — 60% — passed on existence alone. And all three share a trait: the path is entirely correct, only the operation is impossible. You can stare at the spelling of that path forever and find nothing.

I also recorded what happens if you proceed anyway.

CaseActual failure
Not writabletouch: cannot touch ...: Permission denied
File where a directory was expectedtouch: cannot touch ...: Not a directory
Has .git but is not a repositoryfatal: not a git repository (exit 128)
Read-only mounttouch: cannot touch ...: Read-only file system

The painful part of an unattended run is when these surface. All the heavy work completes, and only the final write fails. In this repository, the stage that reads and tallies 1,594 article files (about 19.29 million characters) takes 0.093 seconds. The five capability probes together take 2.57 milliseconds. If your first stage takes minutes instead of milliseconds, those minutes are thrown away in full.

As a share of that first stage, the probes cost roughly 2.8%. Across three consecutive runs, the ratio between "finish everything, then fail" and "probe first, then fail" measured 6,470x, 8,315x, and 6,892x. Probes are cheap because they perform the real operation at a trivial scale rather than reasoning about permissions. There is no inference to get wrong.

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
Five broken-environment cases measured side by side: three passed the existence check while the operation was impossible
A directory where os.access returns True and create, append, and rename all succeed — but unlink fails with EPERM
How a probe that read a credential differently from production rejected a perfectly valid token, and the rule that prevents it
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.

or
Unlock all articles with Membership →
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.

  • Copy-paste ready implementation code
  • New advanced guides published daily
  • $5/mo or $10 for lifetime access
View Membership →

Related Articles

Claude Code2026-06-27
Will It Stay Light When You Run It Unattended? Observing and Capping Claude Code's Long-Session Memory
How to keep long, unattended Claude Code sessions from slowly getting heavier — with a tiny ps-based RSS sampler, a rolling-baseline watchdog, and session segmentation, shown with working scripts and a before/after comparison.
Claude Code2026-06-19
An Article My Gate Rejected Got Published — The Cost of Chaining the Quality Gate and git push in One Call
In an unattended publishing pipeline, an article my quality gate had rejected went live anyway. The cause was chaining the gate and git push into a single shell call. Here is how the exit code gets swallowed, and a two-phase publish-marker design that refuses to push until every gate has demonstrably passed.
Claude Code2026-06-17
When an Announced Billing Change Is Withdrawn at the Last Minute, Change No Code
A billing change that was supposed to take effect was withdrawn on the day. To survive announce, apply, and revert without touching code, I keep platform behavior behind a single flag and project the monthly delta from real logs.
📚RECOMMENDED BOOKS
Build a Large Language Model (From Scratch)
Sebastian Raschka
LLM Dev
Prompt Engineering for LLMs
Berryman & Ziegler
Prompting
AI Engineering
Chip Huyen
AI Eng
* Contains affiliate links
See all →