The evidence agent
The agent runs next to your AI product. It receives spans from the Tellproof SDK (or any OpenTelemetry exporter), drops all message content, and sends Tellproof one signed batch of aggregates per hour. It is open source, and --dry-run shows exactly what it would send.
Try it locally
Local mode needs no account, no server and no token. The agent signs each hourly batch with a key of its own and keeps it in its data directory; nothing is sent anywhere.
pip install tellproof-agent && tellproof-agent run --local
npx tellproof-agent run --local
docker run -d --name tellproof-agent -p 127.0.0.1:4318:4318 -p 127.0.0.1:4319:4319 \
-v tellproof-agent:/data ghcr.io/lumetrix-advanced-technologies/tellproof-agent:latest run --local
Add the SDK to your app (below), make a model call, and about a minute later open the dashboard at http://127.0.0.1:4319: calls and tokens per model and region, guardrail coverage and personal-data redaction over time, tool use, a timeline of changes, anomalies and evaluations, and the evidence chain. The agent serves it on loopback only and it loads nothing from elsewhere. Set TELLPROOF_DASHBOARD_LISTEN (or dashboard_listen) to move it, or to off. The same figures in a terminal:
tellproof-agent report
tellproof-agent report --json --since 2026-10-01
report checks every batch's signature against agent.pub and the chain from the first batch, then sums the calls per model and region, guardrail decisions, personal-data redaction, agent activity, prompt and model changes and anomalies. It exits 1 if a batch was edited or is missing. Keep a copy of agent.pub elsewhere: the log proves it has not changed relative to that key.
For packs evaluated against Tellproof's evidence objectives and signed by an independent issuer, which a reviewer can verify, request early access to the hosted service. Connecting starts a new agent with its own data directory; the local log stays local.
Governance as code
Declare what the AI system may use in tellproof.policy.json, next to its code, and check the evidence against the eleven evidence objectives with the same evaluator that issues signed packs:
tellproof-agent policy init --name "Claims Triage Agent" --timezone Australia/Sydney # declare what the log has seen; review it
tellproof-agent policy validate # in CI, on every policy change
tellproof-agent check # pass, attention or fail per objective
tellproof-agent check --junit check.xml --strict # gate a release
tellproof-agent check --self-test # prove each objective can fail
tellproof-agent aibom --out aibom.cdx.json # CycloneDX 1.6 AI bill of materials
The policy declares models and regions (lineage and residency) and keeps the change, incident and evaluation registers (the change, incident and evaluation-freshness objectives); its JSON Schema is spec/policy.schema.json. check verifies the log first, then shows each objective's measurement, target, the framework references it supports and any register entries that are missing; it exits 1 when an objective fails. The dashboard shows the same results in its Evidence objectives panel. A GitHub Action, Lumetrix-Advanced-Technologies/tellproof, runs policy validate or check in CI.
check --self-test adds, for each objective, the least synthetic evidence that should fail it to a copy of the input and requires it to fail; it reports a register that leaves no room for a violation as vacuous, and checks that an edited, re-signed or missing batch fails verification on a copy of the log. Guardrail canaries from the SDK (schedule_canaries, scheduleCanaries) send known-bad probes through your own guardrail and record only whether each was caught (objective EO-CAN-01).
For codebases, tellproof-agent ci records each CI gate's outcome on a commit (exit status, duration, test counts; never logs, code or command lines), runs must-fail canaries that apply a breaking patch in a temporary worktree and require the gate to fail, and writes a signed in-toto statement per commit, including how many commits name a coding agent. ci verify and tellproof-verify ci check it against the policy's ci section.
Connect to Tellproof
- In the Tellproof app, open your AI system's Setup and sources page and choose Create enrolment token. The page shows the command below with the token and server filled in. The token works once, for 24 hours.
- Run the agent with it, then add one line to your app.
docker run -d --name tellproof-agent --restart unless-stopped -p 127.0.0.1:4318:4318 \
-v tellproof-agent:/data -e TELLPROOF_SERVER=https://<server> \
ghcr.io/lumetrix-advanced-technologies/tellproof-agent:latest connect <token>
connect enrols the agent if its data directory is not enrolled yet, then runs. Running the same command again, for example after a restart, does not enrol again. About a minute after your app's first model call, the system page lists the agent and its first batch.
Install
Container
The image ghcr.io/lumetrix-advanced-technologies/tellproof-agent is a static binary on a distroless base, for linux/amd64 and linux/arm64, running as a non-root user. Keep the /data volume (see the data directory).
Binary
Release binaries for Linux, macOS and Windows on amd64 and arm64 are on the open-source repository's Releases page. Check a download before you run it:
sha256sum --ignore-missing -c SHA256SUMS
gh attestation verify tellproof-agent-linux-amd64 --repo lumetrix-advanced-technologies/tellproof
TELLPROOF_SERVER=https://<server> ./tellproof-agent-linux-amd64 connect <token>
Use a tellproof-agent-bedrock-* binary if you need Amazon Bedrock usage from CloudWatch.
From source
go install github.com/lumetrix-advanced-technologies/tellproof/cmd/agent@latest
pip or npm
pip install tellproof-agent or npm install -g tellproof-agent (or npx tellproof-agent) install the same static binary as the release for your platform. Nothing is downloaded at install time and nothing runs on install.
Instrument your app
Install the SDK (pip install tellproof or npm install tellproof) and add one line at start-up:
import tellproof; tellproof.init() # Python 3.10+
import * as tellproof from 'tellproof'; tellproof.init(); // Node.js 18+
The SDK instruments the OpenAI, Anthropic and Bedrock client libraries that are installed. It records one span per model call (provider, model, region, token counts, operation, timing and error status) and never reads prompts, completions, arguments or return values. It has no dependencies, and it never blocks or breaks your app: if the agent is down, spans are dropped and counted.
| Environment variable | Default | Meaning |
|---|---|---|
TELLPROOF_AGENT_URL | http://127.0.0.1:4318 | Where the agent listens. |
TELLPROOF_SERVICE | OTEL_SERVICE_NAME | The service name on every span. |
TELLPROOF_ENVIRONMENT | none | The deployment environment, such as production. |
TELLPROOF_DISABLED | unset | 1 turns the SDK off. |
Serving your own models? There is no client library to patch: wrap each inference request in your serving layer with tellproof.llm_call("your-company", model, region=...) (Node.js: tellproof.llmCall({provider, model, region}, fn)) and report the tokens with c.usage(input, output).
Without the SDK, point an OTLP/HTTP JSON exporter at http://127.0.0.1:4318/v1/traces and set the tellproof.* attributes yourself, as listed in spec/semconv-map.json. Do not use both for the same calls, or they are counted twice.
See what would be sent
Dry run prints every batch the agent would send, with its payload decoded, and sends, queues and stores nothing. Replay feeds an OTLP JSON export through the same pipeline and exits:
tellproof-agent run --config agent.json --dry-run
tellproof-agent run --config agent.json --dry-run --replay export.jsonl
A batch holds counts and short names only: tokens and calls per provider, model and region, counts of spans with personal data and how many were redacted, guardrail and evaluation results, agent activity counts, which models and prompt versions were live, and one Merkle root over the hour's traces. The full format is spec/batch.schema.json.
Configuration
connect needs no file. For anything more, write a JSON file and pass --config agent.json. These environment variables override it:
| Environment variable | Config key | Default |
|---|---|---|
TELLPROOF_SERVER | server | none (required) |
TELLPROOF_DATA_DIR | data_dir | ./.tellproof-agent (/data in the container) |
TELLPROOF_OTLP_LISTEN | otlp_listen | 127.0.0.1:4318 |
TELLPROOF_DASHBOARD_LISTEN | dashboard_listen | 127.0.0.1:4319 in local mode; off turns it off |
TELLPROOF_OTLP_ALLOW_REMOTE=1 | otlp_allow_remote | off: only loopback addresses may be used |
TELLPROOF_ENROL_TOKEN | The token for tellproof-agent enrol when --token is not given. | |
TELLPROOF_SALT_SECRET | salt_secret_env names the variable | With connect, a random secret kept in the data directory. |
A complete file, with every source off:
{
"server": "https://<server>",
"data_dir": "./.tellproof-agent",
"otlp_listen": "127.0.0.1:4318",
"langfuse": { "enabled": false, "base_url": "https://cloud.langfuse.com",
"public_key_env": "LANGFUSE_PUBLIC_KEY", "secret_key_env": "LANGFUSE_SECRET_KEY", "eval_scores": [] },
"usage": {
"openai": { "enabled": false, "admin_key_env": "OPENAI_ADMIN_KEY", "project_ids": [] },
"anthropic": { "enabled": false, "admin_key_env": "ANTHROPIC_ADMIN_KEY", "workspace_ids": [] },
"bedrock": { "enabled": false, "region": "ap-southeast-2" }
},
"salt_secret_env": "TELLPROOF_SALT_SECRET",
"salt_secret_file": "",
"aggregation": { "grace_minutes": 5, "first_batch_seconds": 60,
"anomaly": { "min_calls": 20, "error_rate": 0.05, "guardrail_block_rate": 0.03 } }
}
Secrets are never written in the file. The file names the environment variable that holds each one (*_env), or a file with mode 0600 for the salt secret.
aggregation.grace_minutes: how long after the hour a window stays open for late spans. Later spans are counted in the next window as late.aggregation.first_batch_seconds: after a start, the open hour is sent once this long after the first spans, so a new agent shows up at once. The rest of the hour follows when it closes.aggregation.anomaly: an hour with at leastmin_callscalls and an error or guardrail-block rate above these is reported as an anomaly window.
More evidence sources
Each source is read-only and off until you turn it on.
- Langfuse (
langfuse): pulls traces from Langfuse with your project keys, dropping content the same way.eval_scoresmaps a Langfuse score to an evaluation suite:{"name": "faithfulness", "suite": "rag-eval", "pass_at_least": 0.8}. - OpenAI and Anthropic usage (
usage.openai,usage.anthropic): polls the providers' usage APIs with an admin key, so a pack can compare traced tokens with billed tokens (the coverage objective). Limit it to the projects or workspaces of this system. - Amazon Bedrock usage (
usage.bedrock): reads Bedrock's CloudWatch metrics inregionwith the default AWS credential chain. Needs a-bedrockbuild.
The data directory
Keep it, and back it up. It holds:
- the agent's Ed25519 private key (mode
0600), which signs every batch; losing it means enrolling a new agent; - the queue of batches not yet accepted by the server, fsynced before they are acknowledged and retried with backoff of up to 15 minutes;
- each window's commitment leaves and, with
connect,salt.secret. Together they let you later disclose one trace to a reviewer and prove it was counted, without revealing any other.
Networking
- Inbound: only the span receiver, on
127.0.0.1:4318by default. It has no authentication. Inside the container it listens on all interfaces, and the documented command publishes it on the host's loopback only. If your app runs on other hosts (for example other pods), allow remote addresses and restrict who can reach the port with a network policy or firewall. - Outbound: the Tellproof server you configure, over HTTPS. If you turn them on, also the Langfuse API and the providers' usage APIs.
Troubleshooting
- No agent on the system page: check the agent's log for an enrolment error. An expired or used token needs a new one from the app. The same
connectline works again once the data directory is enrolled. - Agent listed, no batches: check that your app reaches
TELLPROOF_AGENT_URL, and run--dry-runto see what the agent is building. - Counts doubled: the SDK and another OpenTelemetry exporter are both sending the same calls to the agent. Use one.
- Exit status: 0 ok, 1 runtime error, 2 usage or configuration error.
tellproof-agent versionprints the version.