Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/xcoder-es/governance-layer/llms.txt

Use this file to discover all available pages before exploring further.

The Governance Layer separates ontology storage behind a single abstract interface — OntologyBackend — so governance code never imports a database driver directly. Two concrete implementations are shipped: a lightweight in-memory backend used by default and a Neo4j Aura backend that provides durable, queryable storage across process restarts.

The abstract interface

All backend operations go through the OntologyBackend ABC defined in src/governance/ontology/backend.py. The contract is intentionally minimal:
class OntologyBackend(ABC):
    def add_entity(self, type_: str, properties: Dict[str, Any]) -> str: ...
    def add_relationship(self, from_id: str, to_id: str, relation: str) -> bool: ...
    def query_relationships(self, entity_id: str) -> List[Tuple[str, str, str]]: ...
    def get_entity(self, entity_id: str) -> Optional[Dict[str, Any]]: ...
    def get_entities_by_type(self, type_: str) -> List[Dict[str, Any]]: ...
    def get_identity_vector(self) -> List[float]: ...
    def set_identity_vector(self, vector: List[float]): ...
    def close(self): ...
Both backends implement this interface identically from the caller’s perspective.

MemoryBackend (default)

MemoryBackend stores everything in plain Python dicts and lists — no external process, no credentials, no network. It is the default choice when no Neo4j credentials are present.
from governance.ontology.memory_backend import MemoryBackend

backend = MemoryBackend()
eid = backend.add_entity("decision", {"step": 1, "action": 2, "reward": 1.0})
backend.add_relationship(eid, eid, "self_reference")
print(backend.get_entity(eid))
Entity IDs are 12-character hex strings derived from hashlib.sha256(secrets.token_bytes(16)), making them collision-resistant without requiring a database sequence.
All data stored in MemoryBackend is lost when the Python process exits. Do not rely on it for experiment logging you intend to analyse later.

Neo4jBackend (persistent)

Neo4jBackend connects to a Neo4j Aura instance using the official neo4j driver (included in the base dependencies as neo4j>=5.20). It stores entities as graph nodes with a JSON-serialised properties field and relationships as RELATES edges. The backend reads credentials from the .env file at the project root, falling back to environment variables if the file is absent:
NEO4J_URI=neo4j+s://your-instance.databases.neo4j.io
NEO4J_USER=neo4j
NEO4J_PASSWORD=your-password-here
Neo4j Aura Free provides a hosted instance at no cost and is the recommended way to run the Neo4j backend. The neo4j+s:// URI scheme used in .env.example is the Aura connection format.
The backend can also be instantiated directly with explicit credentials, which takes precedence over the .env file:
from governance.ontology.neo4j_backend import Neo4jBackend

backend = Neo4jBackend(
    uri="neo4j+s://your-instance.databases.neo4j.io",
    user="neo4j",
    password="your-password",
)
Always call backend.close() when you are done to release the driver connection.

Auto-detection in the dashboard

The Streamlit dashboard (src/governance/dashboard/app.py) auto-detects which backend to use at startup. It reads the .env file and checks whether NEO4J_URI is set. If a valid URI is found, it attempts to connect and falls back silently to MemoryBackend on failure.
@st.cache_resource
def get_ontology_backend():
    if _neo4j_available():
        try:
            from governance.ontology.neo4j_backend import Neo4jBackend
            backend = Neo4jBackend()
            backend.get_identity_vector()   # connection probe
            return backend
        except Exception as e:
            st.sidebar.warning(f"Neo4j connection failed: {e}. Falling back to memory.")
            return MemoryBackend()
    return MemoryBackend()
The active backend type is shown in the dashboard sidebar under Ontology.

What the ontology stores

Both backends record the same categories of data during a parliament session:
Entity typeContents
"action"Named action entries from the identity ontology
"decision"Per-step decisions: action, reward, violations, is_default flag
"member_score"Per-member scores attached to each decision
"benchmark"Aggregate benchmark run statistics
Identity nodeThe current identity vector (Neo4j only: persisted as a dedicated node)
Relationships are typed strings (e.g. "outgoing", "incoming") and are navigable from any entity using query_relationships.

Choosing a backend

MemoryBackend

Use for: local development, unit tests, quick demos, CI runs.
  • Zero configuration — just import and instantiate
  • No network latency
  • Data is ephemeral; lost on process restart
  • Already the default in all dashboard and experiment code

Neo4jBackend

Use for: persistent decision logging, multi-session research, production-adjacent deployments.
  • Durable storage across restarts
  • Full graph query capability via Cypher
  • Requires a running Neo4j instance and valid credentials in .env
  • neo4j>=5.20 is included in core dependencies — no extra install needed

Build docs developers (and LLMs) love