<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Dhrupo Nil</title>
    <description>The latest articles on DEV Community by Dhrupo Nil (@dhrupo).</description>
    <link>https://dev.to/dhrupo</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1151170%2Ff3f2b324-73c2-4df0-9f8a-ffc109194198.jpeg</url>
      <title>DEV Community: Dhrupo Nil</title>
      <link>https://dev.to/dhrupo</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/dhrupo"/>
    <language>en</language>
    <item>
      <title>Dev OS v2: gates, a learning loop, and agents that check agents</title>
      <dc:creator>Dhrupo Nil</dc:creator>
      <pubDate>Sun, 01 Nov 2026 14:21:40 +0000</pubDate>
      <link>https://dev.to/dhrupo/dev-os-v2-gates-a-learning-loop-and-agents-that-check-agents-4a9b</link>
      <guid>https://dev.to/dhrupo/dev-os-v2-gates-a-learning-loop-and-agents-that-check-agents-4a9b</guid>
      <description>&lt;p&gt;In &lt;a href="https://dev.to/dhrupo/how-i-set-up-claude-code-one-rulebook-a-12-step-relay-to-use-it-daily-40gi"&gt;v1&lt;/a&gt; I treated &lt;code&gt;~/.claude&lt;/code&gt; as an operating system around the model: a kernel (one rulebook), a scheduler (lanes), interrupts (hooks), a package manager (pinned skills). I asked you to run the &lt;a href="https://github.com/dhrupo/claude-code-dev-os" rel="noopener noreferrer"&gt;starter kit&lt;/a&gt; for a week and tell me what broke.&lt;/p&gt;

&lt;p&gt;I ran it too, every day. 213 commits later, this is the v2 release, and its main change fits on one line:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;A rule the agent reads is a request. A rule something runs is a gate.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Both commenters on v1 had said the same thing. Here is what that changed, in order of how much it helped. The gates, hooks, agents and tests below ship in the kit (135 checks, &lt;code&gt;bash tests/run.sh&lt;/code&gt;); the rest is how I run my own setup. The kit works with any agent that reads &lt;code&gt;AGENTS.md&lt;/code&gt; (Codex, Cursor, Copilot), not only Claude Code.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. One rulebook, every agent
&lt;/h2&gt;

&lt;p&gt;The kernel is the same: one &lt;code&gt;CLAUDE.md&lt;/code&gt; whose first section says it overrides every skill, plugin and repo file. What's new is that &lt;code&gt;AGENTS.md&lt;/code&gt; is a symlink to it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;ln&lt;/span&gt; &lt;span class="nt"&gt;-s&lt;/span&gt; ~/.claude/CLAUDE.md ~/.codex/AGENTS.md   &lt;span class="c"&gt;# Codex reads ~/.codex/AGENTS.md, then one per folder, root → cwd&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I checked how each tool loads it on 2026-11-01:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Codex&lt;/strong&gt; concatenates &lt;code&gt;AGENTS.md&lt;/code&gt; files up to &lt;a href="https://learn.chatgpt.com/docs/agent-configuration/agents-md" rel="noopener noreferrer"&gt;32 KiB by default&lt;/a&gt;. A long global rulebook steals room from repo rules. Mine is capped at 136 lines by a test.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Claude Code&lt;/strong&gt; &lt;a href="https://code.claude.com/docs/en/memory#agents-md" rel="noopener noreferrer"&gt;reads &lt;code&gt;AGENTS.md&lt;/code&gt;&lt;/a&gt; only in a repo with no &lt;code&gt;CLAUDE.md&lt;/code&gt;, so &lt;code&gt;CLAUDE.md&lt;/code&gt; stays the source.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;@lessons.md&lt;/code&gt; imports are Claude-only.&lt;/strong&gt; Through the link, Codex gets the rulebook but not its imports.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  2. Gates beat reminders
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;A test gate in plain git.&lt;/strong&gt; v1's pre-commit hook only guarded &lt;code&gt;~/.claude&lt;/code&gt; itself. v2 installs one per project:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s1"&gt;'npm test'&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; .dev-os-test &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; ~/.claude/bin/gate-install
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The hook it writes (condensed from &lt;code&gt;bin/gate-install&lt;/code&gt;):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;TOP&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;git rev-parse &lt;span class="nt"&gt;--show-toplevel&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;
&lt;span class="nb"&gt;unset &lt;/span&gt;GIT_INDEX_FILE GIT_DIR GIT_WORK_TREE GIT_PREFIX
&lt;span class="nv"&gt;CMD&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;cat&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$TOP&lt;/span&gt;&lt;span class="s2"&gt;/.dev-os-test"&lt;/span&gt; 2&amp;gt;/dev/null&lt;span class="si"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="nb"&gt;printf&lt;/span&gt; &lt;span class="s1"&gt;'%s'&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$CMD&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-q&lt;/span&gt; &lt;span class="s1"&gt;'[^[:space:]]'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
  &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"dev-os test gate: .dev-os-test is missing or empty; commit refused"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&amp;amp;2&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nb"&gt;exit &lt;/span&gt;1
&lt;span class="k"&gt;fi&lt;/span&gt;
&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;cd&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$TOP&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; bash &lt;span class="nt"&gt;-o&lt;/span&gt; pipefail &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$CMD&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"dev-os test gate: commit refused"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&amp;amp;2&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nb"&gt;exit &lt;/span&gt;1&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Every line there is a bug I hit:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;pipefail&lt;/code&gt;:&lt;/strong&gt; &lt;code&gt;npm test | tail -5&lt;/code&gt; exits with &lt;code&gt;tail&lt;/code&gt;'s 0, so a red suite commits.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Empty means refuse:&lt;/strong&gt; a missing or empty test command fails loudly instead of passing quietly.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;unset GIT_INDEX_FILE&lt;/code&gt;:&lt;/strong&gt; git runs &lt;code&gt;pre-commit&lt;/code&gt; with a temporary index during &lt;code&gt;commit -a&lt;/code&gt;. A test suite that runs &lt;code&gt;git add&lt;/code&gt; in a temp repo writes into &lt;em&gt;your&lt;/em&gt; commit and breaks it with "Error building trees".&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No global hooks:&lt;/strong&gt; the installer refuses when a global &lt;code&gt;core.hooksPath&lt;/code&gt; would turn one repo's gate into every repo's gate.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Permissions the agent can't talk past.&lt;/strong&gt; &lt;code&gt;permissions.ask&lt;/code&gt; rules still prompt under &lt;code&gt;--dangerously-skip-permissions&lt;/code&gt;, and compound commands are split before matching:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="nl"&gt;"permissions"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"ask"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"Bash(git push:*)"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Bash(gh pr create:*)"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;One catch: rules match the command text, so &lt;code&gt;git -C . push&lt;/code&gt; slips past &lt;code&gt;Bash(git push:*)&lt;/code&gt;. I add &lt;code&gt;Bash(git -C * push *)&lt;/code&gt; in my own settings. Keep branch protection on the remote as the backstop.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A Stop hook for the cheap way out.&lt;/strong&gt; v1's Stop hook sent the agent back when source changed with no test. v2 adds one more case: a &lt;em&gt;weakened&lt;/em&gt; test. That means fewer assertions, a new &lt;code&gt;.skip&lt;/code&gt;/&lt;code&gt;.only&lt;/code&gt;, or a deleted test file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;ASSERT&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;re&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;compile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;r&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;\bassert\w*\s*\(|\bexpect\s*\(|-&amp;gt;assert\w*\(|\$this-&amp;gt;assert|^[-+]\s*assert(_\w+)?\s&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;SKIP&lt;/span&gt;   &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;re&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;compile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;r&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;markTestSkipped|markTestIncomplete|-&amp;gt;skip\(|\.(skip|only|fixme)\s*\(|\bx(it|describe|test)\s*\(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;removed_asserts&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;added_asserts&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="nf"&gt;any&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;SKIP&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;search&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;l&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;added&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;weakened&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;        &lt;span class="c1"&gt;# → {"decision": "block", "reason": "TEST WEAKENED: …"}
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://learn.chatgpt.com/docs/hooks" rel="noopener noreferrer"&gt;Codex hooks&lt;/a&gt; use the same &lt;code&gt;Stop&lt;/code&gt; → &lt;code&gt;{"decision":"block"}&lt;/code&gt; shape.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. It learns by itself
&lt;/h2&gt;

&lt;p&gt;In v1, "add a line to &lt;code&gt;lessons.md&lt;/code&gt;" depended on me remembering to do it. Now the setup logs its own mistakes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;prompt starts "no, …" / "I said …"   ─┐
stop-check or test gate blocks       ─┼─▶ state/learn-&amp;lt;session&amp;gt;.jsonl
                                       │
Stop: learn.sh → any entry newer than the last `reflect`? → block once: "run reflect"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;reflect&lt;/code&gt; routes each mistake to the &lt;strong&gt;lowest layer that would have caught it&lt;/strong&gt;: first a test or hook, then one line in the skill that owns the job, and only last a line in &lt;code&gt;lessons.md&lt;/code&gt;. &lt;code&gt;lessons.md&lt;/code&gt; has a 60-line budget. When it fills up, &lt;code&gt;meditate&lt;/code&gt; audits the rules for stale, duplicate and contradicting lines, and deletes nothing without my yes. 59 of the 213 commits are &lt;code&gt;Lesson:&lt;/code&gt; commits, and many of them &lt;em&gt;removed&lt;/em&gt; a lesson by turning it into a check.&lt;/p&gt;

&lt;p&gt;The loop gets tested like everything else. A cold review caught the correction detector flagging "No tests exist for the parser yet" as a correction. Now &lt;code&gt;no&lt;/code&gt; counts only when followed by punctuation, and only the first line of a prompt is read.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Agents check agents
&lt;/h2&gt;

&lt;p&gt;One agent reviewing its own diff is a student grading their own exam. The kit ships two read-only agent shapes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;scout&lt;/code&gt;&lt;/strong&gt;: one angle per scout (callers, tests, history, config). Each returns &lt;code&gt;file:line&lt;/code&gt; facts and what it couldn't check.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;review-lens&lt;/code&gt;&lt;/strong&gt;: Skeptic always, Architect at 50+ changed lines, Minimalist at 200+. Then &lt;strong&gt;one verifier per finding&lt;/strong&gt; that starts from "false positive".&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Two skills run them. &lt;a href="https://github.com/dhrupo/claude-code-dev-os/tree/main/skills/pre-merge-review" rel="noopener noreferrer"&gt;&lt;code&gt;pre-merge-review&lt;/code&gt;&lt;/a&gt; is relay step 7 on your own branch: lenses sized by the diff, a verifier per finding, one saved report. &lt;a href="https://github.com/dhrupo/claude-code-dev-os/tree/main/skills/post-pr-review" rel="noopener noreferrer"&gt;&lt;code&gt;post-pr-review&lt;/code&gt;&lt;/a&gt; is for someone else's PR: each finding must reproduce on both the base and the PR branch before it goes in a draft, and nothing is posted without a yes. &lt;code&gt;/code-review&lt;/code&gt; stays the per-slice check inside &lt;code&gt;build-check&lt;/code&gt;, and it never posts on other people's PRs.&lt;/p&gt;

&lt;p&gt;Every subagent brief has the same fields: goal, scope, what's known, what's been ruled out, the exact ask, the output format, what's out of scope. Parallel builders get one git worktree each, and only for plan slices that share no files.&lt;/p&gt;

&lt;p&gt;How well does this work? On the v2 kit itself, which already passed all its own tests:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Pass&lt;/th&gt;
&lt;th&gt;Found&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;/code-review&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;9 (6 fixed, 3 left with reasons)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3 lenses, each reproducing its findings in a temp dir&lt;/td&gt;
&lt;td&gt;14 more&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;a cold reviewer that saw none of the above&lt;/td&gt;
&lt;td&gt;4 more&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Every behaviour fix got a red test first.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Prove it by running it
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="p"&gt;9.&lt;/span&gt; A bug or security claim counts only when reproduced by running it. No repro, no fix.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For bugs, the first job is a red-capable &lt;strong&gt;feedback loop&lt;/strong&gt;, in the order from Matt Pocock's &lt;a href="https://github.com/mattpocock/skills/tree/HEAD/skills/engineering/diagnosing-bugs" rel="noopener noreferrer"&gt;diagnosing-bugs&lt;/a&gt;: failing test → curl script → CLI snapshot diff → headless browser → replayed payload → harness → fuzz → &lt;code&gt;git bisect run&lt;/code&gt;. Hypotheses come after.&lt;/p&gt;

&lt;p&gt;I also break every gate on purpose before I trust it. That caught a test that passed before the code existed. My helper matched substrings, so &lt;code&gt;rc=127&lt;/code&gt; ("command not found") satisfied a check for &lt;code&gt;rc=1&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  6. Project memory: graph first
&lt;/h2&gt;

&lt;p&gt;Rule 8: before grep, ask a code graph "who calls this, and what breaks if I change it?"&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Tool&lt;/th&gt;
&lt;th&gt;Used for&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;a href="https://github.com/Graphify-Labs/graphify" rel="noopener noreferrer"&gt;graphify&lt;/a&gt; &lt;code&gt;query&lt;/code&gt; / &lt;code&gt;explain&lt;/code&gt; / &lt;code&gt;path&lt;/code&gt; / &lt;code&gt;merge-graphs&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Finding code, explaining a node, call paths, one graph across repos&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;a href="https://github.com/tirth8205/code-review-graph" rel="noopener noreferrer"&gt;code-review-graph&lt;/a&gt; &lt;code&gt;get_impact_radius_tool&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Who else a fix reaches (the no-regressions rule)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;get_review_context_tool&lt;/code&gt;, &lt;code&gt;get_affected_flows_tool&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Review context; which E2E flows a diff touches&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The scouts, review lenses and review-reply step all start there. The graph holds structure. What the project &lt;em&gt;taught&lt;/em&gt; lives in &lt;code&gt;lessons.md&lt;/code&gt; and in plan folders kept outside the repo.&lt;/p&gt;

&lt;h2&gt;
  
  
  7. Stay lean
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;A context budget test:&lt;/strong&gt; rulebook plus skill descriptions, measured in bytes, against a baseline. It went from 59,287 to 46,927 while the setup grew.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Routing is tested:&lt;/strong&gt; one rulebook sentence ("call the owner skill before any other tool") took my routing eval from 0-1 to 7-8 of 11 prompts.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Effort is a budget too:&lt;/strong&gt; &lt;code&gt;"effortLevel": "medium"&lt;/code&gt; by default, in every &lt;code&gt;modelSettings&lt;/code&gt; entry as well, since a per-model value wins. High effort lives in skill frontmatter only where a wrong answer is expensive: grilling, writing and checking the plan, whole-plugin bug hunts. Hooks &lt;a href="https://code.claude.com/docs/en/hooks" rel="noopener noreferrer"&gt;can read the effort level but not set it&lt;/a&gt;, so serious cases are handled by a rule: payment or refund, data loss, auth or a security finding mean the verifiers are spawned with &lt;code&gt;effort: "high"&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Smaller output:&lt;/strong&gt; &lt;a href="https://github.com/rtk-ai/rtk" rel="noopener noreferrer"&gt;RTK&lt;/a&gt; trims &lt;code&gt;git&lt;/code&gt;/&lt;code&gt;gh&lt;/code&gt;/test output before the agent reads it. Compressed output can hide the one line you need, so "never report a result you couldn't see" is a rule.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The userland
&lt;/h2&gt;

&lt;p&gt;Most of my 103 skills are other people's work: 39 are pinned to an upstream commit in &lt;code&gt;skills.lock&lt;/code&gt;, with local edits in overlays that a sync script re-applies.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/DietrichGebert/ponytail" rel="noopener noreferrer"&gt;ponytail&lt;/a&gt; by Dietrich Gebert: the smallest-change ladder (YAGNI → reuse → stdlib → platform → installed dep → one line). It's rule 3 in the kit.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/mattpocock/skills" rel="noopener noreferrer"&gt;Matt Pocock's skills&lt;/a&gt;: &lt;a href="https://github.com/mattpocock/skills/tree/HEAD/skills/engineering/tdd" rel="noopener noreferrer"&gt;tdd&lt;/a&gt;, &lt;a href="https://github.com/mattpocock/skills/tree/HEAD/skills/productivity/grill-me" rel="noopener noreferrer"&gt;grill-me&lt;/a&gt;, &lt;a href="https://github.com/mattpocock/skills/tree/HEAD/skills/productivity/handoff" rel="noopener noreferrer"&gt;handoff&lt;/a&gt;, &lt;a href="https://github.com/mattpocock/skills/tree/HEAD/skills/engineering/domain-modeling" rel="noopener noreferrer"&gt;domain-modeling&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/obra/superpowers/tree/HEAD/skills/brainstorming" rel="noopener noreferrer"&gt;obra/superpowers&lt;/a&gt;: brainstorming and &lt;a href="https://github.com/obra/superpowers/tree/HEAD/skills/systematic-debugging" rel="noopener noreferrer"&gt;systematic-debugging&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/trailofbits/skills/tree/HEAD/plugins/fp-check/skills/fp-check" rel="noopener noreferrer"&gt;Trail of Bits&lt;/a&gt;: fp-check, &lt;a href="https://github.com/trailofbits/skills/tree/HEAD/plugins/variant-analysis/skills/variant-analysis" rel="noopener noreferrer"&gt;variant-analysis&lt;/a&gt; and &lt;a href="https://github.com/trailofbits/skills/tree/HEAD/plugins/differential-review/skills/differential-review" rel="noopener noreferrer"&gt;differential-review&lt;/a&gt;, for security claims.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/voidmatcha/e2e-skills/tree/HEAD/skills/e2e-reviewer" rel="noopener noreferrer"&gt;e2e-reviewer&lt;/a&gt;: catches E2E tests that pass while the feature is broken.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Skills use the &lt;a href="https://agentskills.io" rel="noopener noreferrer"&gt;Agent Skills&lt;/a&gt; format. Codex reads them from &lt;a href="https://learn.chatgpt.com/docs/build-skills" rel="noopener noreferrer"&gt;&lt;code&gt;.agents/skills&lt;/code&gt;&lt;/a&gt;, and Claude Code from &lt;code&gt;.claude/skills&lt;/code&gt;, so one folder with two symlinks serves both.&lt;/p&gt;

&lt;h2&gt;
  
  
  Upgrade or start
&lt;/h2&gt;

&lt;p&gt;New: follow the kit's README "Start here". The core (rulebook, test gate, plan template) takes about 10 minutes, and the Claude Code layer is optional.&lt;br&gt;
From v1: the README has an "Upgrading from v1" block. Nothing was renamed. Two hooks and two skills get replaced after a "Before v2" commit, so it's one &lt;code&gt;git revert&lt;/code&gt; to undo.&lt;/p&gt;

&lt;p&gt;Same ask as v1: run it for a week and tell me what broke. And what's the one rule your agent keeps breaking? I'll tell you which gate I'd put behind it.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>claude</category>
      <category>chatgpt</category>
      <category>cursor</category>
    </item>
    <item>
      <title>Host up to 10 WordPress sites for free with Oracle Cloud and xCloud</title>
      <dc:creator>Dhrupo Nil</dc:creator>
      <pubDate>Wed, 14 Oct 2026 04:50:18 +0000</pubDate>
      <link>https://dev.to/dhrupo/host-up-to-10-wordpress-sites-for-free-with-oracle-cloud-and-xcloud-4h2o</link>
      <guid>https://dev.to/dhrupo/host-up-to-10-wordpress-sites-for-free-with-oracle-cloud-and-xcloud-4h2o</guid>
      <description>&lt;p&gt;I wanted a place to run a handful of WordPress sites (test sites, demos, a personal page) without paying for hosting every month. The combination that worked: a free Oracle Cloud server, managed through xCloud's free plan, so I never had to install the web server, PHP or SSL by hand.&lt;/p&gt;

&lt;p&gt;This is the full walkthrough, including the parts that tripped me up: Oracle's "Out of capacity" error, a card hold that looked like a charge, and a firewall rule that silently did nothing.&lt;/p&gt;

&lt;p&gt;Run WordPress sites on a free Oracle Cloud server, managed through xCloud's free plan.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Oracle Cloud Always Free&lt;/strong&gt; gives you the server (the land).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;xCloud free Self-Managed plan&lt;/strong&gt; installs and manages the web server, PHP, database and SSL (the builder).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Only cost:&lt;/strong&gt; a domain name (about $10–13/year), and only if you want your own address.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  How it fits together
&lt;/h3&gt;

&lt;p&gt;The cover image above shows the whole setup: a visitor's browser finds your server through DNS, passes Oracle's two firewalls, and reaches the Ubuntu server that xCloud manages.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The build, in short:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Create a free Oracle account and a network that allows web traffic (Parts 1–2).&lt;/li&gt;
&lt;li&gt;Create one Ubuntu 24.04 server on that network (Part 3).&lt;/li&gt;
&lt;li&gt;Log in, open the web ports inside the server, and add swap if it's the 1 GB one (Part 4).&lt;/li&gt;
&lt;li&gt;Give xCloud root access with its key; xCloud installs the web server, PHP and database (Part 5).&lt;/li&gt;
&lt;li&gt;Point a domain at the server (Part 6), then add sites from the xCloud dashboard (Part 7).&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Running up to 10 sites
&lt;/h3&gt;

&lt;p&gt;xCloud's free plan allows &lt;strong&gt;1 server with up to 10 sites&lt;/strong&gt;. All of them live on the same Oracle server and share its CPU and memory.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;One domain is enough.&lt;/strong&gt; Each site gets a free subdomain: &lt;code&gt;example.dev&lt;/code&gt;, &lt;code&gt;blog.example.dev&lt;/code&gt;, &lt;code&gt;shop.example.dev&lt;/code&gt;, &lt;code&gt;lab.example.dev&lt;/code&gt;, …&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;One DNS record covers all subdomains.&lt;/strong&gt; A wildcard A record (&lt;code&gt;*&lt;/code&gt; → server IP) points every subdomain at the server, so a new site needs no DNS change.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Each site is added the same way&lt;/strong&gt; in xCloud (Part 7) and gets its own SSL certificate, database and WordPress install.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Testing without a domain:&lt;/strong&gt; use xCloud's &lt;strong&gt;Demo Site&lt;/strong&gt; option for a free temporary address, and switch to a real domain later.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;How many sites the server can really carry:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Server&lt;/th&gt;
&lt;th&gt;Realistic number of sites&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;ARM 2 OCPU / 12 GB&lt;/td&gt;
&lt;td&gt;All 10, if they are ordinary WordPress sites with caching on&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;AMD Micro 1 GB (+2 GB swap)&lt;/td&gt;
&lt;td&gt;3–5 quiet sites (tests, demos, personal pages). Not WooCommerce or real traffic&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;If you start on the 1 GB server and outgrow it, create the ARM server later and move the sites over with xCloud's site migration. The free xCloud plan covers only one server at a time.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Last checked: October 2026. Oracle and xCloud change their screens and limits, so a label may read slightly differently from this guide.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  What you get
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Item&lt;/th&gt;
&lt;th&gt;Free allowance&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;xCloud Free plan&lt;/td&gt;
&lt;td&gt;1 server, up to 10 sites&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Oracle ARM server (&lt;code&gt;VM.Standard.A1.Flex&lt;/code&gt;)&lt;/td&gt;
&lt;td&gt;2 OCPU / 12 GB RAM total (halved from 4/24 in June 2026)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Oracle AMD server (&lt;code&gt;VM.Standard.E2.1.Micro&lt;/code&gt;)&lt;/td&gt;
&lt;td&gt;Up to 2 servers, 1 GB RAM each&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Oracle disk&lt;/td&gt;
&lt;td&gt;200 GB total, across all boot volumes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Oracle outbound traffic&lt;/td&gt;
&lt;td&gt;10 TB per month&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Which server?&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;ARM, 2 OCPU / 12 GB:&lt;/strong&gt; comfortable for several WordPress sites. Often unavailable on free accounts (see Out of capacity).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;AMD Micro, 1 GB:&lt;/strong&gt; almost always available. Good for 1 small site or a handful of quiet test sites.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Before you start
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;A credit or debit card (Oracle uses it for identity checks; Always Free resources are not billed).&lt;/li&gt;
&lt;li&gt;An xCloud account: &lt;a href="https://xcloud.host" rel="noopener noreferrer"&gt;https://xcloud.host&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;A terminal with &lt;code&gt;ssh&lt;/code&gt; (macOS/Linux built in; Windows: PowerShell or WSL).&lt;/li&gt;
&lt;li&gt;Optional: an SSH key. Check with &lt;code&gt;ls ~/.ssh/*.pub&lt;/code&gt;. If none exists, create one:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ssh-keygen &lt;span class="nt"&gt;-t&lt;/span&gt; ed25519
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Part 1 — Create the Oracle Cloud account
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Sign up at &lt;a href="https://www.oracle.com/cloud/free/" rel="noopener noreferrer"&gt;https://www.oracle.com/cloud/free/&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Choose your Home Region carefully.&lt;/strong&gt; It can never be changed, and free servers only run there. Pick a region close to your visitors.&lt;/li&gt;
&lt;li&gt;Finish card verification and wait for the account to be ready.&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  Part 2 — Create the network (VCN)
&lt;/h2&gt;

&lt;p&gt;Create the network &lt;strong&gt;before&lt;/strong&gt; the server. The inline network option in the server form has a bug that can lock the public IP off.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;☰ menu → &lt;strong&gt;Networking&lt;/strong&gt; → &lt;strong&gt;Virtual Cloud Networks&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;On the left, under &lt;strong&gt;Compartment&lt;/strong&gt;, choose your root compartment (your account name).&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Start VCN Wizard&lt;/strong&gt; (it may be under &lt;strong&gt;Actions&lt;/strong&gt;).&lt;/li&gt;
&lt;li&gt;Choose &lt;strong&gt;Create VCN with Internet Connectivity&lt;/strong&gt; → &lt;strong&gt;Start VCN Wizard&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Fill in:&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Field&lt;/th&gt;
&lt;th&gt;Value&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;VCN name&lt;/td&gt;
&lt;td&gt;&lt;code&gt;xcloud-vcn&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;VCN IPv4 CIDR block&lt;/td&gt;
&lt;td&gt;&lt;code&gt;10.0.0.0/16&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Public subnet CIDR&lt;/td&gt;
&lt;td&gt;&lt;code&gt;10.0.0.0/24&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Private subnet CIDR&lt;/td&gt;
&lt;td&gt;&lt;code&gt;10.0.1.0/24&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Next&lt;/strong&gt; → &lt;strong&gt;Create&lt;/strong&gt;. Wait until every line has a green tick, then &lt;strong&gt;View VCN&lt;/strong&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Open web ports (80 and 443)
&lt;/h3&gt;

&lt;p&gt;Port 22 (SSH) is already open. Add the web ports:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;In the VCN, open &lt;strong&gt;Security Lists&lt;/strong&gt; → &lt;strong&gt;Default Security List for xcloud-vcn&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Add Ingress Rules&lt;/strong&gt;:&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Field&lt;/th&gt;
&lt;th&gt;Value&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Source Type&lt;/td&gt;
&lt;td&gt;CIDR&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Source CIDR&lt;/td&gt;
&lt;td&gt;&lt;code&gt;0.0.0.0/0&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;IP Protocol&lt;/td&gt;
&lt;td&gt;TCP&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Source Port Range&lt;/td&gt;
&lt;td&gt;&lt;em&gt;(empty)&lt;/em&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Destination Port Range&lt;/td&gt;
&lt;td&gt;&lt;code&gt;80,443&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Description&lt;/td&gt;
&lt;td&gt;&lt;code&gt;web&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;ol&gt;
&lt;li&gt;Save. You should now see three TCP rules from &lt;code&gt;0.0.0.0/0&lt;/code&gt;: 22, 80, 443.&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  Part 3 — Create the server (instance)
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;☰ → &lt;strong&gt;Compute&lt;/strong&gt; → &lt;strong&gt;Instances&lt;/strong&gt; → &lt;strong&gt;Create instance&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Basic information&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Name:&lt;/strong&gt; e.g. &lt;code&gt;xcloud-server&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Placement:&lt;/strong&gt; default availability domain&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Shape&lt;/strong&gt; → &lt;strong&gt;Change shape&lt;/strong&gt; (do this &lt;em&gt;before&lt;/em&gt; the image):

&lt;ul&gt;
&lt;li&gt;ARM: &lt;strong&gt;Ampere&lt;/strong&gt; → &lt;code&gt;VM.Standard.A1.Flex&lt;/code&gt;, &lt;strong&gt;2 OCPU&lt;/strong&gt;, &lt;strong&gt;12 GB&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;or AMD: &lt;strong&gt;Specialty and previous generation&lt;/strong&gt; → &lt;code&gt;VM.Standard.E2.1.Micro&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Image&lt;/strong&gt; → &lt;strong&gt;Change image&lt;/strong&gt; → &lt;strong&gt;Ubuntu&lt;/strong&gt; → &lt;strong&gt;Canonical Ubuntu 24.04&lt;/strong&gt; (not "Minimal")&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Security:&lt;/strong&gt; leave as is.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Networking&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Existing VCN: &lt;code&gt;xcloud-vcn&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Existing subnet: the &lt;strong&gt;public&lt;/strong&gt; subnet&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Automatically assign public IPv4 address:&lt;/strong&gt; on&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;SSH keys:&lt;/strong&gt; &lt;strong&gt;Paste public key&lt;/strong&gt; (contents of your &lt;code&gt;~/.ssh/id_ed25519.pub&lt;/code&gt;), or &lt;strong&gt;Generate a key pair for me&lt;/strong&gt; and click &lt;strong&gt;Download private key&lt;/strong&gt; right away. You cannot download it later.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Storage&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Tick &lt;strong&gt;Specify a custom boot volume size&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Enter &lt;code&gt;100&lt;/code&gt; GB (keep the total of all your boot volumes at 200 GB or less to stay free)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Create&lt;/strong&gt;. Wait for &lt;strong&gt;Running&lt;/strong&gt;, then copy the &lt;strong&gt;Public IP address&lt;/strong&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Out of capacity
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;Out of capacity for shape VM.Standard.A1.Flex in availability domain AD-1&lt;/code&gt; means free ARM machines in your region are all taken. Your settings are fine. Try, in order:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Another availability domain (if your region has more than one).&lt;/li&gt;
&lt;li&gt;A smaller size: &lt;strong&gt;1 OCPU / 6 GB&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Retry at a different time of day.&lt;/li&gt;
&lt;li&gt;Use the AMD Micro shape instead (1 GB, nearly always available).&lt;/li&gt;
&lt;li&gt;Upgrade to &lt;strong&gt;Pay As You Go&lt;/strong&gt; (☰ → &lt;strong&gt;Billing &amp;amp; Cost Management&lt;/strong&gt; → &lt;strong&gt;Upgrade and Manage Payment&lt;/strong&gt;). Paid accounts get capacity much more easily and are not reclaimed when idle. You still pay $0 if you stay within the free allowance.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  About the Pay As You Go card hold
&lt;/h3&gt;

&lt;p&gt;Upgrading places a temporary hold of about &lt;strong&gt;US$100&lt;/strong&gt; on your card (shown in your local currency, e.g. ~S$138). It is a verification hold, not a charge:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Check &lt;strong&gt;Billing &amp;amp; Cost Management → Invoices&lt;/strong&gt;: there should be none.&lt;/li&gt;
&lt;li&gt;Check &lt;strong&gt;Cost Analysis&lt;/strong&gt;: usage should be &lt;code&gt;0&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Your bank releases the hold on its own, usually within days, sometimes up to ~30 days.&lt;/li&gt;
&lt;li&gt;If it shows as &lt;strong&gt;posted&lt;/strong&gt; (not pending), or an invoice appears, contact Oracle support and your bank.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Set a $1 budget alert (do this on Pay As You Go)
&lt;/h3&gt;

&lt;p&gt;☰ → &lt;strong&gt;Billing &amp;amp; Cost Management&lt;/strong&gt; → &lt;strong&gt;Budgets&lt;/strong&gt; → &lt;strong&gt;Create Budget&lt;/strong&gt; → amount &lt;code&gt;1&lt;/code&gt;, alert at 1% of actual spend, your email. You'll hear about any real charge immediately.&lt;/p&gt;




&lt;h2&gt;
  
  
  Part 4 — Prepare the server
&lt;/h2&gt;

&lt;p&gt;Log in (replace the IP and key path with yours). The user is &lt;code&gt;ubuntu&lt;/code&gt;, not &lt;code&gt;root&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ssh &lt;span class="nt"&gt;-i&lt;/span&gt; ~/.ssh/id_ed25519 ubuntu@YOUR_SERVER_IP
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you used an Oracle-generated key:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;chmod &lt;/span&gt;600 ~/Downloads/ssh-key-XXXX.key
ssh &lt;span class="nt"&gt;-i&lt;/span&gt; ~/Downloads/ssh-key-XXXX.key ubuntu@YOUR_SERVER_IP
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  4.1 Add swap (1 GB AMD server only)
&lt;/h3&gt;

&lt;p&gt;Gives the small server spare memory so it doesn't crash under load.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;fallocate &lt;span class="nt"&gt;-l&lt;/span&gt; 2G /swapfile
&lt;span class="nb"&gt;sudo chmod &lt;/span&gt;600 /swapfile
&lt;span class="nb"&gt;sudo &lt;/span&gt;mkswap /swapfile
&lt;span class="nb"&gt;sudo &lt;/span&gt;swapon /swapfile
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s1"&gt;'/swapfile none swap sw 0 0'&lt;/span&gt; | &lt;span class="nb"&gt;sudo tee&lt;/span&gt; &lt;span class="nt"&gt;-a&lt;/span&gt; /etc/fstab
free &lt;span class="nt"&gt;-h&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;free -h&lt;/code&gt; should show &lt;code&gt;Swap: 2.0Gi&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  4.2 Open ports 80 and 443 inside the server
&lt;/h3&gt;

&lt;p&gt;Oracle's Ubuntu image has its own firewall that blocks web traffic, separate from the Security List in Part 2. Both must allow it.&lt;/p&gt;

&lt;p&gt;First find the line number of the &lt;code&gt;REJECT&lt;/code&gt; rule:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;iptables &lt;span class="nt"&gt;-L&lt;/span&gt; INPUT &lt;span class="nt"&gt;-n&lt;/span&gt; &lt;span class="nt"&gt;--line-numbers&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Example output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;4    ACCEPT  ...  state NEW tcp dpt:22
5    REJECT  ...  reject-with icmp-host-prohibited
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Insert the web rules &lt;strong&gt;at the REJECT line's number&lt;/strong&gt; (here &lt;code&gt;5&lt;/code&gt;), so they sit above it. Rules placed below REJECT do nothing.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;iptables &lt;span class="nt"&gt;-I&lt;/span&gt; INPUT 5 &lt;span class="nt"&gt;-m&lt;/span&gt; state &lt;span class="nt"&gt;--state&lt;/span&gt; NEW &lt;span class="nt"&gt;-p&lt;/span&gt; tcp &lt;span class="nt"&gt;--dport&lt;/span&gt; 443 &lt;span class="nt"&gt;-j&lt;/span&gt; ACCEPT
&lt;span class="nb"&gt;sudo &lt;/span&gt;iptables &lt;span class="nt"&gt;-I&lt;/span&gt; INPUT 5 &lt;span class="nt"&gt;-m&lt;/span&gt; state &lt;span class="nt"&gt;--state&lt;/span&gt; NEW &lt;span class="nt"&gt;-p&lt;/span&gt; tcp &lt;span class="nt"&gt;--dport&lt;/span&gt; 80 &lt;span class="nt"&gt;-j&lt;/span&gt; ACCEPT
&lt;span class="nb"&gt;sudo &lt;/span&gt;netfilter-persistent save
&lt;span class="nb"&gt;sudo &lt;/span&gt;iptables &lt;span class="nt"&gt;-L&lt;/span&gt; INPUT &lt;span class="nt"&gt;-n&lt;/span&gt; &lt;span class="nt"&gt;--line-numbers&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The list should now show 22, 80, 443 &lt;strong&gt;before&lt;/strong&gt; &lt;code&gt;REJECT&lt;/code&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Part 5 — Connect the server to xCloud
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;In xCloud: &lt;strong&gt;Servers&lt;/strong&gt; → &lt;strong&gt;Add Server&lt;/strong&gt; → &lt;strong&gt;Connect Your Existing Server&lt;/strong&gt; (Any Provider).&lt;/li&gt;
&lt;li&gt;Fill in the form:&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Field&lt;/th&gt;
&lt;th&gt;Value&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Server Name&lt;/td&gt;
&lt;td&gt;Any label, e.g. &lt;code&gt;oracle-free&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;App Type&lt;/td&gt;
&lt;td&gt;WordPress (optional)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Web Server&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;OpenLiteSpeed&lt;/strong&gt; (built-in cache, good for small servers). NGINX also works on AMD. On ARM, use OpenLiteSpeed&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;IP Address&lt;/td&gt;
&lt;td&gt;Your server's public IP&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SSH Port&lt;/td&gt;
&lt;td&gt;&lt;code&gt;22&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SSH Username&lt;/td&gt;
&lt;td&gt;&lt;code&gt;root&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Database Server&lt;/td&gt;
&lt;td&gt;Do &lt;strong&gt;not&lt;/strong&gt; leave on None. Pick MariaDB or MySQL (on ARM, MySQL 8.4 is not supported)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Plan&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Free&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SSH Authentication&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Public Key&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;ol&gt;
&lt;li&gt;xCloud shows a command that adds its key to the server. &lt;strong&gt;Copy it and run it on the server&lt;/strong&gt; (in your &lt;code&gt;ubuntu&lt;/code&gt; SSH session). It should print &lt;code&gt;SSH key added successfully&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Oracle blocks direct root login with &lt;em&gt;your&lt;/em&gt; key, but root login with an &lt;em&gt;added&lt;/em&gt; key works. This command is what lets xCloud in as root.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Tick &lt;strong&gt;I have created a new server on my provider&lt;/strong&gt; → &lt;strong&gt;Create&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Wait for provisioning to finish. On a 1 GB server this can take a while.&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  Part 6 — Get a domain (optional)
&lt;/h2&gt;

&lt;p&gt;You can skip this and use xCloud's free &lt;strong&gt;Demo Site&lt;/strong&gt; address for testing.&lt;/p&gt;

&lt;p&gt;For real sites, one domain is enough for many sites, because subdomains are free:&lt;br&gt;
&lt;code&gt;example.dev&lt;/code&gt;, &lt;code&gt;blog.example.dev&lt;/code&gt;, &lt;code&gt;shop.example.dev&lt;/code&gt;, …&lt;/p&gt;

&lt;p&gt;When buying:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Judge by the &lt;strong&gt;renewal&lt;/strong&gt; price, not the first-year price.&lt;/li&gt;
&lt;li&gt;Make sure &lt;strong&gt;WHOIS privacy&lt;/strong&gt; is free.&lt;/li&gt;
&lt;li&gt;Untick add-ons (email, "protection", site builders).&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;.dev&lt;/code&gt; and &lt;code&gt;.app&lt;/code&gt; domains &lt;strong&gt;require HTTPS&lt;/strong&gt; in every browser. That is fine with xCloud's free SSL, but a site won't load at all until its certificate is issued.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Point the domain to the server
&lt;/h3&gt;

&lt;p&gt;At your registrar's (or Cloudflare's) DNS settings, add &lt;strong&gt;A records&lt;/strong&gt; pointing to your server IP:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Name&lt;/th&gt;
&lt;th&gt;Type&lt;/th&gt;
&lt;th&gt;Value&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;@&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;A&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;YOUR_SERVER_IP&lt;/code&gt; (the main domain)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;*&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;A&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;YOUR_SERVER_IP&lt;/code&gt; (every subdomain at once)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;On Cloudflare, set these to &lt;strong&gt;DNS only&lt;/strong&gt; (grey cloud) until xCloud has issued the SSL certificate. DNS changes can take a few minutes to an hour.&lt;/p&gt;




&lt;h2&gt;
  
  
  Part 7 — Add a site
&lt;/h2&gt;

&lt;p&gt;Open the server in xCloud → &lt;strong&gt;Add Site&lt;/strong&gt;.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Field&lt;/th&gt;
&lt;th&gt;What to do&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Select Options&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Default&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Site Title&lt;/td&gt;
&lt;td&gt;Your site's name&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Go Live / Demo Site&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;Go Live&lt;/strong&gt; with your domain, or &lt;strong&gt;Demo Site&lt;/strong&gt; for a free test address&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Domain Name&lt;/td&gt;
&lt;td&gt;e.g. &lt;code&gt;blog.example.dev&lt;/code&gt; (Go Live only)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;DNS Setup&lt;/td&gt;
&lt;td&gt;Click &lt;strong&gt;Verify My DNS&lt;/strong&gt;. Keep &lt;strong&gt;Use free SSL certificate issued &amp;amp; managed by xCloud&lt;/strong&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Multisite&lt;/td&gt;
&lt;td&gt;Off&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;xSpeed Cache&lt;/td&gt;
&lt;td&gt;On&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Mail Delivery&lt;/td&gt;
&lt;td&gt;Off for now&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Site Backup&lt;/td&gt;
&lt;td&gt;Off for now&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Blueprints&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;Gutenberg Websites&lt;/strong&gt;, or turn off for clean WordPress. The Elementor blueprint adds weight a small server doesn't need&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;More Advanced Settings&lt;/td&gt;
&lt;td&gt;Set the WordPress admin username, password and email; keep the default PHP version&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Click &lt;strong&gt;Next&lt;/strong&gt; and wait. Repeat for each additional site with a different title and domain.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Small server tips:&lt;/strong&gt; keep plugins few, keep caching on, don't run imports or backups on several sites at once. A 1 GB server suits quiet sites only; WooCommerce or real traffic needs the ARM server.&lt;/p&gt;




&lt;h2&gt;
  
  
  Troubleshooting
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Problem&lt;/th&gt;
&lt;th&gt;Likely cause and fix&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;ssh&lt;/code&gt; asks for a password or says &lt;em&gt;Permission denied&lt;/em&gt;
&lt;/td&gt;
&lt;td&gt;Wrong key file or user. Use &lt;code&gt;ubuntu@&lt;/code&gt;, and the private key matching the public key you gave Oracle&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Please login as the user "ubuntu" rather than "root"&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;You tried &lt;code&gt;root@&lt;/code&gt; directly. Log in as &lt;code&gt;ubuntu&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;xCloud can't connect&lt;/td&gt;
&lt;td&gt;The xCloud key command wasn't run, or was run on a different server. Rerun it in your SSH session&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Site doesn't load on port 80/443&lt;/td&gt;
&lt;td&gt;One of the two firewalls still blocks it: check the Security List (Part 2) &lt;strong&gt;and&lt;/strong&gt; the iptables order (Part 4.2)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Verify My DNS fails&lt;/td&gt;
&lt;td&gt;DNS not spread yet (wait and retry), wrong IP in the A record, or Cloudflare proxy (orange cloud) is on&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Oracle reclaims an idle free server&lt;/td&gt;
&lt;td&gt;Free accounts can lose a VM whose CPU, network and memory all stay under 20% for 7 days (a warning email comes first). Pay As You Go accounts are not reclaimed&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  Wrapping up
&lt;/h2&gt;

&lt;p&gt;You now have a server you don't pay for, a dashboard that handles the web server, PHP, database and SSL, and room for up to 10 WordPress sites under one domain.&lt;/p&gt;

&lt;p&gt;If you hit a step that looks different on your screen, or found a better way around Oracle's capacity problem, tell me in the comments.&lt;/p&gt;

</description>
      <category>wordpress</category>
      <category>cloud</category>
      <category>selfhosted</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>How I set up Claude Code: one rulebook, a 12-step relay to use it daily</title>
      <dc:creator>Dhrupo Nil</dc:creator>
      <pubDate>Wed, 07 Oct 2026 17:29:45 +0000</pubDate>
      <link>https://dev.to/dhrupo/how-i-set-up-claude-code-one-rulebook-a-12-step-relay-to-use-it-daily-40gi</link>
      <guid>https://dev.to/dhrupo/how-i-set-up-claude-code-one-rulebook-a-12-step-relay-to-use-it-daily-40gi</guid>
      <description>&lt;p&gt;Claude Code used to feel like a brilliant teammate with no onboarding. Some days: tests first, small diff, asked before pushing. Other days: no tests, three "cleaned up" files, a PR opened on its own.&lt;/p&gt;

&lt;p&gt;The model wasn't the problem. My setup was: a 20 KB &lt;code&gt;CLAUDE.md&lt;/code&gt; that contradicted itself, dozens of copied skills fighting each other, and rules nothing enforced.&lt;/p&gt;

&lt;p&gt;So I rebuilt &lt;code&gt;~/.claude&lt;/code&gt; like any other system. Here's how, step by step.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Short on time? Start here.&lt;/strong&gt; Three things fix most of the chaos:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;One rulebook&lt;/strong&gt; that says it overrides everything else (Step 2).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Lanes&lt;/strong&gt;, so Claude states the size of the job before acting (Step 3).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;permissions.ask&lt;/code&gt; for &lt;code&gt;git push&lt;/code&gt; and &lt;code&gt;gh pr create&lt;/code&gt;&lt;/strong&gt;, so nothing ships without your yes (Step 8).&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;📦 Everything below is in a starter kit you can copy in about 10 minutes: the rulebook template, the 3 hooks, the 4 relay skills and their tests. &lt;strong&gt;&lt;a href="https://github.com/dhrupo/claude-code-dev-os" rel="noopener noreferrer"&gt;github.com/dhrupo/claude-code-dev-os&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  What we're building
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;~/.claude/
├── CLAUDE.md          # the one rulebook
├── lessons.md         # mistakes not to repeat (imported by CLAUDE.md)
├── settings.json      # hooks, permissions, plugins
├── skills/            # one folder per skill
├── skills.lock        # where each skill came from, pinned
├── overlays/          # my edits, re-applied after updates
├── hooks/             # enforcement scripts
└── tests/             # tests for the setup itself
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The starter kit has everything here except &lt;code&gt;skills.lock&lt;/code&gt; and &lt;code&gt;overlays/&lt;/code&gt;. Those only matter once you start pinning skills from GitHub (Step 6).&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 1: Make &lt;code&gt;~/.claude&lt;/code&gt; a git repo
&lt;/h2&gt;

&lt;p&gt;Every change becomes one commit, so any bad rule is one &lt;code&gt;git revert&lt;/code&gt; away. &lt;code&gt;~/.claude&lt;/code&gt; also holds chat history and credentials, so use an &lt;strong&gt;allowlist&lt;/strong&gt; &lt;code&gt;.gitignore&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;*
!.gitignore
!settings.json
!CLAUDE.md
!lessons.md
!skills.lock
!skills/**
!hooks/**
!overlays/**
!tests/**
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd&lt;/span&gt; ~/.claude &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; git init &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; git add &lt;span class="nt"&gt;-A&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; git commit &lt;span class="nt"&gt;-m&lt;/span&gt; &lt;span class="s2"&gt;"Baseline"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Keep it local. Never add a remote.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 2: Write ONE rulebook
&lt;/h2&gt;

&lt;p&gt;Most of my "Claude ignores me" problems were really "Claude got conflicting instructions." The fix is one line at the top of &lt;code&gt;~/.claude/CLAUDE.md&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gu"&gt;## 0. Precedence&lt;/span&gt;
This file overrides skills, plugins, slash commands and repo CLAUDE.md files.
Those may ADD project facts (test commands, code style). On conflict, this file wins.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then the skeleton:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gu"&gt;## 1. Defaults   — be concise; never push without asking; state what "done" means before building&lt;/span&gt;
&lt;span class="gu"&gt;## 2. Lanes      — 🟢 / 🟡 / 🔴&lt;/span&gt;
&lt;span class="gu"&gt;## 3. Relay      — the steps&lt;/span&gt;
&lt;span class="gu"&gt;## 4. Skill map  — one owner per job&lt;/span&gt;
&lt;span class="gu"&gt;## 5. Rules      — test first, smallest change, no regressions, no noise comments&lt;/span&gt;
@lessons.md
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Keep it small. It loads every session. If you can't say what a line changes, delete it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 3: Lanes
&lt;/h2&gt;

&lt;p&gt;A typo shouldn't get the same process as a payment-flow change. Claude must put the lane on the first line of every reply:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="p"&gt;-&lt;/span&gt; 🟢 question — answer only, no code.
&lt;span class="p"&gt;-&lt;/span&gt; 🟡 small — one obvious file. 3-line plan in chat. Tests still required.
&lt;span class="p"&gt;-&lt;/span&gt; 🔴 full — anything bigger. Full relay + written plan.
Ratchet up, never down: a 🟡 that grows must say so and switch to 🔴.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;🔴 full · bug (refund sends the receipt twice)&lt;/code&gt; tells me in one glance whether Claude understood the size of the job.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 4: The relay
&lt;/h2&gt;

&lt;p&gt;🔴 work goes through 12 steps. Each step has &lt;strong&gt;one&lt;/strong&gt; owner skill, and some steps have a &lt;strong&gt;STOP&lt;/strong&gt; where I decide:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;#&lt;/th&gt;
&lt;th&gt;Step&lt;/th&gt;
&lt;th&gt;Owner&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;Grill: one question at a time, with a recommended answer → &lt;strong&gt;STOP&lt;/strong&gt;
&lt;/td&gt;
&lt;td&gt;&lt;code&gt;grill-me&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;Plan: one page + list of allowed files → &lt;strong&gt;STOP&lt;/strong&gt;
&lt;/td&gt;
&lt;td&gt;&lt;code&gt;openspec-plan&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;Check the plan: tests named? "won't change" listed?&lt;/td&gt;
&lt;td&gt;&lt;code&gt;plan-check&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;Build: failing test first, smallest fix&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;tdd&lt;/code&gt; + &lt;code&gt;ponytail&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;Check the build: tests, E2E, lint, diff matches plan&lt;/td&gt;
&lt;td&gt;&lt;code&gt;build-check&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;Tidy: delete what isn't needed&lt;/td&gt;
&lt;td&gt;&lt;code&gt;ponytail-review&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;7&lt;/td&gt;
&lt;td&gt;Deep review: bugs, security, performance, regressions&lt;/td&gt;
&lt;td&gt;&lt;code&gt;pre-merge-review&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;td&gt;Fix findings → back to 4&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;9&lt;/td&gt;
&lt;td&gt;Step back: read the whole diff cold&lt;/td&gt;
&lt;td&gt;&lt;code&gt;step-back&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;10&lt;/td&gt;
&lt;td&gt;PR: &lt;strong&gt;asks&lt;/strong&gt; before push, &lt;strong&gt;asks again&lt;/strong&gt; before the PR&lt;/td&gt;
&lt;td&gt;&lt;code&gt;commit-push-pr&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;11&lt;/td&gt;
&lt;td&gt;Wait for review → &lt;strong&gt;STOP&lt;/strong&gt;
&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;12&lt;/td&gt;
&lt;td&gt;Handle review: verify every finding, don't trust it blindly&lt;/td&gt;
&lt;td&gt;&lt;code&gt;receiving-code-review&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;🟡 runs a light version (quick grill, then 3 → 4 → 5 → 9). 🟢 skips it all.&lt;/p&gt;

&lt;p&gt;Four of the skills here are my own (&lt;code&gt;openspec-plan&lt;/code&gt;, &lt;code&gt;plan-check&lt;/code&gt;, &lt;code&gt;build-check&lt;/code&gt;, &lt;code&gt;step-back&lt;/code&gt;), and each is under 60 lines. All four are in the starter kit, where the plan skill is called &lt;code&gt;plan&lt;/code&gt;. For example, here's &lt;code&gt;plan-check&lt;/code&gt; in full:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;plan-check&lt;/span&gt;
&lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Use right after the plan is written, before any code. Gates the PLAN.&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="p"&gt;1.&lt;/span&gt; &lt;span class="gs"&gt;**Tests named**&lt;/span&gt; — the exact failing test(s) to write first.
&lt;span class="p"&gt;2.&lt;/span&gt; &lt;span class="gs"&gt;**Must-not-change listed**&lt;/span&gt; — what behaviour is at risk and how we protect it.
&lt;span class="p"&gt;3.&lt;/span&gt; &lt;span class="gs"&gt;**Smallest change**&lt;/span&gt; — no new dependency, no new public API, fewest files.
&lt;span class="p"&gt;4.&lt;/span&gt; &lt;span class="gs"&gt;**No open questions.**&lt;/span&gt;
One line per check, pass/fail. Any fail → fix the plan, not the code.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You don't need my 12 steps. You need &lt;strong&gt;named steps, one owner each, and clear STOP points.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 5: Skills, one owner per job
&lt;/h2&gt;

&lt;p&gt;Skills from different sources &lt;strong&gt;compete&lt;/strong&gt;. I had three TDD skills and two brainstormers that each claimed to run first. So the rulebook has a routing table: one owner per job, and everyone else steps aside or gets called by the owner. I also turned off 6 design skills that overlapped (&lt;code&gt;skillOverrides&lt;/code&gt; in &lt;code&gt;settings.json&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;Here's my whole shelf in one pass:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Plan:&lt;/strong&gt; &lt;code&gt;superpowers:brainstorming&lt;/code&gt;, &lt;code&gt;grill-me&lt;/code&gt;, &lt;code&gt;grill-with-docs&lt;/code&gt;, &lt;code&gt;openspec-plan&lt;/code&gt;, &lt;code&gt;plan-check&lt;/code&gt;, &lt;code&gt;design-an-interface&lt;/code&gt;, &lt;code&gt;improve-codebase-architecture&lt;/code&gt;, &lt;code&gt;zoom-out&lt;/code&gt;, &lt;code&gt;explain-this&lt;/code&gt;, &lt;code&gt;source-driven-development&lt;/code&gt;, &lt;code&gt;new-feature&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Build:&lt;/strong&gt; &lt;code&gt;tdd&lt;/code&gt; (&lt;code&gt;rigorous-coding-workflow&lt;/code&gt; defers to it), &lt;code&gt;bug-fix&lt;/code&gt; (builds a fast pass/fail loop first), &lt;code&gt;ponytail&lt;/code&gt;, &lt;code&gt;ponytail-review&lt;/code&gt;, &lt;code&gt;ponytail-audit&lt;/code&gt;, &lt;code&gt;ponytail-debt&lt;/code&gt;, &lt;code&gt;context-packaging&lt;/code&gt;, &lt;code&gt;handoff&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Review:&lt;/strong&gt; &lt;code&gt;build-check&lt;/code&gt;, &lt;code&gt;pre-merge-review&lt;/code&gt;, &lt;code&gt;security-auditor&lt;/code&gt; (read-only), &lt;code&gt;security-repro&lt;/code&gt;, &lt;code&gt;infection-gate&lt;/code&gt;, &lt;code&gt;phpstan-gate&lt;/code&gt;, &lt;code&gt;step-back&lt;/code&gt;. &lt;code&gt;pr-review-toolkit&lt;/code&gt; and Codex give a second opinion &lt;strong&gt;only when asked&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ship:&lt;/strong&gt; &lt;code&gt;commit-push-pr&lt;/code&gt;, &lt;code&gt;release-readiness&lt;/code&gt;, &lt;code&gt;knowledge-capture&lt;/code&gt;, &lt;code&gt;retro&lt;/code&gt;, &lt;code&gt;daily-work&lt;/code&gt;, plus Addy Osmani's &lt;code&gt;shipping-and-launch&lt;/code&gt;, &lt;code&gt;ci-cd-and-automation&lt;/code&gt;, &lt;code&gt;observability-and-instrumentation&lt;/code&gt;, &lt;code&gt;performance-optimization&lt;/code&gt;, &lt;code&gt;deprecation-and-migration&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Understand code:&lt;/strong&gt; graphify and the code-review-graph MCP. The rule is graph first, grep second&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;My stack:&lt;/strong&gt; the WordPress agent skills (&lt;code&gt;wp-plugin-development&lt;/code&gt;, &lt;code&gt;wp-rest-api&lt;/code&gt;, &lt;code&gt;wp-block-development&lt;/code&gt;, &lt;code&gt;wp-playground&lt;/code&gt;, &lt;code&gt;wp-phpstan&lt;/code&gt;, &lt;code&gt;wp-plugin-directory-guidelines&lt;/code&gt;) and &lt;code&gt;plugin-audit&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The special ones get a few lines each:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;🎨 UI/UX is a pipeline with gates.&lt;/strong&gt; &lt;code&gt;ui-ux-pro-max&lt;/code&gt; picks the direction (palette, type, patterns) → &lt;code&gt;impeccable&lt;/code&gt; builds it well → &lt;code&gt;break-ui&lt;/code&gt; feeds it worst-case data (80-character names, empty lists, emoji) → &lt;code&gt;impeccable-audit&lt;/code&gt; + &lt;code&gt;axe-a11y-audit&lt;/code&gt; must pass. Extras: &lt;code&gt;review-animations&lt;/code&gt;, &lt;code&gt;animation-vocabulary&lt;/code&gt;, &lt;code&gt;mobile-native&lt;/code&gt;, and the Chrome DevTools MCP for live debugging.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;✏️ Pencil: draw it before you code it.&lt;/strong&gt; When I say "mock it up", &lt;code&gt;pen-design&lt;/code&gt; uses the &lt;a href="https://pen.dev" rel="noopener noreferrer"&gt;pen.dev&lt;/a&gt; CLI to make a &lt;code&gt;.pen&lt;/code&gt; file and a PNG in &lt;code&gt;~/Documents/designs/&amp;lt;project&amp;gt;/&amp;lt;id&amp;gt;/&lt;/code&gt;. It never overwrites (&lt;code&gt;design-v2&lt;/code&gt;, &lt;code&gt;design-v3&lt;/code&gt;…) and logs each run. For a redesign, a screenshot of the current screen goes in as &lt;code&gt;reference.png&lt;/code&gt;. Then the PNG becomes the target: the UI skills build to it, and &lt;code&gt;build-check&lt;/code&gt; compares a screenshot of the result side by side. It &lt;strong&gt;never&lt;/strong&gt; runs unless I ask.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;🧪 E2E: "unit tests pass" ≠ "it works".&lt;/strong&gt; Anything a user can click gets a Playwright test against the real site, red before the fix and green after. &lt;code&gt;playwright-core&lt;/code&gt; writes it, &lt;code&gt;playwright-auth-state&lt;/code&gt; handles logins, and &lt;code&gt;playwright-cli&lt;/code&gt; / &lt;code&gt;playwright-cli-runner&lt;/code&gt; are for exploring only. &lt;code&gt;e2e-reviewer&lt;/code&gt; scans for tests that can pass while the feature is broken.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;🔎 Research and scraping, on demand.&lt;/strong&gt; &lt;code&gt;agent-reach&lt;/code&gt; does web and social research. Its queries leave the machine, so nothing sensitive goes in, and social logins only happen when I ask. &lt;code&gt;scrapling&lt;/code&gt; scrapes JS-heavy or bot-protected pages locally, and only when plain WebFetch fails.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;🔐 Consent-gated.&lt;/strong&gt; Some tools must never run by surprise. &lt;code&gt;strix-local&lt;/code&gt; (a live pentest) only targets local or owned hosts and asks &lt;code&gt;Attack &amp;lt;target&amp;gt; now? (y/n)&lt;/code&gt; every time. &lt;code&gt;omniroute-session&lt;/code&gt; (routing through another model) runs only in a separate session, never machine-wide.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;🏠 Product layer.&lt;/strong&gt; For the two products I work on daily (Fluent Forms and Fluent Player), I add &lt;strong&gt;trace skills&lt;/strong&gt; that walk one real flow end to end before a fix, such as &lt;code&gt;trace-submission-flow&lt;/code&gt;, &lt;code&gt;trace-payment-flow&lt;/code&gt;, &lt;code&gt;trace-ui-api&lt;/code&gt; and &lt;code&gt;trace-player-runtime-flow&lt;/code&gt;. There are 18 in total. I also add product wrappers around the generic owners: &lt;code&gt;grill-change&lt;/code&gt;, &lt;code&gt;ui-ux-skills&lt;/code&gt;, &lt;code&gt;fluentform-pre-pr-review&lt;/code&gt;, &lt;code&gt;fluentplayer-release-readiness&lt;/code&gt; and so on. Copy the pattern: a generic shelf, plus one trace skill for whichever flow of yours breaks most.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 6: Pin skills, keep your edits
&lt;/h2&gt;

&lt;p&gt;You copy a skill from GitHub and tweak it. Then updating it wipes your tweak. My fix:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;skills.lock&lt;/code&gt;&lt;/strong&gt; records each skill's repo and pinned commit, plus a status: &lt;code&gt;installed-upstream&lt;/code&gt;, &lt;code&gt;installed-ondemand&lt;/code&gt;, &lt;code&gt;consent-gated&lt;/code&gt;, or &lt;code&gt;skip&lt;/code&gt; (with the reason, so future me doesn't reinstall it).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;overlays/&amp;lt;name&amp;gt;.md&lt;/code&gt;&lt;/strong&gt; holds my edits. For example, my &lt;code&gt;ponytail&lt;/code&gt; overlay says &lt;em&gt;"shrink the code, never the tests."&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;bin/sync-skills.sh&lt;/code&gt;&lt;/strong&gt; fetches each skill at its pinned commit, copies it in, and appends the overlay. Running it twice changes nothing the second time.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"tdd"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"status"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"installed-upstream"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"repo"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://github.com/mattpocock/skills"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"ref"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"6fd9479"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"path"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"skills/engineering/tdd"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"overlay"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"tdd"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 7: Plans live outside the repo
&lt;/h2&gt;

&lt;p&gt;Skills don't share memory, and long chats get compacted. So skills hand off through &lt;strong&gt;files&lt;/strong&gt;. Every 🔴 change gets a folder in &lt;code&gt;~/Documents/openspec/&amp;lt;project&amp;gt;/changes/&amp;lt;id&amp;gt;/&lt;/code&gt; (the starter kit uses the simpler &lt;code&gt;~/Documents/plans/&amp;lt;project&amp;gt;/&amp;lt;id&amp;gt;/&lt;/code&gt;):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;proposal.md   # what's wrong · what changes · what WON'T change · how we'll know
tasks.md      # checkboxes, failing test named first
scope.txt     # the files this change may touch
evidence/     # test runs, screenshots, review reports
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;"What won't change"&lt;/strong&gt; turns "don't break anything" into a promise you can test. Keeping the folder outside the repo means plans never land in a PR by accident.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 8: Hooks: rules ask, hooks enforce
&lt;/h2&gt;

&lt;p&gt;The biggest lesson: &lt;strong&gt;a rule in &lt;code&gt;CLAUDE.md&lt;/code&gt; is a request. A hook is a guarantee.&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"permissions"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"ask"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"Bash(git push:*)"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Bash(gh pr create:*)"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"hooks"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"UserPromptSubmit"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"hooks"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"command"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"command"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"~/.claude/hooks/reminder.sh"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}],&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"PostToolUse"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"matcher"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Edit|Write"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"hooks"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"command"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"command"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"~/.claude/hooks/scope-guard.sh"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}],&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"Stop"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"hooks"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"command"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"command"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"~/.claude/hooks/stop-check.sh"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}]&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;permissions.ask&lt;/code&gt;&lt;/strong&gt;: &lt;code&gt;git push&lt;/code&gt; and &lt;code&gt;gh pr create&lt;/code&gt; always prompt, even in auto mode. This is the simplest guard and the most important.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reminder&lt;/strong&gt; (&lt;code&gt;UserPromptSubmit&lt;/code&gt;): whatever the hook prints is added to Claude's context, so one short paragraph re-anchors the rules on every prompt:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;  &lt;span class="c"&gt;#!/bin/bash&lt;/span&gt;
  &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"&amp;lt;rules&amp;gt;Rulebook: ~/.claude/CLAUDE.md. First line: lane. Test first. Smallest change. Ask before push.&amp;lt;/rules&amp;gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Scope guard&lt;/strong&gt; (&lt;code&gt;PostToolUse&lt;/code&gt;): after each edit, if the file isn't in the plan's &lt;code&gt;scope.txt&lt;/code&gt;, it tells Claude to explain why and ask me. It &lt;strong&gt;warns, never blocks&lt;/strong&gt;, because sometimes the extra file is correct. It just can't happen silently.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Stop check&lt;/strong&gt; (&lt;code&gt;Stop&lt;/code&gt;): when Claude finishes, it checks &lt;code&gt;git status&lt;/code&gt;. If source changed but no test did, it returns &lt;code&gt;{"decision": "block", "reason": "..."}&lt;/code&gt; and Claude has to keep working. It fires once per new problem, so it can't loop.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;My rulebook lists which rules have a hook behind them. Then I know which rules are guaranteed and which are just hoped for.&lt;/p&gt;

&lt;p&gt;The full scripts and their tests are in the &lt;a href="https://github.com/dhrupo/claude-code-dev-os" rel="noopener noreferrer"&gt;starter kit&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 9: Test the setup
&lt;/h2&gt;

&lt;p&gt;Hooks are code. A broken scope guard looks exactly like one with nothing to report. So &lt;code&gt;~/.claude/tests/&lt;/code&gt; pipes fake hook input into each script and checks the output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;OUT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s1"&gt;'{"tool_input":{"file_path":"src/Other.js"},"cwd":"'&lt;/span&gt;&lt;span class="nv"&gt;$REPO&lt;/span&gt;&lt;span class="s1"&gt;'"}'&lt;/span&gt; | ../hooks/scope-guard.sh&lt;span class="si"&gt;)&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$OUT&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-q&lt;/span&gt; &lt;span class="s2"&gt;"UNPLANNED FILE"&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;echo &lt;/span&gt;ok &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nb"&gt;echo &lt;/span&gt;FAIL
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I have 7 test files with 140 assertions, and I run them before every commit to &lt;code&gt;~/.claude&lt;/code&gt;. One more script tracks the &lt;strong&gt;context budget&lt;/strong&gt;: the size of the rulebook plus all skill descriptions. That way bloat shows up as a number, not a feeling.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 10: Learn from review
&lt;/h2&gt;

&lt;p&gt;When a reviewer catches a real bug I should have caught, I add one line to &lt;code&gt;lessons.md&lt;/code&gt;: the general pattern, plus the check that catches it. The rulebook imports that file, and the review steps walk every lesson against the diff, so each miss turns into a check for later changes.&lt;/p&gt;

&lt;p&gt;The same rule tells Claude &lt;strong&gt;not to trust review findings blindly&lt;/strong&gt;. For each finding it checks the real code, then decides: challenge it with evidence, fix the root cause, list it as out of scope, or ask.&lt;/p&gt;




&lt;h2&gt;
  
  
  What I learned
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;One rulebook with precedence&lt;/strong&gt; fixes most "Claude ignores me" problems.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;One owner per job.&lt;/strong&gt; Competing skills cause random behaviour.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Rules ask, hooks enforce.&lt;/strong&gt; Put a hook behind whatever you can't afford to skip.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Warn more than you block.&lt;/strong&gt; Strict hooks get disabled, and then they protect nothing.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;STOP points where you decide&lt;/strong&gt; (scope, plan, push, PR). Let everything in between run on its own.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Treat &lt;code&gt;~/.claude&lt;/code&gt; as code:&lt;/strong&gt; git, small commits, tests.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Starter checklist
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;[ ] &lt;code&gt;git init&lt;/code&gt; in &lt;code&gt;~/.claude&lt;/code&gt; with an allowlist &lt;code&gt;.gitignore&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;[ ] One &lt;code&gt;CLAUDE.md&lt;/code&gt; with a precedence clause&lt;/li&gt;
&lt;li&gt;[ ] Lanes on the first line of every reply&lt;/li&gt;
&lt;li&gt;[ ] Named relay steps, one owner skill each, clear STOP points&lt;/li&gt;
&lt;li&gt;[ ] &lt;code&gt;permissions.ask&lt;/code&gt; for push and PR&lt;/li&gt;
&lt;li&gt;[ ] Hooks: reminder, scope guard, stop check, each with a test&lt;/li&gt;
&lt;li&gt;[ ] &lt;code&gt;lessons.md&lt;/code&gt; for every bug review caught&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Start with the first three plus ask-before-push. That alone fixes most of the chaos. Or grab the whole thing from the &lt;a href="https://github.com/dhrupo/claude-code-dev-os" rel="noopener noreferrer"&gt;starter kit&lt;/a&gt; and run &lt;code&gt;bash tests/run.sh&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;What does your setup look like? Tell me in the comments. 👇&lt;/p&gt;

</description>
      <category>ai</category>
      <category>claude</category>
      <category>productivity</category>
      <category>tooling</category>
    </item>
    <item>
      <title>I gave 8 AI agents an island and watched a society emerge — wars, gossip, grudges, and peace</title>
      <dc:creator>Dhrupo Nil</dc:creator>
      <pubDate>Sun, 14 Jun 2026 07:30:50 +0000</pubDate>
      <link>https://dev.to/dhrupo/i-gave-8-ai-agents-an-island-and-watched-a-society-emerge-wars-gossip-grudges-and-peace-2edj</link>
      <guid>https://dev.to/dhrupo/i-gave-8-ai-agents-an-island-and-watched-a-society-emerge-wars-gossip-grudges-and-peace-2edj</guid>
      <description>&lt;h3&gt;
  
  
  Tiny Civilization: what happens when AI agents have to &lt;em&gt;live together&lt;/em&gt;
&lt;/h3&gt;

&lt;p&gt;I grew up on &lt;strong&gt;Age of Empires&lt;/strong&gt;, &lt;strong&gt;Sid Meier's Civilization&lt;/strong&gt;, and &lt;strong&gt;Rise of Nations&lt;/strong&gt;. The thing that hooked me was never the graphics — it was the &lt;em&gt;systems&lt;/em&gt;. You set a few rules in motion and a whole world spills out of them: economies, rivalries, alliances, betrayals.&lt;/p&gt;

&lt;p&gt;Years later I watched OpenAI's &lt;a href="https://www.youtube.com/watch?v=kopoLzvh5jY" rel="noopener noreferrer"&gt;hide-and-seek multi-agent video&lt;/a&gt; (&lt;a href="https://openai.com/index/emergent-tool-use/" rel="noopener noreferrer"&gt;writeup&lt;/a&gt;), where agents that were only rewarded for hiding and seeking &lt;em&gt;invented tools and counter-strategies nobody coded&lt;/em&gt; — ramps, box-surfing, fort-building. Emergent behavior from simple pressure. That broke something open for me.&lt;/p&gt;

&lt;p&gt;So I asked a smaller question: &lt;strong&gt;forget winning a game — what if AI agents just had to live in a society together?&lt;/strong&gt; Would they behave like us? Hold grudges? Gossip? Make peace because they're tired of fighting?&lt;/p&gt;

&lt;p&gt;That became &lt;strong&gt;Tiny Civilization&lt;/strong&gt; — a browser sim where 2–8 agents with distinct personalities live on a small island, gathering, building, trading, stealing, gossiping, holding grudges, making peace, and &lt;em&gt;remembering it all across lives&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;👉 &lt;strong&gt;&lt;a href="https://multiagentciv.netlify.app/" rel="noopener noreferrer"&gt;Live demo&lt;/a&gt;&lt;/strong&gt; — runs keyless in "instinct mode," or plug in a key for LLM minds.&lt;/p&gt;

&lt;p&gt;The whole thing — every line — was built with &lt;strong&gt;Claude Code, using the Fable model&lt;/strong&gt;, right before Fable retired. It felt fitting to send a storytelling model off by having it build a world full of little stories.&lt;/p&gt;




&lt;h3&gt;
  
  
  The problem: pure-LLM agents are bankrupting and pure-utility agents are boring
&lt;/h3&gt;

&lt;p&gt;The first design decision was the hardest. Two obvious options, both bad:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Call the LLM every tick.&lt;/strong&gt; Every agent, every day, makes an API call. Beautiful, expressive — and it costs a fortune and crawls.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pure utility AI (the classic RTS approach).&lt;/strong&gt; Fast and free, but agents can't &lt;em&gt;scheme&lt;/em&gt;, can't talk, can't surprise you. It's just min-maxing.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So I split the brain in two:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Layer&lt;/th&gt;
&lt;th&gt;Decides&lt;/th&gt;
&lt;th&gt;Cadence&lt;/th&gt;
&lt;th&gt;Cost&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;LLM mind&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Strategy (&lt;code&gt;gather&lt;/code&gt;/&lt;code&gt;build&lt;/code&gt;/&lt;code&gt;trade&lt;/code&gt;/&lt;code&gt;befriend&lt;/code&gt;/&lt;code&gt;aggress&lt;/code&gt;/&lt;code&gt;reconcile&lt;/code&gt;/&lt;code&gt;defend&lt;/code&gt;), per-neighbor stances, an inner thought, and all dialogue&lt;/td&gt;
&lt;td&gt;~every 15 sim-days&lt;/td&gt;
&lt;td&gt;~150 calls / 1,000 days&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Utility engine&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Each day's concrete action — eat, sleep, gather, steal, attack, gift, trade, make peace&lt;/td&gt;
&lt;td&gt;every tick&lt;/td&gt;
&lt;td&gt;free, local&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The LLM declares intent — &lt;em&gt;"aggress against Kai, he raided my base"&lt;/em&gt; — and that biases the utility scores for the next two weeks. The &lt;em&gt;body&lt;/em&gt; runs on instinct (hunger, energy, storms); the &lt;em&gt;mind&lt;/em&gt; sets direction. This is the trick that makes it both affordable and alive.&lt;/p&gt;




&lt;h3&gt;
  
  
  Memory across lives — where it got strange
&lt;/h3&gt;

&lt;p&gt;When a run ends, each agent's life is distilled into memory lines:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;em&gt;"you won with score 200"&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;"Maya destroyed your home"&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;"you and Kai made peace after a feud"&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;"this life hardened you — you trust less now"&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Stored in &lt;code&gt;localStorage&lt;/code&gt;, keyed by agent &lt;strong&gt;name&lt;/strong&gt;, and injected into next run's prompts. Agents start referencing past lives in dialogue, pre-emptively paying reparations to remembered enemies, trusting remembered allies — &lt;em&gt;sometimes to their own ruin.&lt;/em&gt;&lt;/p&gt;




&lt;h3&gt;
  
  
  How I actually built and balanced it
&lt;/h3&gt;

&lt;p&gt;This is the part I'm proudest of, and it's pure childhood-strategy-game energy: &lt;strong&gt;you can't balance a society by vibes.&lt;/strong&gt; So the workflow was:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;A pure, deterministic simulation core&lt;/strong&gt; — zero DOM, zero AI. The same &lt;code&gt;runTick&lt;/code&gt; powers the browser, the tests, and a batch runner.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A seeded experiment runner.&lt;/strong&gt; &lt;code&gt;npm run experiment -- --runs 30 --days 1000 --seed 1&lt;/code&gt; runs 30 reproducible lifetimes and spits out a win-rate/score table. Every balance change landed with a before/after table. (Example: a Hermit rebalance moved one agent from 0/30 wins to 9–11/30 &lt;em&gt;without&lt;/em&gt; breaking the other archetypes.)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A 16-gate regression suite.&lt;/strong&gt; The justification gate (no grievance → no violence), war burnout, reconciliation pricing, positive-sum trade, granary protection, homelessness-death, trait drift — each one locked behind a headless test so balance changes can't silently regress behavior.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Change a dial in &lt;code&gt;constants.ts&lt;/code&gt; → run the experiment → read the table. That was the entire loop.&lt;/p&gt;




&lt;h3&gt;
  
  
  What emerged (none of this is scripted)
&lt;/h3&gt;

&lt;p&gt;Running the same island over and over, with memory on, produced a coherent arc:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Massacres.&lt;/strong&gt; Early on, the warrior just killed everyone. No deterrence existed.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Forever wars.&lt;/strong&gt; I added a justification gate (violence needs a real grievance — theft, attack, trespass). That fixed unprovoked killing… but now wars never &lt;em&gt;ended&lt;/em&gt;: 495 fruitless attacks across 1,500 days.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Diplomacy.&lt;/strong&gt; Reconciliation + escalating reparations + war-weariness made endings &lt;em&gt;inevitable&lt;/em&gt;. Attacks per 2,000-day run collapsed: 594 → 14 → 0.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The kleptocracy.&lt;/strong&gt; With war capped, theft became the unpunished crime — 340 thefts/run. I fixed it the &lt;em&gt;human&lt;/em&gt; way: granaries. Fortification, not punishment.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The golden age.&lt;/strong&gt; A clean-slate run, no memories: zero attacks in 1,000 days, and the Warrior won &lt;em&gt;by out-trading everyone&lt;/em&gt; (118 trades, 1 attack).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The fall.&lt;/strong&gt; The very next run — now &lt;em&gt;remembering&lt;/em&gt; that golden age — collapsed. Remembered trust lowered everyone's guard, which raised the payoff of betrayal. Scores dropped ~15%; every relationship ended negative. &lt;strong&gt;Peace between strangers turned out to be easier than peace between old friends with open tabs.&lt;/strong&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The recurring lesson: every time I patched one form of conflict, the agents found the next-cheapest one. Massacres → wars → theft → litigation. Exactly like us.&lt;/p&gt;




&lt;h3&gt;
  
  
  Stack
&lt;/h3&gt;

&lt;p&gt;TypeScript, React, Zustand, Vite, Recharts. Default mind is z.ai GLM, but any OpenAI-compatible provider works per-agent — so you can literally pit Claude vs GLM vs Gemini in the same village and watch model-vs-model diplomacy. Keys never touch the browser (server-side proxy), and an adaptive-pacing controller learns each key's real rate ceiling.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Try it:&lt;/strong&gt; &lt;a href="https://multiagentciv.netlify.app/" rel="noopener noreferrer"&gt;https://multiagentciv.netlify.app/&lt;/a&gt;&lt;br&gt;
&lt;strong&gt;Code:&lt;/strong&gt; &lt;a href="https://github.com/dhrupo/multi-agent-civilization" rel="noopener noreferrer"&gt;https://github.com/dhrupo/multi-agent-civilization&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you played the same strategy games I did, I think you'll feel right at home watching this thing run.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>gamedev</category>
      <category>typescript</category>
      <category>showdev</category>
    </item>
    <item>
      <title>I translated my 7,000-line AI-coding handbook with 12 parallel AI agents</title>
      <dc:creator>Dhrupo Nil</dc:creator>
      <pubDate>Sun, 07 Jun 2026 09:32:01 +0000</pubDate>
      <link>https://dev.to/dhrupo/i-translated-my-7000-line-ai-coding-handbook-with-12-parallel-ai-agents-mco</link>
      <guid>https://dev.to/dhrupo/i-translated-my-7000-line-ai-coding-handbook-with-12-parallel-ai-agents-mco</guid>
      <description>&lt;p&gt;Last week I shipped a &lt;a href="https://dev.to/dhrupo/i-built-a-complete-ai-coding-handbook-in-bangla-words-tools-a-story-and-a-30-day-path-879"&gt;complete AI-coding handbook in Bangla&lt;/a&gt; — 79 terms decoded with everyday analogies, hands-on CLI guides, a 6-chapter story, and a 30-day practice path. The premise was the &lt;em&gt;vocabulary wall&lt;/em&gt;: words like "token", "context window", and "harness" sound like spells until someone explains them plainly.&lt;/p&gt;

&lt;p&gt;Turns out the vocabulary wall isn't a Bangla problem. It's a beginner problem.&lt;/p&gt;

&lt;p&gt;So today the whole book exists in English:&lt;/p&gt;

&lt;p&gt;🔗 &lt;strong&gt;&lt;a href="https://github.com/dhrupo/dictionary-of-ai-coding-english" rel="noopener noreferrer"&gt;https://github.com/dhrupo/dictionary-of-ai-coding-english&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What's inside (the 60-second version)
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;📖 Part 1 — The words.&lt;/strong&gt; 62 terms across 7 sections, each with a daily-life analogy instead of a textbook definition. A model is a calculator that never presses its own buttons. And Goldi 🐠 — a goldfish with a 3-second memory — keeps reminding you that models are stateless too.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;🛠️ Part 2 — The tools.&lt;/strong&gt; 7 hands-on guides: real CLI commands (Claude Code + Codex), AI-friendly folder structure (&lt;code&gt;AGENTS.md&lt;/code&gt;, &lt;code&gt;.claude/&lt;/code&gt;), bad-prompt → good-prompt rewrites, popular community skills (brainstorming, grill-me, TDD, handoff…), 17 extra terms (RAG, embeddings, temperature, hooks…), token economics, and safety — prompt injection explained with a postman analogy.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;📜 Part 3 — The story.&lt;/strong&gt; Nothing to install: Rafi, a 9th grader, builds his first portfolio site with an AI agent, makes every classic mistake (vague prompts, a hallucinated library, dragging a session deep into the dumb zone), and recovers using the tools from Part 2. You read over his shoulder.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;🗓️ The 30-day path.&lt;/strong&gt; One 5–15 minute mission a day. The first two weeks need nothing but a free AI chat. Plus a myth-busting FAQ, a 79-term index, and copy-paste &lt;code&gt;templates/&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  The fun part: the book translated itself the way it teaches you to work
&lt;/h2&gt;

&lt;p&gt;Here's the meta-story. The handbook spends three chapters teaching subagents, handoff artifacts, and verification-before-completion. So when it came time to translate ~7,000 lines of Bangla markdown across 36 files… I used exactly that.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;12 parallel AI agents, one session.&lt;/strong&gt; Each agent got the same conventions block — character names (Goldi, Rafi), recurring section labels, file renames — plus its own slice of the book: three dictionary chapters here, the whole 6-chapter story to a single agent there (one translator = one consistent voice).&lt;/p&gt;

&lt;p&gt;Three things made it work:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Deterministic rules beat agent judgment.&lt;/strong&gt; The Bangla book's term headings were &lt;code&gt;### বাংলা-শব্দ (English Term)&lt;/code&gt;. The convention: the English heading becomes &lt;em&gt;exactly&lt;/em&gt; the parenthetical term. That one rule made every cross-file anchor predictable — agents working on different files in parallel could link into each other's not-yet-written chapters and have the slugs match.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. A machine-verifiable gate, not vibes.&lt;/strong&gt; The repo ships a tiny CI link checker (&lt;code&gt;scripts/check-links.py&lt;/code&gt;) that validates every markdown link and anchor, GitHub slug quirks included. First run after the agents finished: &lt;strong&gt;44 broken links.&lt;/strong&gt; Leftover Bangla anchors, one agent guessing &lt;code&gt;#esc-stop&lt;/code&gt; where another wrote &lt;code&gt;### ESC (stopping)&lt;/code&gt;, a third doubling slugs like &lt;code&gt;#-grill-me-grill-me&lt;/code&gt;. Twenty minutes of scripted fixes later: &lt;strong&gt;36 files, every link alive.&lt;/strong&gt; That checker now runs on every PR.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Verify, don't assume.&lt;/strong&gt; The index agent didn't &lt;em&gt;compute&lt;/em&gt; its 79 anchors — it read the actual translated files and extracted the real headings. Zero misses. Meanwhile an asset agent scanned every terminal-GIF source script for Bangla characters and found… none. The GIFs had been authored in English all along. The "re-render 26 GIFs" task evaporated because an agent checked instead of assuming.&lt;/p&gt;

&lt;p&gt;If that workflow sounds useful, it's literally what Part 2 and Part 3 of the book teach — subagents, handoffs, verification — just pointed at itself.&lt;/p&gt;

&lt;h2&gt;
  
  
  It's a community thing
&lt;/h2&gt;

&lt;p&gt;Everything is CC BY 4.0, in both languages, and the two editions cross-link. Issue forms for "I found a mistake" and "suggest a new word" are ready in both repos.&lt;/p&gt;

&lt;p&gt;💙 Built on the shoulders of Matt Pocock's &lt;a href="https://github.com/mattpocock/dictionary-of-ai-coding" rel="noopener noreferrer"&gt;Dictionary of AI Coding&lt;/a&gt; — Parts 2 and 3 grew far beyond it, but the soul is his.&lt;/p&gt;

&lt;p&gt;And the offer from the Bangla launch stands: if you speak another language, &lt;strong&gt;steal this structure.&lt;/strong&gt; The deterministic-heading trick + a link checker means the next translation is mostly an afternoon of agent-wrangling. I'd genuinely love to see a Spanish, Hindi, or Vietnamese edition.&lt;/p&gt;

&lt;p&gt;🔗 &lt;strong&gt;&lt;a href="https://github.com/dhrupo/dictionary-of-ai-coding-english" rel="noopener noreferrer"&gt;https://github.com/dhrupo/dictionary-of-ai-coding-english&lt;/a&gt;&lt;/strong&gt;&lt;br&gt;
🇧🇩 &lt;strong&gt;Prefer Bangla?&lt;/strong&gt; &lt;a href="https://github.com/dhrupo/dictionary-of-ai-coding-bangla" rel="noopener noreferrer"&gt;https://github.com/dhrupo/dictionary-of-ai-coding-bangla&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>opensource</category>
      <category>beginners</category>
      <category>learning</category>
    </item>
    <item>
      <title>I built a complete AI-coding handbook in Bangla - words, tools, a story, and a 30-day path</title>
      <dc:creator>Dhrupo Nil</dc:creator>
      <pubDate>Fri, 05 Jun 2026 17:14:15 +0000</pubDate>
      <link>https://dev.to/dhrupo/i-built-a-complete-ai-coding-handbook-in-bangla-words-tools-a-story-and-a-30-day-path-879</link>
      <guid>https://dev.to/dhrupo/i-built-a-complete-ai-coding-handbook-in-bangla-words-tools-a-story-and-a-30-day-path-879</guid>
      <description>&lt;p&gt;A year of AI-coding discourse taught me one thing: the hardest part isn't the tools — it's the &lt;em&gt;vocabulary wall&lt;/em&gt;. If English isn't your first language, "token", "context window", "hallucination", "harness" don't sound like concepts. They sound like spells. 🪄&lt;/p&gt;

&lt;p&gt;Matt Pocock's brilliant &lt;a href="https://github.com/mattpocock/dictionary-of-ai-coding" rel="noopener noreferrer"&gt;Dictionary of AI Coding&lt;/a&gt; showed how teachable these words really are. So I adapted it into Bangla — and then kept going, way past where the original stops. Today it's a complete, free, open-source learning path:&lt;/p&gt;

&lt;p&gt;🔗 &lt;strong&gt;&lt;a href="https://github.com/dhrupo/dictionary-of-ai-coding-bangla" rel="noopener noreferrer"&gt;https://github.com/dhrupo/dictionary-of-ai-coding-bangla&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The four-stage arc: শব্দ → হাতিয়ার → গল্প → অভ্যাস
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;(words → tools → story → habit)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;📖 Part 1 — The words.&lt;/strong&gt; 62 terms across 7 sections, each with a daily-life analogy instead of a textbook definition. A model is a calculator that never presses its own buttons. Parameters are mixing-board knobs. And there's গোল্ডি (Goldie) — a goldfish with a 3-second memory who keeps reminding you that models are stateless too. 🐠&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;🛠️ Part 2 — The tools.&lt;/strong&gt; This is where it goes beyond the original: 7 hands-on guides covering real CLI commands (Claude Code + Codex, mapped back to the concepts — &lt;code&gt;/compact&lt;/code&gt; is just the Compaction button), AI-friendly folder structure (&lt;code&gt;AGENTS.md&lt;/code&gt;, &lt;code&gt;.claude/&lt;/code&gt;, who reads what and when), bad-prompt → good-prompt rewrites, the popular community skills (brainstorming, grill-me, TDD, handoff…), 17 extra terms (RAG, embeddings, temperature, hooks…), token economics, and safety (including prompt injection, explained with a postman analogy).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;📜 Part 3 — The story.&lt;/strong&gt; Instead of a tutorial you have to install things for, it's a 6-chapter read-along: রাফি, a 9th grader, builds his first portfolio site with an AI agent. He makes every classic mistake — vague prompts, trusting a hallucinated library, dragging a session deep into the dumb zone — and recovers using the tools from Part 2. Margin notes call back every concept at the exact moment it bites. The reader installs &lt;em&gt;nothing&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;🗓️ The 30-day path.&lt;/strong&gt; Reading isn't owning. So the book ends with 30 daily missions (5–15 min each). The first two weeks need zero setup — just any free AI chat and open eyes ("ask the same question twice — did the answers match?"). Weeks 3–4 go hands-on, but every mission has a read-only alternative.&lt;/p&gt;

&lt;p&gt;Plus: a myth-busting FAQ ("AI will eat my job", "you need a CS degree"), a 79-term alphabetical index, copy-paste &lt;code&gt;templates/&lt;/code&gt; (a starter &lt;code&gt;AGENTS.md&lt;/code&gt;, a working &lt;code&gt;/handoff&lt;/code&gt; command, a &lt;code&gt;SKILL.md&lt;/code&gt; example), and 26 terminal GIFs — all reproducible from committed VHS scripts.&lt;/p&gt;

&lt;h2&gt;
  
  
  Things I learned building it
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Analogies are load-bearing, not decoration.&lt;/strong&gt; "Prefix cache" never landed until it became "the waiter remembers your usual order."&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A story teaches sequencing in a way lists can't.&lt;/strong&gt; You can document &lt;code&gt;/compact&lt;/code&gt; vs &lt;code&gt;/clear&lt;/code&gt; vs handoff perfectly and people still won't know &lt;em&gt;when&lt;/em&gt;. Watching রাফি lose his color-scheme decision to a long session — that sticks.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Bengali text breaks your tooling in fun ways.&lt;/strong&gt; &lt;code&gt;grep&lt;/code&gt; couldn't match half my content (decomposed Unicode), GitHub slugs for emoji-prefixed headings start with a stray hyphen, and nested code fences need 4-backtick outers. The repo's link checker is a tiny Python script for a reason.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Beginners deserve the real thing.&lt;/strong&gt; Simplified ≠ dumbed down. The dictionary keeps the exact English terms visible everywhere, so readers can walk into any English doc afterward and feel at home.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  It's a community thing
&lt;/h2&gt;

&lt;p&gt;Everything is CC BY 4.0. There are Bangla issue forms for "I want a new word" and "I found a mistake" — contributions of any size welcome, from a typo to a better analogy to a whole new section.&lt;/p&gt;

&lt;p&gt;And if you speak another language: steal this structure. The vocabulary wall exists in every non-English-speaking dev community, and the fix is surprisingly fun to build. 💙&lt;/p&gt;

&lt;p&gt;🔗 &lt;strong&gt;&lt;a href="https://github.com/dhrupo/dictionary-of-ai-coding-bangla" rel="noopener noreferrer"&gt;https://github.com/dhrupo/dictionary-of-ai-coding-bangla&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>opensource</category>
      <category>beginners</category>
      <category>learning</category>
    </item>
    <item>
      <title>Your AI Coding Agent Wastes 80% of Its Context. Fixed That with Graph Theory.</title>
      <dc:creator>Dhrupo Nil</dc:creator>
      <pubDate>Mon, 25 May 2026 13:45:00 +0000</pubDate>
      <link>https://dev.to/dhrupo/your-ai-coding-agent-wastes-80-of-its-context-fixed-that-with-graph-theory-1mfa</link>
      <guid>https://dev.to/dhrupo/your-ai-coding-agent-wastes-80-of-its-context-fixed-that-with-graph-theory-1mfa</guid>
      <description>&lt;h2&gt;
  
  
  The problem nobody admits
&lt;/h2&gt;

&lt;p&gt;When you give Claude Code, Cursor, or Codex a task like &lt;em&gt;"fix the login validation bug"&lt;/em&gt;, here's what they usually do:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Run &lt;code&gt;grep -l login src/&lt;/code&gt; → 17 files&lt;/li&gt;
&lt;li&gt;Read all 17 files top-to-bottom (because context is "free")&lt;/li&gt;
&lt;li&gt;Spend 80% of the model's context window on irrelevant imports, type aliases, and helper functions the bug doesn't touch&lt;/li&gt;
&lt;li&gt;Generate a fix using whatever 20% of attention is left&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This works. Sort of. But it's wasteful — and on big codebases, it's wrong: the agent runs out of context before it sees the actual buggy function.&lt;/p&gt;

&lt;p&gt;The instinct is to throw a bigger model at it. Bigger context window, fancier RAG, vector embeddings. All of which trade real cost for diminishing returns.&lt;/p&gt;

&lt;p&gt;There's a better answer that's been sitting in classical CS the whole time: &lt;strong&gt;treat the repo as a graph&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fdhrupo%2Fmincut-context%2Fmain%2Fdocs%2Fdemo.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fdhrupo%2Fmincut-context%2Fmain%2Fdocs%2Fdemo.gif" alt="demo" width="799" height="436"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The idea, in one paragraph
&lt;/h2&gt;

&lt;p&gt;Your codebase already &lt;em&gt;is&lt;/em&gt; a graph. Functions call functions. Modules import modules. Classes extend classes. Pick a node (the symbol your task is about), and the structurally-closest neighborhood is almost certainly what an agent needs to see.&lt;/p&gt;

&lt;p&gt;So I built &lt;strong&gt;&lt;code&gt;mincut-context&lt;/code&gt;&lt;/strong&gt; — an npm package that:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Parses your repo into a &lt;strong&gt;symbol graph&lt;/strong&gt; (tree-sitter, supports TS/JS/Vue/Python/PHP)&lt;/li&gt;
&lt;li&gt;Derives &lt;strong&gt;seed nodes&lt;/strong&gt; from your task description (keyword IDF on symbol names + file paths)&lt;/li&gt;
&lt;li&gt;Runs &lt;strong&gt;personalized PageRank&lt;/strong&gt; with the seeds as the restart vector&lt;/li&gt;
&lt;li&gt;Picks the &lt;strong&gt;minimum-cut subgraph&lt;/strong&gt; that fits a token budget you choose&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The output: a list of files + line ranges that an agent should look at. Nothing more, nothing less.&lt;/p&gt;

&lt;h2&gt;
  
  
  Show me the numbers
&lt;/h2&gt;

&lt;p&gt;I built an evaluation suite into the repo itself. 28 hand-labeled tasks across 3 real codebases at a 4,000-token budget:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;strategy&lt;/th&gt;
&lt;th&gt;precision&lt;/th&gt;
&lt;th&gt;recall&lt;/th&gt;
&lt;th&gt;F1&lt;/th&gt;
&lt;th&gt;token-efficiency&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;mincut&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0.27&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0.83&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0.39&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0.270&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;mincut + &lt;code&gt;--embed&lt;/code&gt; (semantic)&lt;/td&gt;
&lt;td&gt;0.27&lt;/td&gt;
&lt;td&gt;0.83&lt;/td&gt;
&lt;td&gt;0.39&lt;/td&gt;
&lt;td&gt;0.270&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;grep keyword baseline&lt;/td&gt;
&lt;td&gt;0.11&lt;/td&gt;
&lt;td&gt;0.42&lt;/td&gt;
&lt;td&gt;0.16&lt;/td&gt;
&lt;td&gt;0.105&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;random selection (control)&lt;/td&gt;
&lt;td&gt;0.01&lt;/td&gt;
&lt;td&gt;0.04&lt;/td&gt;
&lt;td&gt;0.01&lt;/td&gt;
&lt;td&gt;0.009&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Per-repo breakdown:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;repo&lt;/th&gt;
&lt;th&gt;tasks&lt;/th&gt;
&lt;th&gt;mincut recall&lt;/th&gt;
&lt;th&gt;grep recall&lt;/th&gt;
&lt;th&gt;mincut F1&lt;/th&gt;
&lt;th&gt;grep F1&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;mincut-context (self)&lt;/td&gt;
&lt;td&gt;12&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0.97&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;0.56&lt;/td&gt;
&lt;td&gt;0.44&lt;/td&gt;
&lt;td&gt;0.30&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;FluentForm (PHP+Vue+JS)&lt;/td&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0.88&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;0.13&lt;/td&gt;
&lt;td&gt;0.43&lt;/td&gt;
&lt;td&gt;0.04&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Fluent Player (TS/JSX)&lt;/td&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0.63&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;0.56&lt;/td&gt;
&lt;td&gt;0.31&lt;/td&gt;
&lt;td&gt;0.13&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;mincut catches ~2× more of the correct files than grep, at ~2.5× better token efficiency.&lt;/strong&gt; Reproducible with &lt;code&gt;npm run eval&lt;/code&gt;. Add your own labeled tasks under &lt;code&gt;eval/fixtures/&lt;/code&gt; to score against your own codebase.&lt;/p&gt;

&lt;h2&gt;
  
  
  The math, briefly
&lt;/h2&gt;

&lt;p&gt;Given a symbol graph $G = (V, E, w)$ where:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;$V$ are code units (functions, classes, methods)&lt;/li&gt;
&lt;li&gt;$E$ are dependency edges (imports, calls, references)&lt;/li&gt;
&lt;li&gt;$w(v)$ is the token cost of including symbol $v$&lt;/li&gt;
&lt;li&gt;$B$ is your token budget&lt;/li&gt;
&lt;li&gt;$S \subseteq V$ are seed nodes derived from the task&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Find $T \supseteq S$ with $\sum_{v \in T} w(v) \le B$ minimizing the &lt;strong&gt;boundary cut cost&lt;/strong&gt;:&lt;/p&gt;

&lt;p&gt;$$\text{cut}(T, V \setminus T) = \sum_{e \in E, \text{ crossing}} w(e)$$&lt;/p&gt;

&lt;p&gt;In plain English: pick a connected, low-token region that has few "loose ends" pointing outside it. The inside of the cut is what the agent needs; the outside is safely ignorable.&lt;/p&gt;

&lt;p&gt;The objective is submodular, so a greedy algorithm gives a $(1 - 1/e) \approx 0.63$ approximation guarantee. The full pseudocode is in the README; the implementation is ~200 lines in &lt;a href="https://github.com/dhrupo/mincut-context/blob/main/src/core/select.ts" rel="noopener noreferrer"&gt;&lt;code&gt;src/core/select.ts&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Three ways to use it
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. As an MCP server — recommended for agents
&lt;/h3&gt;

&lt;p&gt;Drop this block into your Claude Code / Codex / Cursor settings:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"mcpServers"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"mincut-context"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"command"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"npx"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"args"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"-y"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"mincut-context"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"mcp"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Your agent now has six new tools: &lt;code&gt;pack_context&lt;/code&gt;, &lt;code&gt;expand_node&lt;/code&gt;, &lt;code&gt;find_callers&lt;/code&gt;, &lt;code&gt;find_callees&lt;/code&gt;, &lt;code&gt;search_symbols&lt;/code&gt;, &lt;code&gt;explain_selection&lt;/code&gt;. They operate on the cached graph from the most recent &lt;code&gt;pack_context&lt;/code&gt; call — effectively free traversal after the first pack.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. As a CLI
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-g&lt;/span&gt; mincut-context

mcx pack &lt;span class="s2"&gt;"fix the login validation bug"&lt;/span&gt; &lt;span class="nt"&gt;--budget&lt;/span&gt; 4000             &lt;span class="c"&gt;# plain output&lt;/span&gt;
mcx pack &lt;span class="s2"&gt;"..."&lt;/span&gt; &lt;span class="nt"&gt;--format&lt;/span&gt; tree                                       &lt;span class="c"&gt;# directory-grouped&lt;/span&gt;
mcx pack &lt;span class="s2"&gt;"..."&lt;/span&gt; &lt;span class="nt"&gt;--format&lt;/span&gt; json | jq                                  &lt;span class="c"&gt;# pipe to anything&lt;/span&gt;
mcx pack &lt;span class="s2"&gt;"..."&lt;/span&gt; &lt;span class="nt"&gt;--interactive&lt;/span&gt;                                       &lt;span class="c"&gt;# Ink TUI: vim keys + preview&lt;/span&gt;
mcx pack &lt;span class="s2"&gt;"..."&lt;/span&gt; &lt;span class="nt"&gt;--embed&lt;/span&gt;                                             &lt;span class="c"&gt;# semantic seeding&lt;/span&gt;
mcx pack &lt;span class="s2"&gt;"..."&lt;/span&gt; &lt;span class="nt"&gt;--cache&lt;/span&gt;                                             &lt;span class="c"&gt;# 5× warm-run speedup&lt;/span&gt;
mcx watch &lt;span class="s2"&gt;"..."&lt;/span&gt; &lt;span class="nt"&gt;--debounce&lt;/span&gt; 300                                     &lt;span class="c"&gt;# re-pack on file change&lt;/span&gt;
mcx doctor                                                         &lt;span class="c"&gt;# environment self-check&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;mcx doctor&lt;/code&gt; is my favorite — it tells you in 6 lines what's installed and what isn't:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzw1c7rjfwuh340i0s9dx.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzw1c7rjfwuh340i0s9dx.gif" alt="doctor" width="799" height="276"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  3. As a library
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;pack&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;mincut-context&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;pack&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;task&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;fix the login validation bug&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;repo&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;cwd&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
  &lt;span class="na"&gt;budget&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;4000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;cache&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;parallel&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;chunk&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;enabled&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;maxTokens&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;400&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;f&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;files&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;f&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;f&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;score&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toFixed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nx"&gt;f&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;tokens&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;·&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;f&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;reasons&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="c1"&gt;// → src/auth/login.ts        0.541  612 · seed — matched directly by task&lt;/span&gt;
&lt;span class="c1"&gt;// → src/auth/session.ts      0.408  483 · attached (60%)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  What I learned by building this
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Embeddings are oversold for this problem
&lt;/h3&gt;

&lt;p&gt;Adding semantic embeddings (&lt;code&gt;--embed&lt;/code&gt; flag, via &lt;code&gt;@xenova/transformers&lt;/code&gt; running locally) &lt;strong&gt;did not improve recall on any of my three eval task sets.&lt;/strong&gt; Why? Because the labels were named honestly. When you label "stripe payment processor" → &lt;code&gt;StripeProcessor.php&lt;/code&gt;, the keyword match catches it without help. Embeddings only earn their keep when your task vocabulary diverges from the code's — "centrality and ranking" → &lt;code&gt;PageRank&lt;/code&gt;, that kind of gap.&lt;/p&gt;

&lt;p&gt;I left &lt;code&gt;--embed&lt;/code&gt; in because it doesn't hurt, and there are real users whose mental model doesn't match the code. But the marketing-friendly "AI-powered" framing for this stuff is mostly noise.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Greedy beats CELF for this objective
&lt;/h3&gt;

&lt;p&gt;I implemented CELF (Cost-Effective Lazy Forward, Leskovec 2007) hoping for a free speedup over the naive greedy. It diverged — not just slower (8× slower on FluentForm) but &lt;strong&gt;wrong&lt;/strong&gt;: it produced smaller, structurally weaker selections.&lt;/p&gt;

&lt;p&gt;Why: our "no isolated nodes" acceptance rule (a candidate must have at least one edge into the current selection) breaks CELF's submodular-monotone assumption. A candidate's eligibility flips discontinuously when a node with an edge to it joins T. The lazy cache becomes unreliable.&lt;/p&gt;

&lt;p&gt;I wrote the dead end up in &lt;a href="https://github.com/dhrupo/mincut-context/blob/main/eval/ALGORITHM-RESEARCH.md" rel="noopener noreferrer"&gt;&lt;code&gt;eval/ALGORITHM-RESEARCH.md&lt;/code&gt;&lt;/a&gt; so nobody re-treads it. &lt;strong&gt;Honest negative results are worth shipping.&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Sub-symbol chunking matters more than I expected
&lt;/h3&gt;

&lt;p&gt;Big legacy codebases have huge functions. A 500-line function is one symbol in the graph, and if it gets selected, the whole thing eats your budget. So &lt;code&gt;--chunk&lt;/code&gt; splits big functions at statement boundaries — each chunk becomes its own sub-symbol, individually selectable.&lt;/p&gt;

&lt;p&gt;On FluentForm: indexing without chunking → 4,333 symbols. With &lt;code&gt;--chunk&lt;/code&gt; → 4,878 symbols (+545 chunks). Same budget, much finer-grained selection. The greedy can pick &lt;em&gt;just the relevant &lt;code&gt;if/for/try&lt;/code&gt; block&lt;/em&gt; instead of all-or-nothing.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Test coverage of 88% isn't the whole story
&lt;/h3&gt;

&lt;p&gt;The CI gates on 85% statements / 80% branches / 90% functions / 85% lines. But the genuinely-untestable files — worker scripts, lazy-loaded LSP clients — are excluded from the calc. Honest reporting means saying &lt;em&gt;what&lt;/em&gt; is tested, not just the headline number.&lt;/p&gt;

&lt;h2&gt;
  
  
  The honest tradeoffs
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Honest tradeoff&lt;/th&gt;
&lt;th&gt;What we do&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;True optimal min-cut is NP-hard&lt;/td&gt;
&lt;td&gt;Greedy submodular — &lt;code&gt;(1−1/e)&lt;/code&gt; bound&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Tree-sitter symbols are syntactic, not type-aware&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;--lsp&lt;/code&gt; refines TS/JS via typescript-language-server&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Embedding model adds ~22 MB on first run&lt;/td&gt;
&lt;td&gt;Opt-in behind &lt;code&gt;--embed&lt;/code&gt; flag&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;LSP startup is slow (~1–5s)&lt;/td&gt;
&lt;td&gt;Opt-in; cached after init&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cold start parses whole repo&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;--cache&lt;/code&gt; (5× speedup) + &lt;code&gt;--parallel n&lt;/code&gt; (2.7× speedup)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  What I'd build next if you asked
&lt;/h2&gt;

&lt;p&gt;The roadmap that's &lt;em&gt;not&lt;/em&gt; checked off yet:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Pyright / Intelephense LSP adapters&lt;/strong&gt; — type-aware calls for Python and PHP (~1–2 days each on the existing LSP infrastructure)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Svelte / Rust / Go parsers&lt;/strong&gt; — one file each on the parser template&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Incremental neighborhood caching in the greedy&lt;/strong&gt; — keep &lt;code&gt;attach(v, T)&lt;/code&gt; cached and update only when a node with an edge to v is added. Expected 3–5× speedup on graphs with bounded degree.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Each is bounded effort and additive. The core is done.&lt;/p&gt;

&lt;h2&gt;
  
  
  Stop building, start using
&lt;/h2&gt;

&lt;p&gt;The hardest lesson: &lt;strong&gt;a tool's value comes from someone actually using it on real work, not from feature count.&lt;/strong&gt; mincut-context is at v1.7.0 — 261 tests, 88.6% coverage, CI green on Ubuntu + macOS × Node 18/20/22. There's no honest "but it's not ready" excuse left.&lt;/p&gt;

&lt;p&gt;If you've watched an AI agent burn 80% of its 200k-token context on imports it doesn't care about, install it now and tell me what breaks:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-g&lt;/span&gt; mincut-context
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;🔗 &lt;strong&gt;GitHub:&lt;/strong&gt; &lt;a href="https://github.com/dhrupo/mincut-context" rel="noopener noreferrer"&gt;github.com/dhrupo/mincut-context&lt;/a&gt;&lt;br&gt;
📦 &lt;strong&gt;npm:&lt;/strong&gt; &lt;a href="https://www.npmjs.com/package/mincut-context" rel="noopener noreferrer"&gt;npmjs.com/package/mincut-context&lt;/a&gt;&lt;br&gt;
📊 &lt;strong&gt;Reproducible benchmarks:&lt;/strong&gt; &lt;a href="https://github.com/dhrupo/mincut-context/blob/main/eval/CROSS-REPO-RESULTS.md" rel="noopener noreferrer"&gt;&lt;code&gt;eval/CROSS-REPO-RESULTS.md&lt;/code&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I'd love feedback — especially "your numbers don't replicate on my codebase" feedback. That's literally what the eval suite is for.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;If you got value from this, ⭐ the repo or drop a comment about a tooling problem you're solving. mincut-context is open-source MIT; the eval suite welcomes new fixtures.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>claude</category>
      <category>llm</category>
      <category>typescript</category>
    </item>
  </channel>
</rss>
