<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Documentation on Code Plato</title><link>https://CodePlato3721.github.io/tags/documentation/</link><description>Recent content in Documentation on Code Plato</description><generator>Hugo -- gohugo.io</generator><language>en</language><lastBuildDate>Sun, 13 Sep 2026 00:00:00 +0000</lastBuildDate><atom:link href="https://CodePlato3721.github.io/tags/documentation/index.xml" rel="self" type="application/rss+xml"/><item><title>A Concise Guide to Writing CLAUDE.md</title><link>https://CodePlato3721.github.io/post/a-concise-guide-to-writing-claude-md/</link><pubDate>Sun, 13 Sep 2026 00:00:00 +0000</pubDate><guid>https://CodePlato3721.github.io/post/a-concise-guide-to-writing-claude-md/</guid><description>&lt;img src="https://pub-deacd49348914a49b1254b01f351ef0d.r2.dev/2026/09/a-concise-guide-to-writing-claude-md/en/banner.png" alt="Featured image of post A Concise Guide to Writing CLAUDE.md" /&gt;&lt;p&gt;This guide applies equally to &lt;code&gt;AGENTS.md&lt;/code&gt;&lt;/p&gt;&#10;&lt;h2 id="what-claudemd-is-for"&gt;What CLAUDE.md Is For&#10;&lt;/h2&gt;&lt;p&gt;First, let&amp;rsquo;s understand what CLAUDE.md is for. A model is like a newborn. Every time you talk to it, it has no idea who you are, who it is, or what you&amp;rsquo;ve said before. It learns all of this from the context you pass it. Of course, Claude Code comes with some preset context, so it knows it&amp;rsquo;s Claude Code, a tool that helps you write code.&#10;So at the start of every new session, it knows nothing about your project. The reason it still works reasonably well is that Claude Code&amp;rsquo;s own preset context teaches it what to do to understand a project before touching it.&#10;That&amp;rsquo;s why it can seem to understand your project quite well, yet still frequently reinvents the wheel. It has a methodology for quickly getting up to speed, but it still can&amp;rsquo;t know every detail of your project. And you wouldn&amp;rsquo;t want it to try — that would burn far too many tokens.&#10;This is where someone needs to use short, plain language to tell it about the project&amp;rsquo;s background, architecture, and so on. Doing this has two benefits:&lt;/p&gt;&#10;&lt;ol&gt;&#10;&lt;li&gt;It won&amp;rsquo;t need to traverse your entire project, saving tokens&lt;/li&gt;&#10;&lt;li&gt;It won&amp;rsquo;t do things that obviously go against your codebase&amp;rsquo;s intent, or reinvent the wheel&#10;This short text is what goes into &lt;code&gt;CLAUDE.md&lt;/code&gt;, or &lt;code&gt;AGENTS.md&lt;/code&gt;. This guide applies equally to &lt;code&gt;AGENTS.md&lt;/code&gt;.&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;h2 id="writing-principles"&gt;Writing Principles&#10;&lt;/h2&gt;&lt;p&gt;A good CLAUDE.md should read like:&#10;&lt;strong&gt;The shortest onboarding guide for a new hire:&lt;/strong&gt; Imagine you&amp;rsquo;re onboarding a new hire for a task. Try to convey just enough knowledge, in the fewest words possible, for them to start working without wrecking your codebase.&#10;&lt;strong&gt;Wording as tight as a résumé:&lt;/strong&gt; A while back I was job hunting, and I learned from an HR contact how to write a résumé. I racked my brain compressing my 4-page résumé down to 2 pages, cutting almost every redundant word, tightening every sentence until it couldn&amp;rsquo;t be trimmed further. You should write &lt;code&gt;CLAUDE.md&lt;/code&gt; the same way.&#10;&lt;strong&gt;Highly abstract knowledge:&lt;/strong&gt; You don&amp;rsquo;t need to tell &lt;code&gt;Claude Code&lt;/code&gt; or &lt;code&gt;Codex CLI&lt;/code&gt; how many spaces to indent, or which line of which file has the database connection. Leave a lot of that to hooks — file names and line numbers change all the time. What you should tell the model are highly abstract design principles.&#10;Generally speaking, a good &lt;code&gt;CLAUDE.md&lt;/code&gt; should be under 200 lines.&lt;/p&gt;&#10;&lt;h2 id="types"&gt;Types&#10;&lt;/h2&gt;&lt;p&gt;Including the &lt;code&gt;CLAUDE.md&lt;/code&gt; at your project root, there are actually 3 kinds of &lt;code&gt;CLAUDE.md&lt;/code&gt;.&lt;/p&gt;&#10;&lt;ol&gt;&#10;&lt;li&gt;&lt;strong&gt;&lt;code&gt;~/.claude/CLAUDE.md&lt;/code&gt;&lt;/strong&gt; — global scope. Used by all of your projects.&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;&lt;code&gt;./CLAUDE.md&lt;/code&gt;&lt;/strong&gt; — project scope.&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;&lt;code&gt;./subdirectory/CLAUDE.md&lt;/code&gt;&lt;/strong&gt; — subdirectories can have their own &lt;code&gt;CLAUDE.md&lt;/code&gt; too.&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;h2 id="framework"&gt;Framework&#10;&lt;/h2&gt;&lt;p&gt;There&amp;rsquo;s no strict, perfect framework for &lt;code&gt;CLAUDE.md&lt;/code&gt;. But drawing on some good examples of &lt;code&gt;CLAUDE.md&lt;/code&gt; and related articles, I&amp;rsquo;ve distilled a reasonably sound structure:&lt;/p&gt;&#10;&lt;ol&gt;&#10;&lt;li&gt;One-line introduction&lt;/li&gt;&#10;&lt;li&gt;Architecture&lt;/li&gt;&#10;&lt;li&gt;Tech stack&lt;/li&gt;&#10;&lt;li&gt;Commands&lt;/li&gt;&#10;&lt;li&gt;Conventions&lt;/li&gt;&#10;&lt;li&gt;Boundaries&lt;/li&gt;&#10;&lt;li&gt;Domain doc map&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;h3 id="one-line-introduction"&gt;One-Line Introduction&#10;&lt;/h3&gt;&lt;p&gt;A brief description of what the project is and roughly what it does. Example:&lt;/p&gt;&#10;&lt;pre tabindex="0"&gt;&lt;code&gt;This is a multi-agent orchestration framework for coordinating parallel Claude Code sub-agents, automating dev/QA workflows on a FastAPI + React codebase.&#10;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id="architecture"&gt;Architecture&#10;&lt;/h3&gt;&lt;p&gt;A brief description of the project&amp;rsquo;s architecture, for example:&lt;/p&gt;&#10;&lt;pre tabindex="0"&gt;&lt;code&gt;## Architecture&#10;- Keep controllers thin — business logic lives in `app/Services/`&#10;- Database access only goes through `app/Repositories/`. No direct Eloquent usage in controllers.&#10;- API resources under `app/Http/Resources/` are responsible for shaping every JSON response.&#10;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id="tech-stack"&gt;Tech Stack&#10;&lt;/h3&gt;&lt;p&gt;A brief description of the project&amp;rsquo;s tech stack, like:&lt;/p&gt;&#10;&lt;pre tabindex="0"&gt;&lt;code&gt;## Tech Stack&#10;- FastAPI, Python 3.11&#10;- PostgreSQL 15 (async SQLAlchemy 2.0)&#10;- Celery + Redis for background jobs&#10;- Poetry for dependency management&#10;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id="commands"&gt;Commands&#10;&lt;/h3&gt;&lt;p&gt;Common commands for the project, for example:&lt;/p&gt;&#10;&lt;pre tabindex="0"&gt;&lt;code&gt;## Commands&#10;- Dev server: `uvicorn app.main:app --reload`&#10;- Run tests: `pytest -x -v`&#10;- DB migrations: `alembic upgrade head`&#10;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id="conventions"&gt;Conventions&#10;&lt;/h3&gt;&lt;p&gt;Abstract conventions that a linter can&amp;rsquo;t capture, like:&lt;/p&gt;&#10;&lt;pre tabindex="0"&gt;&lt;code&gt;## Conventions&#10;- Boolean variables/properties are prefixed with `is`, `has`, or `should`&#10;- All datetimes are stored and passed as UTC&#10;- Event names follow the `domain.action` naming format&#10;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id="boundaries"&gt;Boundaries&#10;&lt;/h3&gt;&lt;p&gt;Boundaries on which files can be modified:&lt;/p&gt;&#10;&lt;pre tabindex="0"&gt;&lt;code&gt;## Boundaries&#10;- `legacy/` — old payment system, emergency bug fixes only, no new patterns or refactors&#10;- `src/generated/` — auto-generated by Prisma/GraphQL&#10;- `vendor/`, `third_party/` — third-party code, fix issues by upgrading the dependency version, don&amp;#39;t edit directly&#10;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id="domain-doc-map"&gt;Domain Doc Map&#10;&lt;/h3&gt;&lt;p&gt;A mapping between domain terms and documentation:&lt;/p&gt;&#10;&lt;pre tabindex="0"&gt;&lt;code&gt;## Domain Doc Map&#10;| Mentions | Read |&#10;|---|---|&#10;| billing, stripe, payment, subscription, invoice | docs/billing.md |&#10;| auth, login, session, oauth, jwt | docs/auth.md |&#10;| migration, schema, drizzle, kysely | docs/db-migrations.md |&#10;| feature flag, rollout, kill switch | docs/feature-flags.md |&#10;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Putting these examples together, a good &lt;code&gt;CLAUDE.md&lt;/code&gt; should look something like this:&lt;/p&gt;&#10;&lt;pre tabindex="0"&gt;&lt;code&gt;This is a multi-agent orchestration framework for coordinating parallel Claude Code sub-agents, automating dev/QA workflows on a FastAPI + React codebase.&#10;&#10;## Architecture&#10;- Keep controllers thin — business logic lives in `app/Services/`&#10;- Database access only goes through `app/Repositories/`. No direct Eloquent usage in controllers.&#10;- API resources under `app/Http/Resources/` are responsible for shaping every JSON response.&#10;&#10;## Tech Stack&#10;- FastAPI, Python 3.11&#10;- PostgreSQL 15 (async SQLAlchemy 2.0)&#10;- Celery + Redis for background jobs&#10;- Poetry for dependency management&#10;&#10;## Commands&#10;- Dev server: `uvicorn app.main:app --reload`&#10;- Run tests: `pytest -x -v`&#10;- DB migrations: `alembic upgrade head`&#10;&#10;## Conventions&#10;- Boolean variables/properties are prefixed with `is`, `has`, or `should`&#10;- All datetimes are stored and passed as UTC&#10;- Event names follow the `domain.action` naming format&#10;&#10;## Boundaries&#10;- `legacy/` — old payment system, emergency bug fixes only, no new patterns or refactors&#10;- `src/generated/` — auto-generated by Prisma/GraphQL&#10;- `vendor/`, `third_party/` — third-party code, fix issues by upgrading the dependency version, don&amp;#39;t edit directly&#10;&#10;## Domain Doc Map&#10;| Mentions | Read |&#10;|---|---|&#10;| billing, stripe, payment, subscription, invoice | docs/billing.md |&#10;| auth, login, session, oauth, jwt | docs/auth.md |&#10;| migration, schema, drizzle, kysely | docs/db-migrations.md |&#10;| feature flag, rollout, kill switch | docs/feature-flags.md |&#10;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id="should-you-write-a-never-section"&gt;Should You Write a &amp;ldquo;Never&amp;rdquo; Section?&#10;&lt;/h3&gt;&lt;p&gt;You may have seen a section in other guides called &amp;ldquo;Never,&amp;rdquo; used to record past mistakes. Sounds good in theory. But I don&amp;rsquo;t recommend adding this section. That&amp;rsquo;s because a &amp;ldquo;Never&amp;rdquo; section has &lt;strong&gt;only the motivation to add, never the motivation to remove&lt;/strong&gt;. It just keeps growing — even Claude Code itself will add to it, and no one ever trims it. Over time it turns into a &lt;strong&gt;graveyard of historical incidents&lt;/strong&gt;.&#10;What I&amp;rsquo;d suggest instead: when a problem comes up, flip the failure mode around and write it as a positive rule. For instance, instead of &amp;ldquo;Never do synchronous database writes in &lt;code&gt;webhook/stripe.ts&lt;/code&gt;,&amp;rdquo; write &amp;ldquo;Database operations only happen inside &lt;code&gt;repository/&lt;/code&gt;.&amp;rdquo;&lt;/p&gt;&#10;&lt;h2 id="trimming"&gt;Trimming&#10;&lt;/h2&gt;&lt;p&gt;Even if you follow the framework above, for a large project, a long-lived one, or one that already has a &lt;code&gt;CLAUDE.md&lt;/code&gt;, you&amp;rsquo;ll still find it hard to keep the file under 200 lines. That&amp;rsquo;s when you move to the trimming step.&#10;Trimming means moving things out of &lt;code&gt;CLAUDE.md&lt;/code&gt;. Here are the destinations and methods, in order:&lt;/p&gt;&#10;&lt;ol&gt;&#10;&lt;li&gt;Custom sub-agents: &lt;code&gt;.claude/agents&lt;/code&gt;&lt;/li&gt;&#10;&lt;li&gt;Rules folder: &lt;code&gt;.claude/rules&lt;/code&gt;&lt;/li&gt;&#10;&lt;li&gt;Subdirectory CLAUDE.md: &lt;code&gt;./subdirectory/CLAUDE.md&lt;/code&gt;&lt;/li&gt;&#10;&lt;li&gt;Fixed workflows: &lt;code&gt;.claude/skills/&lt;/code&gt;&lt;/li&gt;&#10;&lt;li&gt;Other docs: &lt;code&gt;docs/&lt;/code&gt;&#10;Notice these are numbered. That&amp;rsquo;s because extraction has a priority order — from specific to abstract, from precise to general.&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;h3 id="custom-sub-agents"&gt;Custom Sub-agents&#10;&lt;/h3&gt;&lt;p&gt;Move all guidance related to sub-agents into &lt;code&gt;.claude/agents&lt;/code&gt;. For example:&#10;You could define an agent dedicated to running integration tests, named &lt;code&gt;integration-tester.md&lt;/code&gt;, with content like:&lt;/p&gt;&#10;&lt;pre tabindex="0"&gt;&lt;code&gt;---&#10;name: integration-tester&#10;description: Runs integration tests&#10;tools: Bash&#10;model: sonnet&#10;---&#10;&#10;You run and diagnose integration tests. You should follow these steps.....&#10;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id="rules-folder"&gt;Rules Folder&#10;&lt;/h3&gt;&lt;p&gt;Specific rule files can live in &lt;code&gt;.claude/rules&lt;/code&gt;. There are two kinds: path-scoped and non-path-scoped. Non-path-scoped rules carry the same priority as &lt;code&gt;CLAUDE.md&lt;/code&gt;, for example:&lt;/p&gt;&#10;&lt;pre tabindex="0"&gt;&lt;code&gt;# Security Rules&#10;&#10;- All user input is validated at the API boundary&#10;- Secrets and API keys are read from environment variables only&#10;- SQL queries always use parameterized statements&#10;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Path-scoped rules only load when the given path condition is met, for example:&lt;/p&gt;&#10;&lt;pre tabindex="0"&gt;&lt;code&gt;---&#10;paths:&#10; - &amp;#34;tests/**/*.py&amp;#34;&#10; - &amp;#34;**/*.spec.ts&amp;#34;&#10;---&#10;&#10;# Unit Testing Rules&#10;&#10;- One assertion concept per test&#10;- Test names describe behavior, not implementation&#10;....&#10;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;strong&gt;Rules vs. the domain doc map:&lt;/strong&gt; You might wonder: &amp;ldquo;Don&amp;rsquo;t rule files and the domain doc map end up defining the same thing twice?&amp;rdquo; Yes, that overlap can happen. For instance, you might specify that files under &lt;code&gt;billings/&lt;/code&gt; should follow the billing docs, and also have a row in the domain doc map like &lt;code&gt;| billings | docs/billings.md |&lt;/code&gt; — which is indeed redundant.&#10;The fix is to split documentation into &lt;strong&gt;rules&lt;/strong&gt; and &lt;strong&gt;background&lt;/strong&gt;. Rule files are highly enforceable and belong in &lt;code&gt;.claude/rules&lt;/code&gt;. Background files are comparatively looser and belong in &lt;code&gt;docs/&lt;/code&gt;.&lt;/p&gt;&#10;&lt;h3 id="subdirectory-claudemd"&gt;Subdirectory CLAUDE.md&#10;&lt;/h3&gt;&lt;p&gt;Rules specific to certain subdirectories can move into those directories — common cases are &lt;code&gt;sql/&lt;/code&gt;, &lt;code&gt;domains/&lt;/code&gt;, &lt;code&gt;adapters/&lt;/code&gt; folders. A &lt;code&gt;CLAUDE.md&lt;/code&gt; in these directories doesn&amp;rsquo;t need to follow the standard framework, but it should still stay short.&lt;/p&gt;&#10;&lt;h3 id="fixed-workflows"&gt;Fixed Workflows&#10;&lt;/h3&gt;&lt;p&gt;If there are fixed, sequential operations, turn them into a project-level skill and put it under &lt;code&gt;.claude/skills/&lt;/code&gt;.&lt;/p&gt;&#10;&lt;h3 id="other-docs"&gt;Other Docs&#10;&lt;/h3&gt;&lt;p&gt;Everything else goes into the &lt;code&gt;docs/&lt;/code&gt; directory. This directory holds more general documentation — things like a more detailed &lt;code&gt;architecture.md&lt;/code&gt;, or ADRs (Architecture Decision Records) under &lt;code&gt;docs/adr/&lt;/code&gt;, e.g. &lt;code&gt;docs/adr/0001-migrate-to-drizzle.md&lt;/code&gt;.&lt;/p&gt;&#10;&lt;h2 id="getting-started"&gt;Getting Started&#10;&lt;/h2&gt;&lt;p&gt;If you don&amp;rsquo;t yet have a &lt;code&gt;CLAUDE.md&lt;/code&gt; or &lt;code&gt;AGENTS.md&lt;/code&gt;, start with these steps:&lt;/p&gt;&#10;&lt;ol&gt;&#10;&lt;li&gt;Run &lt;code&gt;/init&lt;/code&gt; to generate a first draft&lt;/li&gt;&#10;&lt;li&gt;Revise the draft following the methods above&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;p&gt;Also remember to run &lt;code&gt;/doctor&lt;/code&gt; periodically going forward to keep optimizing &lt;code&gt;CLAUDE.md&lt;/code&gt;.&lt;/p&gt;&#10;&lt;h2 id="references"&gt;References&#10;&lt;/h2&gt;&lt;ul&gt;&#10;&lt;li&gt;&lt;a class="link" href="https://www.humanlayer.dev/blog/writing-a-good-claude-md" target="_blank" rel="noopener"&#10; &gt;https://www.humanlayer.dev/blog/writing-a-good-claude-md&lt;/a&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;a class="link" href="https://chipp.ai/engineering/claude-md-architecture" target="_blank" rel="noopener"&#10; &gt;https://chipp.ai/engineering/claude-md-architecture&lt;/a&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;a class="link" href="https://dev.to/nishilbhave/claudemd-best-practices-the-complete-2026-guide-435j" target="_blank" rel="noopener"&#10; &gt;https://dev.to/nishilbhave/claudemd-best-practices-the-complete-2026-guide-435j&lt;/a&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;a class="link" href="https://medium.com/@arad.haghi/best-practices-for-structuring-claude-code-projects-1b7144a683bc" target="_blank" rel="noopener"&#10; &gt;https://medium.com/@arad.haghi/best-practices-for-structuring-claude-code-projects-1b7144a683bc&lt;/a&gt;&lt;/li&gt;&#10;&lt;/ul&gt;&#10;</description></item></channel></rss>