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

Changelog

Version history for the Kyvvu platform.

For full release notes and older versions, see GitHub Releases.


Unreleased: load failures raise, blocks keep the task open, templates replace

Engine, SDK, kyvvu-claude and API changes from the current batch. Not yet released.

Breaking

  • step.model carries no verb (#588). Emit it with verb=None; a model step with POST or any other verb is rejected. Policies that match POST without a step-type filter no longer match model calls; filter on step.model explicitly. Existing POST model rows remain in stored logs.

  • A policy that cannot be loaded raises PolicyLoadError. There is no dropped-policy state: kv.dropped_policies, status.dropped and PolicyLoadState.all_dropped are gone, four load states remain, and kyvvu try, doctor and serve exit non-zero on an unloadable set. This covers an unknown rule_type, params that do not match the rule, a duplicate name, non-mapping params, a bad regex and the retired scope: key. The release order matters: publish the engine and SDK before the platform serves a rule an older agent does not know, because that agent now refuses to start. See CI/CD.

  • template is a sentinel, and a custom template replaces the built-in. The default is kyvvu.default_template; template=None means no template (refused by start_task and the callback handlers). A custom template governs the steps and the task boundaries, and must cover every boundary. See Writing a Custom Template.

  • function_name and function_name_pattern are removed. Use name and name_pattern on every surface. The scope: key on policies is removed; use enforcement_point.

  • A block no longer ends the task. The blocked step is recorded, the exception is raised, and the task stays open; call error_task(), end_task(), or record a gate and retry.

  • A decorated gate passes unless it raises GateDenied.

  • KV_ENVIRONMENT defaults to production everywhere and works through Kyvvu(...). Set development for local work.

  • domain_allowlist requires target_step_types (security-relevant). An in-scope step with no host is a violation; existing policies without the parameter fail to load.

  • domain_allowlist parses hosts strictly (security-relevant, #617). A URL and a bare host are normalised the same way (lower-case, port, path and one trailing dot removed, host after the last @); a backslash, whitespace, control character or several @ in the authority, a non-DNS name, unicode and an unlisted raw IP are violations. This closes a bypass with https://evil.com\.company.com/.

  • kyvvu serve validates context (#611). An unknown key or an invalid environment or risk_classification is a 422 naming it; a misspelt agent_allowed_tool used to be dropped and fail open.

  • Regexes use re.search in field_matches_regex and template name_pattern (they were start-anchored). Anchor with ^ and $.

  • risk_classification means this class or above.

  • cross_execution_rate_limit is refused at load (no host supplies its counts).

  • Incident reports and trace flushes are asynchronous (bounded queue, worker thread, atexit flush of about 2 seconds). kyvvu-claude hooks rely on that exit flush.

Added

  • kyvvu template show <name>; unmatched callback events recorded as step.unknown; the | omit_empty template filter; kv.flush() and kv.report_status(); restore an unassigned baseline from the dashboard or POST /api/v1/assignments (#469).

v0.21.0 — Workspaces, invitations, and a library that needs no network (2026-09-19)

Engine 0.11.0 · SDK 0.21.0 · kyvvu-claude 0.5.1 · API 0.19.0 · Web 0.16.0.

Changed: membership is plural, and nobody is added without asking

The largest change to accounts since the platform shipped. Previously your organization was decided by your email address: everyone at a domain was put together, and a new member waited for an administrator to verify them.

  • Every account gets a personal workspace at signup — its own, with nobody else in it. A workspace is an organization with a kind: personal or shared.

  • Membership is plural. You may belong to any number of workspaces and move between them with the switcher at the top of the sidebar.

  • Invitations are the only route into an organization. The email-domain rule is gone, and so are the schema columns that carried it — the domain identifier and the admission flag were dropped. Nobody arrives unapproved, so there is nothing to approve.

  • Accepting an invitation signs you in in the same act. There is no second magic link to wait for.

  • Ownership and succession. Exactly one owner per organization, enforced by a partial unique index. Ownership is handed over as a two-party act, and an owner may name a successor who accepts in advance. An owner cannot be demoted or removed by anybody else. Administrator is now an offer you accept.

  • A personal workspace can be promoted to an organization. Its agents, policies, logs and keys stay put and you get a fresh personal workspace.

  • An agent is no longer its credential. An API key belongs to the workspace, survives its creator's account, and one key may serve several agents — which is what lets work change hands between workspaces, audit trail intact.

  • One flag was doing three jobs and is now two. users.is_capped (the platform registration cap, released by Kyvvu staff) is separate from OrganizationMembership.suspended_at (one person stopped in one organization, by an administrator there). GET /auth/me publishes both as is_capped and is_suspended; the single is_verified they replaced meant either, so whichever remedy a screen offered was wrong half the time.

  • The workspace identifier is now opaque and meaningless (org_<hex>), and the display name is just a name. The organization logo URL was removed.

Upgrading: an API below 0.18.0 does not publish is_capped / is_suspended, so a newer CLI reports every waiting account as neither.

New: the manifest library ships inside the platform (#429, #428)

  • Every new workspace starts with Kyvvu/manifests already connected, as an ordinary repository row you can see and delete.

  • Its contents are served from files bundled into the API image, not fetched from GitHub. Reads used to spend our own unchanging content against GitHub's 60-an-hour anonymous limit, keyed by the server's IP, so a busy hour left new workspaces with an empty catalogue and no explanation.

  • The paths and git blob SHAs are the repository's own, so nothing downstream can tell the difference.

  • Tradeoff: the library is pinned to the build, so a change upstream arrives with a platform release rather than immediately.

  • KV_GITHUB_FALLBACK_TOKEN (optional) attaches a platform credential to repository reads that carry none of their own, so a tokenless connection to a public repository of your own stops sharing one anonymous budget. It must grant public read only; the API refuses a private repository when the caller supplied no token.

Changed: the dashboard separates the account from the workspace

  • The sidebar item formerly called Settings is now Workspace, keeping the gear icon. Its tabs: General, Members (shared organizations only), API Keys, Usage, Platform Events, Reports.

  • Account settings is its own screen, reached from the account menu at the foot of the sidebar — as is Appearance. One path to each, instead of two into a screen that mixed them.

  • New organization moved into the workspace switcher, where it reads as the special action it is.

  • Roles and access became reference material behind an (i) in the Members header, rather than an inert block at the top of the tab.


v0.20.0 — Governed from the first step (2026-09-13)

Engine 0.11.0 · SDK 0.20.0 · kyvvu-claude 0.5.0 · API 0.17.0 · Web 0.15.0.

This is the release currently running in production.

New: every agent is governed at registration (#442, #444)

  • Registering an agent applies a frozen 15-policy baseline automatically — OWASP Top 10 for Agentic Applications plus EU AI Act minimal risk. No manifest to assign, no repository to connect.

  • The policy content is bundled in the kyvvu package (Apache-2.0), not the engine (BSL-1.1), so the set the server applies and the set kyvvu try enforces are the same set rather than two copies asserted to be equal.

  • On the platform it appears as an ordinary assignment whose repo_id is null.

  • Default-on, not mandatory: unassign either manifest and it stays unassigned. Re-registering will not bring it back, deliberately.

New: a first run with no account at all (#426)

  • kyvvu try evaluates a three-step demo agent against the bundled baseline and blocks its ungated code execution — no account, no API key, no network.

  • kyvvu serve --baseline and --policy-file serve policies with no credentials.

  • log_location now defaults to auto and follows the policy source, so an offline trial never ships its trace to the network even in a shell exporting KV_API_KEY.

New: onboarding you can see, and diagnose (#445, #441)

  • A dashboard checklist for a new workspace, dismissible.

  • kyvvu doctor — versions, credentials, and what is actually enforced, across nine checks.

  • "0 policies" is loud. When nothing is enforced, one line goes to stderr naming which PolicyLoadState it is: none_configured, unavailable or all_dropped. The other two — enforcing and stale_cache — mean at least one policy is in effect. Read it with kv.policy_status(), kv.policy_load_state and kv.dropped_policies. A count of zero alone could not tell those three apart, and all three allow every step.

  • A runner with no policy source fails when it is built, not on the first governed step (#427).

New: light / dark / auto theme

Defaults to auto, so a user whose system is dark gets a dark dashboard without touching anything. Cycled from Appearance in the account menu.

New: the demo environment (#338)

demo.kyvvu.com — its own VPC, database, secrets and edge. The six demo agents run in one container behind the dashboard's nginx at /demos/{key}/, gated on a platform login. They previously ran as six containers on ports 8101-8106.

Fixed

  • Repository connections returned a bare 500 when the server's Fernet key was missing or malformed, and the generated key was never valid: random_id's b64_url strips the padding a Fernet key requires. Both fixed (#471).

  • /auth/session now applies the human-credential policy (#462).

  • The access JWT is mirrored into a session cookie.

  • Kyvvu staff are administrators on every environment.


Releases v0.16.0 – v0.19.0 are not written up here. They fell between 2026-06-19 and 2026-08-27 and carried the authentication rework — password login retired, magic link made the only path, and the CLI moved to a device-code flow. See GitHub Releases for the commit-level history until they are backfilled.

v0.15.0 — Claude hardening & dashboard scale (2026-06-19)

Engine 0.7.0 · SDK 0.15.0 · kyvvu-claude 0.2.0 · API 0.12.0 · Web 0.9.0.

New: dashboard tasks-list endpoint & server-paginated trace view (#240)

  • GET /api/v1/logs/tasks — a distinct-task summary endpoint. A SQL group-by on task_id returns one row per task (task_id, agent_id, agent_name, environment, step_count, first_ts, last_ts, status) with offset-based pagination (skip / limit, default 20, max 100) and a total count of distinct tasks. Status is derived in SQL via conditional aggregation over task.end / task.error steps (error > completed > running), portable across PostgreSQL and SQLite. Ownership/auth mirror GET /logs; the /tasks route is registered before /{log_id}. Adds TaskSummary / TaskListResponse schemas.

  • Dashboard trace view now lists tasks server-side (20/page) and lazy-loads a task's steps via GET /logs?task_id only when a row is expanded. Replaces the previous flat 1000-log fetch + client-side grouping, which never showed more than ~2 tasks for 500+-step agents.

Changed: shared template engine & path-containment (#239)

  • The BehaviorTemplate loader / matcher / interpolation machinery moved into kyvvu_engine.templates (canonical, integration-agnostic). The name registry (from_builtin / _BUILTIN_TEMPLATES) was removed — integrations load their template by path. Per-integration *.template.yaml files stay with their integration.

  • kyvvu-claude mapper is now template-driven (claude-code.template.yaml, all 29 named tools + MCP catch-all) instead of a hardcoded if-tool ladder. A Claude-side pre-pass derives a Bash write target (>, >>, tee, cp, mv, dd of=, sed -i) → target.host, and detects shell secret reads (cat/cp/… of .env/.pem/…) → data.classification:secret, so the scope-containment and tainted-path policies arm for Bash. Shell parsing stays in kyvvu-claude; the engine never learns shell syntax.

  • New path_within_root rule (allowlist containment): returns true when the target resolves at/under EvalContext.project_root, false when it escapes. Scoped to writes (POST/PATCH/DELETE/exec), fails open when project_root is unset. The Claude-code-safety "No write outside project" policy now uses it instead of a hardcoded denylist. Paths are normalized lexically (.. collapsed; symlinks not resolved — documented limit).

  • kyvvu-claude PreToolUse hook populates EvalContext.project_root from the session cwd.

Changed: claude-code-safety destructive-command policies (#238)

  • The single mis-scoped "No rm -rf root" policy (which critical-blocked scoped cleanups like rm -rf /tmp/x while rm -fr /, rm -r -f /, and parent-traversal chains slipped through) was replaced with four per-target, force-agnostic, anchored policies: root, home, parent traversal, and system directories (/usr, /var intentionally excluded). Recursive detection tolerates flag order/splits.

  • All six exec.command destructive policies (rm + git) gained a command-position prefix (leading separator ;/&&/||/| or exec-wrapper sudo/doas/env/xargs/time/nice) so prefixed and chained dangerous commands (sudo rm -rf /, cd x && rm -rf /, build; git reset --hard) are caught while echo rm -rf / still passes (the engine matches field_matches_regex start-anchored).

  • New stopgap shell policies: no shell write to sensitive paths (redirect/tee/cp/mv/dd/install into /etc /usr /var ~/.ssh ~/.aws …) and no shell read of secret files (cat/less/head/base64/… of .env/.pem/.key/credentials/…), mirroring the destructive-delete pattern directly on exec.command.

  • Match/no-match + known-gap fixtures (tests/rm_policies.py, tests/shell_policies.py) load the live manifest regexes and exercise them with the engine's re.match / DOTALL semantics.

Changed: kyvvu-claude sub-agent partial-order stamping & session concurrency (#237)

  • Transcript cursor is now per-path (transcript_cursors: dict[path -> lines_read]) instead of a single int, so the main transcript and each sub-agent transcript (…/subagents/agent-{id}.jsonl) advance independently — fixes skipped / double-counted step.model records. Legacy scalar cursors migrate on load.

  • New mutate_session() / transact_session() context manager holds the file lock across the full read-modify-write, so concurrent hook processes no longer lose a step/history entry. The post-threshold flush trims by count (not history.clear()) so concurrent appends survive.

  • New subagent.py: every step is stamped with properties["kyvvu.subagent"] = {id, depth, spawn_step} (flat storage). Tag derives from transcript_path (main for the parent, agent-{id} for a sub-agent); within-sub-agent order reconstructs by (tag, timestamp); the parent→child spawn_step back-reference comes from a new SubagentStart lifecycle hook. Cross-sibling order is deliberately dropped. Tags are storage-only and never scope enforcement: replay stays whole-task, so a secret read in one sub-agent still taints exec anywhere in the task.

  • kyvvu-claude CLI init / status now surface the configurable incident sink (KV_INCIDENT_LOCATION / KV_INCIDENT_FORMAT, #225).


v0.14.x — Standardized logging, integrations & hardening (June 2026)

Sprint 1-3. Engine 0.6.x, SDK 0.14.x, kyvvu-claude 0.1.x.

New: kyvvu-claude (Claude Code integration)

  • Hook-based Claude Code integration — policy enforcement via PreToolUse / PostToolUse / SessionStart / SessionEnd hooks.

  • Claude Code tools mapped to Kyvvu behaviors (Bash, Read, Write, Edit, Glob, Grep, WebFetch, WebSearch, Agent, MCP tools, …).

  • LLM call capture from the session transcript (model name, token usage, proposed tools).

  • Secret file classification: .env, .pem, .key, etc. tagged with data.classification:secret for tainted-path policies.

  • Incident reporting to the API on policy blocks.

  • Hooks deny the offending tool call but do not stop the session; a tainted path is permanent for the session.

  • Published to PyPI as kyvvu-claude (Apache 2.0).

New: Claude Code Safety manifest

  • 9 policies (all severity critical): credential-exfiltration guard (no exec / no network after secret read), destructive-command protection (force push, rm -rf /, git reset --hard), scope containment (no write outside project), runaway prevention, and PII scanning in commands.

  • Tainted-path policies key on data.classification:secret.

New: Standardized logging & exporters (#212)

  • Pluggable exporters: stdout, file (JSONL), Kyvvu HTTP API, OTLP, callback.

  • Policy evaluation results embedded in the audit trail — meta["kyvvu.eval"] on every step (action, risk_score, per-policy outcomes).

  • OTLP shipped as a default engine dependency.

New: LangGraph & CrewAI integrations (#213, #214, #218)

  • KyvvuLangGraphHandler — node metadata (langgraph.node_name), GraphInterrupt mapped to step.gate, tool extraction from graph nodes. LangGraph Research example agent (port 8105).

  • KyvvuCrewAIListener — event-bus integration, parallel tool-call pairing via event_id / started_event_id, step.message framing, and a circuit breaker (listener.is_blocked) for post-kickoff block detection. CrewAI Research example agent (port 8106).

Changed: canonical log_location / log_format (#222)

  • log_location (where) and log_format (how) are now the single canonical logging settings across engine, SDK, and kyvvu-claude. Resolvers: effective_log_location / effective_log_format.

  • Legacy log_endpoint / log_exporters settings removed entirely.

Changed: configurable incident sink (#225)

  • incident_location / incident_format configure where incidents are sent and in what format. Both default to the trace sink (the incident location is derived from the log location; the Kyvvu HTTP path is …/api/v1/incidents).

Changed: blocked steps in the audit trail (#219)

  • Blocked steps are now always recorded with output.status=blocked (previously dropped). task.error + end_task fire on block so the audit trail is always flushed. KyvvuBlockedError propagates correctly across all integrations (decorator, LangChain, LangGraph, CrewAI, kyvvu-claude).

New: manifest provenance in the audit trail (#217)

  • Policies materialised from a manifest assignment now carry their origin. The policy-fetch response includes manifest_id, manifest_name, manifest_repo, manifest_path, manifest_sha, manifest_assigned_at, and manifest_assigned_by (null for hand-authored policies).

  • Engine: EvalContext.manifests (list of ManifestRef), optional manifest_id / manifest_name on each loaded policy, manifest_id on each per-policy result. The in-effect manifest set is attached to meta["kyvvu.manifests"] on the task.start atom, and per-policy manifest_id appears in meta["kyvvu.eval"]["policies"][i].

  • No database migration: the Assignment model already stored these fields.

  • Provenance is now also surfaced on the single-policy GET and standard policy-list responses (round-tripped via PolicyResponse), not just the policy-fetch endpoint (#217 follow-up).

Hardening & code quality (#233, #164)

  • SDK schemas ported to (str, Enum) enums and Pydantic v2 payloads with a byte-stable serializer.

  • Regex parity: field_matches_regex uses re.DOTALL on both the pre-compiled (PolicyStore) and fallback paths, so compiled and uncompiled evaluation behave identically.

  • API: full strict-mypy compliance across all modules (type annotations only, no runtime changes).

Infrastructure

  • deploy-main.yml: inline PyPI publish (no cross-workflow trigger dependency) and build-before-down (downtime ~2 min → ~5 s).

  • kyvvu-claude test job added to merge-dev.yml and deploy-main.yml.

  • KV_LOG_LEVEL passed to the API container in production.

  • Nginx routes for the LangGraph (8105) and CrewAI (8106) demo agents.

  • bump-version.sh includes kyvvu-claude.


v0.13.0 — Manifests (2026-05-14)

Platform

  • Manifests: YAML policy files in GitHub repos replace server-side policy templates

  • Assignments: Assign manifests to agents with per-agent policy materialization and risk filtering

  • Repos: Connect GitHub repos (public or private) with encrypted token storage

  • Dashboard restyle: Sidebar navigation (6 tabs), Settings page with sub-tabs (API Keys, Platform Events, Reports, Organization, Members)

  • Dashboard overview: 4 stat cards, recent incidents table, recent activity feed

  • Agents page: simplified 5-column table, last policy fetch, expandable row with assigned manifests, view policies

  • Repo delete protection: 409 if active assignments exist

  • Policy unique constraint: includes agent_id to allow same manifest on multiple agents

  • Hash chain validation: re-enabled in dashboard via verify_either_auth

CLI

  • kyvvu list-manifests — list available manifests from connected repos

  • kyvvu assign-manifest — assign a manifest to an agent

  • kyvvu list-assignments — list manifest assignments

  • kyvvu init simplified — pure scaffolding, no auth required, no policy application

  • kyvvu list-policies — new Source column showing manifest origin

Removed

  • Policy template endpoints (/api/v1/policy-templates/*)

  • Templates and Policies dashboard tabs

  • Default seeded policies (replaced by manifest assignment)

  • TemplateLoader, template YAML files, template router, 97 template tests


v0.11.0 (2026-04-29)

Engine

  • 26 built-in rule functions across six categories (field, path, count, classification, content, flow).

  • Compound rules: all_of, any_of, not with unlimited nesting.

  • KyvvuRunner with TTL-based policy fetch, incident webhooks, and log flush.

  • kyvvu serve — local HTTP server for non-Python agents.

  • Performance: p99 < 300 us with 100 policies and 50-step history.

  • explain() method for human-readable evaluation traces.

  • sweep_stale_tasks() for abandoned task cleanup.

  • Payload redaction (KV_LOG_PAYLOADS=metadata_only).

SDK

  • @kv.step decorator with sync and async support.

  • KyvvuLangChainHandler for LangChain and LangGraph.

  • YAML behaviour templates with first-match-wins evaluation and deep-merge.

  • FrameworkAdapter base class for custom integrations.

  • Programmatic task API: start_task(), end_task(), error_task().

  • ContextVar-based concurrent task tracking.

  • CLI: kyvvu register, login, logout, whoami, init, serve, list-agents, list-policies.

API

  • Policy templates with YAML definitions and apply/remove API.

  • OWASP Top 10 for Agentic Applications default template (8 policies).

  • Organization-scoped data isolation.

  • Incident lifecycle: open / active / resolved / ignored.

  • Hash chain for tamper-evident log ingestion.

  • Registration cap with waitlisting.

  • declared_tools field on agent registration.

  • Hosted engine evaluation routes were registered, but remain unavailable (501).

  • Audit report generation (PDF, XML).

Dashboard

  • Policy management with dynamic forms from rule schemas.

  • Template application UI.

  • Incident triage workflow.

  • Log viewer with hash chain validation.

  • Organization member management.


Next steps

Last updated