.claudeignore Doesn't Exist. Here's What Does.

.claudeignore Doesn’t Exist. Here’s What Does.

Every time you drop into a Claude Code session, it starts indexing your project. In a .NET solution, that means bin/ and obj/ directories first: tens of thousands of compiled IL files, PDB symbols, generated Razor views, and NuGet extraction caches that serve exactly zero purpose in an AI context window. Then come the test coverage reports, the generated code, the environment files. All of it lands in context unless you tell Claude otherwise.

So you ask Claude how to control which files it can see.

And Claude tells you about .claudeignore.

Of course it does. The concept is obvious: .gitignore keeps files out of version control, .dockerignore keeps files out of Docker build context, so naturally .claudeignore keeps files out of Claude’s context. Clean, consistent, intuitive. You add it to the project root, list your secrets and production config files, commit it alongside your .gitignore, and get on with your day.

The AI assistant is properly restricted. Your teammates are protected. The security audit will go smoothly.

One small problem.

The Problem: Claude Hallucinated Its Own Feature

Here’s what actually happened. Someone asked Claude how to prevent it from touching third-party licensed code in their repository. Claude, being helpful, explained that Claude Code supports a .claudeignore file with the same syntax as .gitignore: just drop it in the project root, and Claude will leave those files alone.

Except that feature doesn’t exist. Claude invented it.

The hallucination spread remarkably well. It turned up in blog posts, Stack Overflow answers, Reddit threads, and engineering wikis. Claude then read those discussions, concluded that .claudeignore must be real because everyone was talking about it, and started recommending it again. Confidently. Every time. An AI coding assistant invented a capability it doesn’t have, the made-up documentation spread across the internet, and now the AI keeps training on that documentation to reinvent the same capability. You couldn’t design a better hallucination feedback loop if you tried.

Meanwhile, developers were sleeping soundly. They had a .claudeignore in their repository. They had listed appsettings.Production.json. They had excluded .env.*. They had blocked secrets/. They had done the responsible thing, ticked the box, and assured their security teams the AI assistant was properly restricted.

Production database connection strings: protected. API keys: safe. OAuth client secrets: completely off-limits.

None of that was true. The file did nothing. It still does nothing. It is a text file with glob patterns that no tool reads.

To be precise about the scope of the problem: .claudeignore is fiction, and it isn’t unique to Claude. Neither Claude Code, nor GitHub Copilot, nor OpenAI Codex offers a simple .claudeignore-style file at the project root. The mechanisms that actually exist are more fragmented, more verbose, tool-specific, and in several important cases considerably less capable than a plain ignore file would be.

Here’s what you’re actually working with.

Claude Code: permissions.deny in Settings

Claude Code’s real mechanism for restricting file access is the permissions section in .claude/settings.json. Instead of a clean, readable standalone file, you get JSON with tool permission syntax:

{
  "permissions": {
    "deny": [
      "Read(./.env)",
      "Read(./.env.*)",
      "Read(./secrets/**)",
      "Read(./appsettings.Production.json)",
      "Read(./appsettings.Staging.json)"
    ]
  }
}

Each entry in the deny array is a tool call pattern. Read(path) denies Claude Code’s Read tool access to the matched path. The path supports glob patterns, so Read(./secrets/**) blocks the entire secrets directory tree.

The settings file comes in two variants. .claude/settings.json is committed to version control and applies to the whole team. .claude/settings.local.json is personal, automatically gitignored by Claude Code when created. For security-relevant exclusions, use settings.json so restrictions are consistent across the team.

A practical baseline for .NET projects:

{
  "permissions": {
    "deny": [
      "Read(./.env)",
      "Read(./.env.*)",
      "Read(./secrets.json)",
      "Read(./appsettings.Production.json)",
      "Read(./appsettings.Staging.json)",
      "Read(./**/bin/**)",
      "Read(./**/obj/**)"
    ]
  }
}

Now here’s the part most writeups about this topic quietly skip: permissions.deny rules are tool-level controls, not filesystem-level blackouts.

Read(./bin/**) blocks Claude Code’s Read tool from opening files in bin/. But Glob and Grep are separate tools, and Read deny rules don’t cover them. Claude can still discover those paths and search their contents. It just can’t read a file directly.

I asked Claude Code directly whether it had access to bin/ folders after a Read deny rule was active. The answer: yes, Glob found them just fine.

So permissions.deny alone does not make a directory invisible. For build artifacts like bin/ and obj/, the more reliable mechanism is the .gitignore file you already have. Claude Code respects .gitignore by default (respectGitignore: true), and that exclusion applies across all discovery mechanisms, not just the Read tool. In practice, directories already in .gitignore are not surfaced by Glob or Grep in normal operation. Adding Read deny rules on top gives you a second layer, but .gitignore is doing the heavier lifting.

For secrets and credentials specifically, this distinction matters in a way that should make you uncomfortable. A production config file sitting in the repository root is not protected by a Read deny rule the way you might assume. Claude can still see that the file exists, discover its path with Glob, and match content patterns against it with Grep. The deny rule prevents reading the full file contents, but the file remains visible. The real answer, as always, is not having that file in the repository at all.

GitHub Copilot: Exists, But Read the Fine Print

GitHub Copilot does have a content exclusion feature. Before you get optimistic: it requires Copilot Business or Copilot Enterprise. Individual, Free, and Pro tiers don’t get it.

It also isn’t a file you commit to your repository. There’s no .copilotignore. Exclusions are configured through GitHub’s web UI at the repository, organization, or enterprise level, and the configuration lives on GitHub’s end, not yours. If you want to know what’s excluded in a given repository, you navigate through GitHub’s admin interface to find out.

The configuration format at least uses familiar YAML path patterns:

"*":
  - "**/.env"
  - "**/appsettings.Production.json"
  - "**/secrets/**"

Here’s the part that really matters: these restrictions apply when Copilot is accessed through the IDE extension for code completion and inline chat. They do not apply to Agent mode, Copilot CLI, or the cloud agent. GitHub states this explicitly in their documentation.

The agentic workflows are exactly the ones where unrestricted file access is most concerning. They’re also the ones the exclusion feature doesn’t cover.

GitHub’s content exclusion is a governance feature for enterprise administrators, not a developer-facing tool for managing what an agent can see. The use case it serves is “prevent this entire codebase from reaching the AI at the org level.” The use case it doesn’t serve is “control what the agent accesses when I’m actively using it.”

OpenAI Codex: Nothing

As of May 2026, OpenAI Codex has no built-in mechanism for file exclusion. Codex is an API. What goes into the context window is entirely the responsibility of the client making the call. If you’re using Codex through a third-party tool or IDE integration, that tool may or may not have its own ignore mechanism. The model itself is indifferent to what you send it.

What This Means for .NET Projects

Given the actual state of tooling, here’s where that leaves you:

On Claude Code: use permissions.deny in .claude/settings.json, but understand you’re adding a tool-level restriction, not a filesystem blackout. Prioritize secrets and environment-specific config files. Build artifacts are better handled by .gitignore, which you almost certainly already have and which provides broader coverage across all discovery mechanisms.

On GitHub Copilot Business or Enterprise: configure content exclusions at the organization level for sensitive repositories if you need the governance coverage. Accept that none of this applies to agent-based workflows. For individual context management in the IDE, the exclusion feature is your only option. For agents, there is no equivalent.

On Codex or API-based tools: the exclusion problem is entirely at the integration layer. Read your tool’s documentation, not Codex’s.

The Feature That Should Exist But Doesn’t

The .claudeignore hallucination spread so effectively because it named something developers genuinely need: a simple, version-controlled file that tells an AI coding assistant which files to leave alone. Same syntax as .gitignore. Lives in the project root. Gets committed like any other configuration. Readable by anyone on the team.

That doesn’t exist. What exists instead is a JSON config with Read tool denial patterns that doesn’t cover Glob and Grep, a web-based admin feature that costs extra and doesn’t work for agents, and an API that does whatever the client tells it to.

The gap between what developers want and what the tooling provides is real. Claude filling that gap by inventing a feature called .claudeignore is understandable: the concept is obvious, the need is legitimate, the name is perfect. It’s also deeply unhelpful, because developers have implemented .claudeignore files in their repositories, committed them, documented them in their onboarding guides, and assumed they were doing something. They weren’t.

The actual security takeaway: don’t put credentials in your repository. Azure Key Vault, user secrets during development, environment variable injection in CI/CD: these are not just best practices, they’re the only mechanisms that actually guarantee your production credentials don’t end up in an AI context window. permissions.deny and GitHub’s content exclusion are useful layers on top. They are not a substitute for that foundation.

The .claudeignore situation is a concrete illustration of a broader rule worth internalizing: AI tools recommend nonexistent features with the same confident tone they use for everything else. A hallucinated configuration file and a correct one read exactly the same way. Verify against official documentation before you trust it, especially for anything security-adjacent.

The official documentation for Claude Code’s actual file exclusion mechanism is at code.claude.com/docs/en/settings#excluding-sensitive-files. That’s where a search for .claudeignore should have taken you from the beginning.

Comments

VG Wort