aiprov logo: a white salmon leaping up a waterfall in a teal-to-blue circle

aiprov

AI provenance, recorded, open, verifiable

When an AI model drafts your code or your text, two questions come later: who did what, and who checked it? aiprov writes the answers into a plain Turtle file next to your work, as a profile of W3C PROV-O.

A demo: one report, two claims, one human check

Alice asks an AI model to turn her benchmark notes into a short report. Nine commands later, the graph below holds the whole story. The data is invented, the graph is real: this page ran the commands with aiprov 0.2.0 (git 2d72755) when it was built.

The demo graph: Alice and Model X, the draft and the promotion, two files, two claims, and the verification ladderactedOnBehalfOfwasAssociatedWithwasAssociatedWithusedusedwasGeneratedBywasGeneratedBywasGeneratedBynotes.md: used as inputnotes.mdSource (input)Draft the report from the notesdraft-reportAuthoringPass, 2,000 tokensAlice Example: a person, ORCID 0000-0002-1825-0097Alice ExampleHumanAgent, ORCID iDclaim: The new parser is twice as fast. (human-confirmed)The new parser is twice as fast.claim c-speedhuman-confirmedModel X: an AI model (model-x)Model XAIAgent, Example AIreport.md: sha256:2ce88f8ca38578dedc9065068533895d80e52c1ddcbf9fa851bc0fa3be701216report.mdArtefact, sha256 2ce88f8cclaim: All public functions are tested. (unverified)All public functions are tested.claim c-testsunverifiedPromotion of c-speed: ai-confirmed -> human-confirmed (Re-ran the benchmark myself)promotion of c-speedAuditPass, human-confirmed1234The verification ladderunverifiedneeds researchreference resolvedAI-confirmedsource vendoredhuman-confirmedhuman-readhumans only5c-speed, promoted by Alice (4)c-tests stays here
Shapes follow the W3C PROV notation: agents as houses, activities as rectangles, entities as ovals. Claims are entities with a verification state. Hover a node for its details; the numbers match the steps below.
  1. Who. Alice is a person, registered with her ORCID iD. Model X is an AI model that acts on her behalf (prov:actedOnBehalfOf).
  2. What. Model X drafted report.md from notes.md. The activity records the model, both files (the output with its sha256) and the tokens the tool reported: 1,200 in, 800 out.
  3. Claims. The report makes two statements. Each becomes a claim with a parent activity and a state on the ladder: "twice as fast" was checked by the model (AI-confirmed), "all functions tested" by nobody yet (unverified).
  4. Human check. Alice re-ran the benchmark and promoted the speed claim to human-confirmed. The promotion is an activity of its own, an audit pass associated with Alice, so the graph says who granted the step and when.
  5. The rule. Model X then tried to mark the other claim as human-read. provlog refused: the top two steps are for registered humans. validate checks the same rule on the whole file, so a hand-edited graph cannot slip it in either.

The commands, as run for this page

Each with --base https://example.org/demo/; the output is what provlog printed.

$ provlog init
Seeded provenance.ttl (519 triples, base https://example.org/demo/, schema 0.3.0)
$ provlog agent --id alice --type human --name "Alice Example" \
    --orcid 0000-0002-1825-0097
agent:alice registered (human)
$ provlog agent --id model-x --type ai --name "Model X" --model model-x \
    --provider "Example AI" --acted-on-behalf-of alice
agent:model-x registered (ai)
$ provlog log --activity draft-report --pass authoring --agent model-x \
    --label "Draft the report from the notes" --used notes.md \
    --generated report.md --input-tokens 1200 --output-tokens 800
act:draft-report logged (544 triples total)
$ provlog claim --id c-speed --text "The new parser is twice as fast." \
    --parent draft-report --agent model-x --state ai-confirmed
claim:c-speed added (state ai-confirmed)
$ provlog claim --id c-tests --text "All public functions are tested." \
    --parent draft-report --agent model-x --state unverified
claim:c-tests added (state unverified)
$ provlog promote --id c-speed --to human-confirmed --agent alice \
    --note "Re-ran the benchmark myself"
c-speed: ai-confirmed -> human-confirmed (logged as AuditPass, agent:alice)
$ provlog claim --id c-tests --text "All public functions are tested." \
    --parent draft-report --agent model-x --state human-read
REFUSED: rung 'human-read' is human-only; agent:model-x is not a registered HumanAgent. An AI must never grant this rung.
(exit 1)
$ provlog validate
[ OK ] parentless claims: 0
[ OK ] unattributed claims: 0
[ OK ] human-only rungs granted by AI agents: 0
[ OK ] human-only rungs without a recorded human promotion activity: 0
[ OK ] sources above needs-research without DOI/URL: 0
[ OK ] activities without agent: 0
[ OK ] session activities with no measurable span (a logging instant, not the span of the work): 0
[ OK ] agents referenced but not registered: 0
[ OK ] agents typed as both AI and human: 0
[ OK ] wasInformedBy targets that are not logged activities: 0
[ OK ] external references (nodes defined in another graph): 0
[ OK ] external references that carry a file path or a label: 0
[ OK ] sub-activities outside the orchestration plan: 0
[ OK ] orchestrations logged twice or informed by themselves: 0
[ OK ] sub-activities logged before their orchestration: 0
[ OK ] entities generated by two activities that carry a model role: 0
[ OK ] fallbackOf targets that are not other logged activities: 0
[ OK ] activities that are part of something that is not a session: 0
[ OK ] messages without a sender: 0
[ OK ] replies to a message that is not in this graph: 0
[ OK ] messages without a content hash, or whose kept text does not match it: 0
[ OK ] message text kept in a channel above internal or of unknown class: 0
[ OK ] records made by another agent or in arrears without a source (recordedFrom): 0
[ OK ] sessions with token sums from more than one capture path (only one is counted): 0
[ OK ] viaHarness targets that are not registered harnesses: 0
[ OK ] activities via a harness with neither a model nor a stated reason: 0
[ OK ] telemetry chain anchors without one valid head, a length of at least 1 and an author: 0
[ OK ] premises that are not claims: 0
[ OK ] premise cycles: 0
[ OK ] atleast claims with minPremises missing or above the number of premises: 0
[ OK ] composite claims without premises: 0
[ OK ] claims stated above their effective rung: 0
[ OK ] decisions that are malformed (asker, hash, two options, recommendation, text matching hash): 0
[ OK ] options or deciding activities that are incomplete: 0
[ OK ] chosen options that the decision did not offer: 0
[ OK ] decisions set to done by an agent that is not a registered human: 0
[ OK ] supersedes links to a missing decision, to itself or in a cycle: 0
[ OK ] decision text kept where the data class is unknown or above internal: 0
[ OK ] graph states its schema version

The resulting graph: demo.ttl (Turtle, with the vocabulary), and the dashboard that aiprov-dashboard builds from it.

Try it

$ pip install git+https://github.com/noheton/aiprov
$ provlog --base https://your.org/prov/ init

Then register your agents and log your steps as above. The README lists every command; issues and pull requests are welcome.

Cite

Krebs, F. (2026). aiprov: domain-agnostic AI provenance over PROV-O (Version 0.2.0) [Software]. Zenodo. https://doi.org/10.5281/zenodo.23651340

All versions: https://doi.org/10.5281/zenodo.23651333. Citation metadata: CITATION.cff.