[{"data":1,"prerenderedAt":663},["ShallowReactive",2],{"guide-en":3},{"id":4,"title":5,"attribution":6,"body":7,"definition":654,"description":655,"extension":656,"eyebrow":657,"meta":658,"navigation":227,"path":659,"seo":660,"stem":661,"__hash__":662},"docs\u002Fen\u002Fguide.md","How to apply Context Architecture to an existing codebase",null,{"type":8,"value":9,"toc":639},"minimark",[10,14,17,26,29,34,37,40,51,55,58,61,94,97,101,104,107,139,147,157,161,164,177,180,192,196,202,205,292,295,299,302,305,310,318,321,325,344,350,365,369,384,387,398,402,425,431,437,443,447,450,456,460,466,472,489,492,574,580,592,596,602,606,635],[11,12,13],"p",{},"A repo starts clean and grows for three years. Conventions drift. The docs stop matching the code.\nThe folder names tell you which framework built the thing, not what the thing does.",[11,15,16],{},"Now hand it to a reader with no memory: someone on their first day, or an AI agent started cold. Ask\nfor one change. They cannot tell what anything means, where the change goes, or which of two competing\npatterns is the current one. The repo grew. Nobody designed it to be read.",[11,18,19,20,25],{},"That is the problem this fixes. The ",[21,22,24],"a",{"href":23},"\u002F","specification"," says what Context Architecture is and why.\nThis page is the part you do with your hands: how to apply it to a repo you already have.",[11,27,28],{},"The \"already have\" matters. A new project starts with the structure its framework hands it, and this\nproblem does not exist yet. It shows up later, once the code grows past what one person holds in their\nhead. So this is not a way to start a project. It is a way to fix one. You are not building a new\ncity, you are putting street names on one that already sprawled.",[30,31,33],"h2",{"id":32},"before-you-start-is-it-worth-it","Before you start: is it worth it?",[11,35,36],{},"It has a real cost. The restructuring up front, the checks that are themselves code you have to keep\ngreen, and a small tax on every pull request to keep each claim tied to a check.",[11,38,39],{},"It pays off in proportion to how much agent or multi-person work the repo takes on. Worth it on a\ncodebase that absorbs refactors, migrations, spec-driven features, agent contributions. Not worth it\non a throwaway prototype or a problem you have not figured out yet. There the tax costs more than it\nreturns, and skipping it is the right call. Saying that out loud is part of the discipline.",[41,42,44],"callout",{"color":43},"neutral",[11,45,46,50],{},[47,48,49],"strong",{},"The one reader to design for."," Assume a reader who keeps nothing between sessions and knows only\nwhat the repo states out loud. An AI agent is exactly that reader. A new teammate is close. The metric\nunderneath all of it is one number: how long until that reader makes a correct change.",[30,52,54],{"id":53},"the-order-of-operations","The order of operations",[11,56,57],{},"Do it in small steps. You do not stop everything and restructure at once. You land one bounded,\nreversible change at a time, and each one ships with the check that keeps its claim honest. No\nbig-bang rewrite.",[11,59,60],{},"The order runs cheapest and safest first:",[62,63,64,68,71,79,82,85,88,91],"ol",{},[65,66,67],"li",{},"Read the repo as a cold reader, and name the failure modes you hit.",[65,69,70],{},"Fix the docs that lie.",[65,72,73,74,78],{},"Put ",[75,76,77],"code",{},"AGENTS.md"," at the top boundaries.",[65,80,81],{},"Turn your most-repeated review comment into a lint rule.",[65,83,84],{},"Break up one junk-drawer folder.",[65,86,87],{},"Make the capabilities findable.",[65,89,90],{},"Move toward a domain-first layout, last, and only if it earns the churn.",[65,92,93],{},"Wire the loop that keeps it from rotting again.",[11,95,96],{},"The rest of the guide is one step per section, then one full example.",[30,98,100],{"id":99},"step-1-audit-the-repo-as-a-cold-reader","Step 1: audit the repo as a cold reader",[11,102,103],{},"Open the repo as if you had never seen it and remember nothing. Read the top-level tree, then the\nboundaries, then a handful of leaf files. At each level, one question: could I make a correct change\nhere without asking anyone? Every \"no\" is a defect you just found.",[11,105,106],{},"The defects come in five shapes. None of them is the model's fault, which is why a better model or a\ncleverer prompt does not fix any of them:",[62,108,109,115,121,127,133],{},[65,110,111,114],{},[47,112,113],{},"Reimplementation."," The source of truth was not findable, so the reader rebuilds what already exists.",[65,116,117,120],{},[47,118,119],{},"Invented structure."," Nothing was imposed, so the reader imposes its own.",[65,122,123,126],{},[47,124,125],{},"Obedience to false docs."," It cites deleted files or contradicts the current code, with full confidence.",[65,128,129,132],{},[47,130,131],{},"Deprecated-pattern spread."," It copies the loudest pattern even when that pattern is dead.",[65,134,135,138],{},[47,136,137],{},"Coin-flip on ambiguity."," Two conventions coexist, so it picks whichever it read first.",[11,140,141,142,146],{},"Write down, per principle, a verdict and the evidence. Do it by hand, or load the\n",[21,143,145],{"href":144},"\u002Fskill","Context Architecture skill"," into your agent and let it write the report.",[11,148,149,152,153,156],{},[47,150,151],{},"What this looks like."," On a payments service, the first pass finds refund logic spread across three\nfolders (reimplementation waiting to happen), a ",[75,154,155],{},"README"," pointing at a deploy script that was deleted\nmonths ago (false docs), and two date helpers with different signatures (a coin-flip). Three failure\nmodes named before you touch a line.",[30,158,160],{"id":159},"step-2-fix-context-rot-first","Step 2: fix context-rot first",[11,162,163],{},"Start by stopping the docs from lying. A doc that cites a deleted file or contradicts the code is\nworse than no doc at all, because a confident reader does what it says.",[11,165,166,167,169,170,172,173,176],{},"Find it by hand or by script: pull every file path, command, symbol, and link out of your ",[75,168,155],{},",\nyour ",[75,171,77],{}," and ",[75,174,175],{},"CLAUDE.md"," files, and your design docs, and check that each one still exists or\nstill runs. Fix each lie against what the code actually does today.",[11,178,179],{},"Then make the rot impossible to bring back. Add a test that asserts every path the docs cite still\nexists on disk. Now \"this doc is accurate\" is a claim with a check behind it, instead of a hope.",[11,181,182,184,185,187,188,191],{},[47,183,151],{}," The ",[75,186,155],{}," documents a ",[75,189,190],{},"deploy.sh"," that was deleted a year ago. You drop\nthe dead reference, write down the real command, and add that path-check test. The next time someone\nmoves a file out from under a doc, the suite goes red in the same pull request, not in production six\nweeks later.",[30,193,195],{"id":194},"step-3-place-agentsmd-at-the-top-boundaries","Step 3: place AGENTS.md at the top boundaries",[11,197,198,199,201],{},"Context belongs next to the code it describes, at every boundary that owns something. Put there, it\nages at the same rate as the code and gets read by the same agent about to edit it. Start at the root\nand the two or three busiest directories. That is where each ",[75,200,77],{}," buys the most legibility.",[11,203,204],{},"Write down only what you cannot get from reading the code: the source of truth, the invariants, the\ntech debt you accepted on purpose, and the reasoning a spec left behind. Keep each one short.",[206,207,212],"pre",{"className":208,"code":209,"language":210,"meta":211,"style":211},"language-markdown shiki shiki-themes material-theme-lighter github-light github-dark","# AGENTS.md (billing)\n\nOwns invoicing, refunds, and the dunning schedule.\n\n## Source of truth\nPrices come from the `pricing-engine` package, never hard-coded here.\n\n## Invariants\n- A refund never exceeds the captured amount. Enforced by `refunds\u002Fguard.test.ts`.\n- All money is integer cents, no floats. Enforced by the `no-float-money` lint rule.\n\n## Accepted tech debt\nThe legacy `chargeV1` path stays until the 2026-Q3 migration. Do not extend it.\n","markdown","",[75,213,214,222,229,235,240,246,252,257,263,269,275,280,286],{"__ignoreMap":211},[215,216,219],"span",{"class":217,"line":218},"line",1,[215,220,221],{},"# AGENTS.md (billing)\n",[215,223,225],{"class":217,"line":224},2,[215,226,228],{"emptyLinePlaceholder":227},true,"\n",[215,230,232],{"class":217,"line":231},3,[215,233,234],{},"Owns invoicing, refunds, and the dunning schedule.\n",[215,236,238],{"class":217,"line":237},4,[215,239,228],{"emptyLinePlaceholder":227},[215,241,243],{"class":217,"line":242},5,[215,244,245],{},"## Source of truth\n",[215,247,249],{"class":217,"line":248},6,[215,250,251],{},"Prices come from the `pricing-engine` package, never hard-coded here.\n",[215,253,255],{"class":217,"line":254},7,[215,256,228],{"emptyLinePlaceholder":227},[215,258,260],{"class":217,"line":259},8,[215,261,262],{},"## Invariants\n",[215,264,266],{"class":217,"line":265},9,[215,267,268],{},"- A refund never exceeds the captured amount. Enforced by `refunds\u002Fguard.test.ts`.\n",[215,270,272],{"class":217,"line":271},10,[215,273,274],{},"- All money is integer cents, no floats. Enforced by the `no-float-money` lint rule.\n",[215,276,278],{"class":217,"line":277},11,[215,279,228],{"emptyLinePlaceholder":227},[215,281,283],{"class":217,"line":282},12,[215,284,285],{},"## Accepted tech debt\n",[215,287,289],{"class":217,"line":288},13,[215,290,291],{},"The legacy `chargeV1` path stays until the 2026-Q3 migration. Do not extend it.\n",[11,293,294],{},"Look at the invariants: each one names the check that enforces it. That is the whole point. An\ninvariant with nothing behind it is just a new line that can rot. If the check does not exist yet,\nwrite it in the same change, or phrase the line as a known gap, not a guarantee.",[30,296,298],{"id":297},"step-4-codify-the-loudest-convention","Step 4: codify the loudest convention",[11,300,301],{},"Take the comment you leave most often in review, the one that lives only in your team's heads, and put\nit in the toolchain. A convention an agent cannot read is a convention it will break, every time.",[11,303,304],{},"This is the move the rest of the steps lean on. When a claim needs to hold, this is how it holds:\na lint rule that states the convention and fails in the same place, or a type that makes the wrong\nthing refuse to compile.",[11,306,307,309],{},[47,308,151],{}," The comment you leave most is \"import from the package root, not deep\npaths.\" Today it lives in reviewers' heads, so an agent breaks it on its first commit.",[206,311,316],{"className":312,"code":314,"language":315,"meta":211},[313],"language-text","# before: a convention that lives in reviewers' heads\n\"always import from the package root, never deep paths\"\n\n# after: the convention, written down and enforced\n.oxlintrc.json   # a no-restricted-imports rule that fails the deep path in CI\n","text",[75,317,314],{"__ignoreMap":211},[11,319,320],{},"Once the rule is in the linter, the deep path fails on the spot, with a message that cites the rule,\nnot a reviewer who happened to be paying attention that day.",[30,322,324],{"id":323},"step-5-name-a-junk-drawer-boundary","Step 5: name a junk-drawer boundary",[11,326,327,330,331,330,334,330,337,330,340,343],{},[75,328,329],{},"utils\u002F",", ",[75,332,333],{},"common\u002F",[75,335,336],{},"helpers\u002F",[75,338,339],{},"core\u002F",[75,341,342],{},"lib\u002F",". This is where responsibility goes to die. Nothing in\nthe name pushes back on unrelated code, so the folder grows forever. Pick the worst one and split it\ninto folders whose names each say what they own.",[206,345,348],{"className":346,"code":347,"language":315,"meta":211},[313],"# before\nsrc\u002Futils\u002F        # 40 unrelated files\n\n# after\nsrc\u002Fpricing\u002F      # the price math that was hiding in utils\nsrc\u002Fauth-session\u002F # the session helpers that were hiding in utils\nsrc\u002Fshared\u002F       # what is genuinely generic, kept small and dependency-free\n",[75,349,347],{"__ignoreMap":211},[11,351,352,353,356,357,360,361,364],{},"The name is doing the work. A folder called ",[75,354,355],{},"pricing"," resists code that is not about pricing, because\nit stops fitting. If you cannot name a boundary precisely, the boundary is wrong, and ",[75,358,359],{},"shared"," is not\nthe answer. A tiny ",[75,362,363],{},"shared\u002F"," for a date formatter or a result type is fine. Reaching for the generic\nname to dodge the question of where something belongs is the debt.",[30,366,368],{"id":367},"step-6-make-capabilities-discoverable","Step 6: make capabilities discoverable",[11,370,371,372,375,376,379,380,383],{},"A capability an agent cannot find is, to that agent, a capability that does not exist. It just gets\nrebuilt, or skipped. Move your scripts, generators, and commands to predictable, named places, and\nname them for what they do: ",[75,373,374],{},"package.json"," scripts, a ",[75,377,378],{},"scripts\u002F"," or ",[75,381,382],{},"skills\u002F"," directory, commands you\nactually wrote down.",[11,385,386],{},"Better, generate the list of capabilities from those conventional paths instead of keeping it by hand,\nand test that the list is complete. A hand-kept list is one more claim waiting to rot.",[11,388,389,391,392,394,395,397],{},[47,390,151],{}," Three deploy and seed scripts live in one engineer's home directory and a\nSlack thread nobody can find. You move them into ",[75,393,378],{}," with names that say what they do and list\nthem in ",[75,396,374],{},". The next agent finds them where it looks first, instead of writing a fourth.",[30,399,401],{"id":400},"step-7-move-toward-a-domain-first-structure-last","Step 7: move toward a domain-first structure (last)",[11,403,404,405,330,408,411,412,415,416,330,419,330,422,424],{},"The top level should say what the system does, not which framework built it: ",[75,406,407],{},"billing\u002F",[75,409,410],{},"onboarding\u002F",",\n",[75,413,414],{},"payments\u002F",", not ",[75,417,418],{},"controllers\u002F",[75,420,421],{},"services\u002F",[75,423,329],{},". The framework lives one level down, inside the\ndomain it serves.",[11,426,427,428,430],{},"This is the expensive move and the one most likely to break imports, so it goes last and goes in\nslices. Often a partial move plus a root ",[75,429,77],{}," that spells out the structure you are migrating\ntoward buys more legibility, per file moved, than reshuffling everything at once.",[206,432,435],{"className":433,"code":434,"language":315,"meta":211},[313],"# before: organized by technical layer\nsrc\u002F\n  controllers\u002F   services\u002F   models\u002F   utils\u002F\n\n# after: organized by domain, framework one level down\nsrc\u002F\n  billing\u002F\n    controllers\u002F   services\u002F   models\u002F   # the framework, inside the domain it serves\n  onboarding\u002F\n  payments\u002F\n",[75,436,434],{"__ignoreMap":211},[11,438,439,440,442],{},"Keep it from sliding back with a lint rule that stops domain code from leaking into a layer folder,\nand keep the target structure in the root ",[75,441,77],{}," so a reader who lands mid-migration knows which\nway is forward.",[30,444,446],{"id":445},"step-8-install-the-metabolism","Step 8: install the metabolism",[11,448,449],{},"The mature version does not just check context, it feeds it. A repo that checks itself cannot rot in\nsilence. A repo that feeds itself takes in new knowledge the moment it is created.",[11,451,452,453,455],{},"One line in the root ",[75,454,77],{}," and the review checklist does it: when a pull request adds a source of\ntruth or an invariant, it documents that in the same pull request, with a check behind it. Now the\ncontext grows with the system instead of trailing six months behind it.",[30,457,459],{"id":458},"a-worked-example-end-to-end","A worked example, end to end",[11,461,462,463,465],{},"A service that started as one framework app and grew for three years. The tree screams the framework,\nnot the product, and the only doc is a ",[75,464,155],{}," that is half wrong.",[206,467,470],{"className":468,"code":469,"language":315,"meta":211},[313],"# before\nsrc\u002F\n  controllers\u002F      # 22 files, mixed domains\n  services\u002F         # 18 files, mixed domains\n  models\u002F\n  utils\u002F            # the junk drawer\n  helpers\u002F          # a second junk drawer\nREADME.md           # points at a deploy script deleted last year\n",[75,471,469],{"__ignoreMap":211},[11,473,474,475,330,477,330,479,482,483,485,486,488],{},"Ask an agent to \"add a partial-refund flow\" here and watch it hit three of the five failure modes in\none task: it cannot find where refunds live (split across ",[75,476,418],{},[75,478,421],{},[75,480,481],{},"models\u002F","), it\nrebuilds money math that already sits in ",[75,484,329],{},", and it follows the ",[75,487,155],{}," to a deploy script that\nis gone.",[11,490,491],{},"The fix, in the order above, with no big-bang commit:",[62,493,494,508,517,527,549,560],{},[65,495,496,499,500,502,503,172,505,507],{},[47,497,498],{},"Context-rot."," Drop the dead deploy reference from the ",[75,501,155],{},", write the real command, add a\ntest that every path the ",[75,504,155],{},[75,506,77],{}," cite still exists.",[65,509,510,513,514,516],{},[47,511,512],{},"Embedded context."," A root ",[75,515,77],{}," (what the service owns, the structure it is migrating\ntoward) and one in the busiest area.",[65,518,519,522,523,526],{},[47,520,521],{},"Codify."," The most-repeated review comment was \"money is integer cents.\" That becomes a\n",[75,524,525],{},"no-float-money"," lint rule.",[65,528,529,532,533,172,535,537,538,541,542,545,546,548],{},[47,530,531],{},"Name."," Split ",[75,534,329],{},[75,536,336],{},": money math becomes ",[75,539,540],{},"money\u002F",", session code becomes\n",[75,543,544],{},"auth-session\u002F",", the genuinely generic remainder stays in a small ",[75,547,363],{},".",[65,550,551,554,555,557,558,548],{},[47,552,553],{},"Discoverable."," The ad-hoc scripts move into ",[75,556,378],{}," with real names, listed in ",[75,559,374],{},[65,561,562,565,566,569,570,573],{},[47,563,564],{},"Domain-first, in slices."," Move ",[75,567,568],{},"refunds"," first: a ",[75,571,572],{},"billing\u002Frefunds\u002F"," that keeps its controller,\nservice, and model together. The next agent asked about refunds finds them in one place.",[206,575,578],{"className":576,"code":577,"language":315,"meta":211},[313],"# after\nsrc\u002F\n  billing\u002F\n    AGENTS.md       # invariants and the source of truth for billing\n    refunds\u002F        # controller + service + model, together\n    invoices\u002F\n  auth-session\u002F\n  money\u002F            # the math that was buried in utils, now named and enforced\n  shared\u002F           # small, generic, dependency-free\nscripts\u002F            # named, listed in package.json\nAGENTS.md           # the rules of the house, and the structure being migrated toward\nREADME.md           # accurate, and a test keeps it that way\n",[75,579,577],{"__ignoreMap":211},[11,581,582,583,585,586,588,589,591],{},"Now the same task lands in ",[75,584,572],{},", against an ",[75,587,77],{}," that states the refund invariant,\nreusing the ",[75,590,540],{}," package the lint rule already points at. The failure modes have nowhere left to\nhappen.",[30,593,595],{"id":594},"run-it-with-the-skill","Run it with the skill",[11,597,598,599,601],{},"Step 1 and most of the moves above are things an agent can run. The\n",[21,600,145],{"href":144}," is a single file you load into your agent: it reads the repo as a\ncold reader, finds the docs that lie, and hands back the backlog in the order above. Point it at your\nrepository and start with what it flags first.",[30,603,605],{"id":604},"where-to-go-next","Where to go next",[607,608,609,615,622,628],"ul",{},[65,610,611,612,614],{},"The ",[21,613,24],{"href":23},": the rule, the four pillars, the mechanism, and the eight principles in full.",[65,616,611,617,621],{},[21,618,620],{"href":619},"\u002Fcomparison","comparison"," with context engineering and harness engineering: which layer each one\ndesigns, and why this one sits below them at design time.",[65,623,611,624,627],{},[21,625,626],{"href":144},"skill",": to run the rework with your own agent.",[65,629,611,630,634],{},[21,631,633],{"href":632},"\u002Fglossary","glossary",": the terms used across the specification, defined.",[636,637,638],"style",{},"html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"title":211,"searchDepth":224,"depth":224,"links":640},[641,642,643,644,645,646,647,648,649,650,651,652,653],{"id":32,"depth":224,"text":33},{"id":53,"depth":224,"text":54},{"id":99,"depth":224,"text":100},{"id":159,"depth":224,"text":160},{"id":194,"depth":224,"text":195},{"id":297,"depth":224,"text":298},{"id":323,"depth":224,"text":324},{"id":367,"depth":224,"text":368},{"id":400,"depth":224,"text":401},{"id":445,"depth":224,"text":446},{"id":458,"depth":224,"text":459},{"id":594,"depth":224,"text":595},{"id":604,"depth":224,"text":605},"Context Architecture is applied to a codebase that already exists, by reworking it in small steps, never by scaffolding a new one. You read the repo as someone with no context, fix the documentation that lies, and back every claim it makes about itself with a check that fails when the claim stops being true.","A hands-on guide to reworking a repository so it is legible to people and AI agents: audit it as a cold reader, fix the docs that lie, put AGENTS.md at the boundaries, and back every claim with a check. A specification by Sergio Azócar.","md","Guide",{},"\u002Fen\u002Fguide",{"title":5,"description":655},"en\u002Fguide","su5KaW6k_vX9d-N9EUDpR5R6OLhXWV4Uo47egayZ7RE",1781920627983]