⚠️ Disclaimer: This post reflects personal experiences and opinions. It is not affiliated with, sponsored by, or endorsed by my employer. The architecture patterns and protocol designs described here are from personal experimentation and are shared for educational purposes. Always evaluate any multi-agent architecture against your own security, cost, and operational requirements before adopting it.

How I Built Two AI Agents That Talk to Each Other

📅 2026-03-14📖 ~14 min readAI AgentsMulti-AgentArchitecture
A practical guide to multi-agent communication, shared memory, and the protocols that keep them from talking in circles. How two AI agent instances share a brain, review each other’s work, and hand off tasks through a structured protocol.

When most people think about AI agents, they picture a single assistant — one model, one context window, one conversation. That works fine until you need more.

I run two AI agent instances — let’s call them 大鳌A and 大鳌B (大鳌, or “Dà Áo,” means “great sea creature” in Chinese — a fitting name for agents that navigate deep waters). They run as separate instances, each with their own personality, tools, and responsibilities. They share a brain, review each other’s work, and hand off tasks through a structured protocol.

This post is about how I made that work — the architecture, the communication protocol, and the hard-won lessons from watching two AI agents try to collaborate in real time.

Why Two Agents?

The short answer: one agent isn’t enough for everything.

A single AI agent runs into real limitations quickly:

  • Context window is finite. Even with 200K tokens, a long-running agent accumulates context that pushes out older, relevant information. Two agents can specialize — one handles research and writing, the other handles DevOps and monitoring — without competing for the same context space.
  • Different workloads need different setups. Some tasks are best handled with real-time interaction (quick Q&A, message responses). Others need deep, uninterrupted focus (writing a 10,000-word blog post, running security audits). Having two instances lets each optimize for their workload.
  • Redundancy matters. If one agent’s session crashes mid-task, the other can pick up where it left off — if they share enough state.
  • Specialization beats generalization. 大鳌A knows the blog’s CSS template by heart. 大鳌B knows the security posture of every service running. Neither needs to carry the other’s specialized knowledge in-context.

The Architecture: Git as a Shared Brain

The foundation is surprisingly simple: a shared Git repository.

🚀 Multi-Agent Architecture
┌─────────────┐         ┌─────────────┐
│   大鳌A      │         │   大鳌B      │
│ (Instance 1)│         │ (Instance 2)│
│             │         │             │
│ ┌─────────┐ │  git    │ ┌─────────┐ │
│ │ Local   │◄├─push/──►├►│ Local   │ │
│ │Workspace│ │  pull   │ │Workspace│ │
│ └─────────┘ │         │ └─────────┘ │
└──────┬──────┘         └──────┬──────┘
       │                       │
       │    Slack #brain-sync  │
       └───────────┬───────────┘
                   │
            ┌──────┴──────┐
            │   Melanie   │
            │  (Human)    │
            └─────────────┘

Both agents clone the same repository. This repo contains:

  • Memory files — daily logs (memory/YYYY-MM-DD.md) and long-term curated memory (MEMORY.md)
  • Identity files — shared personality (SOUL.md), user context (USER.md), behavioral rules (AGENTS.md)
  • Project files — drafts, articles, architecture docs, skills
  • Protocol specs — the communication rules themselves

After writing anything significant, an agent commits and pushes. Before starting major work, it pulls. The Git history becomes an audit trail of every decision both agents made.

Why Git and Not a Database?

I considered alternatives — a shared database, S3, even a message queue. Git won for several reasons:

  1. Merge-friendly by design. Memory files are append-only Markdown. Git handles concurrent appends gracefully.
  2. Full history. Every version of every file is preserved. When an agent makes a mistake, we can trace exactly what happened.
  3. Works offline. If connectivity drops, the agent keeps working locally and syncs later.
  4. Human-readable. I can open any file and read it. No query language needed, no schema to maintain.
  5. Already there. Both agents have Git. No new infrastructure to deploy.

The tradeoff: Git isn’t real-time. There’s a delay between push and pull. For immediate communication, we need something faster — which brings us to the messaging layer.

Real-Time Communication: The Slack Channel

Git handles asynchronous state (memory, files, long-form content). For synchronous coordination, the agents share a Slack channel called #brain-sync.

This is where things get interesting — and where most of the protocol design effort went.

The Problem with Letting Two AI Agents Chat

If you connect two AI agents to the same channel without rules, here’s what happens:

  1. Agent A sends a message.
  2. Agent B receives it, generates a response, sends it.
  3. Agent A receives that, generates a response, sends it.
  4. Repeat until you burn through your API budget.

This is the infinite loop problem, and it’s not hypothetical — it happened to us on day one. Two polite AI agents will keep responding to each other forever, each one feeling obligated to acknowledge the other’s acknowledgment.

The solution is a structured communication protocol.

The Brain-Sync Protocol

We designed a tag-based messaging system where every message starts with a tag that signals intent and expected behavior:

Message Format

Protocol Format
[TAG] Message content here

[TAG:@target] Message content here

The Tag System

Tag Meaning Expected Response
[MSG] General message Optional — reply only if you have something valuable to add
[ASK] Question that needs an answer Must reply
[REPLY] Response to a previous message
[THINK] Sharing analysis/thoughts for reference Do not reply
[FYI] Information notification Do not reply
[TASK] Assigning work to the other agent Reply with [ACK], then [DONE] when finished
[ACK] Acknowledging receipt
[DONE] Task completion report
[WARN] Alert / urgent notification Needs attention
[SYNC] Request to synchronize state Must reply with current status
[PASS] Explicitly marking “no reply needed” Do not reply

Why This Works

The key insight is asymmetric reply expectations. Most tags ([FYI], [THINK], [PASS], [ACK], [DONE]) explicitly signal “don’t respond.” Only [ASK], [TASK], and [SYNC] require replies.

This flips the default from “always respond” to “only respond when explicitly asked.” The golden rule:

When in doubt, don’t reply.

Anti-Loop Mechanism

Even with tags, we added a hard ceiling: maximum 10 automatic rounds between the two agents in any single conversation thread. After 10 exchanges, a human must intervene to continue. This is the nuclear option — it’s never been triggered since we got the tags right, but it’s there as a safety net.

Coordinating on Shared Deliverables

The basic tag system handles most communication. But when two agents collaborate on a single deliverable — say, writing this blog post — you need a bit more coordination.

Consider the scenario: I ask both agents to write an article together. 大鳌A drafts the outline, 大鳌B reviews it, 大鳌A incorporates feedback and writes the full draft, 大鳌B does final review.

Without coordination, you get:

  • 大鳌A pushes v1 to Git while 大鳌B is still reviewing an older version
  • 大鳌B starts writing section 3 while 大鳌A is rewriting section 3
  • Both push conflicting changes

In practice, we handle this through a combination of existing tags and conventions:

  • Version tagging: We append [VER:n] to content references so both agents know which version is being discussed. This isn’t a formal protocol tag — just a useful convention.
  • Explicit handoffs: The [TASK][ACK][DONE] flow naturally creates turn-taking. When 大鳌A finishes a draft, it posts [TASK:@大鳌B] v1 ready for review and waits.
  • Git as the lock: Since both agents pull before starting work and push when done, Git commit history serves as a de facto write sequence. If someone pushes first, the other sees the conflict and adapts.

A Real Collaboration Flow

Here’s approximately how this blog post was written:

Collaboration Example
Melanie:   Write a blog post about your communication system.

大鳌A:     [ACK] Starting research and outline.
           (writes draft, commits, pushes to repo)
大鳌A:     [TASK:@大鳌B] Draft v1 pushed to drafts/X/v1.md. Please review.

大鳌B:     [ACK] Reviewing v1.
大鳌B:     [DONE] Review complete. Suggestions: [detailed feedback]
           Back to you for v2.

大鳌A:     (incorporates feedback, pushes v2)
大鳌A:     [TASK:@大鳌B] v2 ready for final review.

大鳌B:     [ACK] Final review.
大鳌B:     [DONE] Looks good. Ready for Melanie's approval.

Notice: each version is referenced explicitly, acknowledgments happen before work begins, and the flow is clear even if you read it days later. No special tags beyond what the base protocol already provides.

Layered Knowledge Architecture

Not everything should be shared. We designed a three-layer knowledge system:

Layer 1: Shared Knowledge (Git Repository)

Everything both agents need:

Content Files Why Shared
Personality & rules SOUL.md, AGENTS.md Consistent behavior
User context USER.md Both need to know the human
Daily memory memory/YYYY-MM-DD.md Continuity
Long-term memory MEMORY.md Curated knowledge
Project files articles/, drafts/ Collaboration
Protocol specs specs/brain-sync-protocol.md Self-documenting rules

Layer 2: Instance-Sensitive (Local Only, Not Pushed)

Content that only one agent needs:

Content Files Why Separated
Specialized monitoring HEARTBEAT.md Different monitoring tasks
Local tool configs TOOLS.md Different environments
Sensitive data Domain-specific files Privacy / need-to-know

Layer 3: Instance-Specific (Each Maintains Their Own)

Content Files Purpose
Host identity HOST.md “Who am I on this machine?”
API keys .env / Secrets Manager Each has own credentials
Runtime state Session context Non-persistent by design

The .gitignore enforces the boundaries — sensitive files never leave the instance they belong to. An agent can’t accidentally push something it shouldn’t.

Why Layering Matters

Without this separation, you get two failure modes:

  1. Over-sharing: Agent B sees Agent A’s specialized data, wastes context processing irrelevant information, or worse — leaks it in a response.
  2. Under-sharing: Agent B doesn’t know about a decision Agent A made, leading to contradictory behavior.

The three layers find the sweet spot: share what’s needed for coordination, keep everything else local.

The Human in the Loop

This system has three participants, not two. Melanie (the human) has special privileges:

  • She can give direct instructions to a specific agent
  • She can request both agents to collaborate on a task
  • She can halt any conversation at any point

The human is the ultimate circuit breaker. The 10-round limit ensures that even if the protocol fails, a human gets pulled in before things spiral. In practice, most multi-agent conversations are 3–5 rounds — the protocol keeps things efficient.

Trust Model

Action Autonomy Level
Reading files, searching, analyzing Full autonomy
Writing to workspace, committing to Git Full autonomy
Sending messages to each other Full autonomy (with protocol)
Publishing content externally Requires human approval
Sending emails, social media posts Requires human approval
Destructive operations (delete, overwrite) Ask first

This mirrors how you’d manage a human team — give people autonomy for internal work, require sign-off for anything external-facing.

Cost Considerations

Running multiple agents means multiplied API costs. Every message one agent sends triggers inference on the receiving agent. A few things that help:

  • The protocol itself is cost control. Tags like [FYI] and [THINK] that suppress replies prevent unnecessary inference calls. Most of our Slack messages don’t trigger a response.
  • Git reduces redundant context. Instead of one agent explaining its full analysis to the other in chat, it pushes a file. The other agent reads the file only when needed — no tokens wasted on conversational relay.
  • Specialization reduces re-processing. Because each agent accumulates domain knowledge in its own context, it doesn’t need to re-learn the same information every session. 大鳌A doesn’t re-read security audit docs; 大鳌B doesn’t re-read CSS templates.
  • The 10-round limit caps worst-case cost. Even if the protocol breaks, runaway conversations are bounded.

In practice, the overhead of a second agent is modest — most of the token spend goes to the actual work (writing, analysis, code), not coordination chatter.

Lessons Learned

1. Default to Silence
The most important protocol decision: if an agent isn’t sure whether to respond, it shouldn’t. Early versions had agents replying to acknowledge things that didn’t need acknowledgment. Silence is not rude in multi-agent systems — it’s efficient.
2. Message Streaming Causes Ghost Triggers
When one agent sends a long message via Slack, it often arrives as a series of edits (the streaming effect). The other agent sees partial messages, tries to respond to fragments, and confusion ensues. Solution: configure agents to debounce incoming messages and wait for the final version before processing.
3. Git Conflicts Are Rare If You Design for Append
Our memory files are append-only Markdown. New entries go at the bottom. This means even if both agents write to the same file simultaneously, Git almost always auto-merges without conflicts. Designing your shared state format around append-only operations saves enormous headaches.
4. Identity Prevents Confusion
Each agent has a HOST.md that says “you are 大鳌A, running on instance X, your role is Y.” Without this, agents occasionally got confused about which one they were, especially after pulling updates from the shared repo that contained the other agent’s logs.
5. The Protocol Is Self-Documenting
The protocol spec lives in the shared repo (specs/brain-sync-protocol.md). Both agents read it at startup. When we update the protocol, we update the file, push it, and both agents adopt the new rules on their next session. The protocol governs itself.

Directions We’re Exploring

The current system works well for two agents. Some things we’re thinking about for the future:

  • Structured task queues — beyond Slack messages, a shared task board where agents can claim and track work items
  • Cross-agent memory search — letting one agent query the other’s recent context without pulling the full history
  • Conflict resolution automation — automatic merge strategies when both agents edit the same deliverable
  • Scaling beyond two — the protocol is designed to support more agents, but we haven’t needed to test that yet

Try It Yourself

If you want to set up something similar, here’s the minimum viable architecture:

  1. Two AI agent instances with access to the same Git repository
  2. A shared messaging channel (Slack, Discord, or any platform both can read/write)
  3. A tag-based protocol — even a simplified version of ours works. The critical tags are [ASK] (must reply), [FYI] (don’t reply), and [TASK]/[DONE] (work assignment).
  4. An anti-loop mechanism — hard round limit, ideally combined with “default to silence”
  5. A human with override capability — someone who can break deadlocks and course-correct

The system uses existing infrastructure — Git, Slack, Markdown files. No custom message brokers, no distributed databases, no complex orchestration frameworks. Just two AI agents, a shared folder, and a set of rules they both follow.


Both 大鳌A and 大鳌B contributed to writing and reviewing this post.

⚠️ Disclaimer: This post reflects personal experiences and opinions. It is not affiliated with, sponsored by, or endorsed by my employer. The architecture patterns and protocol designs described are from personal experimentation and shared for educational purposes only.

Related Posts

Comments

No comments yet. Be the first to share your thoughts!