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

kyvvu try

What you'll learn: How to see Kyvvu block an unsafe agent step with no account, no API key and no network — and how to run your own manifest and your own behaviour path the same way.


Usage

Usage: kyvvu try [OPTIONS]

Options:
  -m, --manifest TEXT   Manifest YAML to enforce (repeatable).
                        Default: the bundled frozen baseline.
      --steps TEXT      YAML file describing your own behaviour path.
      --json            Emit JSON instead of a report.
      --record-trial    Opt in to a local trial marker in ~/.kyvvu. Off by
                        default; sent nowhere.
      --forget-trial    Delete the local trial marker and exit.

The 30-second version

pip install kyvvu
kyvvu try
kyvvu try — enforcement with no account, no API key and no network

  Policy source   bundled frozen baseline (owasp-agentic-default, eu-ai-act-minimal)
  Policies        15 offered, 15 enforcing (state=enforcing)
                  7 evaluated per step, 8 at agent registration
  Agent           hello-kyvvu   risk=minimal   tools: fetch_user_data, call_llm, run_script
  Environment     production   (set KV_ENVIRONMENT=development to change)
  Path            bundled demo path

#  DECISION  RISK  BEHAVIOUR                          VIOLATED POLICY
1  ALLOW     0.00  step.resource GET fetch_user_data  —
2  WARN      0.75  step.model call_llm           AI-generated content must be marked before
                                                      delivery (high)
3  BLOCK     1.00  step.exec run_script               Code execution requires a preceding gate
                                                      (critical)

BLOCKED — run_script was stopped before it ran (risk 1.00)
    Code execution requires a preceding gate (critical)

The same step, after an approval gate
    recorded  step.gate human_approval  properties.guard.result = "pass"
    run_script is now ALLOW (risk 0.00)
    Same step, same policies, different path.
    A gate only counts when it carries a result.

No login, no key, no dashboard, nothing on the network.

What it actually did

Three steps of the agent kyvvu init scaffolds, evaluated against the frozen baseline set bundled inside the kyvvu package:

  1. fetch_user_data — a step.resource GET. In the declared allowlist, so allowed.

  2. call_llm — a step.model. The EU AI Act set's Article 50 transparency policy is high, so it warns rather than blocking.

  3. run_script — a step.exec with no approval gate in front of it. The OWASP set's ASI05 policy is critical, so it blocks and the step never runs.

Then it records a step.gate and re-evaluates step three, which is now allowed. That is the product's thesis in one screen: the decision depends on the path, not on the step. The same run_script call is blocked or allowed depending on what the agent has already done in this task.

The gate has to carry a result. step_requires_gate looks for properties.guard.result == "pass"; a bare step.gate, or one whose result is "approved", clears nothing.

Enforce your own manifest

Any manifest from Kyvvu/manifests — or one you wrote — runs from disk:

An invalid manifest is refused with every problem listed, rather than loading the half that parsed:

Run your own behaviour path

Describe your agent's steps in YAML and evaluate them without changing your agent code:

allowed_tools matters more than it looks. The OWASP allowlist policy reads the agent's declared tool allowlist and fails closed: with the list empty, every step.resource, step.exec and step.credential blocks on "Tool calls must be in the declared allowlist". When you omit allowed_tools, kyvvu try defaults it to every step name in your path, which is what registration would have declared.

For a blocked simple rule, the verdict line shows the value it checked: the normalised host for domain_allowlist, the field path and value for field_* rules, or the current step type for current_is. For example, a rejected region prints request.region = "forbidden-zone" on the BLOCKED line. Long values are shortened on that line; the policy detail below and --json output retain the untruncated compared value.

After evaluating the steps, kyvvu try warns on stderr for each step policy whose field or property filter path resolved on none of the trial steps. The warning names the policy and the path, including paths inside compound rules. For example, request.hots warns if the steps only carry request.host. A path present on even one step does not warn. The warning is diagnostic: a path may be absent because the trial did not exercise it, and the run's exit status stays the same. It also goes to stderr with --json, leaving stdout as one JSON object.

Machine-readable output

--json emits one object — useful as a CI smoke test that a manifest still enforces what you think it does:

Exit codes

A block is not a failure. kyvvu try exits 0 when it ran and enforced, whether the path was allowed, warned or blocked. A step that was blocked does not change the exit code: a BLOCK row is the thing you asked to see.

Exit code
Meaning

0

The policies loaded, at least one is in effect, and the path was evaluated. Any verdict, including BLOCK.

1

The run did not really enforce: the manifest or steps file failed to load, or no policy is in effect (zero policies, for example a valid manifest with policies: []).

2

A usage error (an unknown flag).

Exit 1 means "nothing trustworthy was evaluated", never "a step was blocked". The causes of a load failure are a missing file, a rule_type that is misspelled or unknown, params that do not match their rule, a step type or verb that is not in the vocabulary, a duplicate policy name, a regex that does not compile, or the retired scope: key. A policy set is loaded whole or refused whole; there is no run that enforces the half that parsed. The command says which on stderr, so --json's stdout stays parseable. A green exit from this command means an agent that is actually governed, not that its path was allowed.

To assert a verdict in CI, parse --json; do not read the exit code. blocked is true when any step was blocked, and decisions has one entry per step:

action is allow, warn or block. Run the kyvvu try line first and stop the job if it exits non-zero, so a manifest that no longer loads fails the build instead of passing the jq test on a stale verdict.json.

Read load_state, not just policies_enforcing. A run that enforces nothing looks configured while allowing everything, and load_state names which of the four load states you are in: enforcing (at least one policy is in effect), none_configured (the source has no policies), unavailable (nothing is loaded and nothing could be fetched) and stale_cache (a cached set is enforcing because the source stopped answering). A run that enforces nothing announces it once on stderr.

The Environment line, and the environment key in --json, is the environment the run was evaluated as: KV_ENVIRONMENT, else production. Environment-scoped policies behave differently in development and production, so the report says which one it used. When it is not development the line ends with the hint (set KV_ENVIRONMENT=development to change); in a development run there is nothing to change and the line is just the name. kyvvu try reads KV_ENVIRONMENT from the shell and from a .env in the current directory (see where settings are read).

Offline by construction

kyvvu try pins every setting that could redirect the run — the policy source, the credentials and the log sink — in the command itself rather than reading them from the environment. So it stays offline, and enforces the policies it names, even if your shell exports KV_API_KEY, KV_LOG_LOCATION or KV_POLICY_FILE, which is the normal state of anyone who already has an account. The test suite exports all of those and then installs an audit hook that fails on any socket operation, so this is enforced rather than intended.

It is a real KyvvuRunner, though — the same class an instrumented agent uses, with the same policy-load dispatch and the same non-enforcement signalling. The trial is the product, not a demo of it.

The trial marker is opt-in

kyvvu try records nothing by default. --record-trial writes a small JSON file to ~/.kyvvu/try-marker.json:

That is the whole feature: the file is written locally and sent nowhere. It carries an opaque random id, timestamps, a run count, the version, which kind of source enforced the run, the decision counts, and when the first block happened. No file paths - not even the manifest's - no step names, no agent content, no hostname, no username.

Nothing reads it to decide what to enforce or what to print, so declining costs you nothing. There is deliberately no environment variable that turns it on by default: an opt-in an installer can pre-enable is not opt-in. kyvvu try --forget-trial deletes it.

When a gate does not help

The approval-gate replay only changes the verdict when the policy that blocked the step is one a gate can clear. A path-taint policy is not: once a sensitive read is on the path, the block stays for the rest of the task. kyvvu try replays the step for real either way, so it says so:

The last line names the policy from the replayed verdict. If the replay only warns, it reads "still WARN" and "warns on it". A run where nothing was blocked has no replay and prints neither.


Next steps

Last updated