Skip to main content

riskrouter-recorder (Python)

Evidence from where decisions are already made. Each record stays in your own journal; only SHA-256(salt || RFC 8785 of the record) and its kind are sent, in batches from a background thread, to a log that speaks the RiskRouter evidence API (https://riskrouter.eu/spec), or to none. Python 3.8 or later, standard library only.

pip install riskrouter-recorder

The same package is published at https://riskrouter.eu/kit/recorder/python/ if you would rather copy it into your project.

import logging, os
from riskrouter_recorder import Recorder, EvidenceHandler, EvidenceSpanProcessor

recorder = Recorder(api_key=os.environ.get("RISKROUTER_API_KEY"), journal="evidence.jsonl")

# 1. Directly
recorder.record({"kind": "ai.decision", "record_id": "dec-2291", "model": "credit-v4", "outcome": "refer"})

# 2. From logging: records emitted with extra={"evidence": record}
log = logging.getLogger("decisions")
log.addHandler(EvidenceHandler(recorder))
log.info("referred", extra={"evidence": {"kind": "ai.decision", "record_id": "dec-2292", "outcome": "refer"}})

# 3. Around a function that decides (digests of arguments and result by default)
@recorder.decision("ai.decision")
def score(application): ...

# 4. From OpenTelemetry: spans with evidence.kind become records
provider.add_span_processor(EvidenceSpanProcessor(recorder))

bundle = recorder.bundle(record_digest)   # what a supervisor checks offline
recorder.close()                          # sends what is pending

Files you keep elsewhere

digest_file(path) returns the SHA-256 of a file read in chunks, for a record that names a file it does not contain, such as a call recording (mifid.call-recording). The file stays where it is.

Completeness chains

With a chain secret, every record goes in a numbered chain, so a record later left out is a gap an auditor sees (https://riskrouter.eu/spec#chains). The recorder adds chain_tag, chain_seq and chain_prev itself, and carries on from its journal after a restart. One process writes a given chain.

recorder = Recorder(chain_secret=os.environ["RISKROUTER_CHAIN_SECRET"], chain="kyc-desk")
recorder.record({"kind": "aml.onboarding", "record_id": "onb-1182"})
bundle = recorder.completeness()   # the log's signed statement and every record of the chain

Agents: LangChain, LangGraph and the OpenAI Agents SDK

Each agent run becomes one record, with its tool calls, model calls, handoffs, guardrails and graph nodes as steps. Steps keep content digests (SHA-256 of the text), never the text, unless you pass include_content=True, which keeps the text in your journal; it is still never sent. Neither framework is a dependency. Design: docs/agent-adapters.md.

from riskrouter_recorder.agents import EvidenceCallbackHandler, EvidenceTracingProcessor

fields = {"system_ref": "claims-agent", "system_version": "2.3"}
graph.invoke(state, config={"callbacks": [EvidenceCallbackHandler(recorder, fields=fields)]})   # LangChain / LangGraph

from agents import add_trace_processor                                                          # OpenAI Agents SDK
add_trace_processor(EvidenceTracingProcessor(recorder, fields=fields))

add_trace_processor keeps the SDK's own exporter, which sends traces to OpenAI; use set_trace_processors([...]) if nothing should go there.

The same guarantees as the Node recorder: nothing is lost (journal first, then send), nothing is claimed (recorded only from the log's answer), no lock-in (any compatible log, or none), and the journal is yours to keep and, where the law requires, to erase from.

Design: docs/recorders.md in the RiskRouter repository. Licence: Apache-2.0 (LICENSE), like the verifiers, the conformance suite and the integration kit (https://github.com/aniljangrabe-dev/riskrouter-verify); the service itself is not licensed.

Metadata

Release files for riskrouter-recorder 0.1.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for riskrouter-recorder 0.1.1
File Size Uploaded
riskrouter_recorder-0.1.1.tar.gz 22.9 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for riskrouter-recorder 0.1.1
File Interpreter ABI Platform
riskrouter_recorder-0.1.1-py3-none-any.whl Python 3 none any Details

Total release size: 41.5 kB

Release files / riskrouter_recorder-0.1.1.tar.gz

Download URL riskrouter_recorder-0.1.1.tar.gz
Size 22.9 kB
Tags Source
SHA-256 checksum
How to use checksums
19966c978476caa98caf3ff73adf139e86760266792fd89bd96bfada059bd3f7
BLAKE2b-256 checksum
How to use checksums
2dc09870051fd762efca943366c48cad68d1ba6d14dd695156807dfdcbe9e63d
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Release files / riskrouter_recorder-0.1.1-py3-none-any.whl

Download URL riskrouter_recorder-0.1.1-py3-none-any.whl
Size 18.7 kB
Tags Python 3
SHA-256 checksum
How to use checksums
b1eb553644717c27a351a8a45254abf52b6369b81ad5849bb25050ad005fe92c
BLAKE2b-256 checksum
How to use checksums
e1dbc0253a16f2078c63f0bfbb80db159fbfae71660ffe6bc6021d16841214a6
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Release history Release notifications | RSS feed

This release

0.1.1 This release

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page