Every project ends up with two kinds of files: the ones that go to git, and the ones that should never. Credentials, personal notes, environment files for the staging server, a list of API keys for a specific feature. The “should never” category is usually managed by a .gitignore and a couple of .env files, but that pattern leaves no room for context. Where is the README that explains what each credential is for? Where are the notes from the production incident last month? Where is the temporary profiling output from the load test you ran in February?

This rule defines a .local/ folder in every project for exactly that purpose. It is gitignored, but searchable. It has structure. It has breadcrumbs in the tracked folders so the next session knows what moved where.

The story behind the rule

The moment I wrote this rule was during a credentials audit on a past project. I was tracking down where each API key in the codebase came from. The trail was scattered:

  • One key was in a .env file at the repo root.
  • Another was in a .env.example (with a placeholder, the real one was somewhere else, I never figured out where).
  • A third was hardcoded in a script that had been “temporarily” committed two months earlier.
  • A fourth was in someone’s local Notes app, shared via screenshot in a chat thread.

The codebase had no convention for where credentials lived. Each new contributor invented their own. The audit found three keys that should have been rotated months ago, two keys that did not belong to the project at all, and one key still active for an account nobody worked with anymore.

After the audit, I wrote the rule and started enforcing it on every project I worked on. Every project gets a .local/ folder. Every credential lives in there. Every move out of a tracked location leaves a breadcrumb. The audit took half a day; the rule takes ten minutes per project to enforce.

The rule

The full rule from ~/.claude/rules/user-local-folder.md:

# Local Folder Convention

`.local/` is a project-specific folder for credentials, personal
notes, and context shared between user and Claude. It is gitignored
but searchable by Claude.

## Structure

.local/
  <feature>/          # Group by feature/topic
    README.md         # Index of contents
    *.env             # Credentials
    *.md              # Notes and docs
  README.md           # Root index

## Rules

- Add `.local/` to `.gitignore` in every project that uses it.
- Group files by feature/domain (e.g., `kafka/`, `database/`,
  `api/`).
- Include `README.md` in each subdirectory.
- When moving sensitive files to `.local/`, leave a breadcrumb file
  (e.g., `CREDENTIALS-MOVED.md`) at the original location pointing
  to the new path.
- Store credentials, API keys, and sensitive configs here instead
  of committing them.

## When to Use

- Credentials and secrets that cannot be committed.
- Personal project context and architecture notes.
- Temporary analysis, profiling results, experiments.
- Incident notes and troubleshooting logs.

The rule is short on prose but specific on structure. Each subsection (<feature>/) gets its own README. The root .local/ gets an index. Breadcrumbs go in the tracked locations. The model loads this rule on every session and follows it without prompting.

Why a folder, not just .env

The natural first instinct is “just use .env files.” That works for environment variables but fails for everything else. A .env cannot hold:

  • A multi-line note explaining what each credential is for.
  • A markdown table of which service uses which key.
  • The output of a load test from last Tuesday.
  • The runbook for the staging server you built six months ago.
  • A breadcrumb pointing to where a file used to live.

.local/ is a folder, so it can hold all of those things. It is gitignored, so nothing leaks. It is structured (one subfolder per feature, each with a README), so it is navigable. The .env files still exist inside .local/<feature>/ for actual environment variables; they just have neighbors.

Why breadcrumbs matter

This is the part that took me longest to learn. When you move a file out of the tracked tree into .local/, the file is gone from where anyone (including a future you) might expect it. The next session that searches for the file finds nothing. The next contributor who clones the repo has no idea the file ever existed. The model that loads the rule does not know to look in .local/ for a specific file unless something points there.

The breadcrumb fixes this. A breadcrumb is a small tracked file at the original location that says “this used to be here, it has been moved to .local/<feature>/, here is what is in it.” The breadcrumb is committed; the moved file is not. Anyone who looks at the original location sees the breadcrumb and follows it.

A breadcrumb might be a CREDENTIALS-MOVED.md file that looks like:

# Credentials Moved

Files with sensitive data moved to `.local/kafka/`.

| Original | New Location |
|----------|--------------|
| `credentials.env` | `.local/kafka/credentials.env` |

A code comment can also serve as a breadcrumb:

// Configuration loaded from .local/database/connection.env
// See .local/database/README.md for setup instructions

Both shapes work. The pattern is: never leave a hole. If something moved, point to where it moved.

Why grouping by feature beats grouping by type

I tried the alternative for a while: one folder for credentials, one for notes, one for analysis. It did not work. When I came back to a project two months later, I had to remember “the staging API key is a credential, so it is in credentials/, and the runbook for staging is a note, so it is in notes/.” Each lookup required mapping the feature to the file type to the folder.

Grouping by feature flips this. Everything related to the staging API lives in .local/staging/. The credentials, the notes, the analysis, the breadcrumbs, all in one place. One lookup gets everything. The cost is that some files (a generic helper script, a credential used by multiple features) do not fit neatly. I keep those in a .local/shared/ subfolder.

The structure in practice

A real example from a past project:

.local/
  kafka/
    README.md
    kafka-ui-portainer-env.txt
    kafka-ui-ec2-only.env
    kafka-ui-env-config.txt
  database/
    README.md
    prod-db-credentials.env
  shared/
    README.md
  README.md

The Kafka folder had three different env configurations from different deployment paths. Each was labeled. The README at .local/kafka/README.md explained when to use which. The root .local/README.md indexed everything.

At the original location (a tracked scripts/kafka/ folder), there was a breadcrumb:

scripts/kafka/
  CREDENTIALS-MOVED.md       # Breadcrumb pointing to .local/kafka/
  README-kafka-config.md     # Public docs (no secrets)

The breadcrumb is committed. The credentials are not. Anyone reading scripts/kafka/ finds the breadcrumb, follows it to .local/kafka/, sees the README, and knows what is there.

When the rule does not apply

There are a few places where .local/ is not the right answer:

  • Truly project-wide secrets that all team members need. Use a team secrets manager (cloud KMS, HashiCorp Vault, AWS Secrets Manager). .local/ is per-developer. Team-shared secrets need a team-shared store.
  • CI environment variables. Those live in the CI provider’s secret management UI, not in .local/. The model never has access to CI secrets anyway.
  • Read-only public documentation. That belongs in docs/, tracked and reviewed. .local/ is for files only you (and the model in your session) should see.
  • Anything you might want to share via PR. PRs cannot include .local/ files because they are gitignored. If a file is on the path to becoming public, do not put it in .local/.

The rule is specifically for the per-developer, per-machine, per-project context that has no good home in either tracked code or shared infrastructure.

Variants you might want

  • Different folder name. Some teams prefer .notes/ or .scratch/. The name does not matter; the convention does. Pick one and stick to it across projects.
  • Encrypted at rest. A stricter version uses git-crypt or age to encrypt .local/ so even a stray clone or backup cannot leak. I do not, because the threat model for my projects is more about accidental commits than about disk theft. Adjust to your context.
  • Cross-project sharing. If you have shared credentials used across many projects (a personal API key for a tool you use everywhere), you can put them in ~/.local/<tool>/ instead of a project-specific path. The model follows the convention either way, as long as the breadcrumb in the project points to the right path.
  • Auto-cleanup policy. A stricter rule could say “anything older than 90 days in .local/analysis/ gets archived.” I do not formalize this; I clean up manually when I notice.

Closing note

The .local/ rule is one of those quiet wins. No one notices it is in place; you just stop having credentials scattered across the repo. The audit becomes “look in one place” instead of “trace each variable.” New contributors do not invent their own pattern; they read the rule and follow it.

For related discipline on what should and should not be committed, see the git rule in this same toolkit series. The git rule has a .env.* pre-commit check; the local folder rule is where those .env files actually live once they are out of the tracked tree.