> For the complete documentation index, see [llms.txt](https://docs.kyvvu.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.kyvvu.com/reference/changelog.md).

# Changelog

**Version history for the Kyvvu platform.**

For full release notes and older versions, see [GitHub Releases](https://github.com/Kyvvu/platform/releases).

***

## 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](https://github.com/Kyvvu/platform/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 endpoint (`POST /api/v1/engine/evaluate`).
* 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

* [Licensing](/reference/licensing.md) — license structure
* [Installation](/getting-started/installation.md) — get started
