From c45d048a53084e05f9d9d05682bf627773f9cc8c Mon Sep 17 00:00:00 2001 From: Rehan Masood Date: Tue, 20 Oct 2026 18:29:08 -0400 Subject: [PATCH 1/3] Lead the README and listing with "Works in Claude Code" This plugin runs in Claude Code. The README now opens with that fact and the two commands that install it there, and the plugin and marketplace descriptions both start with "Works in Claude Code". tests/test_install_routing.py pins it: README line 1, the install block right after it, the description lead, and every README install command pointing at this repo's own marketplace by the names the manifests declare. tests/test_listing_readiness.py adds the directory's manifest checks this repo lacked: kebab-case name, description 30-2000 characters, non-empty keywords, and a marketplace that lists exactly this plugin. Co-Authored-By: Claude Opus 5.5 --- .claude-plugin/marketplace.json | 2 +- .claude-plugin/plugin.json | 2 +- README.md | 7 +++++ tests/test_install_routing.py | 50 +++++++++++++++++++++++++++++++++ tests/test_listing_readiness.py | 31 ++++++++++++++++++++ 5 files changed, 90 insertions(+), 2 deletions(-) create mode 100644 tests/test_install_routing.py create mode 100644 tests/test_listing_readiness.py diff --git a/.claude-plugin/marketplace.json b/.claude-plugin/marketplace.json index aa251ac..371410e 100644 --- a/.claude-plugin/marketplace.json +++ b/.claude-plugin/marketplace.json @@ -9,7 +9,7 @@ { "name": "commitproof", "source": "./", - "description": "Know which commits AI wrote, and prove the record wasn't rewritten. Start with /ai-history (no setup), then /receipt-init for signed, hash-chained receipts verified offline." + "description": "Works in Claude Code. Know which commits AI wrote, and prove the record wasn't rewritten. Start with /ai-history (no setup), then /receipt-init for signed, hash-chained receipts verified offline." } ] } diff --git a/.claude-plugin/plugin.json b/.claude-plugin/plugin.json index d2c8dad..32a2a4b 100644 --- a/.claude-plugin/plugin.json +++ b/.claude-plugin/plugin.json @@ -2,7 +2,7 @@ "name": "commitproof", "displayName": "CommitProof: AI Audit Trail", "version": "1.3.1", - "description": "An audit trail for AI-written code. /ai-history answers 'how much of this repo did Claude help write?' in seconds from git history, no setup. /receipt-init then gives every commit a tamper-evident receipt (AI-assisted or not, model, Claude Code version, file hashes): hash-chained, signed, verified offline. /receipt-report turns the chain into change-control evidence for SOC 2, HIPAA or PCI audits.", + "description": "Works in Claude Code. An audit trail for AI-written code. /ai-history answers 'how much of this repo did Claude help write?' in seconds from git history, no setup. /receipt-init then gives every commit a tamper-evident receipt (AI-assisted or not, model, Claude Code version, file hashes): hash-chained, signed, verified offline. /receipt-report turns the chain into change-control evidence for SOC 2, HIPAA or PCI audits.", "author": { "name": "Rehan Masood", "email": "rmasood524@gmail.com", diff --git a/README.md b/README.md index d353d79..86f392c 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,10 @@ +Works in Claude Code. To install, run these two commands in a Claude Code session: + +``` +/plugin marketplace add Rmasood1122/commitproof +/plugin install commitproof@commitproof +``` + # CommitProof [![CI](https://github.com/Rmasood1122/commitproof/actions/workflows/ci.yml/badge.svg)](https://github.com/Rmasood1122/commitproof/actions/workflows/ci.yml) diff --git a/tests/test_install_routing.py b/tests/test_install_routing.py new file mode 100644 index 0000000..4a5f7f9 --- /dev/null +++ b/tests/test_install_routing.py @@ -0,0 +1,50 @@ +"""The README and the directory listing send installers to Claude Code. + +This plugin runs in Claude Code, so the first thing a reader sees says +"Works in Claude Code" and gives the two commands that install it there, and every +install command in the README must point at this repo's own marketplace by the +names the manifests declare, so a copied command installs this plugin. +""" +import json +import re +from pathlib import Path + +ROOT = Path(__file__).resolve().parents[1] +REPO_SLUG = "Rmasood1122/commitproof" # the public repo users install from +PREFIX = "Works in Claude Code" + +PLUGIN = json.loads((ROOT / ".claude-plugin" / "plugin.json").read_text(encoding="utf-8")) +MARKET = json.loads((ROOT / ".claude-plugin" / "marketplace.json").read_text(encoding="utf-8")) +README = (ROOT / "README.md").read_text(encoding="utf-8") +INSTALL = [f"/plugin marketplace add {REPO_SLUG}", + f"/plugin install {PLUGIN['name']}@{MARKET['name']}"] + + +def _block_after_first_line(lines): + """Lines of the fenced code block that directly follows line 1 (blank lines allowed between).""" + i = 1 + while i < len(lines) and not lines[i].strip(): + i += 1 + assert i < len(lines) and lines[i].startswith("```"), "line 1 must be followed by the install code block" + end = next(j for j in range(i + 1, len(lines)) if lines[j].startswith("```")) + return [l.strip() for l in lines[i + 1:end] if l.strip()] + + +def test_readme_opens_with_claude_code_and_its_install_commands(): + lines = README.splitlines() + assert lines[0].startswith(PREFIX), lines[0] + assert _block_after_first_line(lines) == INSTALL + + +def test_listing_descriptions_lead_with_claude_code(): + assert PLUGIN["description"].startswith(PREFIX) + for entry in MARKET["plugins"]: + assert entry["description"].startswith(PREFIX), entry["name"] + + +def test_every_readme_install_command_points_at_this_repo(): + adds = re.findall(r"marketplace add ([\w.-]+/[\w.-]+)", README) + installs = re.findall(r"plugin install ([\w-]+)@([\w-]+)", README) + assert adds and installs + assert set(adds) == {REPO_SLUG}, adds + assert set(installs) == {(PLUGIN["name"], MARKET["name"])}, installs diff --git a/tests/test_listing_readiness.py b/tests/test_listing_readiness.py new file mode 100644 index 0000000..0a97cce --- /dev/null +++ b/tests/test_listing_readiness.py @@ -0,0 +1,31 @@ +"""Directory-listing readiness: the manifest checks the plugin directory applies. + +Mirrors the manifest part of eval-conductor's readiness battery, so a listing edit +(description, keywords, names) can't silently break what the directory accepts. +""" +import json +import re +from pathlib import Path + +ROOT = Path(__file__).resolve().parents[1] +PLUGIN = json.loads((ROOT / ".claude-plugin" / "plugin.json").read_text(encoding="utf-8")) +MARKET = json.loads((ROOT / ".claude-plugin" / "marketplace.json").read_text(encoding="utf-8")) + + +def test_name_is_kebab_case(): + assert re.fullmatch(r"[a-z0-9]+(-[a-z0-9]+)*", PLUGIN["name"]), PLUGIN["name"] + + +def test_description_length_fits_the_directory(): + assert 30 <= len(PLUGIN["description"]) <= 2000, len(PLUGIN["description"]) + for entry in MARKET["plugins"]: + assert 30 <= len(entry.get("description", "")) <= 2000, entry["name"] + + +def test_keywords_are_a_nonempty_list_of_strings(): + kw = PLUGIN.get("keywords") + assert isinstance(kw, list) and kw and all(isinstance(k, str) and k for k in kw), kw + + +def test_marketplace_lists_exactly_this_plugin(): + assert [p["name"] for p in MARKET["plugins"]] == [PLUGIN["name"]] From 892b6cfe429041adbc6cbc0b2aec5ba12c44757e Mon Sep 17 00:00:00 2001 From: Rehan Masood Date: Tue, 20 Oct 2026 19:18:28 -0400 Subject: [PATCH 2/3] Offer the change-control report as supporting evidence, not as what auditors ask for No SOC 2, HIPAA or PCI control requires AI-code provenance, so the README line "the change-control evidence a SOC 2, HIPAA or PCI auditor asks for" and the listing's "change-control evidence for SOC 2, HIPAA or PCI audits" claimed more than the report can back. Both now say it is a report you can give an auditor as supporting evidence, matching what /receipt-report and the receipt-integrity skill already tell users. test_listing_readiness.py fails on "auditor asks for"-style wording and on a SOC 2 mention without the supporting-evidence framing. Co-Authored-By: Claude Opus 5.5 --- .claude-plugin/plugin.json | 2 +- README.md | 5 +++-- tests/test_listing_readiness.py | 12 ++++++++++++ 3 files changed, 16 insertions(+), 3 deletions(-) diff --git a/.claude-plugin/plugin.json b/.claude-plugin/plugin.json index 32a2a4b..beee20f 100644 --- a/.claude-plugin/plugin.json +++ b/.claude-plugin/plugin.json @@ -2,7 +2,7 @@ "name": "commitproof", "displayName": "CommitProof: AI Audit Trail", "version": "1.3.1", - "description": "Works in Claude Code. An audit trail for AI-written code. /ai-history answers 'how much of this repo did Claude help write?' in seconds from git history, no setup. /receipt-init then gives every commit a tamper-evident receipt (AI-assisted or not, model, Claude Code version, file hashes): hash-chained, signed, verified offline. /receipt-report turns the chain into change-control evidence for SOC 2, HIPAA or PCI audits.", + "description": "Works in Claude Code. An audit trail for AI-written code. /ai-history answers 'how much of this repo did Claude help write?' in seconds from git history, no setup. /receipt-init then gives every commit a tamper-evident receipt (AI-assisted or not, model, Claude Code version, file hashes): hash-chained, signed, verified offline. /receipt-report turns the chain into a change-control report you can give SOC 2, HIPAA or PCI auditors as supporting evidence.", "author": { "name": "Rehan Masood", "email": "rmasood524@gmail.com", diff --git a/README.md b/README.md index 86f392c..4b194f2 100644 --- a/README.md +++ b/README.md @@ -18,8 +18,9 @@ Teams using Claude Code get asked two questions: from the git history you already have. No setup, no key, writes nothing. 2. **"Can you prove that record hasn't been edited since?"** `/receipt-init` gives every commit from then on a tamper-evident receipt: hash-chained, - signed, verifiable offline. `/receipt-report` turns the chain into the - change-control evidence a SOC 2, HIPAA or PCI auditor asks for. + signed, verifiable offline. `/receipt-report` turns the chain into a + change-control report you can give a SOC 2, HIPAA or PCI auditor as + supporting evidence. ## Try it in 30 seconds diff --git a/tests/test_listing_readiness.py b/tests/test_listing_readiness.py index 0a97cce..175d9ef 100644 --- a/tests/test_listing_readiness.py +++ b/tests/test_listing_readiness.py @@ -29,3 +29,15 @@ def test_keywords_are_a_nonempty_list_of_strings(): def test_marketplace_lists_exactly_this_plugin(): assert [p["name"] for p in MARKET["plugins"]] == [PLUGIN["name"]] + + +def test_compliance_wording_offers_evidence_and_claims_no_requirement(): + """No SOC 2, HIPAA or PCI control requires AI-code provenance, so the README and + listing may offer the report as supporting evidence, never as what an auditor asks for.""" + readme = (ROOT / "README.md").read_text(encoding="utf-8") + for text in (readme, PLUGIN["description"]): + lowered = text.lower() + for overclaim in ("auditor asks for", "auditors ask for", "required by soc", "soc 2 requires"): + assert overclaim not in lowered, overclaim + if "soc 2" in lowered: + assert "supporting evidence" in lowered, "SOC 2 mentioned without the supporting-evidence framing" From 8aa4bad3f90b236f589e8f4a6d5adc7601a13ff2 Mon Sep 17 00:00:00 2001 From: Rehan Masood Date: Tue, 20 Oct 2026 19:18:28 -0400 Subject: [PATCH 3/3] Compare whole install-command tokens in the README test The test only matched owner/repo slugs and name@marketplace pairs, so a URL-form `marketplace add https://github.com/...` or a bare `plugin install name` would slip past it. It now compares whole tokens, and an unclosed install block fails with a message instead of a bare StopIteration. Co-Authored-By: Claude Opus 5.5 --- tests/test_install_routing.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/tests/test_install_routing.py b/tests/test_install_routing.py index 4a5f7f9..13505c1 100644 --- a/tests/test_install_routing.py +++ b/tests/test_install_routing.py @@ -26,7 +26,8 @@ def _block_after_first_line(lines): while i < len(lines) and not lines[i].strip(): i += 1 assert i < len(lines) and lines[i].startswith("```"), "line 1 must be followed by the install code block" - end = next(j for j in range(i + 1, len(lines)) if lines[j].startswith("```")) + end = next((j for j in range(i + 1, len(lines)) if lines[j].startswith("```")), None) + assert end is not None, "the install block after line 1 is never closed" return [l.strip() for l in lines[i + 1:end] if l.strip()] @@ -43,8 +44,9 @@ def test_listing_descriptions_lead_with_claude_code(): def test_every_readme_install_command_points_at_this_repo(): - adds = re.findall(r"marketplace add ([\w.-]+/[\w.-]+)", README) - installs = re.findall(r"plugin install ([\w-]+)@([\w-]+)", README) + # whole tokens, so a URL source or an install without @marketplace can't slip past + adds = re.findall(r"marketplace add ([^\s`]+)", README) + installs = re.findall(r"plugin install ([^\s`]+)", README) assert adds and installs assert set(adds) == {REPO_SLUG}, adds - assert set(installs) == {(PLUGIN["name"], MARKET["name"])}, installs + assert set(installs) == {f"{PLUGIN['name']}@{MARKET['name']}"}, installs