◉ANTIGRAVITY LABJP
Articles/Agents & Manager
◈ Agents & Manager/2026-07-15Advanced

The File Is Right There in ls, and Your Agent Still Can't Open It

The agent says the file does not exist. Your terminal says it does. After three days of blaming cloud sync, the answer turned out to be that one voiced consonant mark was never a single character. Detection script and a three-layer gate included.

antigravity464agents145unicodetroubleshooting113workflow57

✦ Premium Article

Here is the line that was sitting in an overnight run log:

FileNotFoundError: [Errno 2] No such file or directory:
  'content/reference/壁紙_配色ガイド.md'

Run ls content/reference/ on the same machine and the file is right there, calm as anything. Character by character, it is the same name. The agent insisted otherwise.

Copy the name and paste it: it opens. Let the agent construct it: it doesn't. That asymmetry was the part that bothered me.

I Spent Three Days Blaming the Wrong Thing

My first theory was wrong. It seems worth admitting that up front.

My working folder sits under cloud sync, and I had been burned before by grabbing a placeholder and reading an empty file. So I assumed a repeat, adjusted exclusion rules, forced a full local download, watched the logs, and got the same error.

Day two, I suspected permissions. Owner was fine. Mode was fine. Nothing to see.

Day three, out of ideas, I looked at the bytes.

$ ls content/reference/ | grep 壁紙 | xxd | head -3
00000000: e5a3 81e7 b499 5fe9 858d e889 b2e3 8299  ....._........
00000010: e382 ace3 82a4 e383 895f 2e6d 6400       ........._.md.

There it is: e3 82 99, a combining voiced sound mark. The character after 配 in that filename was not ガ as a single code point. It was カ followed by a standalone ゛ — two characters wearing one glyph.

The agent was looking for a name containing ガ (e3 82 ac). The filesystem held a name containing カ + ゛. To a human eye, identical. As byte strings, unrelated.

No such file or directory was the correct answer. The agent had been right the whole time.

Why Agents Trip on This and People Don't

This is the crux. As long as humans are the ones touching the repo, this problem stays almost completely invisible.

The reason is mundane: people either copy-paste filenames or hit tab-complete. Both hand you the exact bytes the filesystem returned, so you ask for the file using the same byte string that was written.

Agents don't do that. An agent reconstructs the path from prose in its context. If a design note says "see 壁紙_配色ガイド.md," the model reads that string and rebuilds it as a path. And what a language model emits is, essentially without exception, precomposed (NFC).

macOS, for historical reasons, hands back decomposed (NFD) names. Create a folder in Finder, type a Japanese name, and the voiced mark lands as its own separate character.

So the picture looks like this:

Path came fromForm on diskBytes for "ガ"
Named in macOS FinderNFD (decomposed)e3 82 ab + e3 82 99
Generated by a model from contextNFC (precomposed)e3 82 ac
mkdir on a Linux VMNFC (as handed in)e3 82 ac
Git indexWhatever was writtenEither

Git does not arbitrate here. core.precomposeunicode will normalize what comes in through macOS going forward, but it will not retroactively fix names already committed in decomposed form. My repos still carried NFD files from years before I learned that setting existed.

Then comes the genuinely bad part. When an agent decides a file is missing, it helpfully creates it.

content/reference/壁紙_配色ガイド.md   ← present since 2023 (NFD)
content/reference/壁紙_配色ガイド.md   ← created last night by an agent (NFC)

Two identical-looking rows in ls. Different contents. One holds years of accumulated notes; the other is nearly empty and was born at 3am. Which one gets read depends entirely on how the path was assembled that time. I've started calling these ghost duplicates, and I treat them as an incident rather than a curiosity.

✦

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
✦A 60-line scanner that separates 'looks identical' from 'is identical' by comparing bytes instead of glyphs
✦Three independent failure axes — normalization, case folding, invisible characters — closed by three layers that each do one job
✦Six weeks of unattended runs: 14 drifted names, 3 pairs of ghost duplicates, and where tolerant resolution stops being a good idea
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

Antigravity 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

◈ Agents & Manager2026-09-04
Snapshot Your Agents' Effective Scope So You Notice the Day a Default Changes
Antigravity 1.1.25 made Markdown-defined custom agents inherit the surrounding skills, rules, and subagents by default. Here is the snapshot-and-diff routine I now use to check whether an agent I meant to keep narrow quietly got wider after an update.
◈ Agents & Manager2026-05-10
Defining 'Done' with Antigravity Agents: Writing Acceptance Criteria into Your Prompts
When Antigravity returns code that is only halfway working, the usual cause is a missing Definition of Done. Here is the three-layer fix.
◈ Agents & Manager2026-04-28
Stopping an Antigravity Agent Mid-Run: How to Pause and Resume Without Losing Your Work
When an agent starts heading in the wrong direction, hitting Stop without thinking can leave half-edited files and broken checkpoints. Here is the workflow I use to pause an agent and resume cleanly.