How to Configure the Blackboard Pattern for Multi-Agent Coordination in Embabel-Agent

The Embabel-Agent framework implements a shared mutable state called a blackboard that enables loose-coupled coordination between agents through the classic blackboard architectural pattern.

The embabel/embabel-agent repository provides a Kotlin-based framework for building autonomous agent systems. When you configure the blackboard pattern for multi-agent coordination, you create a shared key-value store that eliminates hard-coded dependencies between agents, tools, and interceptors during a single process execution.

Core Blackboard Components

The framework exposes the blackboard pattern through several key interfaces and implementations defined in the embabel-agent-api module.

Blackboard Interface – Defined in com.embabel.agent.core.Blackboard within [Blackboard.kt](https://github.com/embabel/embabel-agent/blob/main/embabel-agent-api/src/main/kotlin/com/embabel/agent/core/Blackboard.kt), this contract specifies a mutable key-value store that also supports typed objects. It serves as the primary abstraction for shared state.

InMemoryBlackboard – The default implementation located at com.embabel.agent.core.support.InMemoryBlackboard in [InMemoryBlackboard.kt](https://github.com/embabel/embabel-agent/blob/main/embabel-agent-api/src/main/kotlin/com/embabel/agent/core/support/InMemoryBlackboard.kt). This class provides an in-process, mutable store used by the framework and test suites.

BlackboardProvider – A Service Provider Interface (SPI) found in com.embabel.agent.spi.BlackboardProvider at [BlackboardProvider.kt](https://github.com/embabel/embabel-agent/blob/main/embabel-agent-api/src/main/kotlin/com/embabel/agent/spi/BlackboardProvider.kt). This extension point allows you to plug in custom implementations backed by Redis, databases, or distributed caches.

ProcessOptions – The configuration builder located in com.embabel.agent.core.ProcessOptions (demonstrated in [ProcessOptionsBuilderTest.kt](https://github.com/embabel/embabel-agent/blob/main/embabel-agent-api/src/test/kotlin/com/embabel/agent/core/ProcessOptionsBuilderTest.kt)) that accepts a specific blackboard instance when launching an agent run.

BlackboardTools – A utility class at com.embabel.agent.tools.blackboard.BlackboardTools in [BlackboardTools.kt](https://github.com/embabel/embabel-agent/blob/main/embabel-agent-api/src/main/kotlin/com/embabel/agent/tools/blackboard/BlackboardTools.kt) providing ready-made tools (set, get, publish) that agents invoke to manipulate the blackboard.

BlackboardFormatter – An observability utility in com.embabel.chat.agent.BlackboardFormatter within [BlackboardFormatter.kt](https://github.com/embabel/embabel-agent/blob/main/embabel-agent-api/src/main/kotlin/com/embabel/chat/agent/BlackboardFormatter.kt) that formats blackboard contents for tracing and logs.

How the Blackboard Enables Multi-Agent Coordination

The blackboard architectural pattern facilitates coordination through four primary mechanisms:

Shared Context – Every action in a turn reads from or writes to the same blackboard instance. For example, an intent-classification tool can execute set("intent", "support"), and a subsequent knowledge-retrieval tool can call get("intent") to determine which documents to fetch.

Typed Values – The method blackboard.getValue(name, type, agent) returns values cast to the expected Java or Kotlin type. This eliminates manual casting and reduces runtime errors when agents exchange complex objects.

Implicit Propagation – The blackboard automatically becomes part of the observability payload. Tracing utilities extract values such as user.id and conversation.id directly from the blackboard, ensuring consistent telemetry across all agents without explicit logging code.

Extensibility – By providing a BlackboardProvider bean, you replace the in-memory store with a distributed cache. All agents sharing the same backing store—whether in the same process or across microservices—see identical state, supporting true multi-agent collaboration.

Step-by-Step Configuration

The following sections demonstrate how to configure the blackboard pattern for multi-agent coordination using the Embabel-Agent API.

Create or Obtain a Blackboard

Use the default in-memory implementation for single-process coordination:

import com.embabel.agent.core.support.InMemoryBlackboard

val blackboard = InMemoryBlackboard()

Alternatively, load a custom implementation via the ServiceLoader mechanism if you have registered a BlackboardProvider:

import com.embabel.agent.spi.BlackboardProvider
import java.util.ServiceLoader

val blackboard = ServiceLoader.load(BlackboardProvider::class.java)
    .first()
    .blackboard()

Wire the Blackboard into the Process

Inject the blackboard instance when building ProcessOptions to ensure all agents in the run share the same state:

val process = ProcessOptions.builder()
    .withAgent(myAgent)                 // your Agent instance
    .withBlackboard(blackboard)         // inject the shared blackboard
    .build()
    .start()

All agents created from this process instance receive the same blackboard reference.

Use Blackboard-Aware Tools

Configure agents with tools that read from and write to the shared state:

import com.embabel.agent.tools.blackboard.BlackboardTools

val tools = listOf(
    BlackboardTools.publish { blackboard, content ->
        blackboard.set("intent", content)          // publish classification result
    },
    BlackboardTools.get { blackboard, name, type ->
        blackboard.getValue(name, type, myAgent)   // read typed value
    }
)

val runner = AgentInvocation.builder()
    .process(process)
    .tools(tools)
    .build()

runner.invoke(prompt = "I need help with my account")

The publish tool writes intermediate results, while downstream tools read these values to adjust their behavior.

Replace with a Distributed Store (Optional)

Implement BlackboardProvider to enable cross-process coordination:

import com.embabel.agent.spi.BlackboardProvider
import com.embabel.agent.core.Blackboard

class RedisBlackboardProvider : BlackboardProvider {
    override fun blackboard(): Blackboard = RedisBlackboard(redisClient)
}

Register the provider by creating a file at META-INF/services/com.embabel.agent.spi.BlackboardProvider containing the fully qualified class name. Any process loading this provider receives a RedisBlackboard, enabling separate microservices to act as distinct agents while sharing the same Redis-backed state.

Observe Blackboard Contents

When tracing is enabled, the BlackboardFormatter automatically serializes blackboard entries into observability outputs:


blackboard: intent=support, confidence=0.95

You can customize the formatter implementation if your observability platform requires a specific serialization format.

End-to-End Coordination Example

The following complete example demonstrates two agents coordinating through the blackboard without direct dependencies:

// 1. Setup shared state
val blackboard = InMemoryBlackboard()
val process = ProcessOptions.builder()
    .withAgent(myAgent)
    .withBlackboard(blackboard)
    .build()
    .start()

// 2. Define tools that cooperate via the blackboard
val classifyIntent = BlackboardTools.publish { bb, text ->
    val intent = if (text.contains("order")) "order" else "support"
    bb.set("intent", intent)
}

val fetchKnowledge = BlackboardTools.get { bb, name, type ->
    if (bb.getValue("intent", String::class.java, myAgent) == "order")
        "Order-related documentation"
    else
        "General support documentation"
}

// 3. Execute the agent run
val runner = AgentInvocation.builder()
    .process(process)
    .tools(listOf(classifyIntent, fetchKnowledge))
    .build()

val result = runner.invoke(prompt = "I want to track my order")
println(result)   // Returns knowledge fetched based on the shared intent

In this workflow, the first tool publishes an intent classification, and the second tool reads that value to select the appropriate knowledge source. The agents remain decoupled—the blackboard mediates all communication.

Summary

  • The blackboard pattern in Embabel-Agent provides a shared, mutable key-value store that enables loose-coupled multi-agent coordination.
  • InMemoryBlackboard serves as the default implementation for single-process scenarios, while BlackboardProvider allows integration with distributed stores like Redis.
  • Inject blackboards via ProcessOptions.builder().withBlackboard() to ensure all agents in a process share identical state.
  • Use BlackboardTools to expose read and write capabilities to agent toolsets without hard-coding dependencies.
  • The BlackboardFormatter automatically integrates shared state into observability traces for debugging and monitoring.

Frequently Asked Questions

What is the difference between Blackboard and BlackboardProvider?

Blackboard is the interface defining the contract for shared state storage, including methods like set() and getValue(). BlackboardProvider is the SPI (Service Provider Interface) that factories implement to create blackboard instances. You use the provider when you need to inject custom implementations, such as a Redis-backed store, while the blackboard interface is what agents and tools interact with directly.

How do I share state across multiple processes or microservices?

Implement the BlackboardProvider interface to return a blackboard backed by a distributed cache or database, then register the provider via META-INF/services/com.embabel.agent.spi.BlackboardProvider. When each process loads this provider via ServiceLoader, all agents receive blackboard instances pointing to the same external store, enabling cross-process coordination.

Can I store typed objects in the blackboard, or only strings?

The blackboard supports typed objects through the getValue(name, type, agent) method. While you can store any object using set(), retrieval requires specifying the expected class type, which the implementation uses to cast the value safely. This eliminates manual casting and type-checking boilerplate in agent code.

How does the blackboard integrate with observability and tracing?

The framework includes BlackboardFormatter, which automatically extracts key-value pairs from the blackboard and appends them to trace spans and logs. This happens implicitly during process execution, ensuring that shared context—such as user IDs or conversation states—appears consistently across all observability data without requiring explicit instrumentation in your agents.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →