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

> Learn how to configure the blackboard pattern for multi-agent coordination in Embabel-Agent. Implement a shared mutable state for loose-coupled agent collaboration and enhance your AI system.

- Repository: [Embabel/embabel-agent](https://github.com/embabel/embabel-agent)
- Tags: how-to-guide
- Published: 2026-08-08

---

**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/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/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/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/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/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/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:

```kotlin
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`:

```kotlin
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:

```kotlin
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:

```kotlin
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:

```kotlin
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:

```kotlin
// 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.