Skip to main content

SDK & Governance Engine

TraceForge's SDK composes two halves into one object: the observation backbone (EventPipeline, enrich → classify → structure → sinks) and the governance engine (GovernancePipeline, the monitor, plus an optional shield).

Governance is neither a separate track nor the whole pipeline. It is a runtime monitor over a session's event trace, plus an optional shield at the framework's execution boundary. See Governance Overview for the conceptual model; this page is the programmatic reference.

traceforge.sdk.Pipeline

The top-level entry point. Governance is wired in as one stage: when enabled, each pushed event is observed and its SessionMeta stamped onto event.metadata.governance just before the sinks.

from traceforge.sdk import Pipeline
from traceforge.sinks.jsonl import JsonlSink

# enrich -> classify -> structure -> observe -> emit
async with Pipeline.create(sinks=[JsonlSink("events.jsonl")]) as pipeline:
async for event in adapter.stream(...):
await pipeline.push(event) # emitted events carry metadata.governance

Construction

Pipeline.create(
config=None, *, policy=None, sinks=None,
enable_structure=True, enable_title=False, enricher=None, governance=True,
) -> Pipeline
Pipeline.from_config(path=None, *, policy=None, sinks=None, ...) -> Pipeline
ArgumentPurpose
configA GovernanceConfig for the engine (in-memory DB + defaults when omitted).
policyA GatePolicy enabling the shield. Omit for observation-only.
sinksObservation destinations for pushed events. Omit for gating-only.
enable_structure / enable_titlePhase + boundary (and optional title) structuring. Models load lazily.
governanceWire the monitor in as a stage (default True). False for pure observation.

The returned Pipeline exposes await push(event) / push_span / push_usage / flush / close, async with, score_tool_call(payload) -> EventTrace (read-only preflight), the gate_* helpers, and the .governance / .backbone escape hatches.

GovernancePipeline

The composition root and facade, usable standalone. The score / gate CLIs and gating-only SDK use go straight to it.

from traceforge.governance.pipeline import GovernancePipeline

gov = GovernancePipeline.create() # zero-config; or pass GovernanceConfig / policy=

trace = gov.score_tool_call({
"tool_name": "bash",
"tool_input": {"command": "rm -rf /"},
"session_id": "sess-abc",
})
# trace.stage == "assessed"; trace.risk_score == 66; trace.risk_band == "danger"
# trace.suggested_action == "escalate"; trace.reason == "risk_score_danger"

Read vs write entry points

The facade exposes one write entry point and two read entry points:

MethodOwnerSession stateReturns
observe_event(event)SessionMonitoradvances (persists)SessionMeta
score_tool_call_event(event)Scorerread-only (clone)SessionMeta
score_tool_call(payload)Scorerread-only (clone)EventTrace

observe_event is the mutating pipeline stage; score_tool_call* preview against a detached clone of current state, committing nothing. Writer and reader share the same Phase1 and Assessor, so preview and live scoring cannot diverge.

Unified records

EventTrace is the frozen unified record, identity, classification, and assessment on one object:

@dataclass(frozen=True, slots=True)
class EventTrace:
id: str
kind: EventKind
session_id: str
mechanism: Mechanism | None
effect: Effect | None
scope: tuple[Scope, ...]
role: tuple[Role, ...]
action: tuple[Action, ...]
capability: tuple[Capability, ...]
structure: tuple[Structure, ...]
risk_score: int | None
risk_band: RiskBand | None
suggested_action: Recommendation | None # allow/warn/escalate/deny
reason: str | None
stage: TraceStage # adapted -> classified -> assessed

SessionMeta (attached to event.metadata.governance) is the richer stateful output: classification, risk_assessment, recommendation (a RiskRecommendation with .recommended_action, .reason_code, .transform), budget_snapshot, drift, mcp_alerts, and evidence.

class RecommendedAction(StrEnum):
ALLOW = "allow"
WARN = "warn"
ESCALATE = "escalate"
DENY = "deny"
TRANSFORM = "transform"

These are recommendations from the rules engine (the Assessor). On their own they enforce nothing, a registered GatePolicy is what turns a recommendation into an enforced Verdict.

The object model

The engine dissolves into focused collaborators, each with one reason to change, composed by dependency injection at the GovernancePipeline root.

CollaboratorSingle responsibility
SessionStateOne session's accumulators, one tool-call counter, budget, taint ledger, phase window, gate history. Mutated only through its own methods.
SystemStoreDurability: idempotency reservations, atomic commit, crash recovery, audit persistence.
SessionRegistryResidency: where sessions are created/found, with durable (DB-backed) and ephemeral (gate) scopes kept separate.
Phase1The Phase-1 state-advance step, budget, taint (IFC), phase window, pressure.
Assessor(snapshot, event) -> SessionMeta, label + risk + recommendation + drift + MCP. Side-effect-free.
SessionMonitorThe single writer: advance the real SessionState, commit atomically, then assess.
ScorerThe read side: preview Phase1 + Assessor against a detached clone, mutating nothing.
GatePolicyMap an assessed request/result to a Verdict (pre) / PostflightVerdict (post).
ShieldRuntime enforcement: build gate context, run the policy's chains, record allow/deny.
GovernancePipelineComposition root + facade wiring all of the above.

The engine holds to a few guarantees: the monitor is the single writer (only it advances state), the shield is opt-in (observation never enforces), and replay reproduces the live assessment (enrichment is captured onto the event, never re-derived). The core carries no framework dependencies, rules are data, not code, and enforcement is fail-closed (any error in the shield's chains yields DENY / SUPPRESS).

For enforcement patterns and framework adapters, see the Gate page.