{"id":471,"date":"2026-08-21T13:31:34","date_gmt":"2026-08-21T13:31:34","guid":{"rendered":"https:\/\/marcinzygmunt.pl\/blog\/?p=471"},"modified":"2026-08-21T13:31:34","modified_gmt":"2026-08-21T13:31:34","slug":"context-is-money-how-to-work-with-a-large-knowledge-base-without-burning-tokens","status":"publish","type":"post","link":"https:\/\/marcinzygmunt.pl\/blog\/context-is-money-how-to-work-with-a-large-knowledge-base-without-burning-tokens\/","title":{"rendered":"Context is Money. How to Work with a Large Knowledge Base Without Burning Tokens"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\">A model is only as good as the context you give it. Working with AI agents (Claude Code, Copilot, Cursor), you discover this quickly and painfully: context is a real cost. Literally, in tokens, and indirectly, in the quality of answers. An overstuffed context means hallucinations, worse responses, higher bills, and the frustration of constantly correcting your agent.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The fix turns out to be a few simple habits and some structural discipline that will spare you the mistakes I made when I started working with AI. I write about code repositories here because that&#8217;s my main workshop, but the same rules apply to any body of knowledge an agent works with: product docs, a notes vault, team procedures, content.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">1. First things first: context on demand, not &#8220;just in case&#8221;<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">The biggest mistake is dumping everything into context &#8220;because it might be useful.&#8221; The model gets lost in the noise (the so-called <em>lost in the middle<\/em> problem), and you pay for tokens that add nothing.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Instead: <strong>structure that lets the model find what it needs on its own<\/strong>. An AI with a good entry point and a clear map of the repo will read the rest when it has to.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">2. How to AI: CLAUDE.md \/ AGENTS.md \/ a README for the agent<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Every repo should have a short AI file. It&#8217;s not documentation for people, it&#8217;s a <strong>condensed briefing<\/strong>:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>what the project is (2\u20133 sentences),<\/li>\n\n\n<li>stack and versions (Java 21, Spring Boot 3.x, Gradle),<\/li>\n\n\n<li>how to build, test, and run it (exact commands),<\/li>\n\n\n<li>conventions: code style, package structure, the patterns you use,<\/li>\n\n\n<li>what NOT to do (e.g., &#8220;don&#8217;t touch the legacy-billing module without a ticket&#8221;).<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">The key part: <strong>this file must be short<\/strong>, under ~150 lines. It&#8217;s loaded into every session, so every line is a fixed token cost. Move details into separate files and link to them; the model will read them when the topic actually comes up.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Each tool has its own standard, and the conventions are worth knowing:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong><code>CLAUDE.md<\/code><\/strong>: Claude Code (supports a hierarchy too: a global <code>~\/.claude\/CLAUDE.md<\/code> + per-repo + per-directory),<\/li>\n\n\n<li><strong><code>AGENTS.md<\/code><\/strong>: an open standard read by a growing list of tools (Codex, Cursor, Zed, and others),<\/li>\n\n\n<li><strong><code>.cursor\/rules\/<\/code><\/strong>: Cursor (rules with per-path activation conditions),<\/li>\n\n\n<li><strong><code>.github\/copilot-instructions.md<\/code><\/strong>: GitHub Copilot,<\/li>\n\n\n<li><strong><code>llms.txt<\/code><\/strong>: a standard for websites and docs, a model-friendly content map.<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">The pragmatic approach: keep one source of truth in <code>AGENTS.md<\/code>, with <code>CLAUDE.md<\/code> as a symlink or a one-line pointer. Zero duplication.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">3. Layers: think CPU cache<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Think of knowledge as a memory hierarchy.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>L1, always in context:<\/strong> the AI file. Minimal.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>L2, read on demand:<\/strong> <code>docs\/<\/code> with short, single-topic files: <code>docs\/architecture.md<\/code>, <code>docs\/auth-flow.md<\/code>, <code>docs\/deployment.md<\/code>. One file = one topic = one read. A 2,000-line file &#8220;about everything&#8221; is an anti-pattern: the model has to ingest all of it to find one paragraph.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>L3, discovered through search:<\/strong> code, tests, ADRs. Here naming and structure do the work (more on that below).<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">This hierarchy isn&#8217;t specific to code. A notes vault or process documentation lays out the same way: a short entry point, an index, topical files read on demand.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">INDEX.md: a map instead of exploration<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Between L1 and L2, an <strong>index file<\/strong> works great: <code>docs\/INDEX.md<\/code> (or a section in the AI file). It&#8217;s a table of contents for the knowledge in the repo, one line per topic:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>- docs\/architecture.md - modules, boundaries, data flow\n- docs\/auth-flow.md - OAuth2 + JWT, refresh tokens\n- docs\/adr\/ - architecture decisions (ADR-0001..0014)\n- payments\/README.md - Stripe integration, webhooks<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The effect: instead of groping through the repo blindly (a dozen-plus reads, thousands of tokens), the model does <strong>one lookup in the index and one precise read<\/strong>. The same works for large monorepos: an INDEX.md per module describing what lives where. One condition: the index has to stay current. Put it on the PR checklist.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">4. Code structure that explains itself<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">AI navigates a repo the way a new team member does: by names. Everything that helps a human onboard helps the model.<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Package-by-feature over package-by-layer.<\/strong> <code>com.company.orders<\/code> says more than order logic scattered across <code>controllers\/<\/code>, <code>services\/<\/code>, <code>repositories\/<\/code>.<\/li>\n\n\n<li><strong>File names match contents.<\/strong> <code>OrderRefundPolicy.java<\/code> turns up with a single grep. <code>Utils2.java<\/code> never will.<\/li>\n\n\n<li><strong>Small files.<\/strong> A 3,000-line class is a context bomb. The model has to load all of it to change one method.<\/li>\n\n\n<li><strong>Tests as documentation.<\/strong> A good test names a business scenario. AI reads tests to understand intent before it touches the code.<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\"><em>(TIP: DDD projects are naturally easier for AI to read and describe. Bounded contexts and ubiquitous language force a structure that explains itself.)<\/em><\/p>\n\n\n\n<h2 class=\"wp-block-heading\">5. ADRs: decision memory for pennies<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Architecture Decision Records are the most underrated form of knowledge for AI. A short file: context \u2192 decision \u2192 consequences. When the model suggests &#8220;how about we rewrite this on Kafka?&#8221;, ADR-0012 explains why you chose RabbitMQ, and the conversation gets back on track. One page of text saves hours of wandering.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">6. Trimming context in practice<\/h2>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong><code>.gitignore<\/code> and ignore lists for AI:<\/strong> generated files, <code>build\/<\/code>, <code>target\/<\/code>: all of it out of indexing range.<\/li>\n\n\n<li><strong>One session = one task.<\/strong> Long, multi-threaded conversations degrade quality. Finished the feature? New session, fresh context.<\/li>\n\n\n<li><strong>Summarize instead of scrolling.<\/strong> When a session balloons, ask for a concise summary of the work so far and start a new session from it.<\/li>\n\n\n<li><strong>Point, don&#8217;t paste.<\/strong> Instead of pasting 500 lines of code, give the file path and let the tool load exactly as much as it needs.<\/li>\n\n\n<li><strong>Delegate documentation updates to the agent.<\/strong> Keeping docs current is the chore nobody ever assigns, so assign it explicitly, as a rule in the AI file: &#8220;if you change something described in <code>docs\/<\/code>, update that file and <code>INDEX.md<\/code> in the same PR.&#8221; The agent is already making the change and has full context, so it doesn&#8217;t get cheaper than that; what&#8217;s left for you is reviewing the docs diff along with the code.<\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\">7. Tools that do it for you (almost)<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">You don&#8217;t have to start from scratch: there are ready-made tools.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Generating the AI file:<\/strong><\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Claude Code <code>\/init<\/code><\/strong>: scans the repo and generates a starter CLAUDE.md,<\/li>\n\n\n<li><strong>Cursor<\/strong>: can generate rules based on an analysis of the project.<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">A generated file is a draft, not a finished product: before it lands in the repo, review it, trim it, and add what the tool couldn&#8217;t know.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Packing a repo into LLM context:<\/strong><\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Repomix<\/strong>: packs a codebase into a single file (Markdown\/XML), shows token counts per file, respects <code>.gitignore<\/code>, and scans for secrets,<\/li>\n\n\n<li><strong>Gitingest<\/strong>: zero setup, swap <code>hub<\/code> for <code>ingest<\/code> in a GitHub URL and you get a text digest of the repo,<\/li>\n\n\n<li><strong>repo2txt<\/strong>: the browser version, you pick the files yourself.<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Auto-documentation:<\/strong><\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>DeepWiki<\/strong> (Cognition\/Devin): generates an interactive wiki with architecture diagrams for any GitHub repo; there&#8217;s also an open-source equivalent that runs locally.<\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\">8. What to avoid<\/h2>\n\n\n\n<ul class=\"wp-block-list\">\n<li>A monolithic 3,000-line README as the &#8220;source of truth.&#8221;<\/li>\n\n\n<li>Documentation that has drifted from the code. Stale knowledge is worse than no knowledge, because the model trusts it.<\/li>\n\n\n<li>The same information duplicated in several places (you pay for it repeatedly and risk contradictions).<\/li>\n\n\n<li>&#8220;Preventive&#8221; context: adding files nobody asked about.<\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\">Summary<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">A good repo for AI is a good repo for people, just held to a stricter standard: a short entry point, layered knowledge, names that speak, small files, documented decisions. And it&#8217;s not just about code: notes, documentation, and procedures benefit from the same structure.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">This year&#8217;s research gives the practice a mixed review. According to one study (Lulla et al., ICSE 2026), an agent in a repo with an <code>AGENTS.md<\/code> finishes tasks faster (median runtime down ~29%) and uses fewer output tokens (~17% less). According to another (Gloaguen et al., ETH Zurich), a context file doesn&#8217;t raise the share of completed tasks, while inference cost grows by over 20% on average, whether the file was written by a human or an LLM. The difference comes down to what was measured: time and tokens on real pull requests versus success rates on a benchmark. The most practical takeaway is ETH&#8217;s finding about content: <strong>agents follow instructions diligently, but a &#8220;repository overview&#8221; helps with nothing<\/strong>.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">My own experience says the practice holds up regardless of the benchmarks. Since the knowledge my agents get has structure (an entry point, an index, small topical files), sessions are shorter, less time goes into correcting the agent, and I no longer start work by explaining everything from zero. Decisions come out more accurate, I can run different models at lower reasoning effort, and costs drop with them.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">A benchmark measures the average across other people&#8217;s repositories; the effect in yours is something you can check yourself.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Treat tokens as a budget and the structure of your knowledge as the interface to the model.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Practical rules for structuring a repo and knowledge base for AI agents: short entry points, layered docs, INDEX.md, ADRs, and what research says about it.<\/p>\n","protected":false},"author":1,"featured_media":470,"comment_status":"open","ping_status":"open","sticky":true,"template":"","format":"standard","meta":{"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_feature_clip_id":0,"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_post_was_ever_published":false},"categories":[1],"tags":[],"class_list":["post-471","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-uncategorized"],"jetpack_likes_enabled":true,"jetpack_sharing_enabled":true,"jetpack_featured_media_url":"https:\/\/marcinzygmunt.pl\/blog\/wp-content\/uploads\/2026\/08\/cover-v1.png","_links":{"self":[{"href":"https:\/\/marcinzygmunt.pl\/blog\/wp-json\/wp\/v2\/posts\/471","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/marcinzygmunt.pl\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/marcinzygmunt.pl\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/marcinzygmunt.pl\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/marcinzygmunt.pl\/blog\/wp-json\/wp\/v2\/comments?post=471"}],"version-history":[{"count":1,"href":"https:\/\/marcinzygmunt.pl\/blog\/wp-json\/wp\/v2\/posts\/471\/revisions"}],"predecessor-version":[{"id":472,"href":"https:\/\/marcinzygmunt.pl\/blog\/wp-json\/wp\/v2\/posts\/471\/revisions\/472"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/marcinzygmunt.pl\/blog\/wp-json\/wp\/v2\/media\/470"}],"wp:attachment":[{"href":"https:\/\/marcinzygmunt.pl\/blog\/wp-json\/wp\/v2\/media?parent=471"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/marcinzygmunt.pl\/blog\/wp-json\/wp\/v2\/categories?post=471"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/marcinzygmunt.pl\/blog\/wp-json\/wp\/v2\/tags?post=471"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}