Python API Reference¶
bijotel exposes a small public API (see bijotel.__all__). Most users
only need 3-4 symbols.
Public exports¶
from bijotel import (
# Core
__version__,
init,
shutdown,
# Decorators
trace_genai,
wrap,
# Provider adapters
AnthropicAdapter,
OpenAIAdapter,
Provider,
ProviderResponse,
# Policy
PolicyEngine,
PolicyDeniedError,
Decision,
guard,
# Built-in rules
prompt_pattern_deny,
pii_detection,
output_length_limit,
cost_per_call_max,
daily_token_budget,
model_allowlist,
model_version_pin,
rate_limit_calls_per_minute,
routing_recommendation,
energy_budget,
consensus_requirement,
# Processors
HmacChainSpanProcessor,
CasSpanProcessor,
FingerprintSpanProcessor,
EnergySpanProcessor,
DAGNode,
MerkleDAG,
verify_chain,
verify_export,
export_chain,
# Layers
SemanticFingerprinter,
DeterministicFingerprinter,
similarity_search,
ConsensusVoter,
ConsensusResult,
StakesClassifier,
TaskClassifier,
ContainmentGuard,
ContainmentDecision,
Budget,
CarbonCalculator,
EnergyEstimator,
EnergyTracker,
EnergySummary,
ModelRegistry,
ModelResponse,
ParetoRouter,
ASTSafetyChecker,
ASTViolation,
ast_safety_check,
misalignment_check,
MisalignmentReport,
Probe,
ProbeLibrary,
compute_agreement,
# Regression
Anomaly,
AnomalyMethod,
DimensionStats,
RegressionDetector,
compute_baseline,
)
Core init¶
import bijotel
# Lightweight tracer setup (F1 schema discovery)
tracer = bijotel.init(service_name="my-service")
bijotel.shutdown()
For production wire-up, build the TracerProvider yourself and add
processors directly (see Quickstart).
Decorators¶
@trace_genai¶
Auto-emit a gen_ai.* span around any function (sync or async):
from bijotel import trace_genai
@trace_genai(name="my.llm.call", provider="anthropic", operation="chat")
def call_claude(prompt: str) -> str:
...
Custom request/response extractors:
@trace_genai(
provider="anthropic",
request_extractor=lambda kwargs: {
"gen_ai.request.model": kwargs.get("model"),
"gen_ai.usage.input_tokens": estimate_tokens(kwargs.get("messages")),
},
response_extractor=lambda resp: {
"gen_ai.response.model": resp.model,
"gen_ai.usage.output_tokens": resp.usage.output_tokens,
},
)
def my_call(model, messages): ...
@wrap¶
Simpler decorator for OpenAI-compatible providers:
Policy¶
from bijotel import (
PolicyEngine,
prompt_pattern_deny,
pii_detection,
PolicyDeniedError,
)
engine = PolicyEngine(rules=[
prompt_pattern_deny(mode="deny"),
pii_detection(mode="warn"),
])
decision, warnings = engine.evaluate({
"messages": [{"role": "user", "content": "..."}],
"model": "claude-haiku-4-5-20251001",
})
if decision.is_deny:
raise PolicyDeniedError(decision.reason)
The guard helper composes engine + an LLM call:
from bijotel import guard, PolicyEngine
@guard(engine=engine)
def call_llm(prompt: str):
# If engine denies, this function isn't called.
return anthropic_client.messages.create(...)
Verification¶
from pathlib import Path
from bijotel.processors import verify_chain, verify_export
# Verify a chain.db
valid, broken_seq, reason = verify_chain(
Path("chain.db"),
secret_key=bytes.fromhex("..."),
)
if not valid:
print(f"Chain broken at seq={broken_seq}: {reason}")
# Verify an exported JSON
valid, reason = verify_export("export.json", secret=bytes.fromhex("..."))
Provider adapters¶
from bijotel import AnthropicAdapter, OpenAIAdapter
# Anthropic
adapter = AnthropicAdapter()
attrs = adapter.extract_request_attrs(kwargs) # gen_ai.* dict
response_attrs = adapter.extract_response_attrs(response)
# OpenAI-compatible (xAI, Together, DeepSeek, etc.)
adapter = OpenAIAdapter()
Type hints¶
The package ships with py.typed. Type checkers (mypy, pyright)
honor the public API signatures.
Stability¶
Anything in bijotel.__all__ is stable across patch releases.
Changes are versioned per SemVer and documented in
CHANGELOG.md.
Internal modules (e.g. bijotel.processors.canonical) are not part
of the public API and may change between minor versions.