# Understanding the Blackboard System and SharedVariables in Ceres

> Learn about the Blackboard system in Ceres, a global storage for SharedVariables that facilitates data exchange between any nodes and graphs. Understand its core functionality.

- Repository: [AkiKurisu/ceres](https://github.com/akikurisu/ceres)
- Tags: deep-dive
- Published: 2026-02-24

---

**The Blackboard system in Ceres is a central, graph-wide storage mechanism that holds SharedVariables, enabling data exchange between any node in a graph and across multiple graphs through a global blackboard.**

The `akikurisu/ceres` repository implements a powerful data-sharing architecture for visual scripting in Unity. At its core lies the **Blackboard**—a centralized storage system that manages **SharedVariables**, allowing nodes to communicate without direct references. This design pattern decouples node logic while maintaining type safety and runtime flexibility.

## What Is the Blackboard System in Ceres?

The Blackboard acts as a container that stores a list of `SharedVariable` instances. According to the source code in [[`Runtime/Core/Models/Graph/Variables/Blackboard.cs`](https://github.com/akikurisu/ceres/blob/main/Runtime/Core/Models/Graph/Variables/Blackboard.cs)](https://github.com/akikurisu/ceres/blob/main/Runtime/Core/Models/Graph/Variables/Blackboard.cs), each graph maintains its own blackboard instance during execution.

The system supports two distinct scopes:

- **Local Blackboard**: Created per-graph, storing variables that exist only within that specific graph instance
- **Global Blackboard**: A static singleton that enables cross-graph communication when variables are marked with `IsGlobal = true`

## How SharedVariables Interact with the Blackboard

### The SharedVariable Base Class

All shareable data in Ceres inherits from the abstract `SharedVariable` class defined in [[`Runtime/Core/Models/Graph/Variables/SharedVariable.cs`](https://github.com/akikurisu/ceres/blob/main/Runtime/Core/Models/Graph/Variables/SharedVariable.cs)](https://github.com/akikurisu/ceres/blob/main/Runtime/Core/Models/Graph/Variables/SharedVariable.cs). Concrete implementations include `SharedInt`, `SharedFloat`, `SharedObject`, and others.

Each variable maintains critical metadata:
- **IsShared**: Determines if the variable participates in the blackboard system
- **IsGlobal**: Controls whether the variable syncs to the global blackboard
- **IsExposed**: Indicates visibility in the Unity editor inspector

### Linking Variables to the Blackboard

During graph initialization, nodes register their shared variables with the blackboard. In [[`Runtime/Core/Models/Graph/CeresGraph.cs`](https://github.com/akikurisu/ceres/blob/main/Runtime/Core/Models/Graph/CeresGraph.cs)](https://github.com/akikurisu/ceres/blob/main/Runtime/Core/Models/Graph/CeresGraph.cs), the `InitVariables` method (lines 58-71) iterates through all nodes and invokes `variable.LinkToSource(graph.Blackboard)`.

This registration process adds the variable to the blackboard's internal `SharedVariables` list, making it accessible via the `GetSharedVariable` extension method defined in [[`SharedVariableExtension.cs`](https://github.com/akikurisu/ceres/blob/main/SharedVariableExtension.cs)](https://github.com/akikurisu/ceres/blob/main/Runtime/Core/Models/Graph/Variables/SharedVariableExtension.cs).

### Global Variable Scope

After graph compilation, the system invokes `Blackboard.LinkToGlobal()` (lines 152-169 in [`Blackboard.cs`](https://github.com/akikurisu/ceres/blob/main/Blackboard.cs)). This method connects the graph's local blackboard to the static global instance. Any variable marked `IsGlobal = true` becomes available to all other graphs in the application through the same `GetSharedVariable` API.

## Runtime Workflow: From Registration to Retrieval

The Blackboard system operates through a precise lifecycle:

1. **Graph Construction**: When `CeresGraphCompiler.Compile` executes, it instantiates the graph and triggers `InitVariables`
2. **Variable Registration**: Each node calls `LinkToSource`, binding its `SharedVariable` instances to the graph's blackboard
3. **Variable Lookup**: At runtime, nodes query values using:
   ```csharp
   var healthVar = executionContext.Graph.Blackboard.GetSharedVariable("PlayerHealth") as SharedInt;
   ```

4. **Global Synchronization**: Post-compilation, `LinkToGlobal` promotes global variables to the singleton blackboard, enabling cross-graph communication

## Practical Code Examples

### Setting a Shared Variable in a Property Node

The following excerpt from [[`PropertyNode_SetSharedVariableTValue.cs`](https://github.com/akikurisu/ceres/blob/main/PropertyNode_SetSharedVariableTValue.cs)](https://github.com/akikurisu/ceres/blob/main/Runtime/Flow/Models/Nodes/Properties/PropertyNode_SetSharedVariableTValue.cs) demonstrates how nodes write to the blackboard:

```csharp
protected override UniTask Execute(ExecutionContext executionContext)
{
    // Retrieve the variable from the graph's blackboard
    if (executionContext.Graph.Blackboard.GetSharedVariable(propertyName) is SharedInt variable)
    {
        // Write the incoming value
        variable.Value = inputValue.Value;
    }
    executionContext.SetNext(exec.GetT<ExecutableNode>());
    return UniTask.CompletedTask;
}

```

### Getting a Variable from a Custom Script

External systems can access the blackboard directly:

```csharp
public class HealthManager : MonoBehaviour
{
    void Update()
    {
        // Assume a running Ceres graph is attached to this GameObject
        var graph = GetComponent<CeresGraphComponent>().Graph;
        var healthVar = graph.Blackboard.GetSharedVariable("PlayerHealth") as SharedInt;
        if (healthVar != null)
        {
            Debug.Log($"Current health: {healthVar.Value}");
        }
    }
}

```

### Declaring a Global Variable in a Node

To share data across multiple graphs, declare a global variable:

```csharp
[SharedVariable("Score", IsGlobal = true, IsExposed = true)]
public class ScoreVariable : SharedInt { }

```

When the graph compiles, this variable automatically synchronizes with the global blackboard, making it accessible from any other graph in the application.

## Key Source Files and Architecture

| File | Role | Direct Link |
|------|------|-------------|
| [`Blackboard.cs`](https://github.com/akikurisu/ceres/blob/main/Blackboard.cs) | Core storage, global linking, creation helpers | [View](https://github.com/akikurisu/ceres/blob/main/Runtime/Core/Models/Graph/Variables/Blackboard.cs) |
| [`SharedVariable.cs`](https://github.com/akikurisu/ceres/blob/main/SharedVariable.cs) | Abstract base for typed variables, serialization, observation | [View](https://github.com/akikurisu/ceres/blob/main/Runtime/Core/Models/Graph/Variables/SharedVariable.cs) |
| [`SharedVariableExtension.cs`](https://github.com/akikurisu/ceres/blob/main/SharedVariableExtension.cs) | Extension methods for look-up (`GetSharedVariable`) and binding | [View](https://github.com/akikurisu/ceres/blob/main/Runtime/Core/Models/Graph/Variables/SharedVariableExtension.cs) |
| [`CeresGraph.cs`](https://github.com/akikurisu/ceres/blob/main/CeresGraph.cs) | Graph container, initialization of variables/ports, linking to global blackboard | [View](https://github.com/akikurisu/ceres/blob/main/Runtime/Core/Models/Graph/CeresGraph.cs) |
| [`PropertyNode_SetSharedVariableTValue.cs`](https://github.com/akikurisu/ceres/blob/main/PropertyNode_SetSharedVariableTValue.cs) | Example node that sets a shared variable at runtime | [View](https://github.com/akikurisu/ceres/blob/main/Runtime/Flow/Models/Nodes/Properties/PropertyNode_SetSharedVariableTValue.cs) |
| [`FlowBlackboard.cs`](https://github.com/akikurisu/ceres/blob/main/FlowBlackboard.cs) (editor UI) | Visual representation of the blackboard in the Unity editor | [View](https://github.com/akikurisu/ceres/blob/main/Editor/Flow/UIElements/FlowBlackboard.cs) |

## Summary

- The **Blackboard** in Ceres serves as a centralized storage container for **SharedVariables**, enabling decoupled communication between nodes in a visual scripting graph.
- **SharedVariable** instances register with the blackboard via `LinkToSource`, making them accessible through the `GetSharedVariable` extension method.
- The system supports both **local** (graph-specific) and **global** (application-wide) variable scopes, with global variables synchronizing through `LinkToGlobal`.
- Variables can be exposed to the Unity inspector, observed for changes, and accessed from external C# scripts, providing flexibility for both visual and code-based workflows.

## Frequently Asked Questions

### What is the difference between a local and global SharedVariable in Ceres?

A **local** SharedVariable exists only within its specific graph's blackboard and cannot be accessed by other graphs. A **global** SharedVariable, marked with `IsGlobal = true`, synchronizes with the static global blackboard via `Blackboard.LinkToGlobal()`, making it readable and writable from any graph in the application.

### How do nodes access SharedVariables at runtime?

Nodes access SharedVariables through the graph's blackboard using the `GetSharedVariable` extension method defined in [`SharedVariableExtension.cs`](https://github.com/akikurisu/ceres/blob/main/SharedVariableExtension.cs). For example: `executionContext.Graph.Blackboard.GetSharedVariable("Health") as SharedInt`. This retrieves the typed variable instance, allowing nodes to read or write the `Value` property.

### Can SharedVariables be observed for changes?

Yes, the `SharedVariable` base class in [`SharedVariable.cs`](https://github.com/akikurisu/ceres/blob/main/SharedVariable.cs) provides an `Observe()` API that enables reactive patterns. This allows systems to subscribe to value changes without polling, making it suitable for event-driven architectures within Ceres graphs.

### Where is the Blackboard system implemented in the Ceres source code?

The core implementation resides in [`Runtime/Core/Models/Graph/Variables/Blackboard.cs`](https://github.com/akikurisu/ceres/blob/main/Runtime/Core/Models/Graph/Variables/Blackboard.cs) for storage and global linking, [`Runtime/Core/Models/Graph/Variables/SharedVariable.cs`](https://github.com/akikurisu/ceres/blob/main/Runtime/Core/Models/Graph/Variables/SharedVariable.cs) for the variable base class, and [`Runtime/Core/Models/Graph/CeresGraph.cs`](https://github.com/akikurisu/ceres/blob/main/Runtime/Core/Models/Graph/CeresGraph.cs) for initialization logic. Extension methods for variable lookup are found in [`SharedVariableExtension.cs`](https://github.com/akikurisu/ceres/blob/main/SharedVariableExtension.cs).