I ran a routine cleanup pass on this site's infrastructure recently — the kind of housekeeping that usually turns up nothing worth mentioning. This time it did. Sitting in the credential dashboard were three API keys with write access, none of them referenced anywhere in the code, the deploy pipeline, or the automation that actually runs the site.

Nobody had provisioned them for a reason and forgotten to clean up. Each one had been created by an AI coding agent — Claude Code, working autonomously on a scoped task — at the exact moment it needed a credential and couldn't find the one that already existed.

That's the pattern worth naming, because it isn't a one-off. It's a structural property of how isolated AI coding sessions interact with the config your existing automation depends on, and it will keep happening to anyone running agentic coding tools at any real frequency until they design around it.

The mechanism: isolation is the point, and the problem

Modern AI coding tools increasingly run each task in an isolated workspace — a separate git worktree, a fresh container, a sandboxed checkout. The isolation is deliberate and good: it lets multiple sessions work in parallel without one agent's half-finished edit corrupting another's, and it means a task that goes sideways doesn't touch your main working copy.

The trade-off is that an isolated workspace doesn't automatically inherit everything a normal working copy has. A .env file with your API keys, tokens, and service credentials typically isn't tracked in git — it's local-only, .gitignored, sitting in your main checkout and nowhere else. Git's own worktree documentation is explicit that a linked worktree gets its own working directory and index but shares the repository's object store — untracked files are exactly the category that doesn't come along for the ride. Fork a new isolated workspace and that file doesn't come with it. The agent looks for the credential it needs, doesn't find it, and — reasonably, given what it can see — concludes it doesn't exist.

A well-behaved agent then does the only sensible thing available to it: it goes and gets one. It opens the provider's dashboard or CLI, creates a new key with the permissions the task needs, and uses that. The task succeeds. The code works. And a duplicate credential is now sitting in a provider dashboard with nothing tracking that it exists, active until someone happens to notice.

Run enough scoped agent sessions over a few months and this compounds quietly. Each individual session did nothing wrong — it solved the problem in front of it with the information available. The failure is architectural, not behavioral: nothing in the setup told the agent that the credential existed somewhere it simply couldn't see.

The diagnostic: presence in a dashboard proves nothing

The reason this kind of drift survives normal vigilance is that the usual check — does this key work? — always says yes. A newly minted key with correct permissions passes every functional test you'd think to run. The dashboard shows a name, a creation date, and "last used: never expires." Nothing about that view tells you whether anything in your actual system references it.

The diagnostic that catches this is different from a health check. It's a cross-reference in the other direction: for every credential that exists in the provider's dashboard, find the specific line of code, workflow file, or config value that consumes it. Not "does this work if I test it" — "what, concretely, uses this right now." Anything that doesn't show up on that list isn't a working credential you forgot about. It's an orphan, and every orphan is either dead weight or, worse, a live write-capable key nobody is watching.

That inversion — auditing from the credential store outward instead of from the codebase's known-good list — is what surfaces this pattern. Checking your code for the keys it expects will always look clean, because your code only ever references the keys it knows about. The dashboard is the only place the extras show up.

The fix: three layers, not one

The instinct is to patch this by deleting the orphaned keys and moving on. That fixes the symptom for a week. The actual fix has to close the loop at three points, because each one fails independently.

1. Make the shared credential store actually shared. The mechanical root cause is that an isolated workspace can't see the main checkout's config. The fix isn't to copy the config into every workspace — that reintroduces the exact drift problem one layer down, now with multiple copies of the same secret to keep in sync. It's to make every isolated workspace resolve back to the _one_ canonical file. Git already tracks the relationship between a main checkout and its linked worktrees, and exposes it through a single, stable call — `git rev-parse`'s --git-common-dir flag returns the shared .git directory from any worktree, one directory up from which the shared config file lives. A few lines that walk that relationship back to the shared root turn "every session has its own possibly-stale copy" into "every session reads the same file, always." One source of truth, mechanically enforced rather than remembered.

2. Verify liveness, not just presence. A credential sitting in your deploy pipeline's secret store proves it's _configured_. It doesn't prove the provider still honors it — a token can be revoked, rotated elsewhere, or simply expire without anything in your own system knowing. The fix is a post-deploy check that doesn't just confirm a secret is set; it calls the provider's own identity endpoint with that exact value and fails loudly if the provider rejects it. That turns a dead credential into a blocked deploy instead of a mystery failure three weeks later when a scheduled job quietly starts 401ing.

3. Write the constraint into the agent's own instructions. The first two layers fix the infrastructure. The third fixes the behavior that created the problem in the first place. Every agentic coding tool worth using supports some form of persistent, project-level instructions the agent reads before acting. Put an explicit rule there: a missing credential is a lookup problem, not a provisioning problem. Spell out the actual lookup order — check the project's own secrets tooling first, then the shared config file, then the platform's secret store by name only — and make the last resort "stop and ask," never "create a new one." Agents follow explicit written policy far more reliably than they infer unstated intent, and this is exactly the kind of constraint that's cheap to write down once and expensive to have skipped.

None of these three layers is sufficient alone. Fix only the shared file and an agent still can't tell a live key from a dead one. Fix only the liveness check and you're still generating new orphans between checks. Fix only the policy and you're trusting every future session to remember a rule that isn't enforced anywhere. Together, they make the entire failure mode structurally unavailable instead of merely discouraged.

The broader pattern

This isn't really a story about API keys. It's a specific instance of a broader property of agentic coding tools that's easy to miss until it costs you something: an agent's competence is bounded by what it can see, and isolation — the exact feature that makes parallel AI-assisted work safe — is what narrows that view. The same blind spot shows up anywhere a tool assumes local, ambient context that an isolated session doesn't inherit: cached build artifacts, locally-installed dependencies, state a previous session left behind. "The agent couldn't find X" and "X doesn't exist" are different claims, and conflating them is where this class of problem always starts.

The teams getting the most out of agentic coding aren't the ones who trust the tool to infer good judgment in every gap. They're the ones treating every isolation boundary as a place to ask, explicitly, what the agent can't see from here — and closing that gap once, mechanically, instead of hoping each session reasons its way around it correctly.

FAQ

Does this only affect Claude Code, or every AI coding tool that uses isolated sessions?

Any tool that runs tasks in an isolated workspace — a fresh container, a sandboxed checkout, a separate git worktree — has the same structural blind spot toward untracked local files. The specific mechanism described here is git worktrees because that's the isolation model in play, but the underlying problem (an agent can't distinguish "this doesn't exist" from "I can't see this from here") applies to any tool built on the same isolation pattern.

Isn't copying the .env file into every new workspace a simpler fix?

It solves the immediate symptom and reintroduces the exact problem one layer down: now there are multiple copies of the same secret, and nothing keeps them in sync when one gets rotated. The first time a key changes in the main checkout and a stale copy in an old workspace keeps working against the provider's old value, you're debugging drift instead of preventing it. Resolving back to a single canonical file is more work up front and categorically fewer failure modes later.

How do I know if this has already happened in my own setup?

Audit from the credential store outward, not from your codebase inward. For every key that exists in a provider's dashboard, find the specific line of code or config that consumes it — not whether the key works when tested, but what concretely uses it right now. Anything without an answer is an orphan, and if it still has write access, it's worth revoking immediately, not just noting for later.

Does fixing this require giving up worktree isolation?

No — the fix is orthogonal to isolation, which is the point. Isolation solves a real problem (parallel sessions corrupting each other's state) and should stay. What needs fixing is narrower: the specific assumption that untracked local config is either present or nonexistent, when the accurate third state — present, just not visible from here — is the one nothing in the default setup accounts for.

Where to go from here

This is one instance of a pattern worth watching for generally: an AI agent's judgment is bounded by what it can see, and every isolation boundary narrows that view a little. The three-layer audit covers the broader discipline for verifying an agent's work before you trust it, and why an AI assistant's memory isn't something to trust without a live check covers the adjacent failure mode — an agent confidently wrong about state it can't currently observe. For the strategic layer underneath all of this — which model, what stack, how the tokens-to-output math actually works — start with Which AI Model Should You Actually Use to Build Software?, then work with me or subscribe to the newsletter for more field notes from building in public.

Share this article
LinkedIn (opens in new tab) X / Twitter (opens in new tab)
Atticus Li

Experimentation and growth leader. CXL-certified CRO practitioner, Mindworx-certified behavioral economist (1 of ~1,000 worldwide). 200+ A/B tests across energy, SaaS, fintech, e-commerce, and marketplace verticals.