Skip to content

Contracts

Contracts define stable runtime boundaries in mas-runtime. A contract describes what the kernel may call (tools, models, sessions, messaging, governance); a plugin implements one or more contracts.

Machine-readable registry: contracts-registry.yaml.


Implemented in this release (OSS)

These boundaries are wired in the kernel and exercised by tutorials and paper labs:

Contract / plugin Role
ToolContract Tool listing and invocation — reference
MemoryContract Memory read/write at engine boundary
ContextContract / ContextManagerContract Prompt and conversation context
DesignPatternPlugin ReAct, chain-of-thought, single-pass lifecycles
EngineContract LLM, tool, and memory I/O
LLMProvider Chat-completion wire protocol (OpenAI-compatible now; routed like tools). Static knobs: spec.models[] sampling/reasoning/extra + catalog. Dynamic kwargs: stream, stream_options, tool_choice, extra_body, extra_headers, extra_query.
CtxAssembler Context / prompt assembly
ObservabilitySink / EventEmitter Trace and JSONL event emission
BudgetTracker + budget overlays Stateful token/cost governance (lifecycle-control.lab)

The plugin registry lists ingress/egress events and Python modules for each registered contract.

Manifest-selected Protocol categories

PluginRegistry categories are declared by library packages and selected by manifest name. Current examples include tool_provider, governance, hitl_contract, user_io_contract, skill_impl, and the design/context categories. hitl_contract implements HITLContract.request_approval(...); user_io_contract implements UserIOContract.send_progress_update(...). Both default to registry in mas-library-standard. A caller-supplied InstantiationOptions.hitl_contract or .user_io_contract instance wins over the manifest, preserving interactive CLI adapters.

Governance ingress plugins register under the governance category and are selected in spec.governance[].ingress_plugins with type (or name) and optional chain: stop|continue. They receive the ingress intent snapshot and cannot access mutable kernel state.

engine_tool_provider and EngineToolContext

Orchestration-level tools — the ones that run another agent rather than call a function — register under engine_tool_provider. mas-library-standard ships two variants: delegation (existing peers) and spawn_subagent (new children from pre-authored templates).

A plugin in this category never receives the materialized run or the comm bus. It receives an EngineToolContext, which exposes exactly three operations plus three read-only properties:

Member Purpose
run_turn(agent_id, task, ...) Run one turn on an agent of this run
spawn_instance(manifest, *, template_id, manifest_dir=None) Materialize a child, return its minted id
teardown_instance(agent_id) Release the child, its working memory, and its ledger depth
depth Current spawn depth for the session
session_id / parent_agent_id Identity of the calling scope

The budget check lives inside spawn_instance, not in its callers, so a third-party plugin is subject to the same SpawnLedger ceilings as a shipped one. When a ceiling is reached the facade raises EngineToolBudgetExceeded rather than returning a value a plugin could ignore. A plugin holding this object cannot enumerate other agents, read another agent's working memory, or send arbitrary bus messages — none of those are reachable from the facade.

Manifest-facing behaviour is unchanged: spec.behavior.allow_subagent_spawning and spec.behavior.delegation_style still decide whether the tool surface exists at all. This category only changes how the implementing class is found and constructed.


Taxonomy (design target)

The runtime design groups boundaries into three families. Additional contracts below are specified for extension authors; not all have standalone Python protocol classes in OSS yet.

Family Meaning Examples
Capability What the runtime can access or expose ToolContract, model access, SessionContract
Orchestration How control flows across agents WorkflowContract, delegation, transport
Governance What is permitted Budget, routing (sandbox/TBAC: internal-only)

For method signatures and implementation detail on implemented contracts, see developer contract reference in the repository (clone required).


Contract groups (developer reference)

Group Topics
Models, prompts, tools, memory Tool and model access, prompt assembly, memory backends
Sessions, checkpoints, context Session load/save, shared context, prompt context
Messaging & orchestration Sensors, transport, delegation, workflow
Control & observability Execution control, recorder / trace emission
Governance Budget, routing (sandbox/TBAC documented in mas-lab-internal)
Design patterns ReAct, chain-of-thought, single-pass lifecycles

Deep dives (GitHub): model & tools · state & context · messaging & orchestration · execution control · governance · design patterns


Governance (OSS)

User reference: governance.md (chain, plugins). Retries, circuit breaker, error_policy, defaults, and logging: reliability.md.

Stateful governance plugins enforce policy across turns. The paper lifecycle-control lab stacks budget caps, guardrails, and HITL via overlays (e.g. budget-cap on budget_threshold).

Runtime implementation: BudgetTracker in runtime/src/mas/runtime/boundary/gov/budget.py. Design-target contract: BudgetContract (see dev governance.md).

Egress/ingress decisions on every tool/LLM/memory call go through two layers, evaluated in order:

  1. Declarative policies — GovernancePolicyEngine (runtime/src/mas/runtime/boundary/gov/policy_engine.py) matches YAML-authored PolicyDefinitions (trigger condition + action: hitl/block/terminate/log/modify/skip/retry/blacklist) against the call, keyed off spec.governance in the agent/overlay manifest. A matched policy's own params.message (or params.reason) becomes the decision's reported reason; otherwise a reason is synthesized from the policy name and action.
  2. Parametric profiles — GovPolicyProfile (egress) / GovIngressProfile (ingress) fallback when no declarative policy matches: fixed postures like block-destructive, hitl-destructive, retry-on-error. Implementation: resolve_egress_governance / egress_governance_outcome / ingress_governance_outcome in runtime/src/mas/runtime/boundary/gov/policy.py.

Every decision is emitted as a governance_decision observability event (hook, checkpoint, decision, reason, policy_name) — this is what the multilevel trajectory plot's Governance lane and per-call badges render (see pipeline-processors.md § Multilevel trajectory plot).


Plugin registry (v2)

The registry maps contract IDs to Python modules and (where applicable) Mealy / TLA machines. Registered contracts in this release:

ID Role
DesignPatternPlugin Reasoning pattern scheduler (ReAct, CoT, single-pass)
EngineContract LLM, tool, and memory I/O
CtxAssembler Prompt / context assembly
HitlResponder Human-in-the-loop approval
ObservabilitySink Trace and event emission
EnvelopeProduct Contract-call envelope (governance + observability wrap)
EventEmitter JSONL / stderr event sinks (mas-ctl)
EventTransform Boundary → native / OTEL transforms

See contracts-registry.yaml for aliases, ingress/egress events, and bundled implementations.


Typical call paths

Tool execution

Runtime or planner
  -> ToolContract.list_tools()     # required: name, description, parameters
  -> BudgetContract.on_pre_tool_call()
  -> ToolContract.call_tool(name, arguments)   # required two-arg invocation
  -> RecorderContract.emit()

Optional advertise keys and call_tool kwargs are documented in tool-contract.md. Daily ops use the required two-arg call.

Model execution

Runtime
  -> ModelAccessContract.on_collect_models()
  -> BudgetContract.on_pre_llm_call()
  -> ModelAccessContract.complete()
  -> BudgetContract.on_post_llm_call()
  -> RecorderContract.emit()

MAS orchestration

SensorContract.pull() or emit_event()
  -> SessionContract.load_session()
  -> WorkflowContract.run()
  -> DelegationContract.list_tools() and collect_context()
  -> MessageContract.send_message() or TransportContract.send()