Last Updated: 2026-09-22
ForgeProof is a local-only Claude Code plugin. It does not collect telemetry, does not phone home, does not transmit data to any server it controls, and does not access files outside your project directory and the system temp directory (with one read-side exception: verify opens the paths a bundle records — see File System Access). Every claim in this document is verifiable from the source code in this repository.
ForgeProof does not collect any user data.
ForgeProof does not collect, aggregate, or store:
- User prompts or conversation content
- Bash commands or shell history
- File contents (beyond what is hashed for provenance)
- Session metadata, timestamps, or usage patterns
- Device identifiers, IP addresses, or user agents
- Claude Code account information
ForgeProof reads GitHub issue content (title, body, labels, comments) via the gh CLI to extract requirements. This data is processed locally and included in the .rpack provenance bundle stored in your project directory. ForgeProof itself makes no network requests — gh uses your pre-existing GitHub authentication.
ForgeProof makes zero outbound network requests.
ForgeProof does not import or use any HTTP, socket, or networking libraries. The only external programs ForgeProof invokes are:
| Program | Purpose | Network activity |
|---|---|---|
gh (GitHub CLI) |
Fetch issue data, create PRs, check auth status | Uses your existing GitHub auth. ForgeProof does not configure, modify, or intercept these requests. |
ssh-keygen |
Generate Ed25519 keypairs, sign and verify data | Fully local. No network activity. |
Project toolchain (python, pytest, ruff, etc.) |
Detect language, run tests, run linter | Fully local. No network activity. |
ForgeProof does not:
- Contact any analytics or telemetry endpoint
- Ping any server on startup, activation, or shutdown
- Resolve any DNS names
- Open any sockets
ForgeProof contains zero telemetry of any kind.
There are no usage counters, no heartbeat pings, no crash reporters, no feature flags fetched from remote servers, no A/B testing, and no opt-in or opt-out telemetry settings — because there is no telemetry infrastructure to toggle.
This is verifiable: the provenance engine (skills/run/scripts/forgeproof.py) imports only Python standard library modules (argparse, base64, datetime, hashlib, json, os, pathlib, shutil, subprocess, sys, tempfile, typing). No third-party packages. No network-capable imports.
Ephemeral Ed25519 private keys are generated per-bundle and deleted immediately after signing.
Key lifecycle:
- Generation — When
/forgeproof:runinitializes a chain,ssh-keygengenerates an Ed25519 keypair in the system temp directory (/tmpon Unix,%TEMP%on Windows) atforgeproof_<issue>_ed25519. - Usage — The private key signs each block in the hash chain and the final root digest of the
.rpackbundle. From v1.3.0 the engine also parses the key's 32-byte seed locally (pure stdlib, in-process) to make the DSSE attestation signature with the same key — the seed never leaves the process and is never written anywhere. - Deletion — Immediately after the bundle is finalized, the private key and its
.pubcompanion are deleted from the temp directory. This is irreversible — the key cannot be recovered. - Public key persistence — The public key is embedded in the
.rpackbundle (and, from v1.3.0, exported as.forgeproof/issue-<N>.pub.pem) for self-contained verification. It cannot be used to forge signatures without the deleted private key. Note:ssh-keygen's default key comment embedsusername@hostnameof the generating machine, and ForgeProof stores the full public-key line — see "Personal information in the bundle" below.
At no point are private keys:
- Written to the project directory
- Committed to git
- Transmitted over any network
- Stored in any persistent location
ForgeProof reads and writes only within your project directory and the system temp directory, with one read-side exception, stated under Reads: verify follows the paths a bundle records.
- Project source files (to compute SHA-256 hashes for provenance)
pyproject.toml,setup.cfg,setup.py,requirements.txt,package.json,go.mod(to detect project toolchain).gitignore(to check if it exists).forgeproof/directory contents (chain files,.rpackbundles)- When you run
verifyon a bundle: the files at the artifact paths and the chain-file path the bundle records, opened as given and not confined to the project. A bundle from an untrusted source can therefore makeverifyopen a file outside the project, and its verdict discloses whether that file exists and whether it matches the recorded digest. Nothing is written there. (Stated in full indocs/media-type.md, security considerations.)
.forgeproof/chain-<issue>.json— provenance hash chain.forgeproof/issue-<issue>.rpack— signed provenance bundle.forgeproof/issue-<issue>.sigstore.json— the attestation sidecar (v1.3.0+; same content as the copy embedded in the bundle).forgeproof/issue-<issue>.pub.pem— the public key as a PEM for cosign (v1.3.0+)- System temp directory — ephemeral Ed25519 keypairs (deleted after signing)
- System temp directory — transient files for
ssh-keygensign/verify operations (deleted immediately)
ForgeProof does not:
- Write to
${CLAUDE_PLUGIN_DATA} - Write to any directory outside the project root and system temp
- Modify source files (Claude Code's Edit/Write tools do that; ForgeProof only records what changed)
- Access other projects, home directory files, or system configuration (beyond the
verifyread stated above) - Install MIME type definitions or modify
~/.local/share/mime,.gitattributes, or editor settings — the files undershare/are opt-in and documented only
ForgeProof's hooks spawn a short-lived local Python process per matching tool call and act only during ForgeProof workflows.
ForgeProof registers two hooks:
- Matcher:
Bash|PowerShell— the hook process spawns on every Bash or PowerShell tool call while the plugin is enabled. It is read-only and exits immediately (allow) for any command that is notgh pr create. - Behavior: For
gh pr create, checks whether a signed.rpackbundle exists in.forgeproof/. If not, blocks the PR creation with an informational message. - Data handling: The hook reads the tool-call event (tool name and command string) from stdin to make that one local decision. It does not log, store, or transmit it.
- Matcher:
Edit|Write— the hook process spawns after file edit operations. - Behavior: Exits immediately as a no-op unless an active ForgeProof chain exists (
.forgeproof/chain-*.json). During an active run it lints only the edited file and surfaces the findings to Claude. It never blocks an edit. - Scope: No-op outside of active
/forgeproof:runruns.
Neither hook:
- Reads or logs prompt content
- Transmits data anywhere
- Runs background processes (each invocation is a short-lived process that exits when its check completes)
ForgeProof has zero third-party dependencies.
The provenance engine is written in Python 3.11+ using only the standard library. There are no pip packages, no npm modules, no vendored libraries, and no dynamically loaded code.
External programs (gh, ssh-keygen) are invoked as subprocesses. ForgeProof does not bundle, modify, or patch these programs. They use your system installation and your existing configuration.
The .rpack bundle is a local JSON file under your control. ForgeProof does not transmit it anywhere.
An .rpack bundle contains:
| Field | Content | Sensitivity |
|---|---|---|
| Issue metadata | Issue number, title, URL | Low (public GitHub data) |
| Requirements | Extracted from issue body (REQ-1, REQ-2, ...) | Low (derived from public issue) |
| Artifacts | File paths and SHA-256 hashes of changed files | Low (paths, not content) |
| Decisions | Context, choice, and rationale for design decisions | Medium (contains reasoning about code) |
| Evaluation | Test pass/fail counts, lint error counts, requirement coverage | Low (aggregate metrics) |
| Chain hash | SHA-256 of the provenance chain file | Low (integrity check) |
| Public key | Full ssh-ed25519 line, including ssh-keygen's default comment, which embeds username@hostname of the generating machine |
Medium (machine/user identifier) |
| Signature | Ed25519 signature over the root digest | Low (verification data) |
| Attestation (v1.3.0+) | in-toto/SLSA statement: the same issue/requirements/artifact data, builder identity (model id self-reported, Claude Code version, plugin version), and approval events | Medium (see approver email below) |
| Approver email (v1.3.0+) | git config user.email of the local user, recorded in each approval chain block and sealed into the attestation |
Medium (personal identifier; empty string when git has no configured identity) |
| Timestamps (v1.3.0+) | The attestation's startedOn / finishedOn: the times of the run's first and last chain blocks (UTC, to the microsecond). Earlier bundles carry no timestamps. The chain file beside the bundle (.forgeproof/chain-<N>.json) has always recorded a time for every block |
Low (when the run happened) |
The bundle does not contain:
- Source code content (only file paths and hashes)
- User prompts or conversation history
- API keys, tokens, or credentials
Personal information the bundle DOES contain (an earlier version of this
policy wrongly claimed there was none beyond the GitHub issue): the
public_key field's comment embeds the generating machine's
username@hostname (an ssh-keygen default, present since v1.0.0), and from
v1.3.0 each approval records the approver's git email. Both are visible to
anyone who can read the bundle — which, once pushed, means anyone who can
read the repository. Configure git config user.email accordingly if this
matters to you.
The bundle is written to .forgeproof/issue-<N>.rpack in your project directory (with the attestation sidecars beside it). It is only transmitted if you explicitly push it to GitHub via /forgeproof:push. You can delete it at any time with /forgeproof:reset.
Every claim in this document can be verified by reading the source code:
- Provenance engine:
skills/run/scripts/forgeproof.py - Hook definitions:
hooks/hooks.json - Skill prompts:
skills/*/SKILL.md
The entire plugin is open source under the MIT license.
| Date | Version | Change |
|---|---|---|
| 2026-09-22 | 1.4.0 | Added the Timestamps row to the bundle table (the attestation's startedOn / finishedOn, and the chain file's per-block times — an omission corrected, not a new disclosure); the "does not" list gains the MIME-definition / .gitattributes / editor-settings line (the files under share/ are opt-in and never installed); File System Access now states the one read outside the project: verify opens a bundle's recorded artifact and chain-file paths as given |
| 2026-08-15 | 1.3.0 | Corrected a live inaccuracy: the bundle has always carried username@hostname in the public-key comment; the "no personal information" claim was false and is now stated accurately. Added the v1.3.0 additions: approver git email in approval blocks/attestation, the two attestation sidecar files, local in-process seed parsing for DSSE signing, refreshed stdlib import list |
| 2026-07-03 | 1.1.0 | Updated hook scope to match v1.1.0 behavior (matcher Bash|PowerShell, per-call spawn cost stated plainly, per-file lint); refreshed paths and command names after the skill rename |
| 2026-04-15 | 1.0.0 | Initial privacy policy |