How to Solve the Agent Handoff Problem

Heather Downing

These days, one agent is rarely enough. The moment you split work across two, one of them has to tell the other what it learned, and the easy way to do that is to pass along the whole conversation.

That is where things can start to go off the rails.

In this blog, we walk through:

  • Why passing a transcript can break an agent-to-agent handoff
  • What a handoff needs to survive beyond a single session (and across multiple accounts)
  • How to write a rule in code that decides what crosses

If your agents hand work to each other, or to a teammate’s agents, this is the difference between the next agent building on a decision and rebuilding a dead end. This article picks up where How to Persist AI Agent Context Deterministically left off.

That post showed how to get context in. This one shows how to get the right context out.

Understanding the Agent Handoff Problem

A transcript records every approach the first agent tried, including those it abandoned. The second agent has no way to distinguish a decision from a dead end. It builds the wrong thing, confidently, and you pay for both runs.

That is the agent handoff problem. Many AI agent users land on a variation of this approach:

  1. Stop passing transcripts.
  2. Pass a structured payload with the decisions, constraints, and open questions.

This is pretty good advice, but it stops at the prompt boundary. The payload dies when the current context session ends, and it assumes both agents are yours.

In production, however, that may not be the case. The next agent in the flow could belong to a teammate or run under a different account. Either way, your decisions should be cleanly handed off.

Passing the transcript versus passing the decisions
Figure 1: Passing the transcript versus passing the decisions.

This kind of agent handoff flow needs:

  1. a store that outlives the session
  2. a barrier between what one account can read and what the team can read
  3. a rule in code for what crosses the line

Meko gives you all three.

Powered by YugabyteDB, Meko is an agent-native context engine for multi-agent AI systems that handles agent memory and its sharing process. Below, we show this in action, working with three small Python agents written with the Strands Agents framework that hand off a restaurant menu across two Meko user accounts (meko-agent-handoff).

Who Can Read What Your Agent Wrote?

Two kinds of Meko storage matter for a handoff:

  1. Memory is private to the Meko user account that wrote it. Every agent running under that account’s API key reads and writes the same memory. The agent_id on each memory says which agent wrote it; it does not partition anything. Two agents, one account, one memory.
  2. Shared Knowledge is readable by every member of a datapack. A memory gets there when someone promotes it. Promotion is one-way, meaning that no tool call reverses it.

Promotion is the gate: nothing crosses from one account to another until it happens. The promoting account must be an owner or maintainer of the datapack, and promotion can happen in three ways:

  1. A human in the Learnings tab of the Meko portal
  2. An agent with permission to call the MCP server promotion tool
  3. Your own code calling memory_promote

This post uses code because a rule in code runs the same way every time, and it can be read, reviewed, and changed like any other code.

Proving the Pattern in Code

In this example, a chef agent is deciding what will be on an upcoming menu. A kitchen manager agent reads those decisions and works out what to buy. A restaurant manager agent on a second Meko account (and invited to share the same datapack workspace) needs only what will be on the finished menu and doesn’t require the specifics around running the kitchen.

How a decision travels from one account to another in five runs
Figure 2: How a decision travels from one account to another, in five runs.

Each agent is a separate Python process with a fresh context. No model key is required for this sample (although the process is commented out in the file if you want to use one). The scripts ship with example answers in JSON, so that Meko is the only thing being tested. Here is what running each of the scripts does (in order):

  1. chef.py asks the model for three final dishes and one open question, then writes each finding to memory with memory_add.
  2. kitchen_manager.py, in the same account, reads those four records back with memory_search and writes three shopping-list records under its own agent_id.
  3. restaurant_manager.py, in the second account, runs the same two searches and gets zero results. Seven records exist on the datapack. The second account can see none of them.
  4. chef.py --promote applies a policy to every private record and promotes the ones that pass.
  5. restaurant_manager.py runs again and reads the three promoted decisions from knowledgebase_search.

Step 3 is the isolation proof. It runs before anything is shared, so you can see the wall your agents hit.

Why the Agent Uses a Direct Memory Tool Call

The persistence post logged every step with conversation_add_message. That tool stores a turn in the trace and runs memory extraction over the input side of it. The extractor rewrites what it reads and may keep nothing. This is right for a transcript, but wrong for a decision you need to find by exact wording and promote by its ID.

memory_add stores your text as one memory, as written:

def record_decision(client, convo_id: str, d: dict) -> None:
    """Turn one finding into a single line of text and store it as written."""
    text = f"{d['kind'].upper()}: {d['text']} REASON: {d['reason']}"
    if d.get("rejected"):
        text += f" REJECTED: {d['rejected']}"
    call(client, "memory_add", conversation_id=convo_id, text=text)

Every Meko call in the repo goes through call() in meko.py, which adds the agent_id and datapack_id. The conversation_id comes from conversation_create, which each script calls once at the start of a run to open its trace.

The chef agent still posts each run to the trace using conversation_add_message, with a short label in the input and the model’s full answer in the output. The order matters here. A question placed in input becomes a memory of its own and outranks the real decisions in search.

Separating the Signal From the Noise With Rules in Code

The chef agent promotes with a policy function:

def allowed_by_policy(text: str) -> tuple[bool, str]:
    """What the chef is willing to share. Open questions and the kitchen's notes stay private."""
    if text.startswith("OPEN_QUESTION"):
        return False, "open questions stay private until settled"
    if not text.startswith("DECISION"):
        return False, "only decided dishes go on the menu"
    if "REASON:" not in text:
        return False, "a decision without a reason is not ready to share"
    return True, "decided, with a reason"

chef.py --promote searches the first account’s memory, where the kitchen manager’s notes also live, applies this rule to every record, logs each verdict to the trace, and calls memory_promote with the approved memory IDs from memory_search.

This promotion action permanently moves these decisions inside of Meko from Memories to the Shared Knowledge area. The open question stays private to the account that created it until it is settled. The shopping list stays private to the kitchen and chef because the restaurant manager does not need it to do their work. Every promoted memory is still labeled chef:menu-demo, and the promotion is recorded in the trace, so anyone can later see which agent shared what and under which rule.

This is the same principle as the persistence post, just one step later. Whether or not a record is written is control flow. Whether a record is shared is also part of the control flow.

Try Context Handoff With Your Own Agents

Nothing here depends on Strands. The scripts are plain Python that call Meko’s MCP server, and the pattern applies to LangGraph, Pydantic AI, or a bare loop.

It also gives you token control.

When you are running hundreds of agents, the model is never asked whether to save or share anything, because the harness has already decided. Inference is bring-your-own: leave MODEL_PROVIDER empty to use the example answers, or set it to Anthropic, Amazon Bedrock, or Gemini through Google’s Gemini Enterprise Agent Platform (formerly Vertex AI). Meko never sees your model key.

Try it: clone the repo, create a datapack and an API key at cloud.mekodata.ai, share the datapack with a second account’s email, put that account’s API key in .env.teammate, and run the five steps. Watch step 3 return nothing. Watch step 5 return exactly the three records the policy allowed. Then look at your own multi-agent setup and ask which records are crossing between agents today without anyone deciding that they should.

Next steps:

  1. Get the sample repo (works with a free Meko account)
  2. Watch on demand: Shared Memory for AI Coding Agents, a live build of this repo
  3. Sign up free at mekodata.ai
  4. Read the docs
  5. Join the Discord server

If you get stuck on setup, drop a question in the #meko Discord channel. Feedback is welcome, and more sample apps (organized by use case) are on the way.

Heather Downing

Related Posts

Explore Distributed SQL and YugabyteDB in Depth

Discover the future of data management.
Learn at Yugabyte University
Get Started
Browse Yugabyte Docs
Explore docs
PostgreSQL For Cloud Native World
Read for Free