@kyntra/claude-hook
v2.0.0
Published
Governance for Claude Code that costs nothing on ordinary work: blocks destructive or unapproved actions and completion reports that ran no verification, honors approvals given in chat.
Maintainers
Readme
@kyntra/claude-hook
Real-time AI agent governance for Claude Code. Enforce your coding principles via hooks — block destructive commands, catch "complete" reports that ran no verification, and honor the approvals you already gave in chat.
2.0: ordinary work costs nothing. The hook classifies every tool call locally first; only calls in a risk class (destructive deletes, git history rewrites, remote database mutations, deploys/publishes, secret writes, credential or governance-config edits) reach the server. On one workstation's real session history, 58 of 1,580 tool calls (3.7%) did.
$ claude
> fix the bug and push
[KYNTRA] BLOCKED — Force push to main/master branch is blocked
Principle: rule-no-force-push-main
Layer: rulesThis is the open-source client adapter. It communicates with Kyntra's server-side governance engine (patent-pending) over HTTPS.
Why
You told Claude "follow my rules." You pasted a reminder into every session. You still got curl OK — site is live when the site was broken.
The problem isn't the model — reminders are advisory. Hooks are enforcement. Kyntra sits in front of every AI tool call and returns allow / block / warn in under a second.
- Determinism first — a built-in rule engine catches the obvious classes (
rm -rf /,git push --force main,git commit --no-verify,echo >> .env). No model call, no cost, no latency. - LLM for the ambiguous rest — Kyntra's Layer 2 (Haiku) handles contextual judgements your regex can't express, on risky calls only.
- Your approval counts — if you told the agent, in this turn, to do the thing ("delete those rows, go ahead"), a block becomes a warning that quotes your sentence. A blanket "approve everything" does not waive one, and money/credential rules are never waived.
- Completion is judged by what ran — the Stop check reads the turn from the transcript: files edited, and whether any test, build, type check, search, HTTP probe, read-only query, browser check or independent review actually ran. Words in the reply do not count.
- Pro: Layer 3 Sonnet deep review — when Haiku flags a case as warn/block/uncertain, Pro subscribers get a second opinion from Sonnet using the full constitution + trust profile + custom rules. Article 0 supremacy is enforced in code, not in prompt.
- Self-evolving principles — repeat violations bubble up; reliable principles decay. Kyntra's trust-adjustment engine is patent-pending (KR claims 1 & 2).
- Auto-update notice — when a newer release is available, the bridge prints a one-per-day reminder to stderr (deduped in
~/.cache/kyntra/). Hook behavior is never affected by the notice path.
Install
npx @kyntra/claude-hook installThat registers the hook in ~/.claude/settings.json, backs up any existing config, and gives you a copy-paste next-step. Then:
export KYNTRA_API_KEY=ky_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx…and restart Claude Code. Try git push --force origin main — it should be refused at the hook layer, before Claude even shells out.
Get an API key
You need a Kyntra subscription. Plans start at $15/month with a 50% first-month discount and a 14-day money-back guarantee.
Environment
| Variable | Required | Default |
|---|---|---|
| KYNTRA_API_KEY | yes | — |
| KYNTRA_ENDPOINT | no | https://app.kyntra.ai.kr/api/governance/check |
| KYNTRA_TIMEOUT_MS | no | 8000 (on timeout the hook allows) |
| KYNTRA_DISABLED | no | unset — 1, or a ~/.kyntra/disabled file, turns the hook off entirely |
How it works
Claude Code session
│
│ 1. Tool call (Bash / Edit / Write) or Stop
▼
Hook: node bridge.js ← this package (MIT)
│
│ risk.js: is this call in a risk class?
│ no → allow locally, no output, no network (~70ms, most calls)
│ yes → POST /api/governance/check {event, tool, command, human_text, …}
│ Stop → POST with the turn's evidence {edits, verifications, …}
▼
app.kyntra.ai.kr ← server engine (closed-source, patent-pending)
│
│ Layer 0 KV cache → Layer 1 rules → Layer 2 Haiku (risky calls only)
▼
Hook: allow (no output) | warn (one context line) | block
PreToolUse block = permissionDecision "deny" JSON, exit 0
Stop block = {"decision":"block"} so the agent keeps workingPostToolUse and UserPromptSubmit make no server call at all: the tool has already run, so a verdict there prevents nothing.
Exit code 0 always. Claude Code reads the hook's stdout JSON only on exit 0 — a non-zero exit silently discards the verdict. (1.x exited 2 on block; on Windows, process.exit() after a network call aborted Node entirely, so those blocks never applied.)
The client adapter holds no principle logic. Risk classification decides what to ask about; every verdict comes from the server.
Fail-open
If app.kyntra.ai.kr is unreachable or times out (8 s default), the hook allows the call with a note on stderr. Kyntra will never block legitimate work because of its own bugs or network issues.
CLI
npx @kyntra/claude-hook install # install hooks into ~/.claude/settings.json
npx @kyntra/claude-hook uninstall # remove them
npx @kyntra/claude-hook print-config # print the hook snippet for manual setup
npx @kyntra/claude-hook --helpManual setup
If you prefer to edit ~/.claude/settings.json yourself:
npx @kyntra/claude-hook print-config…and merge the output into your existing hooks key.
Personal reminder block (optional)
Drop a short reminder file at ~/.claude/kyntra-userctx.txt (any text, up to 4KB). On every user prompt, the bridge prepends this file's contents to its additionalContext so Claude sees your personal checklist before it starts each turn:
⚠️ Principle check:
- NO-DEFER — finish every request this session, don't push to "next session"
- Verify on production (browser + console errors), not just curl
- (whatever else your team needs)This replaces the "just echo a static JSON via a separate UserPromptSubmit hook" pattern. Consolidating into a single hook avoids Claude Code's multi-hook additionalContext merging ambiguity — in practice only one entry surfaces, so a competing echo hook silently strips the governance feedback block (next section).
One verdict, at the moment it matters
1.x injected a running list of the last 60 minutes of warnings into every prompt. It mixed sessions, grew to 20 entries, and repeated warnings you had already acted on — noise, not correction. 2.0 removed it. A warning is printed once, on the call it is about; a block is delivered where it can still change the outcome.
What Kyntra actually sees
Nothing is sent for ordinary tool calls, for PostToolUse, or for user prompts. Two kinds of event reach the server:
A tool call in a risk class:
event_type,tool,command(the command string),file_path, and for edits the text being written — the server needs the thing it is judgingrisk_classes— which class matched locallyhuman_text— what you typed in this turn (last 4,000 chars), so an approval you already gave is honored instead of asked for againproject/cwd— so a rule written for one repository is not applied to another
A Stop event (the agent is about to finish its turn):
response_text— the assistant's final messageturn— counts only: files edited, verifying tools run, independent reviews run
Repository listings, source files you did not edit in that call, and environment variables are never sent. Secrets are redacted server-side before any verdict evidence is stored. Full details in the Privacy Policy.
License
MIT — see LICENSE.
The MIT license covers this client adapter only. The server-side governance engine at
api.kyntra.ai.kris proprietary to Flowlabs and protected under Korean patent application (claims 1 and 2 cover the compliance verification engine and trust-adjustment engine respectively).
Contact
- Homepage: https://kyntra.ai.kr
- App: https://app.kyntra.ai.kr
- Issues: https://github.com/YBPartners/kyntra-claude-hook/issues
- Email: [email protected]
Built by Flowlabs. Made because I was tired of Claude telling me the deploy was "done" when it wasn't.
