Skip to content

kyvvu-claude changelog

All notable changes to kyvvu-claude are documented in this file.

This file starts at 0.4.0. Releases 0.1.0 through 0.3.0 shipped without a changelog; their contents are recoverable from the claude-v* tags and the commit history rather than reconstructed here.


[1.0.0] - 2026-10-30

Released with kyvvu-engine 1.0.0; 0.8.0 was never published, and its changes ship here.

  • Changed: depends on kyvvu-templates>=1.0.0,<2.0.0, which now ships the behaviour templates the engine no longer exports.

  • Breaking: the standalone kyvvu-claude command is removed. Use kyvvu claude setup, kyvvu claude status, kyvvu claude refresh, kyvvu claude set, kyvvu claude hooks install, and kyvvu claude hooks remove. Setup reuses the API URL saved by kyvvu auth; the agent API key comes from --api-key, KV_API_KEY or a prompt. kyvvu-claude is installed with uv tool install "kyvvu-cli[claude-code]" and requires kyvvu-cli>=1.0.0,<2.0.0.

  • Changed: the installed hooks call the kyvvu-claude-hook script by its absolute path, and hooks written by an earlier release are repointed to it.
  • Changed: per-user state moves from ~/.kyvvu-claude to ~/.kyvvu/integrations/claude-code. The first kyvvu claude command moves every file across unchanged; a file already in the new directory is kept.
  • Changed: registration, policy fetch, trace and incident delivery go through the engine's PlatformClient, and tool inputs and outputs are recorded with the engine's capture functions.

  • Changed: requires kyvvu-engine>=1.0.0,<2.0.0.

  • Breaking: requires Python 3.11 or newer (requires-python = ">=3.11"), with kyvvu-engine 1.0. On 3.10, pip keeps resolving the newest 0.x release.

  • Added: _flush_logs sends seq and hash on every step (the engine's v1 hash chain). Each hook is a new process, so the chain head is kept in the task's .delivered cursor file, written in the same atomic replace as the acknowledged step and only after the API's 201: a batch that was not acknowledged is chained identically when it is resent under the same delivery key. When a split flush is accepted in part, the cursor advances past the batches the API took. A cursor written by an older release has no head, and the rest of that task is sent without hash (the platform computes its chain).

  • Fixed: a cached policy set served for another agent than the config names no longer passes for enforcement. The policy cache records the served agent_id and agent_key (policy_cache.write() and record_fetch_outcome() take them; init/refresh read the X-Kyvvu-Agent-Id header and SessionStart the runner's policy_status().agent_id), and an envelope from before is read from the one agent its policies name (PolicyCacheEnvelope.served_agent_id). A malformed recorded agent_id is an unreadable cache. load_from_cache() takes a required agent_id= and reports a mismatch, or a config naming no agent, as unavailable with the new UnavailableCause.agent_mismatch: a deny under enforce, UNCHECKED in monitor mode, and a message naming both ids and the setup command (now kyvvu claude setup). A matching set is loaded with served_agent_id=, so the runner refuses any other agent_id in the hook process as well. SessionStart checks the agent its fetch was served for the same way, and does not mark the cache untrusted for it. AgentBindingError from evaluate(), restore_task() or anywhere else in a hook denies a PreToolUse under enforce (or fail_mode: closed) and is logged; at the task start it is logged (agent_binding_refused) and the start recorded unevaluated. PreToolUse on an uninitialised config denies under enforce as it already did under fail_mode: closed. The status command (now kyvvu claude status) prints Policies for: and flags a MISMATCH.

[0.7.0] - 2026-10-17

  • Fixed: refused as too old by the platform, kyvvu-claude says so consistently. SessionStart no longer prints the engine's "nothing can be enforced" line before loading a cache it then enforces; one line names the cached set. The status command (now kyvvu claude status) names the too-old cause and pip install -U kyvvu-claude for a cached set, and drops the stray KYVVU: 0 policies in effect notice. With nothing cached, PreToolUse denies with the upgrade reason instead of "no policy cache recording a successful fetch" (a recorded refusal no longer marks the session's cache untrusted; the decision is unchanged). The refresh command (now kyvvu claude refresh) names what the cache still holds.

  • Added: a blocked registration (PolicyStatus.registration_blocked) is mapped like an unavailable policy set, with its own UnavailableCause.registration_blocked: a PreToolUse under enforce is denied, monitor mode logs it UNCHECKED, and the banner and status name the blocking policies.

  • Changed: a hook tool_use_id outside the engine's action_id grammar (letters, digits and . _ : -, 1-255 characters) is mapped to x- plus 32 hex digits of its SHA-256, deterministically, so PreToolUse and PostToolUse still pair; a tool name used as step_name has control characters replaced and is cut to 255 characters. Neither can fail a hook.

  • Breaking: A completed AskUserQuestion emits a human gate with output.decision: pass; its input is kept out of exported properties.

  • Breaking: Recorded steps carry the per-task ordinal as seq, and the sub-agent stamp under properties["kyvvu.subagent"] names the parent spawn spawn_seq (was spawn_step). Session files written by an earlier version stay readable.

  • Breaking: The behaviour field is kind and its enum is ActionKind; the retired field and enum names are rejected. Policy kind parameters are target_kinds, trigger_kinds, forbidden_kind, forbidden_kinds, required_kind, taint_kind, and forbidden_predecessor_kinds; old parameter names are rejected. A step policy's field needs a complete path such as input.recipient or properties.message.recipient (that is, input.<name> or properties.<name>); bare data field names are rejected.

[0.6.0] - 2026-10-01

Requires the matching kyvvu-engine release.

Breaking changes

  • The environment defaults to production and reads KV_ENVIRONMENT. It used to default to development. A value saved in the config file still wins.
  • An unloadable cached policy set is reported as unavailable. The engine raises PolicyLoadError rather than dropping policies; the hooks turn any exception into an allow, so policy_state.load_from_cache catches it and reports the set as unavailable (unloadable_set), which denies under enforce. The per-policy "dropped" lines are gone from kyvvu-claude's status output.

Changed

  • Incident reports and trace flushes are asynchronous in the engine. A hook is a short-lived process; it relies on the engine's atexit flush, which waits up to KV_REPORT_EXIT_FLUSH_SECONDS (default 2 seconds) for queued reports.

[0.4.0] - 2026-08-27

Breaking. Follows kyvvu-engine 0.10.0 in restoring the task.* action-type namespace. Requires kyvvu-engine>=0.10.0.

Breaking changes

  • The four task-lifecycle step types return to the task.* namespace: step.task_start → task.start, step.task_end → task.end, step.task_error → task.error, step.task_idle → task.idle. The StepType members are renamed to match, so the hook and mapper code fails at import against an older engine rather than silently emitting a value nothing matches.

claude-code.template.yaml needed no change: it maps Claude Code tool events onto the eight behavioral step.* types only. The task-boundary markers are emitted programmatically from hooks.py (SessionStart opens a task, Stop closes it), which is where the rename lands.

  • The kyvvu-engine dependency floor moves to >=0.10.0,<1.0.0. Installing 0.4.0 against engine 0.9.0 raises AttributeError on the renamed members at import time.