Skip to main content
Not every file a user attaches has prior provenance. When a file is new to the system, you need to ask: who created this? The answer changes the action type recorded, but in both cases the file gets a content-addressed CID that downstream AI actions can reference.

The Two Cases

Case 1 — Known file (provenance exists)

The file matches an existing record in the system. The existing CID is reused as an inputCid — no additional recording needed.

Case 2 — New file (no prior provenance)

The file is not in the system. Ask the user: “Do you own this file?” Both paths produce a CID. Both CIDs can be used as inputCids in downstream provenance actions.

Why Both Cases Matter

Claimed resources (action.type = "create") establish a clean ownership chain. The provenance graph shows user → creates → file → inputs → AI response. This is strong evidence for copyright claims (see the Human Creative Input pattern). Unclaimed resources (action.type = "reference") are equally important. Recording that an AI response used an unknown-origin file is honest provenance — it accurately represents the training data and inputs used. Silently omitting unattributed inputs is worse than recording their existence.
An unclaimed resource is not a problem in the provenance graph — it’s an honest representation of reality. The absence of a creator entity signals “origin unknown” rather than “created by no one.”

Implementation

Server-side claim endpoint

Client-side with FileProvenanceTag

When the file has no prior provenance, FileProvenanceTag renders FileOwnershipClaim inline:
After the user decides, the component transitions to a success state:

Using the CID in downstream actions

Once the file has a CID (from either a match or a claim), pass it as inputCids when recording the AI response:
The resulting provenance graph:

On-Chain Recording

Both "create" and "reference" actions are eligible for on-chain recording. If CHAIN_PRIVATE_KEY and BASE_SEPOLIA_RPC_URL are set, pk.file() automatically records the action hash to the ProvenanceRegistry contract on Base Sepolia.
On-chain recording is fire-and-forget — if it fails, the off-chain record (in Supabase/PostgreSQL) always stands as the canonical provenance record.

What the Provenance Graph Looks Like

Claimed file

Unclaimed file (referenced)

The difference: create signals Alice made it; reference signals Alice used it but didn’t make it. Both are honest, auditable records.

Gotchas

  • Ask before the message is sent: The ownership decision should happen in the attachment UI, not after submission. FileProvenanceTag handles this — it runs the search and shows the claim prompt while the file is still in the input area.
  • Reuse existing CIDs: If FileProvenanceTag finds a match (score ≥ some threshold), use the existing CID directly as inputCid. Don’t re-record the same file as a new resource.
  • CID propagation: Store the claimed CID in local state immediately after onClaim resolves so it’s available when the message is submitted. FileOwnershipClaim’s onClaim callback is the right place to call setState.
  • Binary files (PDFs): For files where text content can’t be extracted inline, the provenance record still captures the file hash (CID). The LLM won’t see the content, but the provenance chain remains complete.