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), for the recorders only;
the rest of RiskRouter's source is not licensed.
Metadata
Release files for riskrouter-recorder 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| riskrouter_recorder-0.1.0.tar.gz | 22.8 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| riskrouter_recorder-0.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 41.4 kB
Release files / riskrouter_recorder-0.1.0.tar.gz
| Download URL | riskrouter_recorder-0.1.0.tar.gz |
|---|---|
| Size | 22.8 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
c69d94d516989080f842e738fe14464d166acdfaf2ba755062f1f9dad7ad9844
|
|
BLAKE2b-256 checksum How to use checksums |
a6c9da5565b50dc147aa704ed246b6c1475c3138043212f4269c6ad2285f39af
|
| 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.0-py3-none-any.whl
| Download URL | riskrouter_recorder-0.1.0-py3-none-any.whl |
|---|---|
| Size | 18.6 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
2483c8983e434dcdde879821c8560decc618a8a771afada48b8dcdf082120cf2
|
|
BLAKE2b-256 checksum How to use checksums |
d14ab02887a619a52351b19ddcf330910fdc7a1bebb6bb6bff84ad99ca5b3009
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|