provenanceaudit

star 4

Audit forge module provenance and deployment integrity — inspect deployed sidecars, detect drift, clean stale artifacts after renames, trace adoption chains. USE WHEN running forge provenance, auditing a deployed target, debugging drift, cleaning up after a skill rename, or investigating sidecar state.

N4M3Z By N4M3Z schedule Updated 6/16/2026

name: ProvenanceAudit version: 0.1.0 description: "Audit forge module provenance and deployment integrity — inspect deployed sidecars, detect drift, clean stale artifacts after renames, trace adoption chains. USE WHEN running forge provenance, auditing a deployed target, debugging drift, cleaning up after a skill rename, or investigating sidecar state." allowed-tools: Bash, Read, Grep, Glob

ProvenanceAudit

Operational procedures for auditing .provenance/ sidecars in forge deployments and source repos. forge provenance checks deployment integrity: it reads sidecar SLSA attestations, compares the recorded SHA-256 digest against the deployed file content, and reports per-module verification rates. Complements NoVendorLockIn (how assembly rewrites sidecars).

Manifest vs provenance

The two records answer different questions:

  • Provenance: "what produced this file?"
  • Manifest: "was this deployed file modified since we last put it there?"

The manifest is created when files land at the target, whether via forge deploy (from build/) or forge copy (direct from source). It lives at the target as a .manifest dotfile.

Provenance lives at two layers. Source-side .provenance/ records adoption (adopt/v1): upstream URL, pinned commit, transform skills applied. Build-side build/<provider>/.provenance/ records assembly (assemble/v1), regenerated on every install.

Audit a deployed target

forge provenance expects a deployed provider directory (~/.claude, ~/.opencode, ~/.codex, ~/.gemini) — the deploy sidecars it reads are written by forge install in assemble/v1 form. Running it against a source module (forge provenance inside a repo, where --target defaults to .) reports every subject as orphan, because source sidecars use adopt/v1 or init/v1 buildTypes that the audit reader doesn't resolve.

forge provenance --target ~/.claude                  # audit user-scope deployment
forge provenance --target ~/.claude --show-orphans   # include unverified files
forge provenance --target ~/.claude --json           # machine-readable output

Per-module results look like:

https://github.com/N4M3Z/forge-core → ✓ 156 verified
https://github.com/N4M3Z/forge-dev  → ✓ 53 verified
forge-text                           → ✗ 21/22 verified

A means at least one deployed file's digest doesn't match its sidecar — either a post-deploy edit or a tamper. Diff the deployed file against build/<provider>/<path> to identify what drifted.

Compare two trees

forge drift compares any two directories containing markdown content: modules, build output, or deployed targets.

forge drift --upstream ~/upstream-module                 # source (defaults to .) vs upstream
forge drift --source build/claude --upstream ~/.claude   # assembled vs deployed

Do not compare source against deployed content directly. Assembly transforms (frontmatter stripping, heading removal) always show as drift; compare build/<provider> against the target instead.

Trace an adoption chain

Deployed sidecars carry the assemble/v1 buildType with a single input (the source file). The richer adopt/v1 sidecar — with upstream URL, pinned commit, AdoptArtifact reference, and transform-skill digests — exists only in the source repo.

cat agents/.provenance/SkillReviewer.yaml
# resolvedDependencies:
#   - name: upstream
#     uri: https://raw.githubusercontent.com/...
#     digest: sha256:...
#   - name: AdoptArtifact
#     uri: forge-core/skills/AdoptArtifact/SKILL.md
#     digest: sha256:...

Clean stale deployments after a rename

forge install is additive, not idempotent for renames. After renaming skills/OldNameskills/NewName and reinstalling, the old directory persists at every deployed target. Explicit cleanup is required across every provider:

for provider in .claude .codex .opencode .gemini; do
    dir="$HOME/$provider/skills/OldName"
    [ -d "$dir" ] && rm -rf "$dir"
done

If the safety-net plugin blocks rm -rf paths outside cwd, use a per-file loop (find "$dir" -type f -delete; find "$dir" -type d -empty -delete) or ask the user to run the cleanup in their terminal.

After cleanup, confirm: ls ~/.claude/skills/ | grep -iE "OldName|NewName" should return only NewName.

Update sidecars across the rename's blast radius

Renaming a skill, agent, or transform that appears as a resolvedDependencies entry in OTHER artifacts' sidecars has ecosystem-wide impact. Every sidecar referencing the old identifier (name, uri, digest if the content changed) must be updated:

# Find all sidecars that reference the old name as a dependency
rg -l "name: OldName" --glob "**/.provenance/*.yaml"

Before calling a rename complete, grep every checked-out forge module repo for the old name — sidecars in sibling modules are the most-missed targets.

Debug orphan reports

--show-orphans lists deployed files with no sidecar. Common causes:

  • File was added manually (bypassing forge install) — reinstall or delete
  • Sidecar naming mismatch — forge expects <basename>.yaml but some writers produce <basename>.md.yaml (see forge-cli#31)

Known forge-cli limitations: adopt/v1 sidecars aren't rendered by the CLI (schema mismatch on externalParameters.source — see forge-cli#30). For those, cat the YAML directly.

Install via CLI
npx skills add https://github.com/N4M3Z/forge-core --skill provenanceaudit
Repository Details
star Stars 4
call_split Forks 2
navigation Branch main
article Path SKILL.md
More from Creator