Sovereign canonical (git.vake.works). Migrated 2026-07-21.
  • Go 99.3%
  • Makefile 0.7%
Find a file
2026-07-21 13:33:24 +00:00
checks checks: add Gate 5 CONDOC — pair code writes with doc updates 2026-04-13 17:58:58 +02:00
cmd/openearth-gryph release: switch to codeberg.org/openearth/openearth-gryph module path + codeberg.org/openearth/gryph dep 2026-04-15 10:28:02 +02:00
.gitignore Initial scaffold: Go module composing safedep/gryph 2026-04-13 13:43:30 +02:00
go.mod release: switch to codeberg.org/openearth/openearth-gryph module path + codeberg.org/openearth/gryph dep 2026-04-15 10:28:02 +02:00
go.sum release: switch to codeberg.org/openearth/openearth-gryph module path + codeberg.org/openearth/gryph dep 2026-04-15 10:28:02 +02:00
LICENSE Initial scaffold: Go module composing safedep/gryph 2026-04-13 13:43:30 +02:00
Makefile Initial scaffold: Go module composing safedep/gryph 2026-04-13 13:43:30 +02:00
README.md Fix README section header punctuation 2026-07-21 15:20:45 +02:00

openearth-gryph

Apache-2.0 Go binary that composes gryph with additional security checks that enforce the IAS gates protocol at Claude Code (and other supported agent) hook time.

What it does?

gryph is a hook-based interceptor for AI coding agents. Its Check interface lets implementers enforce organisation-specific rules at each tool call. openearth-gryph ships four such Checks that machine-enforce the IAS gates:

Check Enforces Decision
gate1_supplychain Gate 1 — "Before touching any external component, ensure it is assimilated (read + understood)" Guidance (advisory) if a referenced component has assimilation.level < 2 in supply-chain.json
gate3_dockerbuild Gate 3 — "Use docker compose build, never standalone docker build" Block on ^docker\s+build commands
gate4_curl Gate 4 — "Never curl -sf; capture HTTP status separately" Guidance on curl -sf / curl -fs / curl --silent --fail
condoc_pair CONDOC — "Code and docs update together" Guidance when .py/.go/.rs/.kt/.ts is written without any .md touched this session

The binary is a drop-in replacement for gryph in agent hook configs: openearth-gryph _hook claude-code PreToolUse. All gryph subcommands (logs, status, export, stats, cost, …) continue to work because openearth-gryph calls gryph's cli.Execute().

Cross-repo / universal binary

openearth-gryph is installed once per user (~/.local/bin/ + ~/.claude/settings.json hooks) and observes every Claude Code session across every repo. Each Check walks up from event.WorkingDirectory to find an IAS-root marker (config/supply-chain.json + STATEOFCLAUDE.md). In repos that have opted into IAS governance, Checks enforce; in repos that haven't, Checks silently pass through. Result: one install, opt-in enforcement per repo, per-repo config.

Two-level compliance architecture

openearth-gryph is one half of a pair:

  • API proxy (separately maintained) observes Claude's reasoning at the Anthropic API boundary
  • openearth-gryph observes Claude's actions at the Claude Code runtime boundary

Reconciling the two streams catches drift — an agent that plans one thing but does another. Designed for compliance-bound deployments where the full evidence chain (reasoning → action → audit) must be reproducible.

Architecture

Claude Code hook
    ↓ stdin JSON
openearth-gryph _hook claude-code <type>
    ↓
gryph's cli.Execute()  ──→  gryph's NewApp()  ──→  init() hooks:
                                                       ↓
                                              our Checks registered
                                                       ↓
                                              gryph's evaluator loop
                                                       ↓
                                              SQLite audit + hook response

No fork, no patches to gryph's core. openearth-gryph imports github.com/safedep/gryph/cli and uses its extension registry (see upstream PR #TBD) to add our Checks at init() time.

Building

make build           # current OS → bin/openearth-gryph (34-35 MB)
make build-linux     # linux/amd64 → bin/openearth-gryph-linux-amd64 (for Docker)
make test            # Run Check unit tests

Installing — host

make install         # Copies bin/openearth-gryph to ~/.local/bin

Then update ~/.claude/settings.json to replace every "gryph " in hook command fields with "openearth-gryph ". Back up the settings file first:

cp ~/.claude/settings.json ~/.claude/settings.json.pre-openearth-gryph
# Preview the change:
grep -n '"gryph' ~/.claude/settings.json
# Apply (macOS/BSD sed):
sed -i.bak 's|"gryph |"openearth-gryph |g' ~/.claude/settings.json
# Verify:
grep -n '"openearth-gryph' ~/.claude/settings.json

Start a new Claude Code session after editing; openearth-gryph will now receive every hook event and run our Checks on top of gryph's own evaluator. Rollback is cp ~/.claude/settings.json.pre-openearth-gryph ~/.claude/settings.json.

Installing — Docker dev container

Cross-compile the linux binary on the host, then copy it into a running container. Example with a docker-compose stack exposing a dev service named <devservice>:

# 1. Produce the linux/amd64 binary on the host
make build-linux

# 2. Copy into the running container
docker compose cp bin/openearth-gryph-linux-amd64 <devservice>:/usr/local/bin/openearth-gryph

# 3. Permissions: docker cp lands as root; the binary needs +x and,
#    if gryph was previously installed as root into the image, the
#    user's .local tree needs to be chown'd so SQLite can create the
#    audit DB under $HOME/.local/share/gryph/.
docker compose exec -T -u root <devservice> chmod +x /usr/local/bin/openearth-gryph
docker compose exec -T -u root <devservice> chown -R <dev-user>:<dev-user> /home/<dev-user>/.local

# 4. Smoke test
docker compose exec -T <devservice> openearth-gryph version

The SQLite ownership step is the common gotcha: without it, the first _hook invocation inside the container fails with unable to open database file (14) because $HOME/.local/share/gryph/ was created as root during image build.

For a permanent fix, the Dockerfile used to build <devservice> should pre-create the directory with the correct owner:

RUN install -d -o <dev-user> -g <dev-user> /home/<dev-user>/.local/share/gryph

Testing the hook contract without Claude Code

Any gryph-compatible agent hook is a stdin-JSON / stdout + stderr / exit-code protocol. You can exercise openearth-gryph end-to-end — including our custom Checks and gryph's own event pipeline — by piping a synthetic PreToolUse event directly into the binary:

printf '%s' '{
  "session_id":"smoke-1",
  "transcript_path":"/tmp/smoke.jsonl",
  "cwd":"/path/to/your/ias-governed/repo",
  "hook_event_name":"PreToolUse",
  "tool_name":"Bash",
  "tool_use_id":"t1",
  "tool_input":{"command":"docker build -t foo ."}
}' | openearth-gryph _hook claude-code PreToolUse
echo "exit=$?"

Expected responses:

Command in tool_input.command In IAS-root cwd Result
docker build -t foo . yes exit 2, Gate 3 block text on stderr
curl -sf https://example.com/ yes exit 0, Gate 4 guidance text on stderr
curl https://example.com/ yes exit 0, silent
docker build -t foo . no (non-IAS cwd) exit 0, silent — pass-through

This works identically on the host binary and the Linux binary inside Docker, and is the fastest way to verify a fresh install before pointing Claude Code at it.

Upstream dependencies — PRs in flight

This module depends on two upstream PRs to github.com/safedep/gryph:

  1. feat/claude-guidance-output — completes gryph's three-valued security decision model (Allow/Block/Guidance) by wiring the existing but currently-unused DecisionGuidance through to Claude Code's hook output protocol (exit 0 + stderr). Without this PR, gate1_supplychain, gate4_curl, and condoc_pair would have to use Block instead of the semantically correct Guidance.

  2. feat/extension-point-check-factory — adds a package-level cli.RegisterCheckFactory(f func(*config.Config) security.Check) so external binaries composing gryph as a library can register additional Checks without modifying cli/root.go. Idiomatic Go (same pattern as database/sql.Register, image/png decoder registration).

While those PRs are in review, go.mod uses a replace directive pointing at a local gryph fork carrying both PR branches. Once upstream merges, the replace is removed and we pin a release tag.

License

Apache-2.0. See LICENSE.

Layout

openearth-gryph/
├── checks/              # Our Check implementations + unit tests
├── cmd/openearth-gryph/ # Binary entry point
├── go.mod               # Depends on github.com/safedep/gryph
├── Makefile
├── LICENSE              # Apache-2.0
└── README.md