Thin Python SDK for emitting decision-lineage from managed external agents to CriticalBridge Brain
Project description
cb-conformance
Thin Python SDK for emitting decision-lineage from a managed external agent to CriticalBridge Brain.
The agent's TypeScript conformance sidecar (packages/conformance-sidecar)
derives latency / counters from the A2A task envelope. This SDK complements
the sidecar — it adds an in-process hook for things the sidecar can't see:
chain-of-thought, retrieved citations, tool sub-calls, HITL touchpoints,
and the NAIC V2 fields the Brain records per decision. Records correlate
to the sidecar's task envelope via signal_id.
Wire-shape stability
This SDK targets the RecordDecisionLineageInput shape defined in
src/main/brain-coordinator/state/DecisionLineageStore.ts (plus
RetrievedContextSource from src/types/decision-lineage.types.ts),
and the response shape returned by PR 2b (#8402)'s
POST /api/brain/agents/v1/entities/:entityId/agents/:agentId/decision-lineage
route — including the agent-attested HMAC authenticityEnvelope.
Until PR 2b merges, this SDK can be installed for local development
but cannot round-trip against a live Brain. If PR 2b's wire shape
diverges before merge, re-derive RetrievedContextEntry /
ModelInvocation / HITLTouchpoint from the merged source of truth.
Install (local dev)
pip install -e packages/clients/python-conformance # sync only
pip install -e 'packages/clients/python-conformance[async]' # + async (httpx)
The async extra brings in httpx>=0.27 for AsyncConformanceClient.
Sync-only users (requests-only) don't pay the cost.
Production install path is out of scope for this PR (it'll ship via the internal package index once Phase 2 stabilizes).
Use
import os
from cb_conformance import ConformanceClient, ModelInvocation, RetrievedContextEntry
client = ConformanceClient(
brain_url="https://brain.acme.criticalbridge.ai",
entity_id="ent-acme",
agent_id="mgmt-langchain-broker-xyz",
registration_token=os.environ["REGISTRATION_TOKEN"], # from sidecar handoff
)
response = client.record_decision_lineage(
signal_id="sig-from-sidecar-task-abc", # correlates to the sidecar's task envelope
work_item_id="wi-12345",
skill="summarize-tickets",
inputs={"prompt": "..."},
outputs={"summary": "..."},
risk_tier="medium", # 'low' | 'medium' | 'high' | 'critical'
model_invocation=ModelInvocation(
provider="anthropic",
model="claude-opus-4-7",
tokens_in=4200,
tokens_out=180,
),
retrieved_context=[
RetrievedContextEntry(
type="document", # 'document' | 'database' | 'rules_engine' | 'api'
source_id="kb-faq-1",
retrieved_at="2026-06-26T12:00:00.000Z",
source_name="FAQ v3",
excerpt="...trimmed...",
relevance_score=0.91,
),
],
consumer_impacting=False,
)
# Server-stamped response — persist the envelope alongside the record
# for any future auditor-side verification.
print(response["decisionId"])
print(response["signalId"])
print(response["decidedAt"])
envelope = response["authenticityEnvelope"]
print(envelope["signedBy"], envelope["signature"])
signal_id is optional — when omitted (or None), PR 2b's route
stamps a fallback (mgmt-signal-<entityId>-<epoch-ms>). Read the
server-stamped value off response["signalId"].
Async usage
Modern asyncio-native frameworks (LangChain, LlamaIndex, AutoGen) should
use AsyncConformanceClient so a lineage POST doesn't block the event
loop.
pip install 'cb-conformance[async]'
import os
from cb_conformance import AsyncConformanceClient, ModelInvocation
async with AsyncConformanceClient(
brain_url="https://brain.acme.criticalbridge.ai",
entity_id="ent-acme",
agent_id="mgmt-langchain-broker-xyz",
registration_token=os.environ["REGISTRATION_TOKEN"],
) as client:
response = await client.record_decision_lineage(
work_item_id="wi-12345",
skill="summarize-tickets",
signal_id="sig-from-sidecar-task-abc",
model_invocation=ModelInvocation(
provider="anthropic",
model="claude-opus-4-7",
tokens_in=4200,
tokens_out=180,
),
)
print(response["decisionId"], response["authenticityEnvelope"]["signature"])
The async surface mirrors the sync ConformanceClient: same kwargs,
same response shape, same exceptions, same retry behavior (250ms /
500ms / 1000ms + Retry-After honor, just asyncio.sleep instead of
time.sleep). The underlying httpx.AsyncClient is created in
__aenter__ and closed in __aexit__; connection pooling is automatic
within the async with block.
Marshal + parse + retry-schedule helpers in _http.py are shared
between the sync and async clients so the wire shape can't drift.
Behavior
- Sync + async.
ConformanceClient(onerequests.Sessionper instance, connection reuse across calls) andAsyncConformanceClient(onehttpx.AsyncClientperasync withblock, async-native viahttpx). Same surface, same wire shape, same retry behavior. - Retry on 5xx. Up to 3 retries after the first attempt. Default
backoff is exponential (250ms / 500ms / 1000ms). If a 5xx response
carries a
Retry-After: <seconds>header (PR 2b's dormant-flag 503 sendsRetry-After: 60), the SDK honors it for the next attempt, clamped to[1.0, 300.0]seconds so a misconfigured server can't stall a calling agent indefinitely. - 4xx is not retried. It's a caller bug — the Brain validated and said no.
- Redacted logs. On 4xx the SDK emits a single WARN with the status
and
signal_id. The bearer token and request body are never logged. - Client-side validation.
work_item_idandskillare required.risk_tieranddata_classification, when present, are bounded by the same unions the TS route enforces. - Wire shape. SDK surface is
snake_case; the marshal layer converts tocamelCaseat the HTTP boundary (work_item_id→workItemId,model_invocation.tokens_in→modelInvocation.tokensIn,retrieved_context[].source_id→retrievedContext[].sourceId). - Injectable sleep.
ConformanceClient(sleep=...)accepts anyCallable[[float], None]— tests usesleep=fake_sleeps.appendto assert retry schedules without monkey-patching module attributes or waiting in real time.
Tests
cd packages/clients/python-conformance
python -m venv .venv && source .venv/bin/activate
pip install -e '.[dev]' # includes async deps + pytest-asyncio
pytest # sync + async suite (~48 tests)
mypy --strict src/cb_conformance
ruff check src tests
Issue & epic
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file cb_conformance-1.0.0.tar.gz.
File metadata
- Download URL: cb_conformance-1.0.0.tar.gz
- Upload date:
- Size: 33.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
91c1cf5892e830197fe142c11202aa13ea8e1151c129b618995b6c6c747c65a7
|
|
| MD5 |
ae172d16c3feef9fc1ca0bd7aa171c36
|
|
| BLAKE2b-256 |
8d08196405652bea12bcc4a724d9be8368efc58f192cc35a3ac7bb36ee7959c7
|
Provenance
The following attestation bundles were made for cb_conformance-1.0.0.tar.gz:
Publisher:
publish-cb-conformance.yml on fburkitt/CriticalBridgeApp
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
cb_conformance-1.0.0.tar.gz -
Subject digest:
91c1cf5892e830197fe142c11202aa13ea8e1151c129b618995b6c6c747c65a7 - Sigstore transparency entry: 2015761720
- Sigstore integration time:
-
Permalink:
fburkitt/CriticalBridgeApp@7ff3b9ab1bedc1e245d0b09323dba15a4736e393 -
Branch / Tag:
refs/tags/cb-conformance-v1.0.0 - Owner: https://github.com/fburkitt
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish-cb-conformance.yml@7ff3b9ab1bedc1e245d0b09323dba15a4736e393 -
Trigger Event:
push
-
Statement type:
File details
Details for the file cb_conformance-1.0.0-py3-none-any.whl.
File metadata
- Download URL: cb_conformance-1.0.0-py3-none-any.whl
- Upload date:
- Size: 27.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f032c56ec81c1203545ed21173c513be3c4442de6ad06bf660830647b230c16d
|
|
| MD5 |
6ba4f7b83c94ebac7da450749d28e6bb
|
|
| BLAKE2b-256 |
e73b8c1ba6674c2beed5023e54ddab58b50e7aeb0749427a9e44e6df38c3ee17
|
Provenance
The following attestation bundles were made for cb_conformance-1.0.0-py3-none-any.whl:
Publisher:
publish-cb-conformance.yml on fburkitt/CriticalBridgeApp
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
cb_conformance-1.0.0-py3-none-any.whl -
Subject digest:
f032c56ec81c1203545ed21173c513be3c4442de6ad06bf660830647b230c16d - Sigstore transparency entry: 2015761898
- Sigstore integration time:
-
Permalink:
fburkitt/CriticalBridgeApp@7ff3b9ab1bedc1e245d0b09323dba15a4736e393 -
Branch / Tag:
refs/tags/cb-conformance-v1.0.0 - Owner: https://github.com/fburkitt
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish-cb-conformance.yml@7ff3b9ab1bedc1e245d0b09323dba15a4736e393 -
Trigger Event:
push
-
Statement type: