[{"data":1,"prerenderedAt":2725},["ShallowReactive",2],{"tip-topic-claude-code":3,"tips-index-claude-code":23},{"id":4,"title":5,"body":6,"description":13,"extension":14,"icon":15,"meta":16,"navigation":17,"order":18,"path":19,"seo":20,"stem":21,"__hash__":22},"tipTopics\u002Ftips\u002Fclaude-code\u002Findex.md","Claude Code",{"type":7,"value":8,"toc":9},"minimark",[],{"title":10,"searchDepth":11,"depth":11,"links":12},"",2,[],"How I use Claude Code across client work: configuration, memory, custom agents, permissions and automation, plus the mistakes that taught me each rule.","md",null,{},true,1,"\u002Ftips\u002Fclaude-code",{"title":5,"description":13},"tips\u002Fclaude-code\u002Findex","59idZ3x4c01jwOl4bq3UykdobCFINwll3FyL_ok9kPM",[24,431,818,1129,1461,1688,1908,2267,2529],{"id":25,"title":26,"body":27,"category":416,"date":417,"description":418,"extension":14,"meta":419,"navigation":17,"order":18,"path":420,"readingTime":421,"seo":422,"stem":424,"tags":425,"__hash__":430},"tips\u002Ftips\u002Fclaude-code\u002Fyour-claude-md-is-a-contract-not-documentation.md","Your CLAUDE.md Is a Contract, Not Documentation",{"type":7,"value":28,"toc":403},[29,38,45,56,59,64,71,81,88,91,95,98,103,141,144,151,154,158,178,181,184,187,191,206,209,224,227,231,256,259,266,269,273,288,291,305,311,315,318,324,334,354,357,360,363,367,370,375,378,382,385,388,391,394,399],[30,31,32,33,37],"p",{},"Nearly every ",[34,35,36],"code",{},"CLAUDE.md"," I see is a README wearing a different hat. Project description, folder structure, a list of npm scripts. All accurate. All useless.",[30,39,40,41,44],{},"It is useless because Claude can already see your folder structure. It can read your ",[34,42,43],{},"package.json",". Telling it things it can derive in one tool call spends context to buy nothing.",[30,46,47,48,50,51,55],{},"A ",[34,49,36],{}," earns its place when it contains things that are ",[52,53,54],"strong",{},"not"," derivable from the codebase: your preferences, your prohibitions, and the decisions you are tired of repeating.",[30,57,58],{},"Put another way — it is a contract, not documentation.",[60,61,63],"h2",{"id":62},"the-test-for-whether-a-line-belongs","The test for whether a line belongs",[30,65,66,67],{},"Before writing a line, ask: ",[68,69,70],"em",{},"could Claude work this out by reading the repo?",[30,72,73,74,76,77,80],{},"If yes, delete it. \"This project uses Tailwind\" is visible in ",[34,75,43],{}," and every component file. \"This project uses Nuxt 3 with file-based routing\" is visible from the ",[34,78,79],{},"pages\u002F"," directory existing.",[30,82,83,84,87],{},"If no, keep it. \"Use pnpm, never npm\" is not derivable — a ",[34,85,86],{},"pnpm-lock.yaml"," hints at it, but the hint loses to habit under pressure. \"Do not run the dev server unless I ask\" is not derivable at all. It is a preference that exists only in your head until you write it down.",[30,89,90],{},"That single question removes about 80% of what people put in these files.",[60,92,94],{"id":93},"what-mine-actually-says","What mine actually says",[30,96,97],{},"Here are the rules I run globally, across every project. Not a template — the real thing, with the reasoning I would normally leave implicit.",[99,100,102],"h3",{"id":101},"response-rules","Response rules",[104,105,109],"pre",{"className":106,"code":107,"language":108,"meta":10,"style":10},"language-markdown shiki shiki-themes github-light github-dark","- Be concise. Minimize tokens.\n- Do NOT explain unless explicitly asked.\n- Do NOT add background, theory, or justification.\n- DO NOT run npm run dev unless explicitly asked\n- DO NOT run npm build scripts unless explicitly asked\n","markdown",[34,110,111,118,123,129,135],{"__ignoreMap":10},[112,113,115],"span",{"class":114,"line":18},"line",[112,116,117],{},"- Be concise. Minimize tokens.\n",[112,119,120],{"class":114,"line":11},[112,121,122],{},"- Do NOT explain unless explicitly asked.\n",[112,124,126],{"class":114,"line":125},3,[112,127,128],{},"- Do NOT add background, theory, or justification.\n",[112,130,132],{"class":114,"line":131},4,[112,133,134],{},"- DO NOT run npm run dev unless explicitly asked\n",[112,136,138],{"class":114,"line":137},5,[112,139,140],{},"- DO NOT run npm build scripts unless explicitly asked\n",[30,142,143],{},"The first three are about signal. I am a developer; I do not need an assistant explaining what a Vue composable is before it writes one. Every paragraph of unrequested background is a paragraph I have to skim past to find the code.",[30,145,146,147,150],{},"The last two are about control, and they were written after being burned. A dev server started inside an agent session is a process I did not start and might not notice — it holds a port, it rebuilds on every file write, and if the agent is editing files rapidly you get a cascade of rebuilds fighting each other. Build scripts are worse: they are slow, they write to ",[34,148,149],{},"dist\u002F",", and they turn a two-second edit into a ninety-second wait.",[30,152,153],{},"I decide when to run those. Not the tool.",[99,155,157],{"id":156},"code-requests","Code requests",[104,159,161],{"className":106,"code":160,"language":108,"meta":10,"style":10},"- If the user asks for code, output ONLY the code.\n- No explanations, comments, or extra files unless requested.\n- Assume the user knows what they are doing.\n",[34,162,163,168,173],{"__ignoreMap":10},[112,164,165],{"class":114,"line":18},[112,166,167],{},"- If the user asks for code, output ONLY the code.\n",[112,169,170],{"class":114,"line":11},[112,171,172],{},"- No explanations, comments, or extra files unless requested.\n",[112,174,175],{"class":114,"line":125},[112,176,177],{},"- Assume the user knows what they are doing.\n",[30,179,180],{},"\"Assume the user knows what they are doing\" is the highest-leverage line in the file.",[30,182,183],{},"Without it, you get defensive output — try\u002Fcatch around things that cannot throw, comments restating the line above them, a paragraph on why you might prefer a different approach. That is a model optimising for a beginner reader. Telling it who it is talking to changes the output more than any amount of prompt engineering.",[30,185,186],{},"\"No extra files\" matters more than it sounds. Ask for a utility function and you can get the function, a test file, a barrel export, and a README. Four files where you wanted one, three of which you now have to read and delete.",[99,188,190],{"id":189},"modifications-and-fixes","Modifications and fixes",[104,192,194],{"className":106,"code":193,"language":108,"meta":10,"style":10},"- When asked to add, change, or fix something, touch ONLY what is required.\n- Do not refactor, reformat, or improve unrelated code unless explicitly asked\n",[34,195,196,201],{"__ignoreMap":10},[112,197,198],{"class":114,"line":18},[112,199,200],{},"- When asked to add, change, or fix something, touch ONLY what is required.\n",[112,202,203],{"class":114,"line":11},[112,204,205],{},"- Do not refactor, reformat, or improve unrelated code unless explicitly asked\n",[30,207,208],{},"This is the rule I would keep if I could only keep one.",[30,210,211,212,215,216,219,220,223],{},"The failure it prevents is the diff that does the job ",[68,213,214],{},"and"," renames three variables, reorders imports, converts a ",[34,217,218],{},"function"," to an arrow, and reformats a file that a different tool formats. All individually defensible. Collectively, a code review where the actual change is buried in ninety lines of noise, and a ",[34,221,222],{},"git blame"," that now points at the wrong commit.",[30,225,226],{},"Scope discipline is not a style preference. It is what makes a change reviewable.",[99,228,230],{"id":229},"defaults","Defaults",[104,232,234],{"className":106,"code":233,"language":108,"meta":10,"style":10},"- Prefer the simplest correct solution.\n- If an answer can be one line, make it one line.\n- if something is not very clear, ask the user questions if your understanding is correct with options if needed\n- use pnpm to install or update npm packages\n",[34,235,236,241,246,251],{"__ignoreMap":10},[112,237,238],{"class":114,"line":18},[112,239,240],{},"- Prefer the simplest correct solution.\n",[112,242,243],{"class":114,"line":11},[112,244,245],{},"- If an answer can be one line, make it one line.\n",[112,247,248],{"class":114,"line":125},[112,249,250],{},"- if something is not very clear, ask the user questions if your understanding is correct with options if needed\n",[112,252,253],{"class":114,"line":131},[112,254,255],{},"- use pnpm to install or update npm packages\n",[30,257,258],{},"The third one is the interesting one, and it is doing something subtle.",[30,260,261,262,265],{},"Left alone, an agent facing ambiguity will pick an interpretation and build. If it picked wrong, you find out after the work exists — and sunk cost makes you more likely to accept something you did not want. Asking ",[68,263,264],{},"with options"," turns a thirty-minute misunderstanding into a ten-second choice.",[30,267,268],{},"The specific phrasing matters too. \"Ask if you are unsure\" gets ignored, because models are rarely uncertain in a way they can detect. \"Ask if your understanding is correct, with options\" describes an action, not a feeling.",[99,270,272],{"id":271},"read-restrictions","Read restrictions",[104,274,276],{"className":106,"code":275,"language":108,"meta":10,"style":10},"Do not read or search files under these directories unless I explicitly ask:\ndist, .nuxt, node_modules, .git .env\n",[34,277,278,283],{"__ignoreMap":10},[112,279,280],{"class":114,"line":18},[112,281,282],{},"Do not read or search files under these directories unless I explicitly ask:\n",[112,284,285],{"class":114,"line":11},[112,286,287],{},"dist, .nuxt, node_modules, .git .env\n",[30,289,290],{},"Three different reasons in one line.",[30,292,293,296,297,300,301,304],{},[34,294,295],{},"node_modules",", ",[34,298,299],{},"dist"," and ",[34,302,303],{},".nuxt"," are noise — generated or vendored code that will match almost any search and swamp the results. A grep for a function name that returns forty hits from a minified bundle has told you nothing.",[30,306,307,310],{},[34,308,309],{},".env"," is not noise. It is credentials. Anything read into context can end up quoted back in a response, and responses get pasted into tickets and Slack. Keep secrets out of the window entirely.",[60,312,314],{"id":313},"global-versus-project","Global versus project",[30,316,317],{},"Two levels, and they hold different things.",[30,319,320,323],{},[34,321,322],{},"~\u002F.claude\u002FCLAUDE.md"," holds everything above — how I want to be worked with. It is stack-agnostic and it barely changes.",[30,325,326,327,329,330,333],{},"A project's ",[34,328,36],{},", checked into the repo, holds what is true about ",[68,331,332],{},"that"," codebase and not visible at a glance. For this site:",[104,335,337],{"className":106,"code":336,"language":108,"meta":10,"style":10},"## Important Notes\n- WordPress headless CMS for content (using GraphQL API)\n- Nuxt 3 SSR application with dark\u002Flight theme support\n",[34,338,339,344,349],{"__ignoreMap":10},[112,340,341],{"class":114,"line":18},[112,342,343],{},"## Important Notes\n",[112,345,346],{"class":114,"line":11},[112,347,348],{},"- WordPress headless CMS for content (using GraphQL API)\n",[112,350,351],{"class":114,"line":125},[112,352,353],{},"- Nuxt 3 SSR application with dark\u002Flight theme support\n",[30,355,356],{},"That first line is worth its space. Nothing in the Nuxt repo tells you the content comes from WordPress over GraphQL — you would have to read the server routes to find out. That is exactly the kind of fact that saves an agent five tool calls and a wrong assumption.",[30,358,359],{},"The rest of that project file lists commands and folder purposes. Being honest: most of it fails my own test. It is on the list to trim.",[30,361,362],{},"Which is the real lesson — these files rot. Rules accumulate after bad sessions and stay long after they stop mattering. Read yours occasionally and delete what no longer earns its place.",[60,364,366],{"id":365},"rules-are-not-magic","Rules are not magic",[30,368,369],{},"Two honest caveats.",[30,371,47,372,374],{},[34,373,36],{}," shifts probabilities, it does not enforce. A long session with a lot of context can drift from instructions given at the top of it. If a rule genuinely must hold every single time, that is a job for a hook or a permission setting, not prose.",[30,376,377],{},"And rules conflict. \"Be concise\" versus \"ask clarifying questions\" pull opposite ways; so do \"simplest correct solution\" and \"assume the user knows what they are doing\" — one argues for the obvious approach, the other for the sophisticated one. When you notice the same disappointing behaviour repeatedly, the cause is often two of your own rules fighting, not the model ignoring you.",[60,379,381],{"id":380},"where-to-start","Where to start",[30,383,384],{},"Do not write one from a template. Start empty, and add a line the next time something annoys you.",[30,386,387],{},"That is genuinely how mine was built. Every rule is a scar. \"Do not run npm run dev\" exists because of a runaway dev server. \"Touch only what is required\" exists because of a diff I had to unpick by hand.",[30,389,390],{},"Rules earned that way are short, specific, and actually followed — because they describe a real failure rather than an imagined one.",[392,393],"hr",{},[30,395,396],{},[68,397,398],{},"Next in this series: giving Claude a memory that survives past the end of a session — and why I keep it in an Obsidian vault rather than a config file.",[400,401,402],"style",{},"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":10,"searchDepth":11,"depth":11,"links":404},[405,406,413,414,415],{"id":62,"depth":11,"text":63},{"id":93,"depth":11,"text":94,"children":407},[408,409,410,411,412],{"id":101,"depth":125,"text":102},{"id":156,"depth":125,"text":157},{"id":189,"depth":125,"text":190},{"id":229,"depth":125,"text":230},{"id":271,"depth":125,"text":272},{"id":313,"depth":11,"text":314},{"id":365,"depth":11,"text":366},{"id":380,"depth":11,"text":381},"Foundations","2026-08-08","Most CLAUDE.md files fail because they describe a project instead of constraining behaviour. Here is the one I actually use, rule by rule, and why each line earns its place.",{},"\u002Ftips\u002Fclaude-code\u002Fyour-claude-md-is-a-contract-not-documentation",7,{"title":26,"description":423},"Why most CLAUDE.md files are ignored, and how to write rules that actually change what Claude Code does. Real examples from a working setup.","tips\u002Fclaude-code\u002Fyour-claude-md-is-a-contract-not-documentation",[426,427,428,429],"claude code","ai tooling","developer workflow","productivity","JOhJqJna8h_Bu_kMGQNbC2uG9eIKLzjGM-kPQzKgRxo",{"id":432,"title":433,"body":434,"category":416,"date":417,"description":808,"extension":14,"meta":809,"navigation":17,"order":11,"path":810,"readingTime":811,"seo":812,"stem":814,"tags":815,"__hash__":817},"tips\u002Ftips\u002Fclaude-code\u002Fgiving-claude-a-memory-that-outlives-the-session.md","Giving Claude a Memory That Outlives the Session",{"type":7,"value":435,"toc":798},[436,439,442,450,454,460,463,466,469,473,476,484,498,508,514,518,521,536,539,542,545,570,573,577,580,640,643,646,650,653,673,680,697,717,724,728,731,738,741,745,748,758,764,773,776,780,783,786,789,791,796],[30,437,438],{},"Every session starts from zero.",[30,440,441],{},"You spend forty minutes working out why a client's staging environment rejects webhook callbacks. You fix it. The session ends. Three weeks later the same thing happens on a sister site, and you are back at the beginning — because the reasoning lived in a context window that no longer exists.",[30,443,444,449],{},[445,446,448],"a",{"href":447},"\u002Ftips\u002Fclaude-code\u002Fyour-claude-md-is-a-contract-not-documentation\u002F","The previous part"," covered rules, which are static. This is the other half: facts, which accumulate.",[60,451,453],{"id":452},"why-not-just-put-it-in-claudemd","Why not just put it in CLAUDE.md",[30,455,456,457,459],{},"The obvious move is to append findings to ",[34,458,36],{},". It works for about two weeks.",[30,461,462],{},"The file grows. It gets loaded in full at the start of every session, so a fact you needed once in March is now costing you tokens in December. There is no structure — a gotcha about WooCommerce webhooks sits next to a note about your preferred date format. And because it is one file across one project, nothing connects. The webhook fix you made for client A is invisible when you hit the same issue for client B.",[30,464,465],{},"What you want is closer to a wiki: many small notes, each about one thing, retrieved on relevance rather than loaded wholesale, and linked to each other.",[30,467,468],{},"That is what Obsidian already is. So I use it.",[60,470,472],{"id":471},"the-shape-of-the-vault","The shape of the vault",[30,474,475],{},"Four top-level folders, each with a different job.",[104,477,482],{"className":478,"code":480,"language":481},[479],"language-text","Projects\u002F\u003Cproject-name>\u002F\n  index.md\n  Conversations\u002F\n    2026-08-04-webhook-signature-mismatch.md\nPreferences\u002F\nArchitecture\u002F\nTags\u002F\n  tag-taxonomy.md\n","text",[34,483,480],{"__ignoreMap":10},[30,485,486,489,490,493,494,497],{},[34,487,488],{},"Projects\u002F"," holds one folder per codebase. The ",[34,491,492],{},"index.md"," is the living summary — tech stack, patterns, gotchas, key decisions. ",[34,495,496],{},"Conversations\u002F"," holds dated notes from individual sessions, which is where the \"how we solved that weird thing\" material goes.",[30,499,500,503,504,507],{},[34,501,502],{},"Preferences\u002F"," is global and stack-agnostic: how I like things done, independent of project. ",[34,505,506],{},"Architecture\u002F"," holds decision records — the ones you would otherwise write as an ADR and then never write.",[30,509,510,511,513],{},"The split matters because it maps to retrieval. When starting work on a repo, the project note is what you want. When making a technology choice, ",[34,512,506],{}," is what you want. Separate folders make \"read the relevant thing\" a cheap operation instead of a search.",[60,515,517],{"id":516},"the-rule-that-makes-it-work","The rule that makes it work",[30,519,520],{},"Here is the part that took longest to get right, and it is one line:",[104,522,524],{"className":106,"code":523,"language":108,"meta":10,"style":10},"Do NOT ask \"should I save this to memory?\" — just do it silently\nalongside your normal response.\n",[34,525,526,531],{"__ignoreMap":10},[112,527,528],{"class":114,"line":18},[112,529,530],{},"Do NOT ask \"should I save this to memory?\" — just do it silently\n",[112,532,533],{"class":114,"line":11},[112,534,535],{},"alongside your normal response.\n",[30,537,538],{},"Memory systems fail because writing to them is friction. If the assistant asks permission every time, you say no — you are mid-task, the interruption costs more than the note is worth. Ask ten times, get ten noes, and the vault stays empty.",[30,540,541],{},"Making writes silent and automatic inverts it. The cost of a slightly redundant note is near zero. The cost of a lost insight is another forty minutes three weeks from now. Bias hard toward writing.",[30,543,544],{},"The same logic drives the read side:",[104,546,548],{"className":106,"code":547,"language":108,"meta":10,"style":10},"- At the START of every session: read the relevant\n  Projects\u002F\u003Cproject-name>\u002Findex.md for the current working directory.\n- Before making architecture or tech decisions: check Architecture\u002F\n  and the project note for prior decisions.\n",[34,549,550,555,560,565],{"__ignoreMap":10},[112,551,552],{"class":114,"line":18},[112,553,554],{},"- At the START of every session: read the relevant\n",[112,556,557],{"class":114,"line":11},[112,558,559],{},"  Projects\u002F\u003Cproject-name>\u002Findex.md for the current working directory.\n",[112,561,562],{"class":114,"line":125},[112,563,564],{},"- Before making architecture or tech decisions: check Architecture\u002F\n",[112,566,567],{"class":114,"line":131},[112,568,569],{},"  and the project note for prior decisions.\n",[30,571,572],{},"Automatic, tied to a trigger, no asking.",[60,574,576],{"id":575},"what-actually-gets-written","What actually gets written",[30,578,579],{},"Silent writing only works if the triggers are specific. \"Save important things\" produces either nothing or everything. Mine is a list of events:",[581,582,583,590,602,608,616,622,628,634],"ol",{},[584,585,586,589],"li",{},[52,587,588],{},"Bug fixed"," → append to the project note's Gotchas, or a dated conversation note",[584,591,592,595,596,598,599,601],{},[52,593,594],{},"Architecture or tech decision made"," → update the project note ",[68,597,214],{}," create an ",[34,600,506],{}," record",[584,603,604,607],{},[52,605,606],{},"New dependency added or stack changed"," → update the project note's Tech Stack",[584,609,610,613,614],{},[52,611,612],{},"A preference stated"," (\"I prefer X over Y\") → ",[34,615,502],{},[584,617,618,621],{},[52,619,620],{},"Pattern established"," (convention, folder structure, naming) → project note's Patterns",[584,623,624,627],{},[52,625,626],{},"Non-obvious problem solved"," → dated conversation note with the solution",[584,629,630,633],{},[52,631,632],{},"New project encountered"," → full project note from the template",[584,635,636,639],{},[52,637,638],{},"End of a meaningful session"," → summary note",[30,641,642],{},"Every one of those is an observable event, not a judgement call. \"Was a bug fixed?\" has an answer. \"Was this important?\" does not.",[30,644,645],{},"Number 6 is the one that pays for the whole system. Non-obvious problems are exactly the ones you will not re-derive quickly, and exactly the ones you forget you ever solved.",[60,647,649],{"id":648},"linking-or-it-is-just-a-folder-of-files","Linking, or it is just a folder of files",[30,651,652],{},"Notes that do not link are a directory listing with extra steps. Two rules force the graph to form:",[104,654,656],{"className":106,"code":655,"language":108,"meta":10,"style":10},"- Always use [[wiki links]] to connect related notes\n- Every note should link to at least one other note — no orphan nodes\n- Add a ## Related section at the bottom of each note\n",[34,657,658,663,668],{"__ignoreMap":10},[112,659,660],{"class":114,"line":18},[112,661,662],{},"- Always use [[wiki links]] to connect related notes\n",[112,664,665],{"class":114,"line":11},[112,666,667],{},"- Every note should link to at least one other note — no orphan nodes\n",[112,669,670],{"class":114,"line":125},[112,671,672],{},"- Add a ## Related section at the bottom of each note\n",[30,674,675,676,679],{},"The \"no orphans\" rule is doing real work. It forces a question at write time: ",[68,677,678],{},"what is this related to?"," Answering it is how you notice that the webhook problem on client A is the same class of problem as the one on client B — because you are looking for something to link to.",[30,681,682,683,686,687,296,690,300,693,696],{},"Tags do the cross-cutting version. A small controlled taxonomy, defined once in ",[34,684,685],{},"Tags\u002Ftag-taxonomy.md",", rather than free-form tagging that fragments into ",[34,688,689],{},"#bugfix",[34,691,692],{},"#bug-fix",[34,694,695],{},"#bugFix",":",[104,698,700],{"className":106,"code":699,"language":108,"meta":10,"style":10},"Core:   #decision #pattern #bug-fix #preference #gotcha #til\nStatus: #active #archived #revisit\nScope:  #project #global #session\n",[34,701,702,707,712],{"__ignoreMap":10},[112,703,704],{"class":114,"line":18},[112,705,706],{},"Core:   #decision #pattern #bug-fix #preference #gotcha #til\n",[112,708,709],{"class":114,"line":11},[112,710,711],{},"Status: #active #archived #revisit\n",[112,713,714],{"class":114,"line":125},[112,715,716],{},"Scope:  #project #global #session\n",[30,718,719,720,723],{},"Three axes, closed vocabulary. ",[34,721,722],{},"#revisit"," is the sleeper — it marks decisions made under time pressure that deserve a second look, which is otherwise a thought that evaporates the moment you ship.",[60,725,727],{"id":726},"how-it-connects","How it connects",[30,729,730],{},"Obsidian exposes the vault over MCP, so the tools show up like any other. Read, write, patch, search, manage tags, resolve wiki links. Nothing bespoke — the assistant is just editing Markdown files in a folder.",[30,732,733,734,737],{},"That is the property I care about most. ",[52,735,736],{},"The memory is not locked inside a tool."," It is plain Markdown on disk. I can read it in Obsidian, grep it from a terminal, commit it to git, or open it in any editor in twenty years. If I stop using Claude Code tomorrow, I keep everything.",[30,739,740],{},"Compare that to memory features built into a product, where your accumulated project knowledge lives in someone else's database in a format you cannot inspect. For notes about client systems I am contractually responsible for, that is not a trade I will make.",[60,742,744],{"id":743},"what-it-does-not-solve","What it does not solve",[30,746,747],{},"Three honest limits.",[30,749,750,753,754,757],{},[52,751,752],{},"Notes go stale."," A note saying \"auth lives in ",[34,755,756],{},"server\u002Fapi\u002Fauth.ts","\" is wrong the moment you move the file, and nothing tells you. Anything memory says about code structure needs verifying against the repo before you act on it. Treat memory as a hypothesis, not a fact.",[30,759,760,763],{},[52,761,762],{},"Retrieval is imperfect."," Notes surface by relevance matching against their descriptions, so a badly-described note is invisible no matter how good its contents. Write the summary line for the search, not for yourself.",[30,765,766,769,770,772],{},[52,767,768],{},"It can be confidently wrong."," A note recording a decision records what was true when it was written. If you reversed that decision six months later and did not update the note, the old reasoning gets applied to new work. The ",[34,771,722],{}," tag and periodic review are the only real defence.",[30,774,775],{},"None of these are reasons not to do it. They are reasons to keep it in a format you can audit — which is, again, the argument for plain Markdown.",[60,777,779],{"id":778},"start-smaller-than-this","Start smaller than this",[30,781,782],{},"If the full structure looks like a lot, it is — it accreted over dozens of projects and did not start here.",[30,784,785],{},"Start with one folder and one rule: after solving something non-obvious, write a dated note with the problem and the solution. That is it. No taxonomy, no linking, no templates.",[30,787,788],{},"Do that for a month. The structure will suggest itself, because you will get annoyed at not being able to find things — and every folder above exists because of exactly that annoyance.",[392,790],{},[30,792,793],{},[68,794,795],{},"Next: the four ways to extend Claude Code — skills, agents, commands and plugins — and how to tell which one a problem actually needs.",[400,797,402],{},{"title":10,"searchDepth":11,"depth":11,"links":799},[800,801,802,803,804,805,806,807],{"id":452,"depth":11,"text":453},{"id":471,"depth":11,"text":472},{"id":516,"depth":11,"text":517},{"id":575,"depth":11,"text":576},{"id":648,"depth":11,"text":649},{"id":726,"depth":11,"text":727},{"id":743,"depth":11,"text":744},{"id":778,"depth":11,"text":779},"Context windows end. Projects do not. Why I keep my AI's long-term memory in an Obsidian vault instead of a config file, and the rules that decide what gets written.",{},"\u002Ftips\u002Fclaude-code\u002Fgiving-claude-a-memory-that-outlives-the-session",8,{"title":433,"description":813},"How to give Claude Code persistent project memory using an Obsidian vault, with rules for what to write, when to write it, and how to link it.","tips\u002Fclaude-code\u002Fgiving-claude-a-memory-that-outlives-the-session",[426,816,427,428],"obsidian","0INYF4kquqZzBzKlR9g1fMt9yKCVt99ZKOqttyRGXtQ",{"id":819,"title":820,"body":821,"category":1118,"date":417,"description":1119,"extension":14,"meta":1120,"navigation":17,"order":125,"path":1121,"readingTime":421,"seo":1122,"stem":1125,"tags":1126,"__hash__":1128},"tips\u002Ftips\u002Fclaude-code\u002Fskills-agents-commands-plugins-which-one-do-you-need.md","Skills, Agents, Commands, Plugins: Which One Do You Actually Need?",{"type":7,"value":822,"toc":1108},[823,826,829,836,840,871,874,878,885,892,921,927,930,934,937,944,947,953,960,963,966,972,976,987,990,1000,1003,1007,1010,1017,1020,1024,1027,1036,1045,1054,1063,1066,1070,1073,1079,1085,1088,1092,1095,1098,1101,1103],[30,824,825],{},"There are four ways to extend Claude Code, and they overlap enough that people pick by vibes.",[30,827,828],{},"I have roughly eighty skills installed, eleven custom agents, two slash commands and two plugins. That ratio is not an accident, and it took a while to work out why it settles there.",[30,830,831,832,835],{},"The useful question is not \"what can each one do\" — the docs cover that. It is ",[52,833,834],{},"what happens to your context window",", because that is the actual scarce resource.",[60,837,839],{"id":838},"the-one-line-version","The one-line version",[841,842,843,853,859,865],"ul",{},[584,844,845,848,849,852],{},[52,846,847],{},"Skill"," — instructions loaded into ",[68,850,851],{},"your"," context when relevant",[584,854,855,858],{},[52,856,857],{},"Agent"," — a separate context that does work and reports back",[584,860,861,864],{},[52,862,863],{},"Command"," — a prompt you trigger by name",[584,866,867,870],{},[52,868,869],{},"Plugin"," — a distribution wrapper for the other three",[30,872,873],{},"Everything below follows from the first two.",[60,875,877],{"id":876},"skills-knowledge-you-want-in-the-room","Skills: knowledge you want in the room",[30,879,880,881,884],{},"A skill is a folder with a ",[34,882,883],{},"SKILL.md"," describing when it applies. When a task matches, its instructions load into the current conversation.",[30,886,887,888,891],{},"Key word: ",[68,889,890],{},"current",". A skill does not run somewhere else. It changes how the assistant behaves right here, with full access to everything already in the conversation.",[30,893,894,895,898,899,296,902,296,905,296,908,296,911,296,914,296,917,920],{},"That makes skills right for ",[52,896,897],{},"knowledge and standards"," — the \"how we do this\" that should shape work you are actively supervising. My collection is heavily weighted to design and SEO for that reason: ",[34,900,901],{},"frontend-design",[34,903,904],{},"minimalist-ui",[34,906,907],{},"high-end-visual-design",[34,909,910],{},"seo-audit",[34,912,913],{},"seo-schema",[34,915,916],{},"humanizer",[34,918,919],{},"investigate",".",[30,922,923,924,926],{},"These are all cases where I want to see and steer the output. If I invoke ",[34,925,910],{}," I want the findings in front of me, in context, so I can push back on any of them.",[30,928,929],{},"The cost is context. A large skill can be thousands of tokens, and those tokens sit in the window for the rest of the session. Two or three is fine. Ten at once and you have spent a serious fraction of the window on instructions before doing any work.",[60,931,933],{"id":932},"agents-work-you-want-done-elsewhere","Agents: work you want done elsewhere",[30,935,936],{},"A subagent gets its own context window. It runs, it does the work, and only its final report comes back.",[30,938,939,940,943],{},"The point is ",[52,941,942],{},"isolation",". If an agent reads thirty files to answer a question, those thirty files do not land in your window — you get the conclusion.",[30,945,946],{},"Mine are all domain specialists:",[104,948,951],{"className":949,"code":950,"language":481},[479],"wordpress-specialist   nuxt-vue-architect   nuxt-code-reviewer\nvuejs-expert           docker-expert\nseo-technical  seo-content  seo-schema  seo-sitemap\nseo-performance  seo-visual\n",[34,952,950],{"__ignoreMap":10},[30,954,955,956,959],{},"The pattern: each has a large body of domain knowledge that would be wasteful to keep loaded permanently, and each does work whose ",[68,957,958],{},"intermediate steps"," I do not need to see.",[30,961,962],{},"A code review is the clearest case. To review properly it has to read a lot of code. I want the findings, not the reading. That is exactly the isolation an agent provides.",[30,964,965],{},"The trade-off is that an agent cannot see your conversation. It knows only what its prompt tells it. Brief it badly and you get confidently irrelevant work — and unlike a skill, you do not see it going wrong until it is done.",[30,967,968,971],{},[52,969,970],{},"Rule of thumb:"," if you need to watch it happen, use a skill. If you only need the answer, use an agent.",[60,973,975],{"id":974},"commands-a-prompt-with-a-name","Commands: a prompt with a name",[30,977,978,979,982,983,986],{},"A slash command is a saved prompt. ",[34,980,981],{},"\u002Foptimize"," runs whatever ",[34,984,985],{},"~\u002F.claude\u002Fcommands\u002Foptimize.md"," says.",[30,988,989],{},"I have two. That is deliberate — most things that feel like commands are better as skills, because skills load themselves when relevant while commands need you to remember they exist.",[30,991,992,993,996,997,999],{},"Commands earn their place when the trigger is a ",[68,994,995],{},"decision",", not a context. ",[34,998,981],{}," is a thing I choose to do at a moment of my choosing. There is no signal in the conversation that should cause it to fire on its own.",[30,1001,1002],{},"If you find yourself with twenty commands, most of them probably wanted to be skills.",[60,1004,1006],{"id":1005},"plugins-distribution-not-capability","Plugins: distribution, not capability",[30,1008,1009],{},"A plugin bundles skills, agents, commands and hooks into something installable from a marketplace.",[30,1011,1012,1013,1016],{},"It adds no capability. It solves the problem of ",[68,1014,1015],{},"getting"," capability onto a machine — yours next month, or a colleague's.",[30,1018,1019],{},"I run two, both third-party. I have never packaged my own, because everything I have built is either project-specific or personal preference. The moment I needed the same setup on three machines, or wanted to hand a team a standard review workflow, that calculus would change.",[60,1021,1023],{"id":1022},"the-decision-rule","The decision rule",[30,1025,1026],{},"In order:",[30,1028,1029,1032,1033,920],{},[52,1030,1031],{},"1. Does it need its own context?","\nLots of file reading, or long output you do not want in your window → ",[52,1034,1035],{},"agent",[30,1037,1038,1041,1042,920],{},[52,1039,1040],{},"2. Does it need to see the conversation?","\nShould shape work in progress, or needs conversation context to be useful → ",[52,1043,1044],{},"skill",[30,1046,1047,1050,1051,920],{},[52,1048,1049],{},"3. Is it triggered by your decision rather than by context?","\nNothing in the conversation signals it, you just want it on demand → ",[52,1052,1053],{},"command",[30,1055,1056,1059,1060,920],{},[52,1057,1058],{},"4. Does it need to exist on more than one machine?","\n→ wrap whatever you built in a ",[52,1061,1062],{},"plugin",[30,1064,1065],{},"Note these are not exclusive. A plugin can ship a skill that spawns an agent. Start with the smallest thing that works.",[60,1067,1069],{"id":1068},"where-i-get-it-wrong","Where I get it wrong",[30,1071,1072],{},"Two failure modes, both mine.",[30,1074,1075,1078],{},[52,1076,1077],{},"Building an agent for something small."," A subagent has real overhead — spawn cost, and a briefing that has to carry everything it needs since it cannot see the conversation. For a task with a short answer, the briefing costs more than doing it inline. If the work is one grep, just grep.",[30,1080,1081,1084],{},[52,1082,1083],{},"Installing skills I never use."," Eighty is more than I use. Skills are cheap to install and invisible when idle, so they accumulate. The cost is not runtime — it is that a crowded namespace makes the right one harder to surface, and I have definitely forgotten a skill existed and done the work manually.",[30,1086,1087],{},"The fix for both is the same and unglamorous: review the list occasionally and delete.",[60,1089,1091],{"id":1090},"start-with-none-of-them","Start with none of them",[30,1093,1094],{},"If you are new to this, the honest advice is to use plain Claude Code for a few weeks first.",[30,1096,1097],{},"Every agent and skill I have exists because I did something repeatedly and got tired of re-explaining it. Building extensions before you have that friction means building for problems you have imagined rather than met — and those get abandoned.",[30,1099,1100],{},"Wait for the annoyance. Then build the smallest thing that removes it.",[392,1102],{},[30,1104,1105],{},[68,1106,1107],{},"Next: what actually goes inside a domain agent — including why my code reviewer has no write access.",{"title":10,"searchDepth":11,"depth":11,"links":1109},[1110,1111,1112,1113,1114,1115,1116,1117],{"id":838,"depth":11,"text":839},{"id":876,"depth":11,"text":877},{"id":932,"depth":11,"text":933},{"id":974,"depth":11,"text":975},{"id":1005,"depth":11,"text":1006},{"id":1022,"depth":11,"text":1023},{"id":1068,"depth":11,"text":1069},{"id":1090,"depth":11,"text":1091},"Extending","Four ways to extend Claude Code, overlapping enough to be confusing. A decision rule for each, based on what happens to your context window.",{},"\u002Ftips\u002Fclaude-code\u002Fskills-agents-commands-plugins-which-one-do-you-need",{"title":1123,"description":1124},"Skills vs Agents vs Commands vs Plugins in Claude Code","A practical decision rule for choosing between skills, subagents, slash commands and plugins when extending Claude Code.","tips\u002Fclaude-code\u002Fskills-agents-commands-plugins-which-one-do-you-need",[426,427,428,1127],"automation","M8vOI4E6jSLQqVpKsy_mQx1cZV6BoNm_b8Y3xzeu6ak",{"id":1130,"title":1131,"body":1132,"category":1118,"date":417,"description":1452,"extension":14,"meta":1453,"navigation":17,"order":131,"path":1454,"readingTime":811,"seo":1455,"stem":1457,"tags":1458,"__hash__":1460},"tips\u002Ftips\u002Fclaude-code\u002Fbuilding-domain-agents-that-know-your-stack.md","Building Domain Agents That Know Your Stack",{"type":7,"value":1133,"toc":1443},[1134,1137,1140,1185,1188,1192,1199,1202,1205,1208,1243,1250,1260,1264,1272,1283,1286,1289,1296,1307,1314,1318,1321,1330,1333,1336,1342,1345,1349,1364,1367,1371,1374,1384,1390,1393,1397,1400,1403,1406,1410,1431,1434,1436,1441],[30,1135,1136],{},"A subagent is a Markdown file with frontmatter. The frontmatter is where most of the value is, and it is the part people skim.",[30,1138,1139],{},"Here is the header of my Nuxt code reviewer:",[104,1141,1143],{"className":106,"code":1142,"language":108,"meta":10,"style":10},"---\nname: nuxt-code-reviewer\ndescription: MUST BE USED to run a rigorous, security-aware review of all\n  Vue\u002FNuxt code (pages, components, composables, plugins, server routes,\n  middleware) after every feature, bug-fix, or pull-request. Use PROACTIVELY\n  before merging to main.\ntools: LS, Read, Grep, Glob, Bash\n---\n",[34,1144,1145,1150,1155,1160,1165,1170,1176,1181],{"__ignoreMap":10},[112,1146,1147],{"class":114,"line":18},[112,1148,1149],{},"---\n",[112,1151,1152],{"class":114,"line":11},[112,1153,1154],{},"name: nuxt-code-reviewer\n",[112,1156,1157],{"class":114,"line":125},[112,1158,1159],{},"description: MUST BE USED to run a rigorous, security-aware review of all\n",[112,1161,1162],{"class":114,"line":131},[112,1163,1164],{},"  Vue\u002FNuxt code (pages, components, composables, plugins, server routes,\n",[112,1166,1167],{"class":114,"line":137},[112,1168,1169],{},"  middleware) after every feature, bug-fix, or pull-request. Use PROACTIVELY\n",[112,1171,1173],{"class":114,"line":1172},6,[112,1174,1175],{},"  before merging to main.\n",[112,1177,1178],{"class":114,"line":421},[112,1179,1180],{},"tools: LS, Read, Grep, Glob, Bash\n",[112,1182,1183],{"class":114,"line":811},[112,1184,1149],{},[30,1186,1187],{},"Four decisions in five lines. Each one is load-bearing.",[60,1189,1191],{"id":1190},"the-description-is-a-routing-rule","The description is a routing rule",[30,1193,1194,1195,1198],{},"The description is not a summary for humans. It is what the orchestrator matches against when deciding whether to delegate — so it should be written as a ",[68,1196,1197],{},"trigger condition",", not a job title.",[30,1200,1201],{},"\"Reviews Vue and Nuxt code\" is a job title. It tells the router nothing about when to fire.",[30,1203,1204],{},"The version above lists the artefacts (pages, components, composables, plugins, server routes, middleware) and the moments (after every feature, bug-fix or pull request; before merging to main). It is trying to be matched.",[30,1206,1207],{},"My Vue architect goes further and includes worked examples in the description:",[104,1209,1211],{"className":106,"code":1210,"language":108,"meta":10,"style":10},"\u003Cexample>\nContext: User needs to optimize data fetching\nuser: \"The monitor detail page is loading slowly\"\nassistant: \"Let me use the nuxt-vue-architect agent to analyze the data\nfetching pattern and implement optimized SSR data loading...\"\n\u003C\u002Fexample>\n",[34,1212,1213,1218,1223,1228,1233,1238],{"__ignoreMap":10},[112,1214,1215],{"class":114,"line":18},[112,1216,1217],{},"\u003Cexample>\n",[112,1219,1220],{"class":114,"line":11},[112,1221,1222],{},"Context: User needs to optimize data fetching\n",[112,1224,1225],{"class":114,"line":125},[112,1226,1227],{},"user: \"The monitor detail page is loading slowly\"\n",[112,1229,1230],{"class":114,"line":131},[112,1231,1232],{},"assistant: \"Let me use the nuxt-vue-architect agent to analyze the data\n",[112,1234,1235],{"class":114,"line":137},[112,1236,1237],{},"fetching pattern and implement optimized SSR data loading...\"\n",[112,1239,1240],{"class":114,"line":1172},[112,1241,1242],{},"\u003C\u002Fexample>\n",[30,1244,1245,1246,1249],{},"That looks like padding. It is not. Examples show the ",[68,1247,1248],{},"shape"," of a triggering request, which catches cases a list of nouns misses — \"the page is loading slowly\" contains none of the keywords you would have thought to list.",[30,1251,1252,1253,300,1256,1259],{},"The words ",[34,1254,1255],{},"MUST BE USED",[34,1257,1258],{},"PROACTIVELY"," are doing work too. Without them a reviewer only runs when explicitly asked, which means it runs when you remember, which means rarely. That is the opposite of a quality gate.",[60,1261,1263],{"id":1262},"restricting-tools-is-a-safety-feature","Restricting tools is a safety feature",[104,1265,1266],{"className":106,"code":1180,"language":108,"meta":10,"style":10},[34,1267,1268],{"__ignoreMap":10},[112,1269,1270],{"class":114,"line":18},[112,1271,1180],{},[30,1273,1274,1275,1278,1279,1282],{},"No ",[34,1276,1277],{},"Edit",". No ",[34,1280,1281],{},"Write",". My code reviewer physically cannot change code.",[30,1284,1285],{},"This is the single best decision in my agent setup, and it is about incentives rather than trust.",[30,1287,1288],{},"An agent that can both find and fix problems will fix them. That sounds efficient and is not, for two reasons. You lose the review — findings you never saw, now buried in a diff. And it conflates two jobs with opposite dispositions: reviewing wants suspicion and thoroughness, fixing wants minimal intervention. An agent doing both does neither well.",[30,1290,1291,1292,1295],{},"Taking away the write tools makes the output a ",[68,1293,1294],{},"report",". I read it, I decide what is real, I fix what matters. The reviewer's only job is to be right about problems.",[30,1297,1298,1299,1302,1303,1306],{},"The same logic applies elsewhere. A research agent does not need ",[34,1300,1301],{},"Bash",". A doc generator does not need network access. ",[52,1304,1305],{},"Default to the smallest tool set that can do the job"," — not because the agent is malicious, but because capability it does not need is capability that can be misapplied.",[30,1308,1309,1310,1313],{},"Omit ",[34,1311,1312],{},"tools"," entirely and the agent inherits everything. Convenient, and almost never what you want.",[60,1315,1317],{"id":1316},"model-tier-is-a-cost-decision","Model tier is a cost decision",[30,1319,1320],{},"Most of my agents pin a model:",[104,1322,1324],{"className":106,"code":1323,"language":108,"meta":10,"style":10},"model: sonnet\n",[34,1325,1326],{"__ignoreMap":10},[112,1327,1328],{"class":114,"line":18},[112,1329,1323],{},[30,1331,1332],{},"The reasoning is boring and financial. A WordPress specialist answering \"how do I add a field to WooCommerce checkout\" is doing recall against well-documented territory. That does not need the most capable model available; it needs a competent one that responds quickly.",[30,1334,1335],{},"Where I leave the model unpinned — inheriting the session's — is anything requiring judgement across a large surface: architectural review, hard debugging, \"is this finding real or a false positive\".",[30,1337,1338,1339],{},"The heuristic: ",[52,1340,1341],{},"pin down for recall, leave open for judgement.",[30,1343,1344],{},"Watch for it drifting. An agent that started as a lookup helper and grew into something that makes real decisions should have its tier revisited. Mine have not been reviewed in a while, which is a note to self as much as advice.",[60,1346,1348],{"id":1347},"name-your-agent-not-your-file","Name your agent, not your file",[30,1350,1351,1352,1355,1356,1359,1360,1363],{},"Small thing that cost me twenty minutes: my reviewer lives in ",[34,1353,1354],{},"code-reviewer.md"," but declares ",[34,1357,1358],{},"name: nuxt-code-reviewer",". The ",[34,1361,1362],{},"name"," field wins. The filename is just a filename.",[30,1365,1366],{},"If invoking an agent silently does nothing, check that you are using the declared name.",[60,1368,1370],{"id":1369},"what-goes-in-the-body","What goes in the body",[30,1372,1373],{},"Below the frontmatter is the system prompt. Two things separate a useful one from a generic one.",[30,1375,1376,1379,1380,1383],{},[52,1377,1378],{},"Be specific about the stack, not the domain."," \"You are an expert in Vue\" produces textbook Vue. Naming your actual patterns — SSR data fetching with ",[34,1381,1382],{},"useAsyncData",", hydration mismatches, composables over stores, whatever your codebase does — produces advice that fits the code in front of it.",[30,1385,1386,1389],{},[52,1387,1388],{},"Say what the output should look like."," My reviewer specifies a severity-tagged report. Without that, review output drifts between a bulleted list, an essay, and a diff, and you cannot skim it consistently. Specifying the output format is cheap and pays every single run.",[30,1391,1392],{},"What to leave out: generic best practice. \"Write clean code\", \"consider edge cases\", \"follow SOLID\". The model already knows. Those words spend tokens to add nothing, and they dilute the specific instructions that do matter.",[60,1394,1396],{"id":1395},"the-honest-limitation","The honest limitation",[30,1398,1399],{},"An agent cannot see your conversation. It knows its system prompt and the prompt it was handed.",[30,1401,1402],{},"That is the whole point — it is why the isolation is valuable — and it is also the main failure mode. If you have spent twenty minutes establishing that a bug only reproduces under a specific Cloudflare setting, and you then delegate to an agent, that context does not travel. You get a competent investigation of the wrong thing.",[30,1404,1405],{},"So brief them like contractors, not colleagues. Everything needed goes in the prompt. When I catch an agent doing confidently irrelevant work, the cause is almost always my briefing rather than the agent.",[60,1407,1409],{"id":1408},"build-one-not-eleven","Build one, not eleven",[30,1411,1412,1413,296,1416,296,1419,296,1421,296,1424,296,1427,1430],{},"I have eleven and use maybe five regularly. The SEO ones in particular fragmented — ",[34,1414,1415],{},"seo-technical",[34,1417,1418],{},"seo-content",[34,1420,913],{},[34,1422,1423],{},"seo-sitemap",[34,1425,1426],{},"seo-performance",[34,1428,1429],{},"seo-visual"," — because splitting felt tidy at the time. In practice an SEO question rarely respects those boundaries, and I now have to pick between six overlapping agents.",[30,1432,1433],{},"Two or three broad specialists would have served better than six narrow ones. Split when a single agent's instructions genuinely conflict, not when the topics feel conceptually distinct.",[392,1435],{},[30,1437,1438],{},[68,1439,1440],{},"Next: why I turned off auto-compact, and what I do instead.",[400,1442,402],{},{"title":10,"searchDepth":11,"depth":11,"links":1444},[1445,1446,1447,1448,1449,1450,1451],{"id":1190,"depth":11,"text":1191},{"id":1262,"depth":11,"text":1263},{"id":1316,"depth":11,"text":1317},{"id":1347,"depth":11,"text":1348},{"id":1369,"depth":11,"text":1370},{"id":1395,"depth":11,"text":1396},{"id":1408,"depth":11,"text":1409},"A subagent is a job description, not a personality. What goes in one, why my code reviewer cannot write files, and why most of them run on a cheaper model.",{},"\u002Ftips\u002Fclaude-code\u002Fbuilding-domain-agents-that-know-your-stack",{"title":1131,"description":1456},"How to write Claude Code subagents that are actually useful: scoping the description, restricting tools, and choosing the right model tier.","tips\u002Fclaude-code\u002Fbuilding-domain-agents-that-know-your-stack",[426,427,1459,428],"code review","4QMhNa5VcnATVOn4vGknbzK6OyFz-EdU_X-DI05GxgE",{"id":1462,"title":1463,"body":1464,"category":1118,"date":417,"description":1678,"extension":14,"meta":1679,"navigation":17,"order":137,"path":1680,"readingTime":1172,"seo":1681,"stem":1684,"tags":1685,"__hash__":1687},"tips\u002Ftips\u002Fclaude-code\u002Fwhy-i-turned-off-auto-compact.md","Why I Turned Off Auto-Compact",{"type":7,"value":1465,"toc":1670},[1466,1469,1513,1516,1519,1523,1526,1529,1535,1538,1541,1545,1548,1555,1558,1561,1565,1572,1575,1578,1582,1585,1594,1605,1616,1619,1623,1626,1633,1640,1644,1647,1650,1657,1660,1662,1667],[30,1467,1468],{},"One line in my settings that surprises people:",[104,1470,1474],{"className":1471,"code":1472,"language":1473,"meta":10,"style":10},"language-json shiki shiki-themes github-light github-dark","{\n  \"autoCompactEnabled\": false,\n  \"model\": \"opus[1m]\"\n}\n","json",[34,1475,1476,1482,1497,1508],{"__ignoreMap":10},[112,1477,1478],{"class":114,"line":18},[112,1479,1481],{"class":1480},"sVt8B","{\n",[112,1483,1484,1488,1491,1494],{"class":114,"line":11},[112,1485,1487],{"class":1486},"sj4cs","  \"autoCompactEnabled\"",[112,1489,1490],{"class":1480},": ",[112,1492,1493],{"class":1486},"false",[112,1495,1496],{"class":1480},",\n",[112,1498,1499,1502,1504],{"class":114,"line":125},[112,1500,1501],{"class":1486},"  \"model\"",[112,1503,1490],{"class":1480},[112,1505,1507],{"class":1506},"sZZnC","\"opus[1m]\"\n",[112,1509,1510],{"class":114,"line":131},[112,1511,1512],{"class":1480},"}\n",[30,1514,1515],{},"Auto-compaction is the feature that keeps a long session alive. When the context window fills, it summarises what came before and continues with the summary. Without it, long sessions eventually hit a wall.",[30,1517,1518],{},"I turned it off anyway. Here is the actual trade.",[60,1520,1522],{"id":1521},"what-compaction-costs","What compaction costs",[30,1524,1525],{},"Compaction is lossy, and the loss is invisible.",[30,1527,1528],{},"Everything before the compaction point gets replaced by a summary. The summary is good — it keeps the decisions, the file paths, the current task. But it is a summary, so it drops detail, and you do not get told which detail.",[30,1530,1531,1532],{},"The failure mode is specific: ",[52,1533,1534],{},"the assistant becomes confident about something that is now wrong.",[30,1536,1537],{},"Say early in a session you established that a bug only reproduces when a particular Cloudflare setting is on, then ruled that out as the root cause. Post-compaction, the summary might retain \"investigated Cloudflare settings\" but lose \"and eliminated them\". Twenty minutes later you are back to Cloudflare, because as far as the current context knows, that thread is unresolved.",[30,1539,1540],{},"You will not notice this happening. You will notice work getting subtly worse and assume you are having a bad session.",[60,1542,1544],{"id":1543},"what-running-out-costs","What running out costs",[30,1546,1547],{},"Nothing, actually. That is the part that changed my mind.",[30,1549,1550,1551,1554],{},"Hitting the limit is loud. The session stops, you see it, and you deal with it deliberately — start a fresh session with a summary ",[68,1552,1553],{},"you"," wrote, or fork the conversation from before things got long.",[30,1556,1557],{},"Loud failure beats quiet degradation. A wall you can see is easier to work around than a slow leak you cannot.",[30,1559,1560],{},"This is the same instinct behind turning off any automatic recovery that hides a problem. The recovery is not free; it just moves the cost somewhere you are not looking.",[60,1562,1564],{"id":1563},"the-million-token-caveat","The million-token caveat",[30,1566,1567,1568,1571],{},"Fair disclosure: ",[34,1569,1570],{},"opus[1m]"," is a one-million-token context window. That is a lot of room, and it makes this position much cheaper to hold than it would be on a smaller window.",[30,1573,1574],{},"With a large window, a normal working session — read a dozen files, make changes, run tests, iterate — does not come close to the limit. Compaction would rarely fire anyway, so disabling it costs me almost nothing and removes a whole class of confusing behaviour.",[30,1576,1577],{},"On a smaller window the calculation genuinely differs, and auto-compaction may be the right default. This is a preference, not a universal recommendation.",[60,1579,1581],{"id":1580},"what-replaced-it","What replaced it",[30,1583,1584],{},"Three habits, none of them clever.",[30,1586,1587,1590,1591,1593],{},[52,1588,1589],{},"Start sessions narrow."," One task per session. The instinct to keep a long-running session going because it \"knows the project\" is backwards — it knows the project ",[68,1592,214],{}," three abandoned approaches, a stack trace from a bug you fixed, and a file you read for unrelated reasons. Fresh context with a good opening prompt beats accumulated context almost every time.",[30,1595,1596,1599,1600,1604],{},[52,1597,1598],{},"Write things down outside the window."," This is where ",[445,1601,1603],{"href":1602},"\u002Ftips\u002Fclaude-code\u002Fgiving-claude-a-memory-that-outlives-the-session\u002F","the memory vault"," earns its keep. If the important conclusions from a session are in a note on disk, losing the conversation stops being expensive. The window becomes working memory rather than the system of record.",[30,1606,1607,1610,1611,1615],{},[52,1608,1609],{},"Delegate the reading."," When something needs a lot of file reading — where does this pattern appear, what does this subsystem do — that is a ",[445,1612,1614],{"href":1613},"\u002Ftips\u002Fclaude-code\u002Fbuilding-domain-agents-that-know-your-stack\u002F","subagent's job",". It reads thirty files in its own context and hands back a paragraph. Thirty files never enter my window, so the thing that fills windows fastest stops filling mine.",[30,1617,1618],{},"The third one is the highest leverage by a wide margin. Most context exhaustion is file-reading, and most file-reading can be delegated.",[60,1620,1622],{"id":1621},"when-i-do-compact","When I do compact",[30,1624,1625],{},"I still compact — manually, at a moment I choose.",[30,1627,1628,1629,1632],{},"Good moments: a distinct phase just finished, tests pass, the next task is different from the last one. Compacting ",[68,1630,1631],{},"there"," means the summary is written at a natural boundary, and I can read it and correct it before continuing.",[30,1634,1635,1636,1639],{},"The difference is not summarisation versus no summarisation. It is ",[52,1637,1638],{},"who chooses the boundary",". Automatic compaction fires when a token counter crosses a threshold, which is uncorrelated with anything meaningful about the work. Half a debugging session on one side and half on the other is the worst possible cut.",[60,1641,1643],{"id":1642},"should-you-turn-it-off","Should you turn it off?",[30,1645,1646],{},"Probably not, immediately.",[30,1648,1649],{},"If you are on a standard context window and your sessions routinely hit the limit, auto-compaction is doing real work and removing it will just make sessions die.",[30,1651,1652,1653,1656],{},"The transferable idea is not the setting. It is noticing that a feature marketed as convenience is making a decision for you — ",[68,1654,1655],{},"what to forget"," — at a moment it chooses, without telling you what it dropped. That is worth knowing about even if you leave it on.",[30,1658,1659],{},"If you want one thing to try: next time a session feels like it has gone strange, check whether it compacted. The correlation is higher than you would expect.",[392,1661],{},[30,1663,1664],{},[68,1665,1666],{},"Next: which MCP servers actually earn their place in a working setup.",[400,1668,1669],{},"html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}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":10,"searchDepth":11,"depth":11,"links":1671},[1672,1673,1674,1675,1676,1677],{"id":1521,"depth":11,"text":1522},{"id":1543,"depth":11,"text":1544},{"id":1563,"depth":11,"text":1564},{"id":1580,"depth":11,"text":1581},{"id":1621,"depth":11,"text":1622},{"id":1642,"depth":11,"text":1643},"Automatic context compaction saves a session from dying. It also silently rewrites what your assistant believes. Here is the trade, and what I do instead.",{},"\u002Ftips\u002Fclaude-code\u002Fwhy-i-turned-off-auto-compact",{"title":1682,"description":1683},"Why I Turned Off Auto-Compact in Claude Code","Auto-compaction keeps long sessions alive at the cost of silent information loss. Why I disabled it, and the workflow that replaced it.","tips\u002Fclaude-code\u002Fwhy-i-turned-off-auto-compact",[426,427,1686,428],"context management","nXGEDFMrFE48uGS_CjY1Fe1QBtVfJdgeRRLL2sumRZI",{"id":1689,"title":1690,"body":1691,"category":1118,"date":417,"description":1898,"extension":14,"meta":1899,"navigation":17,"order":1172,"path":1900,"readingTime":1172,"seo":1901,"stem":1904,"tags":1905,"__hash__":1907},"tips\u002Ftips\u002Fclaude-code\u002Fmcp-servers-that-earn-their-place.md","MCP Servers That Earn Their Place",{"type":7,"value":1692,"toc":1889},[1693,1696,1702,1706,1709,1712,1715,1719,1722,1727,1734,1741,1745,1762,1772,1778,1791,1795,1798,1810,1816,1822,1826,1829,1839,1842,1846,1849,1859,1865,1872,1876,1879,1882,1884],[30,1694,1695],{},"MCP lets Claude Code talk to things that are not your filesystem — a notes vault, a design tool, a calendar, a database.",[30,1697,1698,1699],{},"The temptation is to connect everything. Resist it, for a reason that is not obvious until you have overdone it: ",[52,1700,1701],{},"every connected server adds tools, and tools are not free.",[60,1703,1705],{"id":1704},"the-cost-nobody-mentions","The cost nobody mentions",[30,1707,1708],{},"Each MCP tool has a name, a description and a JSON schema. Those definitions occupy context. Connect four servers exposing fifteen tools each and you have spent a meaningful chunk of your window on API documentation before typing a word.",[30,1710,1711],{},"There is a subtler cost. A crowded tool namespace makes selection harder. Given sixty tools with overlapping descriptions, the wrong one gets picked more often — and the failure looks like the assistant being dim rather than the setup being cluttered.",[30,1713,1714],{},"Modern setups mitigate this with deferred loading: tool names are visible, full schemas load on demand. It helps a lot. It does not make the question go away.",[60,1716,1718],{"id":1717},"the-test","The test",[30,1720,1721],{},"Before connecting a server:",[30,1723,1724],{},[52,1725,1726],{},"Does this let me do something I cannot already do with a shell command or a file read?",[30,1728,1729,1730,1733],{},"Most things fail. A server wrapping a REST API I could ",[34,1731,1732],{},"curl"," fails. A server reading files I could read directly fails.",[30,1735,1736,1737,1740],{},"What passes is anything with real ",[68,1738,1739],{},"state"," on the other side — an application with its own model of the world, its own auth, its own format. That is where a protocol beats a shell.",[60,1742,1744],{"id":1743},"what-survives","What survives",[30,1746,1747,1750,1751,1754,1755,300,1758,1761],{},[52,1748,1749],{},"Obsidian."," The ",[445,1752,1753],{"href":1602},"memory vault",". This passes the test on a technicality worth understanding: the notes are plain Markdown I could read directly, but the vault has structure the filesystem does not expose — wiki-link resolution, a tag index, frontmatter as queryable metadata. ",[34,1756,1757],{},"find_backlinks",[34,1759,1760],{},"manage_tags"," are not shell commands. That is the difference between a folder and a knowledge base.",[30,1763,1764,1767,1768,1771],{},[52,1765,1766],{},"A design tool."," I use Pencil, which edits ",[34,1769,1770],{},".pen"," files. These are encrypted, so there is no shell fallback — reading a design means going through the tool or not at all. Clearest possible pass: strictly impossible otherwise.",[30,1773,1774,1777],{},[52,1775,1776],{},"A memory hub."," A second, more structured store with explicit graph operations — backlinks, orphan detection, connection suggestions. Overlaps with Obsidian more than I would like, which is honestly a case of having adopted two things that solve the same problem at different times. If I were starting clean I would pick one.",[30,1779,1780,1783,1784,1787,1788,1790],{},[52,1781,1782],{},"Google Workspace."," Drive, Gmail, Calendar. This one is about ",[68,1785,1786],{},"auth"," rather than capability. I could hit these APIs with ",[34,1789,1732],{},", but I would need to manage OAuth tokens, refresh flows and scopes myself. The server does that. Genuinely useful for pulling client-supplied documents into a project without a download-and-move dance.",[60,1792,1794],{"id":1793},"what-did-not-survive","What did not survive",[30,1796,1797],{},"Patterns rather than specific names, since the specifics date fast.",[30,1799,1800,1803,1804,1807,1808,920],{},[52,1801,1802],{},"Wrappers around things with good CLIs."," Anything with a mature command-line tool — git, GitHub, package managers, cloud providers — is better used through that CLI. The CLI is more capable, better documented, and its output is already text. An MCP wrapper around ",[34,1805,1806],{},"gh"," is strictly worse than ",[34,1809,1806],{},[30,1811,1812,1815],{},[52,1813,1814],{},"Servers exposing dozens of tools for one job."," A server with forty tools where you use two has spent forty tools' worth of context to give you two. Prefer narrow servers.",[30,1817,1818,1821],{},[52,1819,1820],{},"Anything with production write access."," A server that can write to a production database is a server that can drop a production table. I do not connect those. Reading production data through a read-only path is fine; writing is a decision I want to make deliberately, with my own hands, not something a tool call can reach.",[60,1823,1825],{"id":1824},"the-headless-caveat","The headless caveat",[30,1827,1828],{},"Worth knowing before you build automation on top of this: servers that authenticate interactively may simply not exist in a headless run.",[30,1830,1831,1832,1834,1835,1838],{},"If a server needs a browser login, a scheduled job or CI run that has no browser may find it missing. Automation built assuming a tool is present will fail in ways that look mysterious — the tool is ",[68,1833,1631],{}," when you test interactively and ",[68,1836,1837],{},"gone"," when it runs at 3am.",[30,1840,1841],{},"Anything scheduled should either avoid interactively-authenticated servers or handle their absence explicitly.",[60,1843,1845],{"id":1844},"security-briefly","Security, briefly",[30,1847,1848],{},"Two things I would not skip.",[30,1850,1851,1854,1855,1858],{},[52,1852,1853],{},"An MCP server is code you are running."," It runs with your permissions, sees what you point it at, and can talk to the network. Connecting one is closer to ",[34,1856,1857],{},"npm install"," than to enabling a setting. Same scrutiny applies.",[30,1860,1861,1864],{},[52,1862,1863],{},"Content from a server is data, not instructions."," Text coming back from a server — a document, a note, a page — is untrusted input. If a fetched document contains something shaped like an instruction, it is still just text in a document. This matters most for servers that read things other people wrote: shared drives, email, web pages.",[30,1866,1867,1868,1871],{},"The practical version: be more careful with servers that read ",[68,1869,1870],{},"other people's"," content than with servers that read your own.",[60,1873,1875],{"id":1874},"start-with-one","Start with one",[30,1877,1878],{},"If you are setting this up from scratch, connect one server, use it for a week, and only then add another.",[30,1880,1881],{},"The value is genuinely high — reaching a notes vault or a design file from the same session where you are writing code removes real friction. But the cost is diffuse and easy to miss, and a setup with eight servers connected \"just in case\" is measurably worse than one with two that you actually use.",[392,1883],{},[30,1885,1886],{},[68,1887,1888],{},"Next: the day I confidently diagnosed the wrong cause of a production outage — and what caught it.",{"title":10,"searchDepth":11,"depth":11,"links":1890},[1891,1892,1893,1894,1895,1896,1897],{"id":1704,"depth":11,"text":1705},{"id":1717,"depth":11,"text":1718},{"id":1743,"depth":11,"text":1744},{"id":1793,"depth":11,"text":1794},{"id":1824,"depth":11,"text":1825},{"id":1844,"depth":11,"text":1845},{"id":1874,"depth":11,"text":1875},"Every MCP server you connect spends context before you type anything. Four that justify it, several that did not, and the test I use to decide.",{},"\u002Ftips\u002Fclaude-code\u002Fmcp-servers-that-earn-their-place",{"title":1902,"description":1903},"MCP Servers That Earn Their Place in Claude Code","How to decide which MCP servers to connect, why tool count matters, and the four that survive in a working developer setup.","tips\u002Fclaude-code\u002Fmcp-servers-that-earn-their-place",[426,1906,427,428],"mcp","wReyJz5Ahwr_NAGgxuKoTsuvCqkEI9lpdVkcpDn6bWw",{"id":1909,"title":1910,"body":1911,"category":2256,"date":417,"description":2257,"extension":14,"meta":2258,"navigation":17,"order":421,"path":2259,"readingTime":421,"seo":2260,"stem":2262,"tags":2263,"__hash__":2266},"tips\u002Ftips\u002Fclaude-code\u002Fdebugging-with-an-ai-that-sounds-certain.md","Debugging With an AI That Sounds Certain",{"type":7,"value":1912,"toc":2247},[1913,1916,1920,1923,1926,1930,1933,1997,2000,2056,2066,2069,2080,2083,2087,2090,2096,2103,2133,2136,2140,2143,2153,2160,2166,2169,2173,2176,2186,2192,2198,2208,2212,2215,2218,2221,2227,2231,2234,2237,2239,2244],[30,1914,1915],{},"This one is a mistake rather than a technique. It is more useful than the techniques.",[60,1917,1919],{"id":1918},"the-symptom","The symptom",[30,1921,1922],{},"Production was broken. The preview deployment of the same build was fine.",[30,1924,1925],{},"That is a good symptom, because it narrows things fast. Same code, same build, different behaviour — so the difference is environmental, not in the source.",[60,1927,1929],{"id":1928},"the-investigation","The investigation",[30,1931,1932],{},"First step was comparing the two directly rather than theorising:",[104,1934,1938],{"className":1935,"code":1936,"language":1937,"meta":10,"style":10},"language-bash shiki shiki-themes github-light github-dark","curl -sS https:\u002F\u002Fkociaj.com\u002F > prod.html\ncurl -sS https:\u002F\u002F\u003Chash>.pages.dev\u002F > prev.html\ndiff prod.html prev.html\n","bash",[34,1939,1940,1958,1987],{"__ignoreMap":10},[112,1941,1942,1945,1948,1951,1955],{"class":114,"line":18},[112,1943,1732],{"class":1944},"sScJk",[112,1946,1947],{"class":1486}," -sS",[112,1949,1950],{"class":1506}," https:\u002F\u002Fkociaj.com\u002F",[112,1952,1954],{"class":1953},"szBVR"," >",[112,1956,1957],{"class":1506}," prod.html\n",[112,1959,1960,1962,1964,1967,1970,1973,1976,1979,1982,1984],{"class":114,"line":11},[112,1961,1732],{"class":1944},[112,1963,1947],{"class":1486},[112,1965,1966],{"class":1506}," https:\u002F\u002F",[112,1968,1969],{"class":1953},"\u003C",[112,1971,1972],{"class":1506},"has",[112,1974,1975],{"class":1480},"h",[112,1977,1978],{"class":1953},">",[112,1980,1981],{"class":1506},".pages.dev\u002F",[112,1983,1954],{"class":1953},[112,1985,1986],{"class":1506}," prev.html\n",[112,1988,1989,1992,1995],{"class":114,"line":125},[112,1990,1991],{"class":1944},"diff",[112,1993,1994],{"class":1506}," prod.html",[112,1996,1986],{"class":1506},[30,1998,1999],{},"Both returned 200 with near-identical byte counts, so the HTML was being served. The difference showed up in the script tags:",[104,2001,2005],{"className":2002,"code":2003,"language":2004,"meta":10,"style":10},"language-html shiki shiki-themes github-light github-dark","\u003C!-- production -->\n\u003Cscript type=\"57dcbe46da9a5ddda93858c2-module\" src=\"\u002F_nuxt\u002FDOSwq-1a.js\">\n\n\u003C!-- preview -->\n\u003Cscript type=\"module\" src=\"\u002F_nuxt\u002FDOSwq-1a.js\">\n","html",[34,2006,2007,2013,2041,2046,2051],{"__ignoreMap":10},[112,2008,2009],{"class":114,"line":18},[112,2010,2012],{"class":2011},"sJ8bj","\u003C!-- production -->\n",[112,2014,2015,2017,2021,2024,2027,2030,2033,2035,2038],{"class":114,"line":11},[112,2016,1969],{"class":1480},[112,2018,2020],{"class":2019},"s9eBZ","script",[112,2022,2023],{"class":1944}," type",[112,2025,2026],{"class":1480},"=",[112,2028,2029],{"class":1506},"\"57dcbe46da9a5ddda93858c2-module\"",[112,2031,2032],{"class":1944}," src",[112,2034,2026],{"class":1480},[112,2036,2037],{"class":1506},"\"\u002F_nuxt\u002FDOSwq-1a.js\"",[112,2039,2040],{"class":1480},">\n",[112,2042,2043],{"class":114,"line":125},[112,2044,2045],{"emptyLinePlaceholder":17},"\n",[112,2047,2048],{"class":114,"line":131},[112,2049,2050],{"class":1480},"\u003C!-- preview -->\n",[112,2052,2053],{"class":114,"line":137},[112,2054,2055],{"class":1480},"\u003Cscript type=\"module\" src=\"\u002F_nuxt\u002FDOSwq-1a.js\">\n",[30,2057,2058,2059,2062,2063,920],{},"Production had ",[34,2060,2061],{},"type=\"module\""," rewritten to a nonsense MIME type. There was also an injected script from ",[34,2064,2065],{},"\u002Fcdn-cgi\u002Fscripts\u002F...\u002Frocket-loader.min.js",[30,2067,2068],{},"That is Cloudflare Rocket Loader. It rewrites script types so it can control execution order, and it is well known for breaking ES modules.",[30,2070,2071,2072,2075,2076,2079],{},"The story fit perfectly. Rocket Loader is a zone-level setting on the custom domain and does not apply to ",[34,2073,2074],{},"*.pages.dev"," — which explains ",[68,2077,2078],{},"exactly"," why preview worked and production did not. Server-rendered HTML with no hydration is precisely what \"broken\" looked like.",[30,2081,2082],{},"I wrote it up with the dashboard path and an API call to disable it.",[60,2084,2086],{"id":2085},"it-was-the-cache","It was the cache",[30,2088,2089],{},"The actual fix was a cache purge.",[30,2091,2092,2093,2095],{},"Rocket Loader was a real thing that was really happening — but its shim does restore ",[34,2094,2061],{}," and re-inject the scripts at runtime. It was noise. The site was serving stale cached HTML from a previous deploy, and purging fixed it.",[30,2097,2098,2099,2102],{},"I found this out because after the purge I re-checked, and Rocket Loader was ",[68,2100,2101],{},"still"," rewriting script tags on a working site:",[104,2104,2106],{"className":1935,"code":2105,"language":1937,"meta":10,"style":10},"curl -sS https:\u002F\u002Fkociaj.com\u002F | grep -o 'type=\"[^\"]*module\"'\n# type=\"7cee160ad24d3eb8b9a8f928-module\"\n",[34,2107,2108,2128],{"__ignoreMap":10},[112,2109,2110,2112,2114,2116,2119,2122,2125],{"class":114,"line":18},[112,2111,1732],{"class":1944},[112,2113,1947],{"class":1486},[112,2115,1950],{"class":1506},[112,2117,2118],{"class":1953}," |",[112,2120,2121],{"class":1944}," grep",[112,2123,2124],{"class":1486}," -o",[112,2126,2127],{"class":1506}," 'type=\"[^\"]*module\"'\n",[112,2129,2130],{"class":114,"line":11},[112,2131,2132],{"class":2011},"# type=\"7cee160ad24d3eb8b9a8f928-module\"\n",[30,2134,2135],{},"Same rewriting. Site fine. The diagnosis was disproved by the evidence that was always available.",[60,2137,2139],{"id":2138},"why-it-was-convincing","Why it was convincing",[30,2141,2142],{},"Worth being precise about this, because \"AI hallucinated\" is the wrong description and the wrong lesson.",[30,2144,2145,2146,2148,2149,2152],{},"Nothing was fabricated. Rocket Loader was genuinely enabled. It genuinely rewrites ",[34,2147,2061],{},". It genuinely is a known cause of hydration failures. It genuinely does not apply to ",[34,2150,2151],{},"pages.dev",". Every fact was true and independently verifiable.",[30,2154,2155,2156,2159],{},"The error was ",[52,2157,2158],{},"causation from correlation",". A real anomaly was found that could explain the symptom, and \"could explain\" got promoted to \"does explain\" without the step that separates them: checking whether the anomaly is present when things work.",[30,2161,2162,2163,2165],{},"That step is cheap. It was one ",[34,2164,1732],{},". It just was not taken, because the story was already coherent — and coherence feels like correctness.",[30,2167,2168],{},"This is a human failure mode too. It is worse with an assistant only because the writeup arrives fast, well-organised, and with a confident tone that a colleague thinking aloud would not have.",[60,2170,2172],{"id":2171},"what-actually-helps","What actually helps",[30,2174,2175],{},"Four things, in rough order of value.",[30,2177,2178,2181,2182,2185],{},[52,2179,2180],{},"Ask what would disprove it."," The strongest habit. Before acting on a diagnosis: ",[68,2183,2184],{},"what would I expect to see if this were wrong?"," Here — the anomaly present on a working page. One command, would have caught it immediately.",[30,2187,2188,2191],{},[52,2189,2190],{},"Distinguish anomalies from causes."," Any sufficiently complex production system has several odd things going on. Finding one during an incident does not make it the cause. Cloudflare zones in particular have a pile of transforms enabled that mangle HTML and mostly do not matter.",[30,2193,2194,2197],{},[52,2195,2196],{},"Prefer differences over anomalies."," The initial diff was the right instinct — comparing working against broken is far more targeted than inspecting broken alone. The mistake came from abandoning that discipline once something interesting turned up, and stopping the diff there.",[30,2199,2200,2203,2204,2207],{},[52,2201,2202],{},"Check the boring causes first."," Cache, DNS propagation, a stale build, an environment variable. The Rocket Loader theory was more ",[68,2205,2206],{},"interesting"," than a stale cache, and interesting is a bias, not evidence. Sequence by prior probability, not by narrative appeal.",[60,2209,2211],{"id":2210},"what-it-does-not-mean","What it does not mean",[30,2213,2214],{},"Not \"do not use AI for debugging\".",[30,2216,2217],{},"The investigation was still faster than doing it alone. Fetching both pages, diffing them, spotting the script-type difference, and knowing what Rocket Loader is and how it interacts with ES modules — that is maybe fifteen minutes of work compressed into a couple of minutes, and the Rocket Loader knowledge is not something everyone has to hand.",[30,2219,2220],{},"The failure was not in gathering evidence. It was in the last step, where evidence became conclusion without a check.",[30,2222,2223,2224,2226],{},"So keep the tool for the part it is good at — gathering and correlating fast — and keep the verification for yourself. The ",[34,2225,1732],{}," that disproved the theory took two seconds. It just needed someone to ask for it.",[60,2228,2230],{"id":2229},"the-honest-bit","The honest bit",[30,2232,2233],{},"I published that diagnosis before the fix was confirmed. It read as authoritative — dashboard path, API call, an aside about Email Obfuscation — and it was wrong about the only thing that mattered.",[30,2235,2236],{},"Which is the actual lesson. Confidence in the writeup is not evidence about the world. It is a property of the writing.",[392,2238],{},[30,2240,2241],{},[68,2242,2243],{},"Next: permissions, and deciding what should never be automatic.",[400,2245,2246],{},"html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .szBVR, html code.shiki .szBVR{--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}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);}html pre.shiki code .sJ8bj, html code.shiki .sJ8bj{--shiki-default:#6A737D;--shiki-dark:#6A737D}html pre.shiki code .s9eBZ, html code.shiki .s9eBZ{--shiki-default:#22863A;--shiki-dark:#85E89D}",{"title":10,"searchDepth":11,"depth":11,"links":2248},[2249,2250,2251,2252,2253,2254,2255],{"id":1918,"depth":11,"text":1919},{"id":1928,"depth":11,"text":1929},{"id":2085,"depth":11,"text":2086},{"id":2138,"depth":11,"text":2139},{"id":2171,"depth":11,"text":2172},{"id":2210,"depth":11,"text":2211},{"id":2229,"depth":11,"text":2230},"In practice","A production site broke. The diagnosis was specific, evidence-backed, and wrong. What that session taught me about verifying confident answers.",{},"\u002Ftips\u002Fclaude-code\u002Fdebugging-with-an-ai-that-sounds-certain",{"title":1910,"description":2261},"A real debugging session where a confident, evidence-backed diagnosis was wrong. How to structure AI-assisted debugging so mistakes surface fast.","tips\u002Fclaude-code\u002Fdebugging-with-an-ai-that-sounds-certain",[426,2264,2265,428],"debugging","cloudflare","XSlFZPnlZKRaOB5FU9ilmpaJiYvrmd0TfXnoohGhGgo",{"id":2268,"title":2269,"body":2270,"category":2256,"date":417,"description":2519,"extension":14,"meta":2520,"navigation":17,"order":811,"path":2521,"readingTime":421,"seo":2522,"stem":2525,"tags":2526,"__hash__":2528},"tips\u002Ftips\u002Fclaude-code\u002Fpermissions-what-to-automate-and-what-never-to.md","Permissions: What to Automate, and What Never To",{"type":7,"value":2271,"toc":2511},[2272,2275,2278,2285,2289,2292,2298,2304,2310,2320,2331,2335,2338,2348,2354,2357,2361,2364,2408,2421,2424,2427,2431,2434,2455,2458,2461,2468,2472,2475,2478,2486,2489,2493,2496,2499,2502,2504,2509],[30,2273,2274],{},"Permission prompts have a design problem: they interrupt you when you are concentrating, and the correct answer is \"yes\" often enough that you stop reading them.",[30,2276,2277],{},"That is not a hypothetical. It is how every security prompt in computing history has gone. Prompt often enough and you have trained a reflex, not a decision.",[30,2279,2280,2281,2284],{},"So the question is not \"how much should I approve?\" It is ",[52,2282,2283],{},"which decisions are worth your attention at all",", and how to make the rest disappear without pretending they are safe.",[60,2286,2288],{"id":2287},"reversibility-not-danger","Reversibility, not danger",[30,2290,2291],{},"The useful axis is not how dangerous an action sounds. It is how hard it is to undo.",[30,2293,2294,2297],{},[52,2295,2296],{},"Trivially reversible"," — reading files, searching, running tests, git status and diff. Worst case is wasted time. Automate freely.",[30,2299,2300,2303],{},[52,2301,2302],{},"Reversible with effort"," — editing files, creating files, local commits. Git makes these recoverable, provided the work was committed at some point. Automate within a project you control.",[30,2305,2306,2309],{},[52,2307,2308],{},"Reversible only with outside help"," — pushing to a shared branch, deploying, publishing a package, sending an email. Recoverable, but it involves other people, or the internet has already seen it. Approve individually.",[30,2311,2312,2315,2316,2319],{},[52,2313,2314],{},"Not reversible"," — dropping a production table, force-pushing over someone's work, deleting a cloud resource, sending to a mailing list. No undo. These should not be automatable at all, and the fact that a tool ",[68,2317,2318],{},"can"," do them is not a reason to let it.",[30,2321,2322,2323,2326,2327,2330],{},"Note that \"dangerous-sounding\" and \"irreversible\" come apart. ",[34,2324,2325],{},"rm -rf node_modules"," sounds alarming and costs a reinstall. ",[34,2328,2329],{},"git push --force"," sounds routine and can destroy work that exists nowhere else.",[60,2332,2334],{"id":2333},"the-line-i-actually-hold","The line I actually hold",[30,2336,2337],{},"Two rules, and they are about outward-facing effects rather than technical risk:",[30,2339,2340,2343,2344,2347],{},[52,2341,2342],{},"Nothing leaves the machine without me asking for it."," Publishing, deploying, emailing, posting. Not because those are technically dangerous, but because they are ",[68,2345,2346],{},"social"," — once content is on an external service it may be cached or indexed even if deleted, and the audience has already seen it. Approval in one context does not carry to the next: agreeing to deploy on Tuesday is not standing permission to deploy on Thursday.",[30,2349,2350,2353],{},[52,2351,2352],{},"Look before overwriting or deleting."," Read the target first. This catches the case where a path is subtly wrong and the destination is not what anyone assumed. Cheap, and it is the check that prevents the worst outcomes.",[30,2355,2356],{},"Neither is about distrust. Both are about the fact that a plausible-looking wrong action executes exactly as smoothly as a right one.",[60,2358,2360],{"id":2359},"allowlists-over-blanket-approval","Allowlists over blanket approval",[30,2362,2363],{},"The productive middle ground is allowing specific things you have verified, rather than approving broadly.",[104,2365,2367],{"className":1471,"code":2366,"language":1473,"meta":10,"style":10},"{\n  \"permissions\": {\n    \"allow\": [\n      \"mcp__pencil\"\n    ]\n  }\n}\n",[34,2368,2369,2373,2381,2389,2394,2399,2404],{"__ignoreMap":10},[112,2370,2371],{"class":114,"line":18},[112,2372,1481],{"class":1480},[112,2374,2375,2378],{"class":114,"line":11},[112,2376,2377],{"class":1486},"  \"permissions\"",[112,2379,2380],{"class":1480},": {\n",[112,2382,2383,2386],{"class":114,"line":125},[112,2384,2385],{"class":1486},"    \"allow\"",[112,2387,2388],{"class":1480},": [\n",[112,2390,2391],{"class":114,"line":131},[112,2392,2393],{"class":1506},"      \"mcp__pencil\"\n",[112,2395,2396],{"class":114,"line":137},[112,2397,2398],{"class":1480},"    ]\n",[112,2400,2401],{"class":114,"line":1172},[112,2402,2403],{"class":1480},"  }\n",[112,2405,2406],{"class":114,"line":421},[112,2407,1512],{"class":1480},[30,2409,2410,2411,296,2414,296,2417,2420],{},"The pattern that works: run normally for a couple of weeks, notice which prompts you approve every single time without thinking, and allowlist exactly those. Read-only shell commands are the usual candidates — ",[34,2412,2413],{},"ls",[34,2415,2416],{},"git status",[34,2418,2419],{},"git diff",", test runners.",[30,2422,2423],{},"This is better than a blanket setting because the surface stays small and legible. You can read your allowlist and understand what you have agreed to. A single \"allow everything\" flag has no such property.",[30,2425,2426],{},"Project-level settings help here too. A repo you own can allow more than a client's production infrastructure. Same tool, different blast radius, different rules.",[60,2428,2430],{"id":2429},"about-the-dangerous-flag","About the dangerous flag",[30,2432,2433],{},"There is a setting that skips the confirmation for permissive modes. Mine is on:",[104,2435,2437],{"className":1471,"code":2436,"language":1473,"meta":10,"style":10},"{ \"skipDangerousModePermissionPrompt\": true }\n",[34,2438,2439],{"__ignoreMap":10},[112,2440,2441,2444,2447,2449,2452],{"class":114,"line":18},[112,2442,2443],{"class":1480},"{ ",[112,2445,2446],{"class":1486},"\"skipDangerousModePermissionPrompt\"",[112,2448,1490],{"class":1480},[112,2450,2451],{"class":1486},"true",[112,2453,2454],{"class":1480}," }\n",[30,2456,2457],{},"Being straight about what this is: it removes a speed bump, not a wall. It is defensible in a disposable environment — a container, a scratch repo, a worktree you are about to throw away.",[30,2459,2460],{},"It is not defensible with production credentials in the environment. And the honest risk is not that you will make a bad decision. It is that you will forget which mode you are in, because the reminder is exactly what you disabled.",[30,2462,2463,2464,2467],{},"If you turn something like this on, make your prompt or status line show the mode. Removing a confirmation is fine. Removing the ",[68,2465,2466],{},"signal"," is what gets people.",[60,2469,2471],{"id":2470},"the-one-nobody-thinks-about","The one nobody thinks about",[30,2473,2474],{},"A prompt is not the only way instructions reach your assistant. Content it reads is another.",[30,2476,2477],{},"If it fetches a web page, reads an email, or opens a shared document, that content enters context. Text shaped like an instruction inside a fetched document is still just text in a document — but a system that reads a page and then acts on what the page says has a real problem.",[30,2479,2480,2481,2485],{},"This is why the earlier point about ",[445,2482,2484],{"href":2483},"\u002Ftips\u002Fclaude-code\u002Fmcp-servers-that-earn-their-place\u002F","MCP servers reading other people's content"," matters more than it first appears. Your own notes are one thing. A shared drive where anyone can drop a file is another.",[30,2487,2488],{},"Practical version: treat fetched content as data. If something read from an external source seems to be asking for an action, that is a red flag, not an instruction.",[60,2490,2492],{"id":2491},"what-i-would-tell-someone-starting","What I would tell someone starting",[30,2494,2495],{},"Do not configure permissions up front. You do not yet know which prompts are noise and which are the ones that will save you.",[30,2497,2498],{},"Run with defaults for two weeks. Keep a note of prompts you approve reflexively. Allowlist those, specifically. Leave everything else prompting.",[30,2500,2501],{},"You will end up with a short allowlist of read-only operations and prompts on everything that writes or reaches the network — which is roughly the right answer, arrived at from evidence rather than from a blog post.",[392,2503],{},[30,2505,2506],{},[68,2507,2508],{},"Next: something concrete. Building a print-perfect A4 PDF page in Nuxt, and every way the browser fights you.",[400,2510,1669],{},{"title":10,"searchDepth":11,"depth":11,"links":2512},[2513,2514,2515,2516,2517,2518],{"id":2287,"depth":11,"text":2288},{"id":2333,"depth":11,"text":2334},{"id":2359,"depth":11,"text":2360},{"id":2429,"depth":11,"text":2430},{"id":2470,"depth":11,"text":2471},{"id":2491,"depth":11,"text":2492},"Permission prompts are friction, and friction gets disabled. A framework for deciding what runs unattended, based on reversibility rather than danger.",{},"\u002Ftips\u002Fclaude-code\u002Fpermissions-what-to-automate-and-what-never-to",{"title":2523,"description":2524},"Claude Code Permissions: What to Automate and What Never To","A reversibility-based framework for deciding which AI actions run unattended, which need approval, and which should never be automated.","tips\u002Fclaude-code\u002Fpermissions-what-to-automate-and-what-never-to",[426,2527,427,428],"security","dIbxrhXB9AkmG1RDupSAP6I7Xz_f0ljRZ3FKQxZy6lY",{"id":2530,"title":2531,"body":2532,"category":2256,"date":417,"description":2715,"extension":14,"meta":2716,"navigation":17,"order":2717,"path":2718,"readingTime":421,"seo":2719,"stem":2722,"tags":2723,"__hash__":2724},"tips\u002Ftips\u002Fclaude-code\u002Floops-background-jobs-and-scheduled-agents.md","Loops, Background Jobs and Scheduled Agents",{"type":7,"value":2533,"toc":2706},[2534,2537,2541,2544,2547,2554,2557,2561,2564,2570,2573,2576,2579,2583,2586,2592,2595,2602,2605,2609,2612,2618,2621,2632,2635,2639,2642,2647,2650,2653,2656,2659,2663,2666,2669,2679,2683,2686,2693,2696,2699,2701],[30,2535,2536],{},"Everything so far assumed you are sitting there. This is about the work that is not interactive — and about being honest that it is the part with the worst effort-to-payoff ratio in the whole setup.",[60,2538,2540],{"id":2539},"background-tasks-the-easy-win","Background tasks: the easy win",[30,2542,2543],{},"The clearest case. A long-running command runs detached, you keep working, and you get notified when it finishes.",[30,2545,2546],{},"Test suites, builds, installs, migrations. Anything where you would otherwise watch a progress bar.",[30,2548,2549,2550,2553],{},"The reason this works so well is that it removes a ",[68,2551,2552],{},"specific"," waste — blocking on something that needs no supervision — without introducing any new risk. The command is one you would have run anyway. It runs the same way. You just stop staring at it.",[30,2555,2556],{},"One thing worth internalising: if a system notifies you when a background job finishes, do not also poll it. Setting a five-minute check on something that will announce itself is pure waste, and it is a surprisingly easy habit to fall into.",[60,2558,2560],{"id":2559},"loops-narrower-than-they-look","Loops: narrower than they look",[30,2562,2563],{},"A loop re-runs a prompt on an interval. The obvious use is polling something that changes on its own — a CI run, a deploy, a queue draining.",[30,2565,2566,2567],{},"The judgement is the interval, and the rule is simple: ",[52,2568,2569],{},"match it to how fast the thing you are watching actually changes.",[30,2571,2572],{},"A CI pipeline that takes eight minutes deserves one check at around eight minutes, not eight checks at one minute. Seven of those are guaranteed to find nothing and cost the same as the one that finds something.",[30,2574,2575],{},"Where loops genuinely earn their place: external state that cannot notify you. A deploy on a platform without webhooks. A third-party API you are waiting to come back. A slow remote job with no callback.",[30,2577,2578],{},"Where they do not: anything inside your own machine that could just tell you when it is done.",[60,2580,2582],{"id":2581},"scheduled-agents-be-honest-about-value","Scheduled agents: be honest about value",[30,2584,2585],{},"Cron for AI sessions. A prompt runs at a set time whether or not you are there.",[30,2587,2588,2589],{},"The compelling pitch is a morning briefing — check overnight CI, summarise new issues, flag failing monitors. It works. But the value depends entirely on one question: ",[52,2590,2591],{},"would you have checked anyway?",[30,2593,2594],{},"If yes, the scheduled version saves you five minutes. If no, you have automated the production of something you will not read, on a schedule, indefinitely.",[30,2596,2597,2598,2601],{},"I run very few of these, and the ones that survived have a property in common: they ",[68,2599,2600],{},"only speak up when something is wrong",". A job that reports \"all fine\" every morning becomes wallpaper within a fortnight. A job that is silent for three weeks and then says \"the staging certificate expires in six days\" has justified itself entirely.",[30,2603,2604],{},"Silence as the default output is the design rule.",[60,2606,2608],{"id":2607},"two-things-that-break-unattended-work","Two things that break unattended work",[30,2610,2611],{},"Both are unobvious until they bite.",[30,2613,2614,2617],{},[52,2615,2616],{},"Interactive auth disappears."," Anything that authenticates through a browser may not exist in a headless or scheduled run. Automation built assuming a tool is present will fail at 3am in a way that looks like nonsense — the tool was there when you tested it interactively.",[30,2619,2620],{},"Check availability explicitly, or do not depend on such tools in scheduled work.",[30,2622,2623,2626,2627,2631],{},[52,2624,2625],{},"Nobody is there to say no."," Everything from ",[445,2628,2630],{"href":2629},"\u002Ftips\u002Fclaude-code\u002Fpermissions-what-to-automate-and-what-never-to\u002F","the permissions piece"," applies double. An unattended job cannot ask. So it either has permission to act — and will, on a misreading you are not there to catch — or it can only report.",[30,2633,2634],{},"Almost all of my scheduled work is in the second category. It observes and reports. It does not change things.",[60,2636,2638],{"id":2637},"the-rule","The rule",[30,2640,2641],{},"One line, and it is the reversibility axis again:",[30,2643,2644],{},[52,2645,2646],{},"Automate what is reversible or read-only. Report on everything else.",[30,2648,2649],{},"A job that reads CI status and summarises it: reversible, in that it changes nothing. Automate freely.",[30,2651,2652],{},"A job that reads dependency updates and opens a PR: a PR is a proposal, not a change. Fine.",[30,2654,2655],{},"A job that reads dependency updates and merges them: not fine, whatever the test suite says. The failure mode is a broken production deploy at 4am with no human in the loop, and you have traded a small recurring saving for a large occasional disaster.",[30,2657,2658],{},"The asymmetry is the point. The upside of automating a decision is a few saved minutes. The downside is an outage. Those do not trade evenly.",[60,2660,2662],{"id":2661},"what-i-actually-run","What I actually run",[30,2664,2665],{},"Being concrete, and slightly deflating: background tasks constantly, loops occasionally for external state, and almost no scheduled agents.",[30,2667,2668],{},"That last one is not a failure of imagination. It is that most of what I do is project work, driven by what a client needs this week, and the useful moment to look at a codebase is when I am about to change it. A daily digest of a repo nobody is touching is noise dressed as diligence.",[30,2670,2671,2672,2675,2676,2678],{},"This piece is last in the series because it is genuinely the least valuable part. If you implemented only the ",[445,2673,2674],{"href":447},"CLAUDE.md rules"," and the ",[445,2677,1753],{"href":1602},", you would get most of the benefit of everything here.",[60,2680,2682],{"id":2681},"where-to-stop","Where to stop",[30,2684,2685],{},"The temptation with all of this is to keep going — automating the automation, building the system that maintains the system. It is enjoyable and it feels productive.",[30,2687,2688,2689,2692],{},"The check I use: ",[52,2690,2691],{},"has this saved more time than it took to build?"," Honestly, and including maintenance.",[30,2694,2695],{},"For background tasks the answer is obviously yes, within a day. For the memory vault it took weeks to break even and now compounds. For a couple of scheduled jobs I built and later deleted, the answer was never, and admitting that took longer than it should have.",[30,2697,2698],{},"Build the thing that removes today's friction. Be suspicious of the thing that removes friction you have merely imagined.",[392,2700],{},[30,2702,2703],{},[68,2704,2705],{},"That is the series. The setup it describes will be different in six months, because every part of it exists because something went wrong first — and things will keep going wrong.",{"title":10,"searchDepth":11,"depth":11,"links":2707},[2708,2709,2710,2711,2712,2713,2714],{"id":2539,"depth":11,"text":2540},{"id":2559,"depth":11,"text":2560},{"id":2581,"depth":11,"text":2582},{"id":2607,"depth":11,"text":2608},{"id":2637,"depth":11,"text":2638},{"id":2661,"depth":11,"text":2662},{"id":2681,"depth":11,"text":2682},"The last step is work that happens while you are not watching. Where that pays off, where it quietly burns money, and the rule that decides which.",{},9,"\u002Ftips\u002Fclaude-code\u002Floops-background-jobs-and-scheduled-agents",{"title":2720,"description":2721},"Loops, Background Jobs and Scheduled Agents in Claude Code","When to run AI work unattended — background tasks, polling loops and scheduled agents — and the reversibility rule that decides what qualifies.","tips\u002Fclaude-code\u002Floops-background-jobs-and-scheduled-agents",[426,1127,427,428],"HSyRGWIBPXMuhJsh90BxTqQ6kwNpn7JCOZCtHxjYY7Q",1790722070342]