{"slug": "five-files-that-go-in-before-the-agent-writes-a-line", "title": "Five files that go in before the agent writes a line", "summary": "A developer outlines five configuration files that should be created before an AI coding agent writes any code, emphasizing that agents lack memory and rely on files for context. The files include CLAUDE.md for working memory, .claude/settings.json for deny rules, .env.example for variable names, .gitignore to prevent key leaks, and a pre-commit hook with gitleaks to scan for secrets. The developer warns about common pitfalls such as command spelling variations and the need to use gitignore-style patterns for deny rules.", "body_md": "You open an empty folder, type \"build me an app\", and for about two days it's magic.\n\nThen week two arrives. The agent drops a database call straight into a component, because nothing ever told it not to. A folder you needed gets renamed. Somewhere in there it explains, with total confidence, a decision you never made. You start every session re-explaining the same things, and each explanation lives exactly as long as that one conversation.\n\nHere's the part that took me too long to internalize: **the agent doesn't remember yesterday**. Not \"sort of remembers\". Doesn't. Every session starts from nothing, and whatever isn't written into a file simply didn't happen.\n\nSo before a line of code exists, five files go in. It's about fifteen minutes, and it's the difference between a project that accumulates and one that resets every morning.\n\n`CLAUDE.md`\n\n- the thing it reads first\nThis is the file the agent opens at the start of every session. Treat it as working memory - the agent has none of its own, so this file is all there is. Documentation for a future teammate is a different job, and it can wait.\n\nWhat actually earns its place in there:\n\nKeep it short enough that you'd actually re-read it. Mine drifts toward a hundred lines and I trim it back.\n\n`.claude/settings.json`\n\n- the things that aren't up for discussion\nRules in prose get weighed against everything else in the context window. A deny rule doesn't get weighed. It just fails.\n\nUse prose for judgement - naming, style, when to stop and ask. Use the deny list for the handful of things that are irreversible:\n\n```\n{\n  \"permissions\": {\n    \"deny\": [\n      \"Bash(rm -rf*)\",\n      \"Bash(rm -fr*)\",\n      \"Bash(git push --force*)\",\n      \"Bash(git reset --hard*)\",\n      \"Read(**/.env)\",\n      \"Read(**/.env.*)\"\n    ]\n  }\n}\n```\n\nTwo things I got wrong here and would rather you didn't.\n\n**Spell the same command every way it can be spelled.** These are prefix matches, not intent detection. `rm -rf`\n\nand `rm -fr`\n\nare the same command to you and two different strings to the matcher. Same with `git push --force`\n\nversus `git push origin +main`\n\n- the `+`\n\nis a force push wearing a different hat, and a rule written for `--force`\n\nnever sees it coming.\n\n**Use `Read(**/.env)`, not `\n\nRead(./.env)`.** The `\n\n./` version anchors to one directory. The `\n\n**/` version follows gitignore semantics and catches the file at any depth. If your project ever grows a `\n\nservices/api/.env`, the first version protects nothing and looks like it does.\n\n`.env.example`\n\n- so it doesn't need the real one\nThe agent needs to know which variables exist. It doesn't need their values. An example file with the names and empty values answers the question completely, and the real file stays denied.\n\n```\nDATABASE_URL=\nSTRIPE_SECRET_KEY=\n```\n\nWorth knowing before you ship anything to a browser: anything prefixed `NEXT_PUBLIC_`\n\nor `VITE_`\n\ngets compiled into the page and is visible to every visitor. That happens at build time, so there's no fixing it afterwards.\n\n`.gitignore`\n\n- before the first commit, not after\nObvious file, easy to postpone, expensive to postpone.\n\nA key that reaches git history doesn't leave when you delete the line. It stays in the history, and public repos get scanned by bots continuously. Rotating a key you know leaked is annoying. The other kind is worse.\n\n`.pre-commit-config.yaml`\n\n- a scanner that runs whether you remember or not\n\n```\nrepos:\n  - repo: https://github.com/gitleaks/gitleaks\n    rev: v8.30.0\n    hooks:\n      - id: gitleaks\n```\n\nThen once, after `git init`\n\n:\n\n```\npip install pre-commit\npre-commit install\n```\n\nThat second command is the whole thing. Without it the YAML sits there looking responsible and scanning nothing. I'd bet a lot of repos have exactly that.\n\nAnd when you test it - don't use `AKIAIOSFODNN7EXAMPLE`\n\n. It's the fake AWS key from the docs, gitleaks allowlists it deliberately, your commit sails through, and you conclude the hook is broken or, worse, that it's working. Use any invented key in a realistic shape.\n\nHere's the one I'd most want to know as a beginner, because nothing warns you.\n\n`CLAUDE.md`\n\nis inherited up the tree. `settings.json`\n\nis not.\n\nYour rules file gets picked up from parent folders. The deny list doesn't travel at all - it's read only from the folder you actually started the session in, and there's no falling back to the parent.\n\nI found this the boring way, reading docs for something else. I keep one project across three folders: notes and plans in one, a website in another, an app in a third. Guess which folder had the strongest deny list, a sandbox config and a working hook on top. The one with the text files. Meanwhile both folders holding real code - live database, deploy, signing key - had nothing at all. Not weak protection. None.\n\nIt had been that way for weeks and I'd have told you the project was locked down, because I'd seen the config with my own eyes. In the wrong folder.\n\nSo: the protection goes in every folder you actually open a session in. If you work in a monorepo and start sessions in subfolders, that's every subfolder, not the root.\n\nNone of it reviews your code, saves a machine that's already compromised, or makes the agent's judgement trustworthy. It removes the failure modes that are common and permanent, and it does that before there's anything to lose.\n\nThe rest is ordinary engineering discipline, same as it ever was.\n\nI keep these files in a repo so I don't retype them: [github.com/mikobuilds/claude-code-security-checklist](https://github.com/mikobuilds/claude-code-security-checklist). MIT, take what's useful.\n\nIf you do this differently - especially if you've got a deny rule that turned out to be theatre - I want to hear it.", "url": "https://wpnews.pro/news/five-files-that-go-in-before-the-agent-writes-a-line", "canonical_source": "https://dev.to/mikobuilds/five-files-that-go-in-before-the-agent-writes-a-line-580e", "published_at": "2026-08-10 20:46:20+00:00", "updated_at": "2026-08-10 21:16:50.131716+00:00", "lang": "en", "topics": ["ai-agents", "developer-tools", "ai-safety"], "entities": ["Claude", "gitleaks", "GitHub", "AWS"], "alternates": {"html": "https://wpnews.pro/news/five-files-that-go-in-before-the-agent-writes-a-line", "markdown": "https://wpnews.pro/news/five-files-that-go-in-before-the-agent-writes-a-line.md", "text": "https://wpnews.pro/news/five-files-that-go-in-before-the-agent-writes-a-line.txt", "jsonld": "https://wpnews.pro/news/five-files-that-go-in-before-the-agent-writes-a-line.jsonld"}}