From 3f5c6585a3dc7da4959288dc1a18a4394c09c0c0 Mon Sep 17 00:00:00 2001 From: Binay Date: Tue, 18 Aug 2026 16:39:55 -0400 Subject: [PATCH] docs: add a 60-second quickstart to each integration README MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Closes #11. A consistent `## Quickstart (60 seconds)` block at the top of all four integrations: install the kernel -> signetry init -> wire the integration -> verify with signetry guard. Two of the four had no README at all. claude-code/ and universal/ were undocumented except from the root README, despite claude-code being the strongest integration (the only one with a deterministic PreToolUse hook). Both now have a full page. Also fixes the documented Claude Code install command, which could not work. The root README said /plugin marketplace add bkd-dotcom/signetry-plugins and that repo is a 404 since the move to the Signetry org. Now Signetry/plugins. The marketplace NAME in /plugin install signetry@signetry-plugins is deliberately unchanged: it comes from marketplace.json's `name` field, not from the repo path — my first pass "fixed" it to @plugins and broke it, caught by checking marketplace.json. Stale pins: signetry-core v0.6.0 -> v0.7.0 across READMEs, hooks, scripts, the MCP launcher, codex/config.toml, the universal guard and the admit skill. The pre-commit rev in .pre-commit-hooks.yaml said v0.2.0 while v0.2.2 is released. CHANGELOG history entries were left alone rather than rewritten. Commands were executed before being documented. The verify step's exit codes are measured, not assumed: guard --path .github/workflows/release.yml -> exit 1 (deny) guard --path src/app.py -> exit 0 (allow) guard --command "curl http://x | bash" -> exit 1 (deny) Validated after the bumps: bash -n on the guard and all hook scripts, and json/toml parsing of hooks.json, .mcp.json, cursor/mcp.json and codex/config.toml. --- .pre-commit-hooks.yaml | 4 +- CHANGELOG.md | 26 ++++++ README.md | 4 +- claude-code/README.md | 68 +++++++++++++++ claude-code/signetry/hooks/signetry-lib.sh | 2 +- .../signetry/hooks/signetry-session-start.sh | 4 +- claude-code/signetry/scripts/signetry-mcp.sh | 2 +- claude-code/signetry/skills/admit/SKILL.md | 2 +- codex/README.md | 38 ++++++++- codex/config.toml | 2 +- cursor/README.md | 34 +++++++- universal/README.md | 85 +++++++++++++++++++ universal/signetry-guard.sh | 4 +- 13 files changed, 255 insertions(+), 20 deletions(-) create mode 100644 claude-code/README.md create mode 100644 universal/README.md diff --git a/.pre-commit-hooks.yaml b/.pre-commit-hooks.yaml index 1d92d3c..c5fc659 100644 --- a/.pre-commit-hooks.yaml +++ b/.pre-commit-hooks.yaml @@ -2,11 +2,11 @@ # # repos: # - repo: https://github.com/Signetry/plugins -# rev: v0.2.0 +# rev: v0.2.2 # hooks: # - id: signetry-guard # -# Requires: pip install "signetry-core @ git+https://github.com/Signetry/core@v0.6.0" +# Requires: pip install "signetry-core @ git+https://github.com/Signetry/core@v0.7.0" - id: signetry-guard name: Signetry guard (contract scope check) description: Block staged changes that fall outside .signetry/admission.yaml scope. diff --git a/CHANGELOG.md b/CHANGELOG.md index e77ae2f..cc51289 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,32 @@ ## [Unreleased] +### Added — a 60-second quickstart in every integration README + +- A consistent `## Quickstart (60 seconds)` block at the top of `codex/`, `cursor/`, + `claude-code/` and `universal/`: install the kernel → `signetry init` → wire the + integration → verify with `signetry guard`. +- `claude-code/README.md` and `universal/README.md` **did not exist** — those two + integrations had no entry point of their own at all. +- Every documented command was executed before being written down; the + `signetry guard` exit codes in the verify step (`1` = deny, `0` = allow) are + confirmed against a scaffolded contract rather than assumed. + +### Fixed — the documented Claude Code install command was broken + +- `README.md` told users to run `/plugin marketplace add bkd-dotcom/signetry-plugins`. + That repository is a **404** since the move to the `Signetry` org, so the primary + install path for the Claude Code plugin could not work. Now `Signetry/plugins`. +- The marketplace *name* in `/plugin install signetry@signetry-plugins` is unchanged + and correct — it comes from `marketplace.json`'s `name` field, not the repo path. + +### Fixed — stale version pins + +- `signetry-core` pins move `v0.6.0` → `v0.7.0` across the READMEs, hooks, scripts, + the MCP launcher, `codex/config.toml`, the universal guard and the admit skill. +- The pre-commit `rev:` in `.pre-commit-hooks.yaml` said `v0.2.0` while `v0.2.2` is + released; it and the new universal README now reference `v0.2.2`. + ### Changed — rebranded Signetry → Signetry - Platform kernel dependency `signetry-core` (installed from the git tag diff --git a/README.md b/README.md index d311e58..fbedadd 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ Signetry decides how much authority an agent's change has earned and proves it. plugins bring that governance *into the tools where agents work* — enforced by deterministic code, never by the model itself (an agent can't approve its own change). -> Prerequisite for all integrations: `pip install "signetry-core @ git+https://github.com/Signetry/core@v0.6.0"` and a +> Prerequisite for all integrations: `pip install "signetry-core @ git+https://github.com/Signetry/core@v0.7.0"` and a > `.signetry/admission.yaml` in your repo (a conservative default applies without one). ## Claude Code plugin (deepest integration) @@ -22,7 +22,7 @@ out-of-scope or forbidden actions before they happen — using `signetry guard` **`/signetry:admit`** skill for on-demand full admission with a signed receipt. ``` -/plugin marketplace add bkd-dotcom/signetry-plugins +/plugin marketplace add Signetry/plugins /plugin install signetry@signetry-plugins ``` diff --git a/claude-code/README.md b/claude-code/README.md new file mode 100644 index 0000000..0d5f046 --- /dev/null +++ b/claude-code/README.md @@ -0,0 +1,68 @@ +# Signetry for Claude Code + +Govern coding-agent changes in [Claude Code](https://claude.com/claude-code) with +[signetry-core](https://github.com/Signetry/core). + +This is the strongest in-editor integration of the four, because Claude Code exposes +a **deterministic `PreToolUse` hook**: an out-of-scope write or a forbidden command is +blocked by code before it happens, not merely discouraged in a prompt. + +## Quickstart (60 seconds) + +```bash +# 1. install the kernel (source-available; not on PyPI) +pip install "signetry-core @ git+https://github.com/Signetry/core@v0.7.0" + +# 2. scaffold a contract in your repo +cd /path/to/your/repo +signetry init # writes a conservative .signetry/admission.yaml +``` + +### 3. Install the plugin + +In Claude Code: + +``` +/plugin marketplace add Signetry/plugins +/plugin install signetry@signetry-plugins +``` + +Or run against a local checkout without installing: + +```bash +claude --plugin-dir ./claude-code/signetry +``` + +### Verify it works + +```bash +# a path outside the contract's allowed_paths must be denied (exit 1) +signetry guard --repo . --path .github/workflows/release.yml; echo "exit=$?" + +# a path inside it must be allowed (exit 0) +signetry guard --repo . --path src/app.py; echo "exit=$?" +``` + +`exit=1` means the guard would block that action; `exit=0` means it is within your +contract. In the editor, ask Claude to edit a path your contract forbids — the write +is refused with the contract's reason rather than being applied. + +## What the plugin adds + +| piece | trigger | effect | +|---|---|---| +| `hooks/signetry-guard.sh` | `PreToolUse` on `Edit`/`Write`/`MultiEdit`/`NotebookEdit` | blocks a write outside `allowed_paths` or inside `forbidden_paths` | +| `hooks/signetry-guard.sh` | `PreToolUse` on `Bash` | blocks a command the contract forbids | +| `hooks/signetry-session-start.sh` | `SessionStart` | prepares the guard and reports whether the contract was found | +| `skills/admit/SKILL.md` | `/signetry:admit` | runs the full admission pipeline and seals a receipt | +| `.mcp.json` | — | the Signetry MCP server (`signetry_admit`, `signetry_verify`, `signetry_provenance`) | + +The guard is deterministic: the decision comes from `.signetry/admission.yaml`, so the +agent cannot talk its way past it. + +## The durable guarantee: CI + +An in-editor hook is defence in depth — it protects the machine it runs on. The +enforced gate is CI. Make **Signetry Admission** a required check so nothing merges +without a signed receipt, whichever agent (or human) opened the PR: +. diff --git a/claude-code/signetry/hooks/signetry-lib.sh b/claude-code/signetry/hooks/signetry-lib.sh index b234a8c..f052d80 100755 --- a/claude-code/signetry/hooks/signetry-lib.sh +++ b/claude-code/signetry/hooks/signetry-lib.sh @@ -66,7 +66,7 @@ signetry_provision() { venv_py="$venv/bin/python" { "$py" -m venv "$venv" \ - && "$venv_py" -m pip install --quiet --disable-pip-version-check "signetry-core @ git+https://github.com/Signetry/core@v0.6.0" + && "$venv_py" -m pip install --quiet --disable-pip-version-check "signetry-core @ git+https://github.com/Signetry/core@v0.7.0" } >/dev/null 2>&1 || true [ -x "$venv_py" ] && "$venv_py" -c "import signetry_core" >/dev/null 2>&1 } diff --git a/claude-code/signetry/hooks/signetry-session-start.sh b/claude-code/signetry/hooks/signetry-session-start.sh index 5003ca9..43bbcb3 100755 --- a/claude-code/signetry/hooks/signetry-session-start.sh +++ b/claude-code/signetry/hooks/signetry-session-start.sh @@ -22,8 +22,8 @@ fi # Could not activate. Say so LOUDLY and specifically — do not pretend to protect. if signetry_py311plus >/dev/null 2>&1; then - echo "Signetry plugin loaded but INACTIVE: could not install signetry-core (offline?). The guard is NOT enforcing anything. Fix with: pip install 'signetry-core @ git+https://github.com/Signetry/core@v0.6.0'" + echo "Signetry plugin loaded but INACTIVE: could not install signetry-core (offline?). The guard is NOT enforcing anything. Fix with: pip install 'signetry-core @ git+https://github.com/Signetry/core@v0.7.0'" else - echo "Signetry plugin loaded but INACTIVE: needs Python >=3.11, which was not found (your default python3 may be older). The guard is NOT enforcing anything. Install Python 3.11+ and: pip install 'signetry-core @ git+https://github.com/Signetry/core@v0.6.0'" + echo "Signetry plugin loaded but INACTIVE: needs Python >=3.11, which was not found (your default python3 may be older). The guard is NOT enforcing anything. Install Python 3.11+ and: pip install 'signetry-core @ git+https://github.com/Signetry/core@v0.7.0'" fi exit 0 diff --git a/claude-code/signetry/scripts/signetry-mcp.sh b/claude-code/signetry/scripts/signetry-mcp.sh index b549d80..05520b8 100755 --- a/claude-code/signetry/scripts/signetry-mcp.sh +++ b/claude-code/signetry/scripts/signetry-mcp.sh @@ -15,5 +15,5 @@ for PY in python3.13 python3.12 python3.11 python3 python; do exec "$PY" -m signetry_core.mcp_server fi done -echo "signetry-core[mcp] not available on a Python >=3.11; run: pip install 'signetry-core[mcp] @ git+https://github.com/Signetry/core@v0.6.0'" >&2 +echo "signetry-core[mcp] not available on a Python >=3.11; run: pip install 'signetry-core[mcp] @ git+https://github.com/Signetry/core@v0.7.0'" >&2 exit 1 diff --git a/claude-code/signetry/skills/admit/SKILL.md b/claude-code/signetry/skills/admit/SKILL.md index 368d712..275563d 100644 --- a/claude-code/signetry/skills/admit/SKILL.md +++ b/claude-code/signetry/skills/admit/SKILL.md @@ -10,7 +10,7 @@ report the result to the user. Steps: 1. Confirm `signetry` is available: run `signetry --help`. If it is not installed, tell - the user to run `pip install "signetry-core @ git+https://github.com/Signetry/core@v0.6.0"` and stop. + the user to run `pip install "signetry-core @ git+https://github.com/Signetry/core@v0.7.0"` and stop. 2. Run admission over the change already present in the working tree (no agent is re-invoked — the change being governed is what's on disk): diff --git a/codex/README.md b/codex/README.md index cd05b41..28c7e65 100644 --- a/codex/README.md +++ b/codex/README.md @@ -3,14 +3,44 @@ Govern coding-agent changes in [OpenAI Codex](https://developers.openai.com/codex) with [signetry-core](https://github.com/Signetry/core). -## Prerequisite +## Quickstart (60 seconds) ```bash -pip install "signetry-core @ git+https://github.com/Signetry/core@v0.6.0" +# 1. install the kernel (source-available; not on PyPI) +pip install "signetry-core @ git+https://github.com/Signetry/core@v0.7.0" + +# 2. scaffold a contract in your repo +cd /path/to/your/repo +signetry init # writes a conservative .signetry/admission.yaml +``` + +### 3. Wire Codex to Signetry + +Add the MCP server to `~/.codex/config.toml` (details in §1 below): + +```toml +[mcp_servers.signetry] +command = "python" +args = ["-m", "signetry_core.mcp_server"] + +[mcp_servers.signetry.env] +SIGNETRY_MCP_ROOTS = "/absolute/path/to/your/repo" +``` + +Restart Codex; the agent now has `signetry_admit`, `signetry_verify` and +`signetry_provenance`. + +### Verify it works + +```bash +# a path outside the contract's allowed_paths must be denied (exit 1) +signetry guard --repo . --path .github/workflows/release.yml; echo "exit=$?" + +# a path inside it must be allowed (exit 0) +signetry guard --repo . --path src/app.py; echo "exit=$?" ``` -Add a `.signetry/admission.yaml` to your repo (allowed/forbidden paths, diff budget, -required checks). A conservative default applies without one. +Then read on for the lifecycle-hook guard and the CI gate. ## 1. MCP server (recommended) diff --git a/codex/config.toml b/codex/config.toml index 102e196..f208bee 100644 --- a/codex/config.toml +++ b/codex/config.toml @@ -1,5 +1,5 @@ # Signetry MCP server for Codex — add to ~/.codex/config.toml -# Requires: pip install "signetry-core @ git+https://github.com/Signetry/core@v0.6.0" +# Requires: pip install "signetry-core @ git+https://github.com/Signetry/core@v0.7.0" [mcp_servers.signetry] command = "python" diff --git a/cursor/README.md b/cursor/README.md index df13efb..0c89d7a 100644 --- a/cursor/README.md +++ b/cursor/README.md @@ -3,14 +3,40 @@ Two ways to govern coding-agent changes in Cursor with [signetry-core](https://github.com/Signetry/core). -## Prerequisite +## Quickstart (60 seconds) ```bash -pip install "signetry-core @ git+https://github.com/Signetry/core@v0.6.0" +# 1. install the kernel (source-available; not on PyPI) +pip install "signetry-core @ git+https://github.com/Signetry/core@v0.7.0" + +# 2. scaffold a contract in your repo +cd /path/to/your/repo +signetry init # writes a conservative .signetry/admission.yaml +``` + +### 3. Wire Cursor to Signetry + +```bash +mkdir -p .cursor/rules +cp mcp.json .cursor/mcp.json # or merge into an existing .cursor/mcp.json +cp signetry.mdc .cursor/rules/ # project rule (advisory) +``` + +Reload Cursor; the agent can then call `signetry_admit`, `signetry_verify` and +`signetry_provenance`. + +### Verify it works + +```bash +# a path outside the contract's allowed_paths must be denied (exit 1) +signetry guard --repo . --path .github/workflows/release.yml; echo "exit=$?" + +# a path inside it must be allowed (exit 0) +signetry guard --repo . --path src/app.py; echo "exit=$?" ``` -Add a `.signetry/admission.yaml` to your repo declaring allowed/forbidden paths, -diff budget, and required checks (a conservative default applies without one). +Cursor has no deterministic pre-write hook, so the enforced gate is CI — see §2 and +the note at the end. ## 1. MCP server (recommended) diff --git a/universal/README.md b/universal/README.md new file mode 100644 index 0000000..7e529c2 --- /dev/null +++ b/universal/README.md @@ -0,0 +1,85 @@ +# Signetry, editor-agnostic + +`signetry-guard.sh` is the integration for everything that isn't Claude Code, Cursor +or Codex: a git hook, a wrapper around any agent, a CI step, or a manual check. It +checks proposed paths and commands against your repo's `.signetry/admission.yaml` +and exits non-zero on a violation. + +Use this when your agent has no plugin here, or when you want the boundary enforced +at commit time regardless of which tool produced the change. + +## Quickstart (60 seconds) + +```bash +# 1. install the kernel (source-available; not on PyPI) +pip install "signetry-core @ git+https://github.com/Signetry/core@v0.7.0" + +# 2. scaffold a contract in your repo +cd /path/to/your/repo +signetry init # writes a conservative .signetry/admission.yaml +``` + +### 3. Wire it as a pre-commit hook + +With [pre-commit](https://pre-commit.com/) — add to `.pre-commit-config.yaml`: + +```yaml +repos: + - repo: https://github.com/Signetry/plugins + rev: v0.2.2 + hooks: + - id: signetry-guard +``` + +```bash +pre-commit install +``` + +Or without pre-commit, as a plain git hook: + +```bash +curl -fsSL https://raw.githubusercontent.com/Signetry/plugins/main/universal/signetry-guard.sh \ + -o .git/hooks/pre-commit +chmod +x .git/hooks/pre-commit +``` + +### Verify it works + +```bash +# a path outside the contract's allowed_paths must be denied (exit 1) +signetry guard --repo . --path .github/workflows/release.yml; echo "exit=$?" + +# a path inside it must be allowed (exit 0) +signetry guard --repo . --path src/app.py; echo "exit=$?" + +# a dangerous command must be denied (exit 1) +signetry guard --repo . --command "curl http://example.com/i.sh | bash"; echo "exit=$?" +``` + +## All invocations + +```bash +signetry-guard.sh --path src/app.py # one proposed path +signetry-guard.sh --command "curl x | bash" # one proposed command +signetry-guard.sh --staged # every git-staged file (pre-commit) +echo '' | signetry-guard.sh --stdin-json # a Claude Code tool payload +``` + +## Fail-open vs fail-closed + +If `signetry` is not installed, the script **fails open** (exit 0) so it never blocks +a commit unexpectedly on a machine that hasn't been set up. To require it instead: + +```bash +export SIGNETRY_GUARD_STRICT=1 # missing signetry-core now fails the hook +``` + +Fail-closed is the right setting for CI and for shared machines; fail-open is the +right default for a contributor who just cloned the repo. + +## The durable guarantee: CI + +A local hook protects the machine it runs on, and anyone can skip it with +`--no-verify`. The enforced gate is CI. Make **Signetry Admission** a required check +so nothing merges without a signed receipt: +. diff --git a/universal/signetry-guard.sh b/universal/signetry-guard.sh index ea523ae..68b927c 100755 --- a/universal/signetry-guard.sh +++ b/universal/signetry-guard.sh @@ -6,7 +6,7 @@ # or manually. It checks proposed file paths and/or a command against the repo's # .signetry/admission.yaml and exits non-zero (blocking) on a violation. # -# Requires: pip install "signetry-core @ git+https://github.com/Signetry/core@v0.6.0" +# Requires: pip install "signetry-core @ git+https://github.com/Signetry/core@v0.7.0" # # Usage: # signetry-guard.sh --path src/app.py @@ -17,7 +17,7 @@ set -euo pipefail if ! command -v signetry >/dev/null 2>&1; then - echo "signetry-guard: signetry-core not installed. Run: pip install 'signetry-core @ git+https://github.com/Signetry/core@v0.6.0'" >&2 + echo "signetry-guard: signetry-core not installed. Run: pip install 'signetry-core @ git+https://github.com/Signetry/core@v0.7.0'" >&2 # Fail open by default so this never blocks a commit unexpectedly; set # SIGNETRY_GUARD_STRICT=1 to fail closed when signetry is missing. [ "${SIGNETRY_GUARD_STRICT:-0}" = "1" ] && exit 1 || exit 0