Tellproof

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

  1. 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.
  2. 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 variableDefaultMeaning
TELLPROOF_AGENT_URLhttp://127.0.0.1:4318Where the agent listens.
TELLPROOF_SERVICEOTEL_SERVICE_NAMEThe service name on every span.
TELLPROOF_ENVIRONMENTnoneThe deployment environment, such as production.
TELLPROOF_DISABLEDunset1 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 variableConfig keyDefault
TELLPROOF_SERVERservernone (required)
TELLPROOF_DATA_DIRdata_dir./.tellproof-agent (/data in the container)
TELLPROOF_OTLP_LISTENotlp_listen127.0.0.1:4318
TELLPROOF_DASHBOARD_LISTENdashboard_listen127.0.0.1:4319 in local mode; off turns it off
TELLPROOF_OTLP_ALLOW_REMOTE=1otlp_allow_remoteoff: only loopback addresses may be used
TELLPROOF_ENROL_TOKENThe token for tellproof-agent enrol when --token is not given.
TELLPROOF_SALT_SECRETsalt_secret_env names the variableWith 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.

More evidence sources

Each source is read-only and off until you turn it on.

The data directory

Keep it, and back it up. It holds:

Networking

Troubleshooting