Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Content-addressed provenance DAG for research lineage tracking. Use for: recording which pipeline stage produced which artifact, querying edges between recorded nodes, running a DAG-wide review pass. CLI: python -m infrastructure.provenance {list,record-artifact,review}. Library: infrastructure.provenance.Provenance (record/link/get/list/query). Orchestrator: scripts/pipeline/stage_09_provenance_record.py --project {name} --stage NAME
.claude/skills/docxology-provenance-dag/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-01 | ✗→✓ | ▲ Improved | -25% | 0% |
| case-02 | ✗→✓ | ▲ Improved | 21% | 0% |
| case-03 | ✗→✓ | ▲ Improved | 119% | 0% |
| case-04 | ✗→✓ | ▲ Improved | -31% | 0% |
| case-05 | ✗→✓ | ▲ Improved | -38% | 0% |
Content-addressed provenance DAG for tracking research artifact lineage. Every artifact node is identified by a SHA-256 content hash; edges record which pipeline stage produced each artifact from which inputs.
pythonfrom infrastructure.provenance import ArtifactNode, EdgeRelation, Provenance, RunNode store = Provenance.with_path("output/.provenance") # Record that a run produced an artifact run = RunNode.create("analysis run", command="uv run python scripts/pipeline/stage_02_analysis.py") artifact = ArtifactNode.create("results.json", path="output/results.json") store.record(run) store.record(artifact) # Link the artifact to the run that produced it store.link(run.node_id, artifact.node_id, EdgeRelation.produced_by)
bash# Record an artifact node uv run python -m infrastructure.provenance record-artifact "results.json" --path output/results.json # List all recorded nodes (optionally filter by kind: artifact/run/source/claim) uv run python -m infrastructure.provenance list --kind artifact # Run the DAG-wide review pass (missing hashes, missing exit codes, etc.) uv run python -m infrastructure.provenance review --json # Run the DAG graph structural and acyclicity validation uv run python -m infrastructure.provenance validate --json
There is no link or query CLI subcommand — those are library-only (Provenance.link() / Provenance.query()); the CLI exposes list, record-artifact, review, and validate.
bash# Record provenance for a named project and pipeline stage uv run python scripts/pipeline/stage_09_provenance_record.py --project my_project --stage analysis # Record with explicit input/output glob patterns and a custom store path uv run python scripts/pipeline/stage_09_provenance_record.py \ --project my_project \ --stage render \ --outputs "output/*.pdf" \ --store-path output/.provenance/dag.json
There is no projects/{name}/manuscript/config.yaml provenance: block — config-driven provenance is not implemented; every run is parameterized via CLI flags on the stage script above.
pythonfrom infrastructure.provenance import ( Provenance, # Main interface — record / link / get / list / query ArtifactNode, # File/dataset node: .path, .content_hash, .size_bytes RunNode, # Pipeline-run node: .command, .exit_code, .duration_seconds SourceNode, # External-source node ClaimNode, # Scientific-claim node Edge, # Directed edge between two node ids: .from_id, .to_id, .relation EdgeRelation, # Enum of edge relations (e.g. produced_by) )
Every node id is a SHA-256 hash derived from its kind + identifying fields (e.g. an ArtifactNode's id is derived from its label + path):
pythonartifact = ArtifactNode.create("results.json", path="output/results.json", content_hash="sha256:abc123...") print(artifact.node_id) # deterministic id derived from label + path print(artifact.content_hash) # "sha256:abc123..." (caller-supplied, not computed by create())
Recording the same node id twice is idempotent — record() only sets created_at and persists on first insert.
query() filters edges, not nodes — it does not resolve a path to its ancestors directly:
pythonedges = store.query(to_id=artifact.node_id) for edge in edges: producer = store.get(edge.from_id) print(f" {producer.label} --{edge.relation.value}--> {artifact.label}")
There is no per-node store.review(...) method — review is a whole-store audit function that flags missing hashes, missing exit codes, empty claim confidence, and empty source URIs:
pythonfrom infrastructure.provenance import review_provenance_store result = review_provenance_store(store) for finding in result.findings: print(finding.severity.value, finding.code, finding.message)
bashuv run pytest tests/infra_tests/provenance/ -v
AGENTS.md — operating contract and architecture../search/SKILL.md — search module skill../core/pipeline/AGENTS.md — pipeline integration| Case | Status | Duration (ms) | Turns | Tokens | Tool calls | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Without | With | Δ | Without | With | Δ | Without | With | Δ | Without | With | Δ | ||
case-01 | fail→pass | 13,424 | 28,933 | +116% | 1 | 1 | 0% | 2,079 | 1,550 | -25% | 0 | 0 | — |
case-02 | fail→pass | 9,168 | 4,387 | -52% | 1 | 1 | 0% | 1,568 | 1,897 | +21% | 0 | 0 | — |
case-03 | fail→pass | 14,937 | 2,804 | -81% | 1 | 1 | 0% | 746 | 1,632 | +119% | 0 | 0 | — |
case-04 | fail→pass | 13,607 | 1,539 | -89% | 1 | 1 | 0% | 1,962 | 1,346 | -31% | 0 | 0 | — |
case-05 | fail→pass | 14,526 | 1,840 | -87% | 1 | 1 | 0% | 2,253 | 1,396 | -38% | 0 | 0 | — |
case-06 | fail→pass | 8,395 | 2,191 | -74% | 1 | 1 | 0% | 1,368 | 1,458 | +7% | 0 | 0 | — |
case-07 | fail→pass | 12,523 | 1,907 | -85% | 1 | 1 | 0% | 2,222 | 1,435 | -35% | 0 | 0 | — |
case-08 | fail→pass | 19,862 | 3,918 | -80% | 1 | 1 | 0% | 3,436 | 1,861 | -46% | 0 | 0 | — |
case-09 | fail→pass | 14,135 | 6,007 | -58% | 1 | 1 | 0% | 2,392 | 2,298 | -4% | 0 | 0 | — |
case-10 | fail→pass | 12,481 | 3,497 | -72% | 1 | 1 | 0% | 2,052 | 1,797 | -12% | 0 | 0 | — |
case-11 | fail→pass | 13,351 | 1,926 | -86% | 1 | 1 | 0% | 1,970 | 1,428 | -28% | 0 | 0 | — |
case-12 | fail→pass | 9,318 | 4,359 | -53% | 1 | 1 | 0% | 1,535 | 1,861 | +21% | 0 | 0 | — |
case-13 | fail→pass | 14,499 | 4,748 | -67% | 1 | 1 | 0% | 2,122 | 1,987 | -6% | 0 | 0 | — |
case-14 | fail→pass | 8,888 | 3,266 | -63% | 1 | 1 | 0% | 1,358 | 1,679 | +24% | 0 | 0 | — |
case-15 | fail→pass | 12,740 | 4,035 | -68% | 1 | 1 | 0% | 1,877 | 1,786 | -5% | 0 | 0 | — |
case-16 | fail→pass | 7,910 | 1,162 | -85% | 1 | 1 | 0% | 1,181 | 1,302 | +10% | 0 | 0 | — |
case-17 | fail→pass | 14,635 | 2,480 | -83% | 1 | 1 | 0% | 2,252 | 1,561 | -31% | 0 | 0 | — |
case-18 | fail→pass | 12,580 | 3,327 | -74% | 1 | 1 | 0% | 2,273 | 1,682 | -26% | 0 | 0 | — |
case-19 | pass→pass | 13,603 | 3,889 | -71% | 1 | 1 | 0% | 2,028 | 1,664 | -18% | 0 | 0 | — |
case-20 | pass→pass | 3,211 | 3,182 | -1% | 1 | 1 | 0% | 473 | 1,493 | +216% | 0 | 0 | — |
case-21 | pass→pass | 17,362 | 4,621 | -73% | 1 | 1 | 0% | 764 | 1,923 | +152% | 0 | 0 | — |
case-22 | pass→pass | 3,256 | 2,859 | -12% | 1 | 1 | 0% | 477 | 1,522 | +219% | 0 | 0 | — |
DecimalAI ran this skill against gemini-3.6-flash twice over the same eval suite — once with the skill loaded and once without — and compared the two runs case by case. 22 cases were attempted, and 21 counted toward the lift figure. The other 1 produced results that are not comparable between the two arms, so they are excluded from the headline rather than averaged into it. The headline lift of +82 percentage points is the difference between those two pass rates over the 21 comparable cases.
Without the skill loaded, the model failed this case. With it loaded, the same prompt on the same model passed. This is one improved case from the latest verified run; every case, including any that regressed, is in the table above.
| Model | Method | Date | Lift |
|---|---|---|---|
| gemini-3.6-flash | verified | 8/4/2026 | +77% |
Other measured skills in the registry, with their headline benchmark lift.