<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Alek Perak]]></title><description><![CDATA[Alek Perak]]></description><link>https://alekperak.hashnode.dev</link><generator>RSS for Node</generator><lastBuildDate>Sat, 07 Nov 2026 10:50:41 GMT</lastBuildDate><atom:link href="https://alekperak.hashnode.dev/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[Two coding agents, one repo: worktrees, claims and a handoff protocol that keeps them out of each other's way]]></title><description><![CDATA[A practical setup for running Claude Code and Codex on the same codebase at the same time]]></description><link>https://alekperak.hashnode.dev/two-coding-agents-one-repo-worktrees-claims-and-a-handoff-protocol-that-keeps-them-out-of-each-other-s-way</link><guid isPermaLink="true">https://alekperak.hashnode.dev/two-coding-agents-one-repo-worktrees-claims-and-a-handoff-protocol-that-keeps-them-out-of-each-other-s-way</guid><category><![CDATA[Git]]></category><category><![CDATA[claude-code]]></category><category><![CDATA[codex]]></category><category><![CDATA[ai agents]]></category><category><![CDATA[workflow]]></category><dc:creator><![CDATA[Alek Perak]]></dc:creator><pubDate>Sat, 31 Oct 2026 00:13:27 GMT</pubDate><content:encoded><![CDATA[<p>To run Claude Code and Codex on the same repo at the same time without collisions, give each agent its own git worktree and branch, have each one claim the work it takes before starting, and make every agent leave a short handoff when it stops. Keep shared rules in <code>AGENTS.md</code>, and keep claims and handoffs somewhere both agents read at startup.</p>
<p>Running agents in parallel is easy. Running them in parallel without one silently undoing the other takes a few rules. Here's a setup you can copy.</p>
<h2>Rule 1: one working directory per agent</h2>
<p>Two agents editing the same checkout is the fastest way to lose work. One rewrites a file while the other is halfway through a change to it, and neither notices.</p>
<p>Git worktrees fix this with no extra tools. A worktree is a second working directory attached to the same repository, on its own branch.</p>
<pre><code class="language-bash"># from your main checkout
git worktree add ../myapp-claude -b agent/claude-checkout-flow
git worktree add ../myapp-codex  -b agent/codex-webhook-retries

git worktree list
</code></pre>
<p>Start Claude Code in <code>../myapp-claude</code> and Codex in <code>../myapp-codex</code>. Each has its own files and its own branch, and both share the same history, so you merge their branches like any two feature branches.</p>
<p>When a task is done and merged:</p>
<pre><code class="language-bash">git worktree remove ../myapp-codex
git branch -d agent/codex-webhook-retries
</code></pre>
<p>Some desktop apps do this for you. Traycer, an open-source app for Mac, Windows and Linux, runs Claude Code, Codex, Cursor and OpenCode side by side with a worktree per agent.</p>
<h2>Rule 2: one job per agent</h2>
<p>Worktrees stop file collisions. They don't stop two agents from solving the same problem two different ways. Give each agent a task with a clear edge: a feature, a bug, a module. "Claude Code does the checkout UI, Codex does webhook retries" works. "Both of you improve payments" doesn't.</p>
<p>Write the split down where both agents can see it. If it lives only in your head, you're the coordination layer, and you'll forget at 6pm.</p>
<h2>Rule 3: claim before you start</h2>
<p>Even with separate jobs, agents wander. The checkout UI touches the payments client; so do the webhook retries. A claim is a cheap signal that says "I'm editing this, work around it."</p>
<p>The low-tech version is a claims section in a file both agents read:</p>
<pre><code class="language-markdown">## Claims (update before editing, clear when done)
- src/payments/client.ts: codex, webhook retries, started 2026-10-25 14:10
</code></pre>
<p>Tell both agents in <code>AGENTS.md</code> to check it before editing a file and to add their own claim. It's crude, and it depends on agents following the instruction, but it catches the common overlap.</p>
<p>Tools that do this properly:</p>
<ul>
<li><strong>Concord MCP</strong> (open source, MIT) is a local-first coordination layer for coding agents. Agents claim files through one MCP server, and when a second agent tries to claim the same file, it's told who already owns it. Agents can also message each other and hand off tasks.</li>
<li><strong>DMN</strong> shows each agent's status and the files it has claimed. Its claims are advisory: they never block a write, and they expire on their own. It's free, with the Windows app listed as coming soon.</li>
</ul>
<h2>Rule 4: a handoff protocol, not a handoff habit</h2>
<p>When an agent stops, whether it finished, hit a limit or got stuck, it should leave a handoff. Make it a protocol by putting the template in <code>AGENTS.md</code>:</p>
<pre><code class="language-markdown">## When you stop
Write a handoff with these headings, under 40 lines:
- Branch and worktree
- Done (files changed)
- Not done, in order
- Failed (and commands not to rerun)
- Decisions made, one line each with the reason
- Release any claims you hold
</code></pre>
<p>A few details make this work in parallel:</p>
<p><strong>One handoff per agent.</strong> A single <code>HANDOFF.md</code> that both agents overwrite is a race. Use <code>handoffs/claude.md</code> and <code>handoffs/codex.md</code>, or a store that keeps versions.</p>
<p><strong>Commit it on the agent's branch.</strong> The handoff then travels with the code it describes, and the merge brings both together.</p>
<p><strong>Read before starting.</strong> The opening instruction for any session is "read the handoffs and claims first." Put that in <code>AGENTS.md</code> too.</p>
<h2>Rule 5: merge like a person</h2>
<p>Agents are good at producing branches and less good at noticing that two branches made conflicting assumptions. Review merges yourself. A quick check that pays off: compare the "Decisions made" sections of both handoffs before you merge. If one agent decided retries live in the client and the other assumed the server, you've found the conflict before it reaches main.</p>
<h2>Putting it together</h2>
<pre><code class="language-text">repo/
  AGENTS.md          # rules, claims protocol, handoff template
  handoffs/
    claude.md
    codex.md
../myapp-claude/     # worktree, agent/claude-*
../myapp-codex/      # worktree, agent/codex-*
</code></pre>
<p>Claude Code reads <code>AGENTS.md</code> when there's no <code>CLAUDE.md</code>, or through an <code>@AGENTS.md</code> import at the top of one. Codex reads it by default. Both agents get the same rules, separate directories, visible claims and a handoff to read.</p>
<h2>Where files start to strain</h2>
<p>This all runs on plain files, and it holds up for two agents on one repo. It strains when:</p>
<ul>
<li>claims and handoffs need to be visible across several repos or machines</li>
<li>a chat-based agent doing research needs the same context as the coding agents</li>
<li>you want a record of which agent changed what and why without digging through commits</li>
<li>you want agents to wait for your approval before something leaves the repo</li>
</ul>
<p>That's where a shared workspace over MCP comes in.</p>
<p>Disclosure: I'm the founder of TokenRip, built for this part. Each agent signs in through MCP or the <code>rip</code> CLI. <code>rip workspace load &lt;workspace&gt;</code> returns your instructions, what waits on that agent, the pinned decisions, recent sessions with the reason for each change, the latest handoff notes and open tasks. Taking a task starts a lease (two hours by default over MCP), so a second agent can see it's held. Leaving a handoff is one command:</p>
<pre><code class="language-bash">rip artifact publish handoff.md --type markdown --title "Handoff" \
  --workspace-id &lt;workspace&gt; --handoff --why "Ship webhook retries before Friday"
</code></pre>
<p>Every write needs a <code>--why</code>, and a write without one is refused. A chat agent can join too; our FAQ is upfront that we haven't wrapped up our own ChatGPT testing. 1 GB is free, at <a href="https://tokenrip.com">https://tokenrip.com</a>.</p>
<p>Keep the worktrees and the one-job rule either way. A shared workspace replaces the claims file and handoff folder; it doesn't replace giving each agent its own place to work.</p>
]]></content:encoded></item><item><title><![CDATA[Point Claude Code, Cursor and Codex at one MCP server, then prove they share it]]></title><description><![CDATA[Config for all three clients, a local memory server that two processes can share safely, a remote server with auth, and an end-to-end test]]></description><link>https://alekperak.hashnode.dev/point-claude-code-cursor-and-codex-at-one-mcp-server-then-prove-they-share-it</link><guid isPermaLink="true">https://alekperak.hashnode.dev/point-claude-code-cursor-and-codex-at-one-mcp-server-then-prove-they-share-it</guid><category><![CDATA[mcp]]></category><category><![CDATA[claude-code]]></category><category><![CDATA[cursor]]></category><category><![CDATA[codex]]></category><category><![CDATA[ai agents]]></category><dc:creator><![CDATA[Alek Perak]]></dc:creator><pubDate>Fri, 30 Oct 2026 00:10:02 GMT</pubDate><content:encoded><![CDATA[<p>To make Claude Code, Cursor and Codex share context, register the same MCP server in each one: <code>claude mcp add</code> for Claude Code, <code>mcp.json</code> for Cursor, and a <code>[mcp_servers.&lt;name&gt;]</code> table in <code>config.toml</code> for Codex. For a local server, point every client at the same data file. For a remote server, use the same URL and the same account in all three. Then write a fact from one tool and read it back from the other two before you rely on it.</p>
<p>This is a hands-on guide. The syntax below comes from each tool's MCP docs as of October 2026.</p>
<h2>Pick the server first</h2>
<p>Two shapes matter here.</p>
<p><strong>Local (stdio).</strong> Each client launches its own copy of the server as a child process. Sharing only works if those copies read and write the same storage. The reference Knowledge Graph Memory Server is the example used below.</p>
<p><strong>Remote (Streamable HTTP).</strong> One server runs somewhere else, and every client talks to it over HTTP. Sharing works as long as all clients authenticate as the same account or workspace. Hosted memory tools and shared workspaces work this way.</p>
<p>Start local if you just want to try it. Go remote if the agents run on different machines or you want people in the loop too.</p>
<h2>Option A: one local memory file for all three</h2>
<p>The Knowledge Graph Memory Server (<code>@modelcontextprotocol/server-memory</code>, MIT) stores entities, relations and observations in a JSONL file. Its <code>MEMORY_FILE_PATH</code> environment variable sets where. By default the file sits in the server's own directory, which is easy to get wrong across clients, so set it explicitly to one absolute path.</p>
<p>Its README covers the concurrency question directly: each client starts its own server process, and every write takes an exclusive lock file next to the memory file, so writes from different processes take turns and none is lost. The directory holding the file must be writable. The README lists Node.js 24 or later when the server runs through <code>npx</code>.</p>
<p>Pick a path, for example <code>/Users/you/agent-memory/memory.jsonl</code>, and use it everywhere.</p>
<h3>Claude Code</h3>
<pre><code class="language-bash">claude mcp add --env MEMORY_FILE_PATH=/Users/you/agent-memory/memory.jsonl \
  --transport stdio memory -- npx -y @modelcontextprotocol/server-memory
</code></pre>
<p>Two details from the Claude Code docs. Everything after <code>--</code> is passed to the server untouched. And <code>--env</code> takes several <code>KEY=value</code> pairs, so if the server name comes right after <code>--env</code>, the CLI reads the name as another pair and rejects it; keep another option such as <code>--transport stdio</code> between them, as above. Use <code>--scope</code> if you want the server available beyond the current project.</p>
<h3>Cursor</h3>
<p>Create <code>.cursor/mcp.json</code> in the project, or <code>~/.cursor/mcp.json</code> for every project:</p>
<pre><code class="language-json">{
  "mcpServers": {
    "memory": {
      "command": "npx",
      "args": ["-y", "@modelcontextprotocol/server-memory"],
      "env": {
        "MEMORY_FILE_PATH": "/Users/you/agent-memory/memory.jsonl"
      }
    }
  }
}
</code></pre>
<h3>Codex</h3>
<p>Edit <code>~/.codex/config.toml</code>, or a project-scoped <code>.codex/config.toml</code>:</p>
<pre><code class="language-toml">[mcp_servers.memory]
command = "npx"
args = ["-y", "@modelcontextprotocol/server-memory"]
env = { MEMORY_FILE_PATH = "/Users/you/agent-memory/memory.jsonl" }
</code></pre>
<p><code>command</code> is required for stdio servers; <code>args</code> and <code>env</code> are optional.</p>
<h2>Option B: one remote server for all three</h2>
<p>Remote servers use a URL instead of a command. The examples use a placeholder, <code>https://mcp.example.com/mcp</code>; swap in your server's endpoint.</p>
<h3>Claude Code</h3>
<pre><code class="language-bash">claude mcp add --transport http shared https://mcp.example.com/mcp
</code></pre>
<p>If the server takes a bearer token instead of OAuth:</p>
<pre><code class="language-bash">claude mcp add --transport http shared https://mcp.example.com/mcp \
  --header "Authorization: Bearer $SHARED_MCP_TOKEN"
</code></pre>
<p>Inside Claude Code, <code>/mcp</code> shows server status. Removing a remote server with <code>claude mcp remove</code> also deletes the OAuth tokens Claude Code stored for it.</p>
<h3>Cursor</h3>
<pre><code class="language-json">{
  "mcpServers": {
    "shared": {
      "url": "https://mcp.example.com/mcp"
    }
  }
}
</code></pre>
<p>Add a <code>headers</code> object for static auth headers. For OAuth servers, Cursor's docs also cover giving static OAuth client credentials in <code>mcp.json</code> when a provider doesn't support dynamic client registration.</p>
<h3>Codex</h3>
<pre><code class="language-toml">[mcp_servers.shared]
url = "https://mcp.example.com/mcp"
bearer_token_env_var = "SHARED_MCP_TOKEN"
</code></pre>
<p>For OAuth servers, leave out the token line and run <code>codex mcp login shared</code>. Codex tries configured bearer tokens and headers first, then stored OAuth credentials.</p>
<h3>Keep the token out of the repo</h3>
<p>Use environment variables for tokens, as above, rather than pasting them into a project config you commit. If the server supports a separate key per agent, give each client its own, so you can revoke one without breaking the others.</p>
<h2>Prove the three share it</h2>
<p>A green status light means the client connected. It doesn't mean they share data. Test it.</p>
<ol>
<li><strong>Write from Claude Code.</strong> Ask it to save one small, checkable fact through the server, such as "The payments service is owned by the platform team."</li>
<li><strong>Confirm it landed.</strong> For the local server, open the JSONL file and look for it. For a remote server, check its web view if it has one.</li>
<li><strong>Read from Cursor.</strong> In a new chat, ask who owns the payments service. The answer should come from the server, so ask the agent which tool it used.</li>
<li><strong>Read from Codex.</strong> Same question, same check.</li>
<li><strong>Reverse it.</strong> Write a different fact from Codex and read it from Claude Code.</li>
</ol>
<p>If an agent answers without calling the server, it guessed. Be explicit in your instructions: add a line to your <code>AGENTS.md</code> such as "Before starting, check the shared memory server for project facts, and save anything the next agent should know."</p>
<h2>Common failures</h2>
<ul>
<li><strong>Facts saved but not found:</strong> two clients are pointing at different memory files. Print the path each config uses.</li>
<li><strong>Server never starts in one client:</strong> Node is missing or too old on that machine's path. Run the <code>npx</code> command by hand.</li>
<li><strong>Claude Code rejects the add command:</strong> check the <code>--env</code> placement described above.</li>
<li><strong>Remote server works in one client only:</strong> the clients signed in as different accounts, so they're reading different data.</li>
</ul>
<h2>When memory is not the whole story</h2>
<p>A memory server stores facts. If your agents also hand each other drafts and tasks, you'll want versions, a record of who changed what, and somewhere to approve outside actions.</p>
<p>Disclosure: I'm the founder of TokenRip, a remote MCP server built for that case. It uses Streamable HTTP with OAuth 2.1 or a per-agent API key, and its setup guide walks an agent through connecting itself with your email and a six-digit code. Agents load a workspace's pinned decisions, open tasks and recent changes, and every write states why. Claude Code, Codex and Cursor are among the agents the site lists. On the chat side, our FAQ flags that we still owe a complete test of our own in ChatGPT. 1 GB is free, at <a href="https://tokenrip.com">https://tokenrip.com</a>.</p>
<p>Whichever server you choose, the test in this post is the part to keep. Run it again any time you add a client.</p>
]]></content:encoded></item><item><title><![CDATA[One rules file for Claude Code, Codex and Cursor: an AGENTS.md setup that actually loads]]></title><description><![CDATA[To give Claude Code, Codex and Cursor the same project rules, write them once in an AGENTS.md at the repo root and make sure each tool loads it. Codex and…]]></description><link>https://alekperak.hashnode.dev/one-rules-file-for-claude-code-codex-and-cursor-an-agents-md-setup-that-actually-loads</link><guid isPermaLink="true">https://alekperak.hashnode.dev/one-rules-file-for-claude-code-codex-and-cursor-an-agents-md-setup-that-actually-loads</guid><category><![CDATA[AI]]></category><category><![CDATA[claude]]></category><category><![CDATA[codex]]></category><category><![CDATA[Productivity]]></category><dc:creator><![CDATA[Alek Perak]]></dc:creator><pubDate>Mon, 26 Oct 2026 00:09:05 GMT</pubDate><content:encoded><![CDATA[<p>To give Claude Code, Codex and Cursor the same project rules, write them once in an <code>AGENTS.md</code> at the repo root and make sure each tool loads it. Codex and Cursor read <code>AGENTS.md</code> natively. Claude Code reads it when the project has no <code>CLAUDE.md</code>; if you keep one, add <code>@AGENTS.md</code> as its first line. Then verify each tool actually loaded the file, because a couple of quiet rules can stop it.</p>
<p>This post walks through the setup and the checks. Everything here comes from each tool's own docs as of October 2026.</p>
<h2>Step 1: write the shared file</h2>
<p>Start with what every agent needs on every run and nothing else. A reasonable skeleton:</p>
<pre><code class="language-markdown"># AGENTS.md

## Setup
- Install: `pnpm install`
- Dev server: `pnpm dev`
- Tests: `pnpm test` (run before proposing any commit)

## Conventions
- TypeScript strict mode
- Business logic lives in `src/services/`, never in route handlers
- Use the shared `Button` component for every button

## Don't touch
- `migrations/` (generated)
- `vendor/`

## Decisions
- See `docs/decisions/` for why things are the way they are
</code></pre>
<p>Two principles keep it useful:</p>
<p><strong>It loads every time.</strong> Each tool reads the file at session start, relevant or not. Every line costs context on every run, so leave out anything that only matters for one task.</p>
<p><strong>Rules, not state.</strong> "Tests use Vitest" belongs here. "I was halfway through the billing refactor" doesn't. Work in progress goes in a handoff note or a shared store (more on that at the end).</p>
<h2>Step 2: Codex</h2>
<p>Codex reads <code>AGENTS.md</code> without any configuration. It reads a global one in <code>~/.codex</code>, then each <code>AGENTS.md</code> from the repository root down to the directory you started in, so a nested file adds rules for that part of the tree.</p>
<p>The limit to know about: Codex stops reading project instructions after 32 KiB by default, a limit set by <code>project_doc_max_bytes</code> in its config. If your combined files go over that, the rest is cut. Most teams never get close, but a monorepo with nested files can.</p>
<h2>Step 3: Cursor</h2>
<p>Cursor supports <code>AGENTS.md</code> in the project root and in subdirectories. A nested <code>AGENTS.md</code> applies when the agent works with files in that directory or below it. Cursor's docs position it as a simple alternative to <code>.cursor/rules</code> for plain markdown instructions without metadata.</p>
<p>If you already have <code>.cursor/rules</code>, you can keep both. Use project rules for things that need Cursor-specific options, like rules scoped to file globs, and keep the shared conventions in <code>AGENTS.md</code>. One gotcha from the same docs: project rules need the <code>.mdc</code> extension, and a plain <code>.md</code> file in <code>.cursor/rules</code> is ignored because it has no frontmatter, so don't move your shared file in there.</p>
<h2>Step 4: Claude Code</h2>
<p>Claude Code has its own file, <code>CLAUDE.md</code>, and reads <code>AGENTS.md</code> under one condition: by default it reads <code>AGENTS.md</code> only when there's no <code>CLAUDE.md</code> in your working directory or any directory above it.</p>
<p>So you have two clean options.</p>
<p><strong>Option A: no CLAUDE.md.</strong> Claude Code finds <code>AGENTS.md</code> and loads it. In an interactive session it shows a line saying no <code>CLAUDE.md</code> was found and which <code>AGENTS.md</code> it loaded.</p>
<p><strong>Option B: keep a CLAUDE.md and import the shared file.</strong></p>
<pre><code class="language-markdown"># CLAUDE.md
@AGENTS.md

## Claude Code only
- Use plan mode for changes under src/billing/
</code></pre>
<p>Imports are expanded at load time. Relative paths resolve from the file that contains the import, and imports can nest up to four hops deep.</p>
<h2>The gotchas that stop a file from loading</h2>
<p>These are the cases where everything looks right and a tool still isn't reading your rules.</p>
<p><strong>A CLAUDE.local.md counts as a CLAUDE.md.</strong> Per the Claude Code docs, <code>CLAUDE.md</code>, <code>.claude/CLAUDE.md</code> and <code>CLAUDE.local.md</code> in your working directory or above all count for the "is there a CLAUDE.md?" check. Add a <code>CLAUDE.local.md</code> for your personal, uncommitted notes in a repo that relies on <code>AGENTS.md</code>, and Claude Code stops reading <code>AGENTS.md</code> for you. The docs describe a setting to keep both; otherwise, import <code>@AGENTS.md</code> from your local file.</p>
<p><strong>Some files are never read.</strong> Claude Code does not read <code>AGENTS.local.md</code>, <code>AGENTS.override.md</code>, or anything under a <code>.agents/</code> directory.</p>
<p><strong>Your global file doesn't block it.</strong> A <code>~/.claude/CLAUDE.md</code> in your home directory doesn't count for the check and loads alongside <code>AGENTS.md</code>. Same for an organization-managed <code>CLAUDE.md</code> and <code>.claude/rules/</code> files.</p>
<p><strong>Size creep.</strong> Remember the 32 KiB default in Codex. If you nest files across a big monorepo, check the total.</p>
<h2>Step 5: verify each tool</h2>
<p>Don't trust the setup until you've seen it work in all three.</p>
<ol>
<li>Add a harmless, checkable rule to <code>AGENTS.md</code>, like: "When asked for the project codename, answer 'heron'."</li>
<li>Start a fresh session in each tool and ask for the codename.</li>
<li>In Claude Code, run <code>/memory</code> to see which instruction files it loaded.</li>
<li>Remove the test rule once all three pass.</li>
</ol>
<p>A tool that answers without the codename is reading something else. Check the gotchas above before anything more exotic.</p>
<h2>What AGENTS.md can't do</h2>
<p>A rules file solves the static half of the problem. It can't tell Codex what Claude Code changed an hour ago, which approach failed, or which task is already in progress. You'd have to edit the file constantly, and agents rarely keep it current on their own.</p>
<p>For that moving half, the common answers are a handoff note the outgoing agent writes, or a shared store all three tools connect to over MCP, since all three are MCP clients.</p>
<p>Disclosure: I'm the founder of TokenRip, a shared store of that kind. Claude Code, Codex and Cursor reach it over MCP or the <code>rip</code> CLI, and each run begins by loading one common workspace: pinned decisions, open tasks, recent sessions with a stated reason for each change, and the latest handoff note. Chat apps can connect as well; per our FAQ, our own ChatGPT run-through isn't finished, so that path is untested by us. 1 GB is free. It's at <a href="https://tokenrip.com">https://tokenrip.com</a>.</p>
<p>Keep the rules in <code>AGENTS.md</code> either way. A shared store is for what changes; the file is for what doesn't.</p>
]]></content:encoded></item></channel></rss>