Blackboard Shared State
Also known as: shared workspace, scratchpad, artifact-passing
Give agents a shared external store to read and write instead of passing state through each other's message histories.
The problem
Multi-agent systems that communicate by passing messages hit two walls. State grows: every handoff carries the accumulated conversation, so context cost climbs with each hop until it exceeds the window. And state distorts: each agent summarizes what it received before passing it on, so the facts degrade like a game of telephone — by the fourth agent, a specific number has become "roughly" and a caveat has vanished entirely.
The pattern
Move shared state out of the message stream into an external store — files, a key-value namespace, a database table — that every agent can read and write by reference. Agents exchange pointers, not payloads. Each agent reads only the keys it needs, writes its findings back under a known key, and its context stays small regardless of how much total state the system holds.
Use when
- Several agents contribute to one growing artifact — a document, a dataset, a codebase
- State is too large to pass in context, or must survive beyond a single run
- Agents need to see each other's findings, which isolated workers cannot
- You want a durable, inspectable record of what the system knows at any moment
Avoid when
- Two agents with a simple linear handoff — a store is overhead for a single pass
- State is small and each agent needs all of it anyway
- Concurrent writers would collide and you are not prepared to handle conflicts
Tradeoffs
GainContext cost stops scaling with the number of hops or the size of shared state
CostCoordination moves to the store: schema, locking, and stale-read handling are now yours
GainState is durable and inspectable — you can see exactly what the system knows
CostAgents must be told what keys exist and be disciplined about reading before writing
GainAgents can genuinely build on each other's work rather than duplicating it
CostConcurrent writes to the same key need a conflict strategy, which agents handle badly
The name comes from a classic AI architecture: independent specialists reading and writing a common blackboard, each contributing when it recognizes something it can help with. The modern version is mundane and effective — a filesystem or a table that agents share.
Exchange references, not payloads
The discipline that makes this work: an agent's output into the message stream is a reference plus a one-line description, while the substance goes to the store. A worker that scraped forty pages writes the extract to `findings/vendor-a.md` and returns "wrote findings/vendor-a.md — pricing and SLA for Vendor A, 3 open questions". The orchestrator's context grows by twenty tokens instead of eight thousand.
BLACKBOARD_TOOLS = [
{"name": "bb_list", "description": "List keys, optionally under a prefix. Cheap — call it before assuming a key is missing."},
{"name": "bb_read", "description": "Read one key. Returns content and a version number."},
{"name": "bb_write", "description": "Write a key. Pass the version you read to avoid clobbering a concurrent write."},
{"name": "bb_append", "description": "Append to a key. Safe under concurrency; prefer this for logs and finding lists."},
]
class Blackboard:
def read(self, key: str) -> tuple[str, int]:
row = self.db.get(key)
return (row.content, row.version) if row else ("", 0)
def write(self, key: str, content: str, expected_version: int) -> WriteResult:
current = self.db.version_of(key)
if current != expected_version:
# Do not silently overwrite. Hand the conflict back as an observation.
return WriteResult(ok=False, error="version_conflict",
current_version=current,
hint="Re-read the key, merge your changes, and write again.")
self.db.put(key, content, version=expected_version + 1)
return WriteResult(ok=True, version=expected_version + 1)
def append(self, key: str, content: str) -> WriteResult:
self.db.append(key, content) # commutative; no conflict possible
return WriteResult(ok=True)Prefer append over write wherever the data allows it. Appends commute, so concurrent agents never conflict — and most multi-agent state (findings, decisions, logs) is naturally append-only.
Give the blackboard a schema
An unstructured shared store becomes a junk drawer within a few runs: agents invent key names, write in incompatible formats, and stop finding each other's work. Define the namespace up front and put it in the system prompt, so every agent knows where to look and where to write.
BLACKBOARD_SCHEMA = """Shared workspace layout. Read before you write.
objective the goal, written once by the orchestrator (read-only)
plan the current plan (orchestrator writes; others read)
findings/<topic> one file per topic; append your findings, never overwrite
questions open questions, append-only
draft the working artifact (writers coordinate via versions)
decisions append one line per decision with a short rationale
Before starting a subtask, bb_list findings/ to see what is already known.
Never duplicate an existing finding — cite its key instead."""Handling conflicts
Optimistic concurrency is the right default: read a version, write with that version, and get a conflict back if someone else wrote first. Return the conflict to the model as an observation with an explicit hint to re-read and merge. Agents handle this reasonably well when told; they handle silent last-write-wins clobbering not at all, because they never learn their work disappeared.
- Messages carry keys and one-line descriptions; the store carries the content
- Publish the namespace schema in every agent's system prompt
- Use append for anything commutative; reserve versioned writes for the shared draft
- Return version conflicts as observations with a merge hint, never clobber silently
- Snapshot the blackboard per run so a failed run is inspectable after the fact
A blackboard is shared mutable state, with all the hazards that implies. An agent that writes a wrong fact to `findings/pricing` has poisoned every agent that reads it afterwards. Keep provenance on every entry — which agent wrote it, when, from what source — so a bad fact can be traced and invalidated.