Skip to content

Latest commit

 

History

History
258 lines (210 loc) · 9.77 KB

File metadata and controls

258 lines (210 loc) · 9.77 KB

Conventions

This document defines how Components communicate, behave, and enforce rules within Brain. For the structural model of Layers, Systems, and boundaries, see Boundaries & Responsibilities.

Check the Glossary for key terms such as Layer, System, Resource, Service, et cetera.


APIs

TL;DR — services/*/*/component.py exports a list of interfaces which are the canonical surface area for a given Service.

Each Service must define a Public API. These Public APIs:

  • Are the canonical and authoritative (Python) interface to the Service
  • Are the sole permitted surface for other Component callers
  • Define method signatures using envelope-like request/response messages

Published HTTP Surface

The Public APIs are canonical. L2 access is provided by a small published HTTP surface implemented in api.py modules as FastAPI route registrars, while internal East-West traffic among Services uses the in-process Python Public API exclusively.

The Brain Core SDK is therefore a thin HTTP client layered on top of the published subset of Service Public APIs. It currently talks to Brain Core over a Unix domain socket and only exposes a limited subset of operations.

The Public API and published HTTP surface are not required to be one-to-one. A Service may expose Public API methods that are internal-only and therefore not published on the Brain Core SDK.


Pydantic Contracts

Pydantic is the canonical contract system for configuration and typed data exchange in Brain.

Scope

  • Use BaseSettings/pydantic-settings for runtime configuration models.
  • Use BaseModel for cross-Service and cross-Layer boundary contracts.
  • Use BaseModel for shared structured error and envelope primitives.

Required model defaults

  • Set extra="forbid" unless there is a concrete, documented reason not to.
  • Set frozen=True unless the model is explicitly stateful and mutable by design.

Validation boundaries

  • Validate at ingress boundaries using model_validate(...).
  • Treat validated models as authoritative inside domain logic; avoid re-validating ad hoc dictionaries throughout call chains.
  • Prefer explicit validation failures with stable error messages over silent coercion paths.

Serialization boundaries

  • Use model_dump(mode="python") for in-process structured handoff where a plain mapping is required.
  • Keep transport adapters explicit about mapping to/from wire types.

Contract shape rule

  • Do not maintain parallel contract shapes for the same boundary (for example: dataclass + dict + Pydantic for one message type). One boundary contract, one canonical typed model.

Envelopes

All cross-Layer and cross-Service communication must use Envelopes. An Envelope consists of:

  • Metadata
  • Payload
  • Errors

Transport API Typing Note

Published HTTP routes should generally use operation-specific request/response models that remain envelope-like (metadata, typed payload, and errors where applicable), rather than a single polymorphic wire envelope for every endpoint.

Envelope Kinds

Command Envelope: Generated by L2 for Capability invocation. Event Envelope: Generated by L1 upon external or system-triggered activity. Result Envelope: Used for responses to other Enveloped messages. Stream Envelope: [TODO]/reserved - future real-time streaming support.

Metadata (Structured)

  • envelope_id: required ULID
  • trace_id: required ULID
  • parent_id: optional ULID
  • timestamp: required int64
  • kind: required string (one of command, event, result, stream)
  • source: required string (e.g. cli, agent, switchboard, job)
  • principal: required string (e.g. operator, commitment, core)

Envelope subclasses may append their own metadata. For clarity, source is the immediate emitting Component for "this" specific Envelope, whereas principal is the accountable identity (effective authority) for the request. Components are required to propagate principal unchanged across calls.

Illustrative (non-literal) example: The Operator requests a reminder in 1 hour. A message is passed from the Switchboard to the Agent like:

  • source = "switchboard"
  • principal = "operator" which results in a message from the Agent to the Scheduler like:
  • source = "agent"
  • principal = "operator"

An hour later, the schedule fires and the Job invokes the Agent like:

  • source = "job"
  • principal = "operator" which results in a message from the Agent to the Attention Router like:
  • source = "agent"
  • principal = "operator"

Tracing

A trace_id scopes a single execution episode. In the example above, the first two Envelopes share the same trace_id. The third and fourth share a new trace_id (distinct from the first two), and the third sets parent_id to the envelope_id of the scheduling Envelope from the prior Trace.

This keeps each execution episode independently observable while preserving cross-Trace causality for long-term lineage and analysis. This provides for a DAG of Envelopes across time, with Trace segments as execution partitions.

Payload

Domain-specific content.

You can use these oats to make oatmeal, bread, whatever you want. I don't care, they're your oats.
— Dwight K. Schrute

Errors

Most usually Errors will be present in a Result Envelope, but are not invalid in any Envelope. Errors are a collection of structured objects representing some failure mode/state.


Principal Identity Model

The Principal is "who the system treats as accountable" for a given request.

operator - All "personal assistant" work should ultimately roll up to the Operator.

<service> (e.g. switchboard, ctlc) - This represents a Layer 1 Service acting autonomously. This is used when Services initiate work without an immediate upstream request (think scheduled jobs, inbound interrupt, etc.)

core - Rare. Only used for truly low-level, cross-cutting "infrastructure" behavior which are explicitly system-meta in nature.


SDKs

Brain SDK

The Brain Core SDK is the public interface for L2 Actors of Brain Core using the published HTTP surface. All L2 Actors must be built on the Brain Core SDK.

The SDK contains no business logic; it simply exists as an access layer across process boundaries to the published subset of L1 Service Public APIs.

Capability SDK

The Capability SDK supports registration and management of Capabilities (Ops and Skills) including both logic and metadata such as Policy declarations.


Error Taxonomy

Errors must be categorized as:

  • terminal
  • retriable

Errors may carry optional category fields such as:

  • conflict
  • dependency
  • not_found
  • policy
  • validation

Policy violations are, by definition, terminal, and should not be retried.

Transport vs Domain Failure Mapping

To avoid ambiguity at Service boundaries:

  • Domain failures (validation, conflict, not_found, policy) are returned as typed structured errors in the envelope-like response.
  • Transport/infrastructure failures (dependency unavailable, internal runtime faults) are surfaced as transport failures at the HTTP boundary.

This keeps domain behavior explicit and machine-readable while preserving normal transport semantics for network/runtime outages.


Policy Enforcement Rule

All Capability invocations (including within Skills) MUST pass through Capability Engine invoke(). Skills must not directly call other Skills or Ops by importing implementations. Policy Service evaluation is mandatory and recursive.

Invocation Lineage and Audit Fields

Capability Engine and Policy Service must persist structured lineage and policy audit metadata for every invocation (allowed or denied).

Required lineage fields:

  • envelope_id
  • trace_id
  • parent_id
  • invocation_id
  • parent_invocation_id
  • source
  • actor
  • channel

Required policy/audit fields:

  • capability_id
  • capability_version
  • policy_decision_id
  • policy_regime_id
  • allowed (bool)
  • reason_codes[]
  • obligations[]
  • approval proposal token when approval is required

Nested capability calls must mint a new envelope_id, set parent_id to the parent envelope, and route through Capability Engine public invoke API so the same policy and audit contract is enforced recursively.

Approval Transport Contracts

Policy Service -> Attention Router approval notifications must be token-only.

Required outbound notification fields:

  • proposal_token
  • capability_id
  • capability_version
  • summary
  • actor
  • channel
  • trace_id
  • invocation_id
  • expires_at

Attention Router -> Policy Service correlation payloads must include actor and channel plus one of the deterministic correlators:

  • approval_token
  • reply_to_proposal_token
  • reaction_to_proposal_token

message_text may be included for immediate next-turn correlation and disambiguation fallback.


Process Assumptions

  • L2 Actors are process-and-network isolated
  • L1 Services are process-local, but restricted to Public APIs
  • L0 Substrates and Adapters are non-local

End of Conventions