TAI BUI
Back to curriculum
BuildPython

Shared Memory and Blackboard Patterns

Two approaches coexist in 2026 multi-agent systems: the **message pool** (everyone sees everyone's messages, as in AutoGen GroupChat or MetaGPT) and the **blackboard with subscription** (agents subscribe to relevant events, as in Context-Aware MCP or the Matrix framework). Both hold the stateful part of a multi-agent system, so both are where the interesting bugs live. The reference failure mode is **memory poisoning**: one agent hallucinates a "fact," other agents treat it as verified, and accuracy decays gradually, which is much harder to debug than an immediate crash. This lesson builds both structures from stdlib, injects a poisoning attack, and walks through the three mitigations that work in production, two of them in code.

TIME: ~75 minutesPREREQUISITES: Phase 16 · 04 (Primitive Model), Phase 16 · 09 (Parallel Swarm Networks)

Learning Objectives

  • Choose between a full message pool and a blackboard with subscription for a given agent count, role mix, and conversation length.
  • Trace how one hallucinated figure becomes a "fact" in downstream agents' reasoning through shared state.
  • Implement provenance-tagged writes, topic-keyed pub/sub, and a read-only verifier in stdlib Python.
  • Apply the three mitigations (provenance, append-only writes, an unwritable verifier) to a shared-memory design.
  • Pick a write-contention pattern: sequential writer, optimistic concurrency, or topic partitioning.

Problem

Multi-agent systems need a place for agents to share facts. You can pass everything in messages, but that reinvents shared state with extra copying. You can give everyone a global log, but global logs grow without bound and poison easily. You can project a view per agent, which scales but costs you a schema.

When one agent hallucinates and writes the hallucination to shared state, the agents downstream read it as fact. By the time a human notices, the reasoning chain is five steps deep and the root cause is the third message ever written. Accuracy decay is harder to debug than a crash.

This is memory poisoning. It is the second-most-documented failure family in the MAST taxonomy (Cemri et al., arXiv:2503.13657), and it is structural: a shared-memory design without provenance and an unwritable verifier will eventually exhibit it.

Warm-up0/3
1. In the four-primitive model from Phase 16 · 04, which primitive holds state that persists across agent turns?Warm-up
Four boxes labelled Agent, Handoff, Orchestrator, Shared state, with a dashed turn-1/turn-2 boundary drawn under them and no indication of which box survives the boundary.
Illustrative; names are the four primitives from Phase 16 · 04.
2. Per Phase 16 · 09, why does a central supervisor limit a swarm as workers are added?Warm-up
A supervisor hub with eight worker circles around it, each joined to the hub by a line, next to a note that workers keep being added (6, 8, 12...).
Illustrative topology from Phase 16 · 09.
3. Which situation from Phase 16 · 09 fits a swarm better than a supervisor?Warm-up
Two topology thumbnails side by side: a Pipeline of three boxes in a strict left-to-right chain, and a Swarm hub with five independent worker circles around it.
Illustrative topologies from Phase 16 · 09.
Check: Problem0/1
1. What is memory poisoning?Define
Three boxes in a row, Agent A writes a claim, Agent B reads A's entry and writes its own, Agent C reads B's entry and writes a verdict, joined by arrows through one shared store.
Illustrative three-agent chain; no claim is marked right or wrong.

Concept

The two main topologies

Full message pool. Each agent reads the whole pool. AutoGen GroupChat and MetaGPT use this. It is simple and easy to inspect, but it stops scaling around 10 agents because each agent's context fills with other agents' work.

agent-A ──write──▶ ┌────────────────┐ ◀──read── agent-D
                   │ message pool   │
agent-B ──write──▶ │                │ ◀──read── agent-E
                   │ (global log)   │
agent-C ──write──▶ └────────────────┘ ◀──read── agent-F

Blackboard with subscription. Agents declare interest in topics; the substrate routes only relevant messages. CA-MCP (arXiv:2601.11595) and the Matrix decentralized framework (arXiv:2511.21686) use this. It scales further, at the price of designing a schema up front so the subscriptions mean something.

                   ┌─ topic: prices ──┐
agent-A ──pub────▶ │                  │ ──▶ agent-D (subscribed)
                   ├─ topic: orders ──┤
agent-B ──pub────▶ │                  │ ──▶ agent-E (subscribed)
                   ├─ topic: alerts ──┤
agent-C ──pub────▶ │                  │ ──▶ agent-F (subscribed)
                   └──────────────────┘

When each wins

  • Full pool wins with few agents (< 10), mixed roles, and a short conversation. Working out who said what is easy when everyone sees the same log.
  • Blackboard wins with many agents of the same role (swarms) and a long-running conversation. Routing cuts token cost and keeps unrelated work out of each context.

Production systems often mix: a small full pool at the top (planning layer), blackboards below (worker layer).

Memory poisoning, in one scenario

Three agents work on a research task: A retrieves, B summarizes, C analyzes.

  1. A fetches a page and writes a message to shared state: "The study reports a 42% accuracy improvement."
  2. The fetched page actually said "4.2% improvement." A hallucinated a decimal.
  3. B, reading shared state, writes: "Large 42% accuracy gain reported (source: A)."
  4. C, reading shared state, writes: "Recommend adoption. A 42% lift is transformative."
  5. The final report cites a 42% number that never existed.

Nothing crashed and no test failed. The system "worked," and the hallucination still crossed from A's context into the reasoning of each downstream agent through shared state.

Why this is structural

Without shared state, agent A's hallucination stays in A's context. Downstream agents would re-fetch or re-derive and might catch the error. With naive shared state, A's context becomes everyone's context, and the hallucination is laundered into fact.

The problem is not shared state itself. It is shared state without provenance and without an independent verifier. Three mitigations address this:

  1. Attribute provenance on every write. Each entry in shared state records who wrote it, when, under what prompt, and (if applicable) what source the agent cited. Downstream agents read with skepticism keyed to provenance.
  2. Version writes; treat them as append-only. A correction is a new entry that supersedes the old, not an in-place update. The audit trail is preserved.
  3. Keep at least one agent that cannot write to shared state. A read-only verifier agent samples entries, re-fetches sources, and flags inconsistencies. Because it cannot write to the pool, it cannot be poisoned by the pool.

Blackboard precedent (Hayes-Roth, 1985)

The blackboard pattern predates LLM agents by four decades. Hayes-Roth (1985, "A Blackboard Architecture for Control") described specialist Knowledge Sources that observe a global blackboard, contribute partial solutions, and trigger other sources. The 2026 blackboard (CA-MCP, Matrix) is the same pattern with LLM agents as Knowledge Sources and JSON blobs as partial solutions. The old literature already documents solutions to write contention, opportunistic control, and consistency, which modern systems rediscover.

Projection vs full view

A pure blackboard gives every subscriber the same projection (topic-scoped). A more aggressive design is per-agent projection: each agent gets a view customized to its role. LangGraph's state reducers are the canonical 2026 implementation: the reducer function folds global state into a role-specific slice.

Per-agent projection scales further but needs a schema. Without one, you rebuild ad-hoc projection in each agent's prompt.

Write-contention patterns

Multiple agents writing simultaneously is a concurrency problem, not just an LLM problem. Three patterns work:

  • Sequential writer (single producer). All writes go through one coordinator agent that serializes. Simple, but a bottleneck.
  • Optimistic concurrency with versioning. Each entry has a version; writers fail on version mismatch and retry. Classic database technique.
  • Topic partitioning. Different agents own different topics. No cross-topic contention. Requires designed partition boundaries.

Most 2026 frameworks default to sequential writer because LLM calls are slow enough that contention is rare and the bottleneck does not hurt.

The unwritable verifier

The most load-bearing mitigation is the read-only verifier. Implementation rules:

  • Verifier shares state with the team (reads the blackboard or pool).
  • Verifier has no write handle to shared state, only to a separate verification channel.
  • Verifier independently fetches sources cited in writes. Flags disagreement.
  • Verifier's own outputs are routed to a human or a separate decision agent, never fed back into the pool.

Without this separation, the verifier's outputs become new entries in the pool, which means a poisoned pool poisons the verifier, which poisons its verifications.

Check: Concept0/24
1. What is a message pool in a multi-agent system?Define
Three agent boxes on the left (agent-A, agent-B, agent-C) each with an arrow into one shared box labelled message pool, and three agent boxes on the right (agent-D, agent-E, agent-F) each with an arrow out of the shared box.
Illustrative agent names.
2. What is a blackboard in the sense this lesson uses the word?Define
Three rows, one per topic (prices, orders, alerts), each showing a publisher box, the topic name in an outlined chip, a dashed line, and a subscriber box.
Illustrative agent and topic names.
3. What does provenance mean for an entry in shared state?Define
A card listing four fields of one shared-state entry: writer, timestamp, prompt_hash, source_uri, with made-up example values, next to a dashed box asking what this group of fields is called.
Illustrative field values.
4. In an append-only shared log, how is a mistaken entry corrected?Define
One log entry, entry #0 holding v1 of a figure, next to a dashed box asking how entry #1 would correct it.
Illustrative entry content.
5. What makes a verifier agent "unwritable"?Define
A shared pool box and a verifier box. An arrow labelled reads goes from the verifier to the pool. A dashed line back from the verifier to the pool is marked writes findings to: with a question mark.
6. What is a projection in shared-memory design?Define
A global state box, an arrow into a dashed box with a question mark, and an arrow out to a box labelled one agent's view.
7. In Hayes-Roth's 1985 blackboard architecture, what is a Knowledge Source?Define
A central box labelled the blackboard with three neutral participant boxes around it, each joined to the board by a line, from Hayes-Roth 1985.
Labels are neutral placeholders.
8. A team runs 4 heterogeneous agents (planner, coder, tester, writer) on a short task. Which shared-state topology fits, per When each wins?Explain
Four role boxes (planner, coder, tester, writer) above a note that this is a short task with few agents of mixed roles, and a dashed box asking what shared-state shape fits.
9. Agent A writes "42%" to shared state although its source said "4.2%". Which set of mitigations in Concept (Why this is structural) targets this failure?Explain
Two cards side by side: an entry agent A wrote reading content 42%, and the source text reading fetched text 4.2%, with a not-equal sign between them and a dashed box below asking what fix applies.
10. Why must the read-only verifier's findings go to a separate channel and not into the shared pool? See The unwritable verifier.Explain
A shared pool box and a verifier box with a reads arrow from verifier to pool, and a dashed line back from verifier to pool labelled findings into the pool with a question mark.
11. Why does a blackboard cost fewer tokens than a full pool for a swarm of same-role agents?Explain
Five same-role agents drawn twice: as a full-pool hub-and-spoke on the left and as a three-topic blackboard on the right, with a question about which shape reads fewer tokens per agent.
12. Without shared state, one agent's hallucination stays in its own context. What changes with naive shared state?Explain
Two panels: agent A's context on its own, and agent A's context next to a dashed box asking who else sees it, under headings without shared state and with naive shared state.
13. Why does topic partitioning remove write contention between agents?Explain
Three topics (billing, shipping, inventory), each with a box on the left showing a question of how many agents might write to it, joined by a dashed line.
Illustrative topic names.
14. Append-only writes do not stop a bad entry from being written. Why do they still help against poisoning?Explain
Three entries in a row, entry #0 marked mistake, entries #1 and #2 plain, next to a dashed box asking whether the mistake can be traced.
Illustrative entry labels.
15. How does per-agent projection differ from a plain topic blackboard?Explain
One topic box (orders) with arrows to two subscriber boxes, each followed by a dashed box asking whether the view each subscriber gets is the same.
Illustrative topic and subscriber names.
16. Which write-contention pattern do most 2026 frameworks default to, per Write-contention patterns?Explain
Three boxes labelled sequential writer, optimistic concurrency, topic partitioning, under a note that LLM calls are slow, with a question about which one is the default.
17. Two writers both read an entry at version 3 and each submit an update. Under optimistic concurrency with versioning, what happens?Apply
One entry at version 3 with two writer boxes each pointing an arrow at it, and a question asking what happens when both submit an update.
18. A team lets its verifier write findings back into the shared pool. Later, a poisoned entry gets "confirmed" by the verifier. Which rule was broken?Analyze
A shared pool and a verifier box, with a reads arrow one way and a writes a finding back into the pool arrow the other way, and text saying a poisoned entry later gets confirmed by the verifier.
19. An agent "corrects" a wrong figure by editing its entry in place. Weeks later an auditor cannot tell what the entry said before. Which mitigation was skipped?Analyze
One entry box showing figure 4.2 percent, an arrow labelled edited, and the same entry box now showing figure 42 percent in its place, with a note that an auditor later cannot tell what it said before.
Illustrative figures.
20. 40 scraper agents share one full message pool. After an hour, costs climb and agents miss instructions. Which diagnosis fits?Analyze
A 40-square grid of scraper agents all connected to one message pool box, with a note that costs climb and agents miss instructions after an hour, asking why.
21. A developer says topic partitions make poisoning a non-issue because agents only read their own topics. What is wrong with that claim?Analyze
A quoted developer claim that topic partitions make poisoning a non-issue, above an owner box writing into a topic box named orders that fans out with dashed lines to three subscriber boxes.
22. You must coordinate 40 same-role scraper agents running for hours, and a few of them only care about price changes. Which design does Concept recommend?Design
A 40-square grid of scraper agents with a few outlined and labelled a few only care about price changes, next to a dashed box asking for a design.
23. A planning layer of 4 mixed-role agents hands work to 60 identical workers. Which shared-state layout fits best?Design
Four planner role boxes above two dashed placeholder rows, one marked for the planner layer and one marked for the worker layer of 60 agents.
24. Six agents each own a separate data domain and never write outside it. You want no serializing bottleneck and no retries. Which contention pattern fits?Design
Six agent boxes in two rows, each labelled agent A through F and owning its own numbered domain, with a note that the team wants no serializing bottleneck and no retries.

Build It

code/main.py implements both topologies in stdlib Python, plus a toy poisoning attack and a read-only verifier.

  • MessagePool: a thread-safe, append-only log of entries with full read-out and a flag method for annotating an entry after the fact.
  • Blackboard: topic-keyed pub/sub. Subscribers register a callback per topic, and publish calls only the callbacks for that topic.
  • ProvenanceEntry: each write records writer, timestamp, prompt hash, and source URI, with optional supersedes and flags fields.
  • retrieval_agent, summarizer_agent, analyst_agent: a three-agent research task where the retriever turns "4.2%" into "42%" and the other two build on it.
  • verifier_agent: a read-only agent that re-fetches each cited source and returns findings. It does not write to the pool, so the caller decides what to do with them.

Run:

python3 code/main.py

Expected output:

  • Run 1 (no verifier): the hallucinated 42% propagates through the summary into the analyst's verdict, and no alarm is raised.
  • Run 2 (with verifier): the verifier flags the retriever's entry as a mismatch with its source, and the printout marks it FLAGGED. The toy analyst does not read flags, so its verdict is unchanged. The flag is there for a downstream agent or a human to act on.
  • Blackboard demo: price subscribers receive entries 0 and 1, alert subscribers receive entry 2, and neither sees the other's topic.
Check: Build It0/6
1. A reviewer opens an entry that has a prompt_hash and a source_uri. What do those two fields let the reviewer do?Explain
A real entry card from main.py's Run 1 showing writer retriever, its prompt_hash and source_uri, next to a dashed box asking what those two fields let a reviewer do.
prompt_hash and source_uri are the real values main.py computed for this entry.
2. After running Build It, what differs between Run 1 and Run 2 in the final output?Apply
Two columns, Run 1 and Run 2, each listing the same three writer entries by id and role, with a dashed box below asking what differs in the final printout.
Both runs hallucinate the same figure on the same source.
3. In the blackboard demo, ids 0 and 1 are published on prices and id 2 on alerts. What do the two subscribers receive?Apply
Three publishes in order, id 0 to topic prices, id 1 to topic prices, id 2 to topic alerts, with two dashed boxes asking what the prices and alerts subscribers each receive.
4. retrieval_agent runs on paper-1 with hallucinate=False, then the summarizer and the analyst run. What verdict does analyst_agent write?Apply
A setup card showing retrieval_agent called on paper-1 with hallucinate=False and the real fetched text, next to a dashed box asking for analyst_agent's eventual verdict.
Fetched text is the real string from main.py's FAKE_SOURCES.
5. retrieval_agent runs on paper-2 with hallucinate=True. What does verifier_agent return?Apply
A setup card showing retrieval_agent called on paper-2 with hallucinate=True and the real fetched text, next to a dashed box asking what verifier_agent returns.
Fetched text is the real string from main.py's FAKE_SOURCES.
6. In the Build It demo, the summarizer's copy of 42% is not flagged even though it repeats the bad figure. Why?Analyze
Two entry cards, entry 0 from retriever with source_uri filled, entry 1 from summarizer with source_uri empty, next to a dashed box asking which entries get checked.
Both entries repeat the same bad figure.

Use It

outputs/skill-memory-auditor.md is a skill that audits any multi-agent system's shared-memory design for provenance, versioning, and verifier separation. Run it on new multi-agent architectures before production.

Ship It

For any shared-memory design:

  • Record provenance on each write: (writer, timestamp, prompt_hash, tool_calls_cited, source_uri).
  • Make the log append-only. Corrections are new entries that reference the superseded one.
  • Deploy at least one read-only verifier agent with independent source access.
  • Route verifier output to a separate channel, not back into the shared pool.
  • Log the ratio of writes that are supersessions, since a rising ratio is early evidence of hallucination patterns.
Check: Ship It0/2
1. A rising share of writes that supersede earlier entries shows up in your logs. How does Ship It say to read that?Explain
A bar chart with four unlabeled-value bars rising across week 1 to week 4, showing the share of writes that supersede an earlier entry, with a question about how to read the trend.
Illustrative trend; no specific values are given in the lesson.
2. Design shared memory for a research team that must attribute every figure, keep the history of corrections, and have an independent check. Which design meets all three?Design
A three-item checklist (attribute every figure, keep correction history, have an independent check) next to a dashed box asking what design satisfies all three.
Author's Note

I'd run main.py and read the two runs side by side before touching the theory. The retriever flips 4.2% to 42% with a single replace call, and you can watch that string get copied into the summarizer's entry and then into the analyst's verdict. The summarizer and analyst do nothing wrong given their input, which is the whole problem.

One thing to notice in run 2: the verifier only checks entries that carry a source_uri. It flags the retriever's entry and leaves the summarizer's copy of the number unflagged. The analyst doesn't read flags either, so its verdict still says adopt. A flag only helps if something downstream acts on it, and in the toy nothing does. I'd treat that as the real exercise: make the analyst refuse to build on flagged entries.

I also left supersedes unused in the demo. ProvenanceEntry has the field and MessagePool.write accepts it, but nothing calls it with a value, so append-only corrections are yours to wire up. The blackboard demo is only about routing, with no poisoning or verifier in it. My bet is that the full pool is the right place to start with a handful of agents, and I'd move to topics once context bloat shows up.

Exercises

  1. Run code/main.py. Confirm run 1 propagates the hallucination and run 2 catches it.
  2. Add a second hallucination: agent B invents a dataset size. The verifier should catch both without being hand-tuned for either.
  3. Switch the full pool to a blackboard with topic partitions (prices, summaries, analyses). Which poisoning scenarios does topic partitioning make harder to pull off, and which does it not help with?
  4. Read Hayes-Roth (1985, "A Blackboard Architecture for Control"). Identify two control patterns from the paper not discussed in this lesson that 2026 systems would benefit from.
  5. Read CA-MCP (arXiv:2601.11595). Map its Shared Context Store to either the MessagePool or Blackboard class in code/main.py. Which primitives does CA-MCP add on top?

Key Terms

TermWhat people sayWhat it actually means
Message pool"Shared chat history"Append-only log that every agent reads. Full transparency, poor scaling.
Blackboard"Shared workspace"Topic-keyed pub/sub. Agents subscribe to relevant topics. Scales farther.
Provenance"Who wrote what"Metadata on each write: writer, timestamp, prompt, sources.
Memory poisoning"Hallucinations spreading"One agent's error enters shared state, downstream agents adopt it as fact.
Append-only"No in-place updates"Corrections are new entries that supersede. Preserves audit trail.
Unwritable verifier"Independent auditor"Read-only agent that re-fetches sources and flags inconsistencies.
Projection"Scoped view"Per-agent view computed from global state. LangGraph reducers are the canonical case.
Knowledge Source"Specialist agent"Hayes-Roth's 1985 term for a blackboard participant.

Further Reading

Code

Ships With