MemClaw · Multi-Agent Fleets

Multi-Agent Fleet with Shared Memory:
Stopping Constraint Contradictions Before They Ship

Five agents build a web page in sequence, each doing its own job correctly — and still ship a page that violates its own performance budget. Here’s the open-source reference fleet that stops it, and the architecture that makes upstream decisions bind downstream agents.

Caura.AI · 9 min read

TL;DR

  • Agents working in isolation can each do their job correctly and still ship a contradiction — a performance agent banning external scripts while an SEO agent loads a schema library from a CDN.
  • Fixing this needs three properties together: persistence, queryability, and enforcement. Prompt-stuffing and written conventions each give you one, never all three.
  • MemClaw’s pattern is recall before acting, write after deciding: every agent queries shared fleet memory via memclaw_recall before it acts and persists its own decisions via memclaw_writeonce it’s done.
  • The reference fleet memclaw-build-fleet proves it with five agents (Frontend, Performance, SEO, Code Review, Manager), each scoped to a specific recall/write allowlist enforced at the MCP tool-schema level, not by instruction.
  • Least privilege is enforced twice over: once by which tool schemas an agent’s model even sees, and again server-side via MemClaw’s trust_level, so a coding mistake in the pipeline can’t quietly grant an agent access it shouldn’t have.

What is a multi-agent fleet?

A multi-agent fleet is a group of LLM agents that each hold a narrow, well-defined role and work together on one larger task, instead of one large agent trying to do everything itself. The reference pipeline this post walks through is memclaw-build-fleet, an open-source repo built around five separate agents: one builds the page’s HTML and CSS, one audits performance, one handles SEO, one reviews the code, and one audits the whole run at the end. Each agent runs its own loop, calls its own set of tools, and hands off to the next agent in sequence.

Under the hood, each agent is just a model wired to a fixed agentic loop: it gets a system prompt defining its role, a list of tools it’s allowed to call, and it keeps calling those tools and reading the results until it decides its turn is done. What makes it a fleetrather than a set of unrelated scripts is that every agent shares the same task context — a single web build being reviewed — and the same downstream consumer of the final result.

Agents reach their tools through MCP (Model Context Protocol), an open standard that lets a model call external tools through a consistent interface. Instead of hard-coding what each tool does into every prompt, an MCP client asks the server for its available tools at the start of a session (tools/list), gets back live JSON schemas, and converts them into the function-calling format the model expects. That’s what keeps a fleet loosely coupled: adding a tool, or restricting an agent to a subset of tools, doesn’t require touching every agent’s code.

The piece that’s easy to skip when you first build a fleet is memory. Individually, each agent can be well-prompted and still produce a result that quietly conflicts with what another agent already decided — simply because neither agent had any way to know what the other did.

Why multi-agent pipelines contradict themselves

Splitting work across specialists mirrors how human teams operate, and for good reason: narrow tasks are easier to get right. But splitting the work introduces a new problem. Agents that cannot see each other’s decisions will contradict them, even when each agent performs its own task correctly.

Consider a concrete example. A performance agent audits a page and decides the JavaScript bundle is too heavy. It writes a rule: no external scripts.Later in the same pipeline, an SEO agent wants to add structured data and reaches for the obvious solution — a schema.org library loaded from a CDN. Both agents did their job well in isolation. Together, they just shipped a page that violates its own performance budget, and nothing caught it because nothing connected the two decisions.

This failure mode is hard to catch because no single agent’s output is wrong. The contradiction exists only between two decisions made by two agents that never communicated. When a pipeline runs end to end without a human reviewing every intermediate step, that kind of contradiction ships.

The real question isn’t how to make individual agents smarter. It’s an architecture question: how do decisions made early in a pipeline become constraints that later agents are actually forced to check?

Three properties real coordination needs

Coordinating a fleet requires a decision made by one agent to become visible, queryable, and binding for every agent that acts after it. Without that, coordination is just hope.

  • Persistence:a decision has to survive after the agent that made it finishes its turn — not just live in a conversation that ends when the agent stops responding.
  • Queryability:a later agent has to be able to find a relevant decision by asking a question, even if it doesn’t know the decision exists yet or phrases its query differently than the agent that stored it.
  • Enforcement:a constraint has to actually shape what a later agent can do — not sit nearby as a suggestion it might read or might skip.

Most pipelines get persistence for free: logs, transcripts, and databases all persist by default. Few get the second and third properties right, and that gap is exactly where contradictions like the JavaScript-bundle example slip through.

Why prompt-stuffing and conventions don’t fix it

Prompt-stuffing— pasting an earlier agent’s output into the next agent’s context — works for a single run but doesn’t scale: every new agent means manually wiring its output into every downstream prompt, and it doesn’t persist across runs. A pipeline running agents in parallel has no shared prompt to stuff in the first place.

A written convention— “check for conflicts with earlier agents before finalizing” — is advisory, not enforced. A model that skips it, misreads it, or behaves slightly differently on a different day produces the exact contradiction the instruction was meant to prevent. (We took this apart in Prompt Rules Aren’t Access Control.)

RequirementPrompt stuffingWritten convention
PersistenceNo — resets every runPartial — only if written down elsewhere
QueryabilityNo — requires manual wiring into each promptNo — relies on the model to search or remember
EnforcementNo — the model can still ignore itNo — purely advisory

Neither fix gives a later agent a reliable way to find and act on an earlier agent’s decision. What’s missing is a layer the agents query directly — one that exists independently of any single prompt or conversation.

How each turn runs: the MCP tool-call loop

Each agent’s turn is a fixed loop, not a single model call. It starts by asking the MCP server for its tools via tools/list, which returns each tool’s live JSON schema, then converts that into the function-calling format the model expects. The agent’s allowlist filters this list before the model ever sees it, so a tool like memclaw_writesimply isn’t present in the schema sent to a read-only agent.

all_tools = mcp.list_tools(agent_id=agent_id)
tools = [t for t in all_tools if t["name"] in allowed_set]

kwargs = {"model": model, "messages": messages}
if tools:
    kwargs["tools"] = tools
    if iterations == 1:
        kwargs["tool_choice"] = "required"

On the first turn, tool_choice is set to required, forcing the model to call at least one tool rather than answering from its own assumptions. When the model returns a tool call, the loop parses the arguments, executes the call against the MCP server, and appends the result back into the message history before looping again — until the model stops issuing tool calls or a fixed iteration cap is hit.

The loop also handles failure at the transport level. A 429rate-limit response triggers linear (incremental) backoff with jitter across four attempts — waiting roughly 20 seconds times the attempt number, with jitter applied. Malformed tool arguments are caught, logged, and fed back to the model as an error message rather than crashing the run, so one bad tool call doesn’t take down the rest of the pipeline.

Recall before acting, write after deciding

Shared fleet memory gives every agent a common place to write decisions and query them back out. The rule that makes it work is simple to state: recall before acting, write after deciding.

Recall before actingmeans an agent’s first move is a memclaw_recallcall, which runs a hybrid search: vector similarity against the memory’s embedding, keyword matching against its text, and a knowledge-graph traversal across entities extracted from prior memories. The hybrid approach is what lets an agent find a relevant decision even when its query is worded differently than the memory that stored it — a pure keyword search would miss a paraphrase, and a pure vector search can miss exact terms that matter, like a specific rule name.

Write after deciding means the agent persists its decision through a memclaw_write call, tagged with an agent ID, a fleet_id that namespaces the memory to this fleet, and a weight— a 0–1 importance hint the agent sets per decision. You can see the spread in the Prism dashboard: around 0.2 for a minor meta rule, up to 0.9 for the hard bundle constraint. (Writes can also carry a run_id for finer-grained per-run scoping.) Every memory written this way is available to any later memclaw_recall within the same fleet, regardless of which agent wrote it or when.

Because recall runs automatically at the start of every turn, and because the store persists independently of any single conversation, a constraint written early reaches every agent downstream without a human wiring the connection by hand.

Tracing the contradiction through the five-agent fleet

The fleet reviews a web build in sequence: a frontend agent, a performance agent, an SEO agent, a code-review agent, and a manager agent that audits the whole run. Each agent has a defined scope for what it can recall and what it can write.

Diagram of the five-agent MemClaw fleet pipeline — Frontend, Performance, SEO, Code Review, and Manager — running left to right over one shared fleet memory, each agent recalling before acting and writing after deciding.
Fig. 1— The five-agent pipeline. Every agent recalls shared fleet memory before acting and writes its decision back after.
AgentRecallsWrites
FrontendNothing (first in the pipeline)HTML5 + CSS structural decisions
PerformanceFrontend's decisionsBundle-size and image rules
SEOAll prior fleet memorySchema + metadata decisions
Code ReviewAll prior fleet memoryLGTM / block verdict, citing memory IDs
ManagerAll prior fleet memoryNothing (read-only audit)

Each agent’s recall and write scope maps directly to its tool allowlist, not to a convention it’s asked to follow:

ALLOWED_TOOLS = ["memclaw_recall", "memclaw_write"]           # SEO agent

ALLOWED_TOOLS = ["memclaw_list", "memclaw_stats",
                 "memclaw_insights", "memclaw_recall",
                 "memclaw_entity_get", "memclaw_keystones"]   # Manager, no write

The frontend agent’s allowlist contains only memclaw_write, so it has no mechanism to check prior memory even if instructed to — correct, since it runs first. Performance and SEO carry memclaw_recall and memclaw_write. The code-review agent additionally carries memclaw_insights.

The JavaScript-bundle example plays out differently inside this fleet. The performance agent decides the bundle is too heavy and writes a rule: no external scripts. When the SEO agent starts its turn, it recalls fleet memory first, before deciding how to add structured data. That recall surfaces the performance agent’s rule directly, so the SEO agent can choose inline JSON-LD instead of a CDN-hosted library. Queryability makes the constraint available at the exact moment the SEO agent needs it.

Constraint propagation diagram: the Performance agent writes a 'bundle < 50 KB, zero external JavaScript' rule to MemClaw fleet memory; the SEO agent recalls it and decides on inline JSON-LD only; the Code Review agent recalls both and returns LGTM with no contradictions found.
Fig. 2— The performance agent’s rule reaches the SEO agent through shared memory, not hard-coded coordination — and the code reviewer confirms no contradiction.

Honest caveat:whether the model acts on the constraint is still probabilistic, not guaranteed. Running this exact repo repeatedly can still produce a different verdict (LGTM vs. BLOCK) across identical runs. The memory layer removes the “the agent never saw the constraint” failure mode — not model variance itself.

For cross-agent contradiction detection, the code-review agent recalls the full fleet’s memory directly across separate memclaw_recallcalls — one each for frontend, performance, and SEO decisions — and reasons over all the results before writing its verdict. memclaw_insightsat its default scope (“agent”) analyzes only the calling agent’s own memories, adding a supplementary staleness check on top of that recall. Pointed at the whole fleet instead (scope "fleet" or "all"), it surfaces cross-agent contradictions and emergent patterns directly — which is exactly how the manager agent uses it. Either way, insights isn’t purely passive: it persists its findings back as insight-type memories.

Least privilege: tool allowlists + trust levels

Least privilege here is enforced through two mechanisms stacked on top of each other: tool allowlists at the client level, and trust levels enforced server-side by MemClaw itself.

The allowlist determines which tool schemas an agent’s model ever sees. Trust level is what MemClaw checks on its own end, independent of what the client sends — and it gates on scope, not just on the tool being called. Reads that stay within an agent’s own memories (scope="agent", the default) need only the default trust_level >= 1. Reading across the whole fleet — scope="fleet" or "all" — raises the bar to trust_level >= 2. That’s why the manager, which enumerates and analyzes every agent’s memories with memclaw_stats, memclaw_list, and memclaw_insights, must be promoted to trust_level 2, while the per-agent recalls earlier in the pipeline run at the default level. Trust is set once per agent through an admin API call and persists across every future run:

curl -X PATCH \
  "https://memclaw.net/api/agents/manager/trust?tenant_id=YOUR_TENANT_ID" \
  -H "X-API-Key: $MEMCLAW_API_KEY" \
  -d '{"trust_level": 2}'

Managed vs. OSS: this reference fleet runs against managed MemClaw — a free memclaw.net account — and leans on two managed-tier capabilities: the Prism dashboard, and elevated trust for the manager’s fleet-wide stats/insights reads. The MemClaw core is Apache-2.0 and self-hostable, but this pipeline is wired to the cloud.

An agent without the required trust level gets a 403from MemClaw directly, regardless of what its local allowlist permits — so the isolation guarantee doesn’t depend on the pipeline’s own code behaving correctly. It’s enforced by the memory platform itself. Three boundaries stack:

  • visibility is the finest-grained control on memclaw_write: set it to scope_agent to restrict a memory to the writing agent only (vs. scope_team / scope_org) — useful for per-agent secrets that shouldn’t propagate downstream. It’s a value of the visibility parameter, not a separate flag.
  • fleet_id is the mid-level boundary, namespacing every memory to the fleet that wrote it, so multiple fleets can share one tenant without their memories mixing.
  • Tenant IDis the outermost boundary, enforced through row-level security at the storage layer — the one guarantee that holds regardless of any agent or fleet configuration.

This is why the manager’s zero-write audit is a claim you can verify two ways: by reading its tool-call log, where memclaw_writenever appears, and by confirming its trust level and allowlist independently — since both layers would have to fail for an unauthorized write to succeed. It’s the same deterministic-policy principle behind keystones.

Applying the pattern to other pipelines

Web-page review is just the example this fleet happens to use. The underlying pattern applies to any pipeline where multiple agents make sequential or parallel decisions that must not conflict:

  • Compliance-review chains, where a legal agent’s ruling on data handling has to constrain what a later engineering agent is allowed to build.
  • Infrastructure-change pipelines, where a security agent’s decision to block a port has to survive into whatever a deployment agent does next.
  • Content pipelines, where a brand or tone agent’s decisions have to propagate to every downstream agent that generates copy.

Adapting the fleet doesn’t require redesigning the coordination logic. It requires defining a new set of agent roles, giving each one a recall/write scope appropriate to its job, and registering them in the same pipeline structure already proven out here.

Conclusion

Multi-agent contradictions aren’t a prompting problem — they’re a memory-architecture problem. Bigger context windows and written conventions can’t give you persistence, queryability, and enforcement all at once; a shared, queryable memory layer with recall-before-acting and write-after-deciding built in can. Constraints written early are automatically visible to every agent downstream, and least privilege is enforced twice over — at the tool schema and at the server — so no agent can act on, or write, more than its role allows.

The reference pipeline is meant to be cloned and adapted, not read as a finished product. Pull the repo, run it against your own MemClaw tenant, and swap the frontend/performance/SEO/code-review/manager roles for whatever specialists your pipeline actually needs. Every memory the fleet writes along the way shows up in the Prism dashboard, so you can watch constraint propagation happen rather than take it on faith.

MemClaw Prism dashboard for one fleet run: rows for performance-agent, seo-agent, frontend-agent and code-review-agent with type, status (active / conflicted), a weight column showing values from 0.2 to 0.7, recall counts, and titles like 'Inline bundle size limit: 50KB' and 'MemClaw landing page uses inline JSON-LD under 50KB'.
The Prism dashboard for one fleet run — every agent’s decisions, with weight and recall counts, in one governed store. Note the conflicted row the fleet surfaced on its own.

FAQ

What's the difference between memclaw_recall and memclaw_insights?

memclaw_recallis a hybrid search — vector similarity, keyword matching, and knowledge-graph traversal — that an agent calls to actively pull relevant memories before acting. memclaw_insights is a pattern-analysis tool (focus modes: contradictions, failures, stale, divergence, patterns, discover). At its default agent scope it needs only trust_level >= 1and looks at the calling agent’s own memories, writing findings back as insight memories; at fleet/all scope it needs trust_level >= 2 and reasons across the whole fleet.

Why does the Manager agent need trust_level 2?

Because those tools gate on scope, not just on being called. memclaw_stats, memclaw_list, and memclaw_insights over the whole fleet (scope=fleet/all) require trust_level >= 2 server-side, and the manager reads across every agent — so it’s promoted to trust_level 2. Agent-scoped reads earlier in the pipeline need only the default trust_level >= 1. Tool allowlists control what the model can see; the trust check is enforced independently by the server, so an agent gets a 403 even if its local allowlist would technically permit the call.

What's the difference between MCP and traditional function calling?

Traditional function calling requires you to hard-code each tool’s schema into your prompt or SDK call. MCP standardizes tool discovery and invocation behind a tools/list and tools/callinterface, so any MCP-compatible client can query a server’s available tools at runtime and convert them into the model’s function-calling format automatically — without custom integration code per tool.

How do vector search and knowledge-graph retrieval differ in agent memory?

Vector search finds memories by semantic similarity to a query embedding, which is good at catching paraphrases but can miss exact terms. Knowledge-graph retrieval traverses explicit entity-relationship links extracted from prior memories, which is better at surfacing structured facts and named entities. Hybrid systems combine both with keyword matching to reduce the blind spots either method has on its own.

What causes 429 rate-limit errors in multi-agent pipelines, and how should retries be handled?

429s happen when a pipeline’s aggregate request rate to an LLM provider exceeds the account’s quota — more likely in multi-agent systems since several agents may call the same gateway in quick succession. The standard fix is linear (incremental) backoff with jitter, retrying a fixed number of times with increasing wait intervals, so a temporary quota spike doesn’t crash the whole run.

Clone the reference fleet.

Run it against your own MemClaw tenant, then swap in your specialists.

MemClaw is governed shared memory for AI agent fleets — multi-agent, multi-fleet, multi-tenant, with permissions and audit trails. Built by Caura.ai.