For the complete documentation index, see llms.txt. This page is also available as Markdown.

Claude Code

What you'll learn: How to add Kyvvu agent security to Claude Code sessions using the kyvvu-claude package.


Overview

kyvvu-claude is a standalone Python package that integrates Claude Code into the Kyvvu ecosystem via Claude Code's native hook system. Every tool call (Bash, Read, Write, Edit, etc.) is evaluated against Kyvvu policies before execution, and all tool calls are recorded as a behavioral audit trail (when the trace goes to the platform, the platform hash-chains it on ingestion; the hook process does not).

Unlike the SDK integrations (LangChain, CrewAI), kyvvu-claude does not wrap your code — it operates via Claude Code's hook system, so it works with any Claude Code session without code changes.

Installation

pip install kyvvu-claude

Quick start

# Interactive setup — connects to API, registers agent, installs hooks
kyvvu-claude init

You'll need:

After init, every Claude Code session is automatically governed.

Architecture

Each hook invocation is a separate short-lived process. There is no long-running daemon. Session state (task ID, step history, policy cache) is persisted to ~/.kyvvu-claude/ between invocations.

Policy evaluation flow

  1. SessionStart: Fetch policies from the Kyvvu API (filtered by this agent's key). Cache to disk.

  2. PreToolUse: Load policies from disk cache. Replay session history into the engine for path-dependent rules. Evaluate the intended tool call. Return allow or deny.

  3. PostToolUse: Record the completed tool call in session history. Capture LLM calls from the transcript.

  4. SessionEnd: Record task.end. Flush the full behavioral trace to the API.

Enforcement

When a policy blocks a tool call:

  1. kyvvu-claude returns permissionDecision: "deny" to Claude Code

  2. Claude Code shows the block reason to the user/model

  3. The blocked step is recorded in the audit trail with output.status = "blocked"

  4. An incident is sent to the incident sink (the Kyvvu API by default) without holding up the tool call; the hook process gives it a short flush when it exits

  5. The model continues reasoning (it may try alternative approaches)

Tool blocks deny the specific tool call but do not stop the session. This is consistent with how Claude Code handles permission denials from users.

Tainted-path enforcement

When Claude Code reads a secret file (.env, .pem, .key, etc.), kyvvu-claude classifies it with data.classification: secret. Tainted-path policies then block subsequent dangerous actions:

  • No exec after secret read — blocks all Bash after a secret file read

  • No network after secret read — blocks every further resource read after a secret file read (web fetches and other file reads alike), so nothing read afterwards can be sent out. This is deliberately conservative

The taint is permanent within the session. Use /clear in Claude Code to start a new session and reset.

What this does not prevent

For Bash calls, kyvvu-claude uses regular expressions over the command text to infer secret-file reads and write targets. This is a best-effort signal, not a shell security boundary. A python -c or here-doc program can write outside the project without a detected target. Writes hidden behind bash -c, eval, xargs, or base64-decoded commands can do the same. Secret reads through a variable, split quotes such as cat .en''v, command substitution such as env $(cat .en''v), or backticks can escape classification. The reverse also happens: echo "value > /etc/hosts" only prints text, but the > inside quotes is treated as a redirect and can trigger a false block.

Use OS controls alongside the hook: a read-only bind mount over protected paths, a restricted PATH, network egress controls, and an agent user that cannot read secret files. We intentionally do not add a shell parser because syntactic parsing still cannot resolve eval, variables, or decoded commands at runtime.

Assign the Claude Code Safety manifest to your agent:

The manifest bundles policies covering credential exfiltration, destructive commands, project containment, runaway prevention and PII scanning. They block rather than warn when enforce is true; in the default monitor mode they are evaluated and recorded but nothing is denied. Run kyvvu-claude policies, or open the manifest in the dashboard, for the current list.

Configuration reference

All settings are in ~/.kyvvu-claude/config.json, configured during kyvvu-claude init:

Setting
Default
Description

api_url

https://platform.kyvvu.com

Kyvvu API URL

log_location

auto

Where logs go: URL, file path, stdout, none, or auto — which follows the policy source: the platform when it is the policy source, otherwise stdout

log_format

kv

Log format: kv, json, or otlp

incident_location

(inherits trace sink)

Where incidents go. Same vocabulary as log_location; empty inherits the trace sink

incident_format

(inherits log_format)

Incident format: kv, json, or otlp. Empty inherits log_format

enforce

false

true = block violations, false = observe only (warn, don't block)

environment

KV_ENVIRONMENT, else production

Deployment environment the agent registers under. A value saved in the config file wins over the variable

flush_threshold

100

Flush logs every N steps (0 = session end only)

OTLP export

To send traces to an OpenTelemetry collector (Jaeger, Grafana Tempo, etc.):

CLI reference

Command
Description

kyvvu-claude init

Interactive setup

kyvvu-claude install-hooks

Install hooks into Claude Code

kyvvu-claude uninstall-hooks

Remove hooks

kyvvu-claude status

Show configuration and status

kyvvu-claude policies

Display cached policies

kyvvu-claude refresh

Force policy refresh

Compatibility

Works with all Claude Code surfaces:

  • Claude Code CLI

  • VS Code extension

  • JetBrains plugin

  • GitHub Actions (anthropics/claude-code-action)

Not supported: Claude Desktop (uses MCP, not hooks).

Troubleshooting

Nothing is being enforced

A session says how many policies are in force, and why when the answer is none. The states are distinct, and they need different fixes:

Session banner / status

What happened

Fix

Policies: N loaded

N policies are being applied.

—

Policies: N loaded (cache not refreshed)

The last fetch failed; the last known set is still being applied.

kyvvu-claude refresh when the API is reachable again.

No policies are configured for this agent

The platform answered, and this agent has nothing assigned.

Assign a manifest or create a policy.

NOT ENFORCING — the last recorded fetch did not succeed

A fetch failed and there was no usable cache. No tool call is being checked.

Check api_url, the API key and network reachability, then kyvvu-claude refresh.

NOT ENFORCING — the policy set was REJECTED

The set arrived but a policy in it could not be loaded (unknown rule_type, invalid or missing params, a duplicate name, a regex that does not compile). A set loads whole or not at all, so none of it is applied.

Fix the policy definitions named in the message; kyvvu-claude status shows the detail.

NOT ENFORCING — the policy cache could not be read

The cache file exists and is corrupt, unreadable or not a policy list.

Delete ~/.kyvvu-claude/policy_cache.json and start a new session, or kyvvu-claude refresh.

NOT ENFORCING — no cache recording a successful fetch

Nothing has been cached yet, or the cache could not be written.

Start a new session, or kyvvu-claude refresh. Check that ~/.kyvvu-claude is writable.

NOT ENFORCING — the policy state could not be determined

Something unforeseen went wrong while loading.

kyvvu-claude status, then kyvvu-claude refresh.

WILL STOP ENFORCING — fetched but not cached

The fetch succeeded and this session is enforcing it, but the result could not be written, and every hook process reads policy from that file.

Make ~/.kyvvu-claude writable, then kyvvu-claude refresh.

kyvvu-claude status prints the same verdict, and the session log records an unchecked tool call as UNCHECKED, never ALLOWED.

In enforce mode, every NOT ENFORCING row denies every tool call rather than allowing it unchecked — including a corrupt cache, which is deliberate: a session that cannot read its policies is in exactly the position of one that never had any. No policies are configured stays an allow in both modes, so an organisation with nothing assigned yet remains usable, and it keeps that tolerance across a failed refresh for as long as the recorded answer is within policy_cache_max_age_seconds.

Agent not appearing in dashboard

Clear the registration cache and re-initialize:

Hooks not firing

Check that hooks are installed:

If not present, run kyvvu-claude install-hooks.

LLM calls missing from trace

LLM calls are captured from Claude Code's session transcript. In very short sessions (<10 seconds), the transcript may not be flushed to disk before the hook reads it. This is a known limitation.

Last updated