Skip to content

Interface stability and versioning

The public library interface is exactly kyvvu_engine.__all__, including the documented behavior of those exports. Submodule imports and private helpers are internal even when Python allows importing them. Before 1.0, a minor release may make a breaking change with a changelog entry. Starting with 1.0, breaking changes to the public interface require a major version. Additive changes may ship in a 1.x release. Policy rule names, accepted parameters, and their enforcement semantics are part of the documented behavior; callers should not depend on internal module paths used to implement them.

The 1.0 public surface, package by package

Every published package is 1.0.0 in this release, and the rule above applies to each of them: what is listed here can change incompatibly only in a major version, and anything not listed is internal.

kyvvu-engine — kyvvu_engine.__all__, which includes:

  • PlatformClient, the one transport to the platform (registration, policy fetch, send_steps, send_incident), and AgentProfile, the registration profile it sends;
  • the value-capture functions capture_dict, capture_step_name and to_ijson_capture, which turn a framework's values into what a step records;
  • the project probe, python -m kyvvu_engine.info: the JSON it prints is described by project_probe.schema.json and versioned by its probe_version field. A change to the shape needs a new probe_version.

kyvvu (the client) — kyvvu.__all__, with the documented behaviour of Kyvvu and the @kv.step decorator.

kyvvu-cli — the kyvvu command: kyvvu auth, kyvvu logout, kyvvu whoami, kyvvu integrations, kyvvu doctor, kyvvu docs, kyvvu explain, kyvvu list-agents, kyvvu list-policies, kyvvu list-manifests, kyvvu assign-manifest, kyvvu list-assignments, kyvvu unassign-manifest, kyvvu try, kyvvu init, kyvvu serve, kyvvu template and kyvvu schema, with their documented options and exit statuses. Hidden commands are not covered. The plugin interface is the kyvvu.cli_plugins entry-point group: an entry point names a module whose app is a Typer application, added as kyvvu <entry point name>, and which may define status(), returning its line in kyvvu integrations, and doctor(), returning its kyvvu doctor check.

kyvvu-baseline — kyvvu_baseline.__all__, including load_baseline_policies and profile_for_integration, and the three bundled manifests it loads.

kyvvu-templates — kyvvu_templates.__all__: BehaviorTemplate, load_template, deep_merge, discover_templates and TemplateError, and the kyvvu.templates entry-point group through which an installed distribution supplies a behaviour template.

kyvvu-claude — the kyvvu claude plugin commands: kyvvu claude setup, kyvvu claude set, kyvvu claude status, kyvvu claude policies, kyvvu claude refresh and kyvvu claude hooks, and the kyvvu-claude-hook script the installed Claude Code hooks call.

kyvvu-langchain — KyvvuLangChainHandler and KyvvuLangGraphHandler, and the langchain and langgraph templates.

kyvvu-crewai — KyvvuCrewAIListener, including listener.kickoff() and listener.gate(), and the crewai template.

Policy rule contract

The built-in rules are the contract every manifest is written against, so from 1.0 they are frozen like the Python interface. For each rule the contract is:

  • its name (the rule_type a policy names);
  • its enforcement points (agent_registration, step_execution);
  • its params: each param's name, type, required flag, enum values, minimum (and maximum), path grammar (full, property, output, agent), and any default, items or properties it declares, at any depth.

Not contract: each rule's and param's description, its example_params, the display name derived from the rule name, and the Python module that implements it.

A breaking change needs a major version: removing or renaming a rule; removing an enforcement point; removing or renaming a param; changing a param's type or path grammar; making an optional param required; adding a required param; removing an enum value or adding an enum where there was none; raising a minimum or lowering a maximum; changing a declared default; adding an items or properties constraint where there was none.

An additive change may ship in a 1.x minor: a new rule; a new enforcement point on an existing rule; a new optional param; a new enum value; making a required param optional; lowering a minimum or raising a maximum; removing an items or properties constraint.

The vocabularies are in the contract too: every param that names an action kind declares the action kinds as its enum (on items for a list), and every param that names a verb declares the verbs, so the snapshot records which params those are and which values they take.

kyvvu-engine/tests/rules/rule_contract.v1.json is the frozen snapshot, and tests/rules/test_rule_contract.py fails on any difference from the live registry, naming each one and whether it is breaking or additive. An additive change still fails until the snapshot is regenerated deliberately (uv run python scripts/update-rule-contract.py, from the repository root) and committed with the change, so every change to the contract is reviewed. A contract key the test does not recognise is treated as breaking.

What a rule decides for a given input is its enforcement semantics, covered by the paragraph above and by the changelog rather than by the snapshot.

What a 1.x release may add

These are additive changes. A 1.x release may make any of them without a major version, and consumers must be written to tolerate them:

  • new KyvvuSettings fields and KV_* settings, with defaults that keep the previous behaviour;
  • new symbols in kyvvu_engine.__all__;
  • new optional fields on result and status models (EvalResult, PolicyResult, PolicyStatus, PolicyLoadReport, ReportStatus, UnresolvedPath) and on the kyvvu serve responses. These are keyword-only or pydantic models, so a new field never breaks construction by name;
  • new kyvvu.* keys in a recorded step's meta;
  • new record types in JSONL and stdout output; a consumer skips a record of a type it does not know (a line without kind);
  • new exception subclasses of the documented exceptions.

Consumers must ignore output fields they do not know, in Python results, in exported steps and incidents, and in HTTP responses.