Installing claims in a consuming project
Direct git-URL plugin, no marketplace listing — see
.scratch/claims-consolidation/issues/03-distribution-mechanism.md’s Answer
for why. .claude-plugin/marketplace.json in this repo is a
self-referencing, single-plugin listing ("source": "./"); a consuming
project points claude’s marketplace registry straight at this repo’s git
URL rather than a central listing.
Install
From inside the consuming project:
claude plugin marketplace add https://github.com/or1can/claims.git --scope project
claude plugin install claims@claims --scope project
The first command registers this repo as a marketplace named claims
(marketplace.json’s own name); the second installs the one plugin it
lists, also named claims, hence claims@claims. Both the skill and the
PreToolUse hook come live from this one install — nothing else to wire up.
--scope project writes both declarations into that project’s own
.claude/settings.json, so the dependency is explicit and travels with the
repo rather than living only in your machine’s global config — the same
thing a second developer cloning the project would need. Both flags default
to user (global, this machine only) if omitted; that’s a reasonable choice
for a quick personal try, but avoid it if this repo (or any other project on
the same machine) ever registers its own marketplace also named claims —
the CLI has no way to alias a marketplace to a different local name than the
one its own marketplace.json declares, so a second claims source at the
same scope silently replaces the first rather than coexisting. This repo’s
own dogfooding setup (a project-scoped claims marketplace pointing at
directory: ".", not this git URL) hit exactly that collision when a
global-scope entry was added alongside it.
Verify:
claude plugin details claims@claims
Component inventory
Skills (1) check-claims
Hooks (1) PreToolUse (harness-only — no model context cost)
Confirmed by installing into a disposable project this way and checking
claims:check-claims and the PreToolUse gate were both live — not just
read off the manifest.
Pinned at install, explicit update. claude plugin marketplace add
resolves and pins the source at add time — an unreviewed upstream change to
this repo doesn’t silently start gating a commit differently mid-project.
Pull in a newer version explicitly, when you choose to — same name and
scope as the install commands above, both required:
claude plugin update claims@claims --scope project
claude plugin update claims alone fails (Plugin "claims" not found —
it defaults to user scope, and the plugin above was installed at
project); claude plugin update claims@claims without --scope project
fails the same way (... is not installed at scope user). Confirmed by
running all three against a real --scope project install — only the
full form above succeeds.
Disabling the automatic hook
Installing always gets you the on-demand check-claims skill; if a project
wants the automatic commit gate off without uninstalling the plugin
entirely, add to that project’s claims.toml:
[hook]
enabled = false
claims/hook.py checks this key (config.get("hook", {}).get("enabled", True)) before running anything — with it false, git commit is never
gated by this plugin, though the skill still works on demand.
To silence just one check at commit time instead of every check, add
enabled = false to that check’s own section instead:
[stale-claims]
enabled = false
Only this commit-time decision is affected, same as the plugin-wide flag
above — python3 -m claims.cli and the skill still run and report that
check’s own findings on demand.
Using it outside Claude Code
The automatic gate above only fires through Claude Code’s own PreToolUse
hook — a human running git commit from a plain terminal, or a CI job,
never triggers it at all; nothing here is a push-time or CI check by
itself (see the top-level README.md’s own “What it isn’t”). claims.cli
is the same underlying runner (claims/hook.py and claims/cli.py both
just call claims/runner.py’s run()), so it works equally well as a
plain git pre-commit hook or a CI step — the same exit code (0/1) a
shell script or CI job already expects.
claims isn’t pip-installable (pyproject.toml’s own package = false)
and the Claude Code plugin cache it normally runs from
(CLAUDE_PLUGIN_ROOT, set only by Claude Code itself when invoking the
hook — see claims/hooks.json) is a per-user, undocumented install
location that won’t exist at all on a CI runner. Outside Claude Code, get
a checkout of this repo some other way instead — a pinned clone step in
CI, a git submodule, or a sibling checkout for a local pre-commit hook —
and point PYTHONPATH at it directly:
# .git/hooks/pre-commit (executable)
#!/bin/sh
PYTHONPATH=/path/to/claims python3 -m claims.cli --repo-root .
# a CI job step, e.g. GitHub Actions
- uses: actions/checkout@v4
with:
repository: or1can/claims
ref: <pinned tag or commit>
path: claims
- run: PYTHONPATH=claims python3 -m claims.cli --repo-root .
What’s different from the full Claude Code experience: every
mechanical check still runs exactly as it does at commit time — the same
run() seam, the same gate/advisory split, the same exit code. Two
things don’t, because both need an LLM to actually interpret what the
mechanical half only sets up:
judgment-agent’s own candidates never become verdicts.claims/checks/judgment_agent.pyonly ever computes the candidate list — a diff-touched subject with a claim about it — and reports each one as an advisory finding; the actual true/false judgment is a separate step, theclaims:judgment-agentsubagent, that only thecheck-claimsskill invokes (claims/skill/SKILL.md). Run this way, those candidates still show up in the output, but as raw, un-judged data points to read yourself — nothing resolves them into an answer.- The skill’s own on-demand
claims.tomlreview doesn’t run at all. Whether a project’s own config values (a staleexcludeglob matching nothing, say) are actually doing anything is reasoned prose thecheck-claimsskill produces on explicit ask — not aFinding, so it was never part ofrun()’s own output to begin with, and nothing here replaces it.
claims.toml
Optional, at the consuming project’s repo root. No file at all means
load_config (claims/config.py) returns {} and every check runs with
its own defaults, defined in its own module under claims/checks/ —
nothing to configure to get started. Where present, each top-level table is
one check’s own config section, read by that check’s name.
See docs/configuration.md for every check’s config keys, their defaults,
and when to reach for each one — or that check’s own module docstring
under claims/checks/ directly, if this page and the code ever disagree.
executable-claims also reads a second, git-ignored, per-machine file,
claims.local.toml — committed claims.toml can’t be the trust boundary
for what commands are allowed to actually run; see
decisions/0001-executable-claims-deny-by-default.md.