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.modelcarries no verb (#588). Emit it withverb=None; a model step withPOSTor any other verb is rejected. Policies that matchPOSTwithout a step-type filter no longer match model calls; filter onstep.modelexplicitly. ExistingPOSTmodel rows remain in stored logs.A policy that cannot be loaded raises
PolicyLoadError. There is no dropped-policy state:kv.dropped_policies,status.droppedandPolicyLoadState.all_droppedare gone, four load states remain, andkyvvu try,doctorandserveexit non-zero on an unloadable set. This covers an unknownrule_type, params that do not match the rule, a duplicate name, non-mapping params, a bad regex and the retiredscope: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.templateis a sentinel, and a custom template replaces the built-in. The default iskyvvu.default_template;template=Nonemeans no template (refused bystart_taskand the callback handlers). A custom template governs the steps and the task boundaries, and must cover every boundary. See Writing a Custom Template.function_nameandfunction_name_patternare removed. Usenameandname_patternon every surface. Thescope:key on policies is removed; useenforcement_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_ENVIRONMENTdefaults toproductioneverywhere and works throughKyvvu(...). Setdevelopmentfor local work.domain_allowlistrequirestarget_step_types(security-relevant). An in-scope step with no host is a violation; existing policies without the parameter fail to load.domain_allowlistparses 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 withhttps://evil.com\.company.com/.kyvvu servevalidatescontext(#611). An unknown key or an invalidenvironmentorrisk_classificationis a 422 naming it; a misspeltagent_allowed_toolused to be dropped and fail open.Regexes use
re.searchinfield_matches_regexand templatename_pattern(they were start-anchored). Anchor with^and$.risk_classificationmeans this class or above.cross_execution_rate_limitis refused at load (no host supplies its counts).Incident reports and trace flushes are asynchronous (bounded queue, worker thread,
atexitflush of about 2 seconds).kyvvu-claudehooks rely on that exit flush.
Added
kyvvu template show <name>; unmatched callback events recorded asstep.unknown; the| omit_emptytemplate filter;kv.flush()andkv.report_status(); restore an unassigned baseline from the dashboard orPOST /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:personalorshared.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 fromOrganizationMembership.suspended_at(one person stopped in one organization, by an administrator there).GET /auth/mepublishes both asis_cappedandis_suspended; the singleis_verifiedthey 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/manifestsalready 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
kyvvupackage (Apache-2.0), not the engine (BSL-1.1), so the set the server applies and the setkyvvu tryenforces are the same set rather than two copies asserted to be equal.On the platform it appears as an ordinary assignment whose
repo_idis 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 tryevaluates a three-step demo agent against the bundled baseline and blocks its ungated code execution — no account, no API key, no network.kyvvu serve --baselineand--policy-fileserve policies with no credentials.log_locationnow defaults toautoand follows the policy source, so an offline trial never ships its trace to the network even in a shell exportingKV_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
PolicyLoadStateit is:none_configured,unavailableorall_dropped. The other two —enforcingandstale_cache— mean at least one policy is in effect. Read it withkv.policy_status(),kv.policy_load_stateandkv.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'sb64_urlstrips the padding a Fernet key requires. Both fixed (#471)./auth/sessionnow 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 ontask_idreturns 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 overtask.end/task.errorsteps (error > completed > running), portable across PostgreSQL and SQLite. Ownership/auth mirrorGET /logs; the/tasksroute is registered before/{log_id}. AddsTaskSummary/TaskListResponseschemas.Dashboard trace view now lists tasks server-side (20/page) and lazy-loads a task's steps via
GET /logs?task_idonly 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
BehaviorTemplateloader / matcher / interpolation machinery moved intokyvvu_engine.templates(canonical, integration-agnostic). The name registry (from_builtin/_BUILTIN_TEMPLATES) was removed — integrations load their template by path. Per-integration*.template.yamlfiles 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_rootrule (allowlist containment): returns true when the target resolves at/underEvalContext.project_root, false when it escapes. Scoped to writes (POST/PATCH/DELETE/exec), fails open whenproject_rootis 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
PreToolUsehook populatesEvalContext.project_rootfrom 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/xwhilerm -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,/varintentionally excluded). Recursive detection tolerates flag order/splits.All six
exec.commanddestructive policies (rm + git) gained a command-position prefix (leading separator;/&&/||/|or exec-wrappersudo/doas/env/xargs/time/nice) so prefixed and chained dangerous commands (sudo rm -rf /,cd x && rm -rf /,build; git reset --hard) are caught whileecho rm -rf /still passes (the engine matchesfield_matches_regexstart-anchored).New stopgap shell policies: no shell write to sensitive paths (
redirect/tee/cp/mv/dd/installinto/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 onexec.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'sre.match/DOTALLsemantics.
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-countedstep.modelrecords. 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 (nothistory.clear()) so concurrent appends survive.New
subagent.py: every step is stamped withproperties["kyvvu.subagent"] = {id, depth, spawn_step}(flat storage). Tag derives fromtranscript_path(mainfor the parent,agent-{id}for a sub-agent); within-sub-agent order reconstructs by(tag, timestamp); the parent→childspawn_stepback-reference comes from a newSubagentStartlifecycle 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/statusnow 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 withdata.classification:secretfor 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 tostep.gate, tool extraction from graph nodes. LangGraph Research example agent (port 8105).KyvvuCrewAIListener— event-bus integration, parallel tool-call pairing viaevent_id/started_event_id,step.messageframing, 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) andlog_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_exporterssettings removed entirely.
Changed: configurable incident sink (#225)
incident_location/incident_formatconfigure 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_taskfire on block so the audit trail is always flushed.KyvvuBlockedErrorpropagates 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, andmanifest_assigned_by(null for hand-authored policies).Engine:
EvalContext.manifests(list ofManifestRef), optionalmanifest_id/manifest_nameon each loaded policy,manifest_idon each per-policy result. The in-effect manifest set is attached tometa["kyvvu.manifests"]on thetask.startatom, and per-policymanifest_idappears inmeta["kyvvu.eval"]["policies"][i].No database migration: the
Assignmentmodel already stored these fields.Provenance is now also surfaced on the single-policy
GETand standard policy-list responses (round-tripped viaPolicyResponse), 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_regexusesre.DOTALLon 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.ymlanddeploy-main.yml.KV_LOG_LEVELpassed to the API container in production.Nginx routes for the LangGraph (8105) and CrewAI (8106) demo agents.
bump-version.shincludes 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 reposkyvvu assign-manifest— assign a manifest to an agentkyvvu list-assignments— list manifest assignmentskyvvu initsimplified — pure scaffolding, no auth required, no policy applicationkyvvu 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,notwith unlimited nesting.KyvvuRunnerwith 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.stepdecorator with sync and async support.KyvvuLangChainHandlerfor LangChain and LangGraph.YAML behaviour templates with first-match-wins evaluation and deep-merge.
FrameworkAdapterbase 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_toolsfield 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
Licensing — license structure
Installation — get started
Last updated
