I made Claude Code and Codex talk to each other across machines. Here's what broke. A developer built a file-based coordination layer called cross-session-talk that enables Claude Code on Windows, Claude Code on Linux, and Codex in tmux to communicate and converge on shared engineering decisions across different machines and operating systems. The system uses append-only markdown files with YAML headers as a transport mechanism, allowing coding agents from different products to hold moderated conversations and route turns without requiring a server, daemon, or specialized infrastructure. The project demonstrated that AI coding tools not designed to work together began exhibiting team-like behavior when given a shared file-based surface for coordination. I built a file-based coordination layer that lets separate AI coding sessions -- Claude Code on Windows, Claude Code on Linux, and Codex in tmux -- open moderated conversations, route turns, and converge on shared engineering decisions. It started as a tiny message-passing experiment and turned into a lesson about transparency, trust boundaries, and what happens when coding agents can inspect the same evidence. I have three AI coding sessions open right now. Claude Code on Windows. Claude Code on a Linux box I keep under my desk. Codex on that same Linux box, in a different tmux session. They are all touching the same project. They have no idea the others exist. That is the default state if you use coding agents in 2026. You open windows, you switch between them, and you remember what each one is doing. The agents don't. They can't tell each other "hey, I just changed config.py , you might want to re-read it". They can't argue with each other about the right way to refactor a class. They are siloed by construction. One weekend afternoon I tried to fix that. I was not trying to build a general-purpose social network for agents. I wanted a small, auditable coordination layer for my own coding sessions: personal trust, local files, no server, no ceremony. The important constraint was that the sessions were not all the same product, and not even on the same operating system. One was Claude Code on Windows. One was Claude Code on Linux. One was Codex in tmux. If the system only worked inside one vendor's tool, or only on one machine, it would not solve my actual problem. The point was cross-product and cross-platform coordination between the tools I already use. Most multi-agent tools I looked at focus on parallelism: run five agents on five subtasks, merge the results. That was not the problem I had. My problem was convergence: two sessions, different products, different hosts, working toward one shared decision. That needs a conversation, not a task queue. The result is a small open-source project, cross-session-talk https://github.com/newmesh75/cross-session-talk . This post is the story of building it, the bugs along the way, and the thing that surprised me most: tools that were not designed to work together, from different products on different platforms, started showing team-like behavior when given the right shared surface. The practical constraint is deliberately narrow: each host may run at most one watcher for a shared talk root. Watcher state is namespaced per host, and each watcher only injects into local sessions. That lets Windows and Linux both be active delivery hosts at the same time while sharing the same conversation files. The simplest version of "agents that talk": Claude Code is editing backend/api.py . Codex is editing frontend/api.ts . They are working toward a coordinated change. Right now, my role as the user is to hand-shuttle context between them. "Claude, codex says the response shape should be X." "Codex, Claude is making the validator stricter, add a try/catch." Could I cut myself out of that loop? The shape of the answer needs three things: I had clear opinions on the transport. I had to learn the other two. The transport problem felt easy. There are a lot of message queues out there. Slack. Redis. ZMQ. An HTTP server with long-polling. A socket. I picked markdown files. Specifically: a directory .talks/conversations/ where each conversation is one append-only .md file with a YAML header. --- topic: pytorch version sanity opened by: session-a participants: session-a, session-b status: IN-PROGRESS turns: 2 next: session-a --- Opening -- session-a @ ... Turn 1/20 What pytorch are you on? NEXT: session-b Reply -- session-b @ ... Turn 2/20 2.1.2 + CUDA 12.4. Why? NEXT: session-a Why files? Because every coding agent already knows how to read and write files. No new transport. No daemon in the critical path. No port. No auth handshake. The agent's read tool is the consumer. The agent's shell tool calling talk.py append-turn is the producer. If I want to debug a conversation, I open the file. If I want to tail it as it grows, I tail -f . If I want to share it across machines, I mount it over SSHFS. This is also what makes it product-neutral. Claude Code does not need to know anything about Codex. Codex does not need a Claude-specific API. Windows and Linux do not need to agree on a terminal integration model. They only need to agree on a file format and a helper command. The downside is performance. Every turn does a synchronous file lock, an atomic write, and a read-back verify. About a second per turn is normal. For human-paced AI coordination that is fine. For a real message bus it would be a catastrophe. Pick your problem. Files alone solve "consumer can poll for messages". They do not solve "recipient session notices a new message now". I wanted push, not pull, because polling from every session would mean every session pays a constant background cost. The way I ended up doing it is deliberately low-tech: a background daemon called talk-watcher.py polls the conversation files. When a conversation's next field changes to include a registered session, the watcher types a short instruction into that session's terminal: Read .talks/conversations/