Skip to main content

Kagua

Unit tests assert your agent did the right thing. Kagua asserts it was ever allowed to.

Kagua replays multi-agent traces against a declared authority envelope and fails the build when the composition of actions exceeds what any principal authorized, even though every individual call passed its own check.

kagua check failing the work-order demo on a Composition violation

Same output as text
$ kagua check fixtures/workorder/

FAIL  Composition / forbidden_composition
  forbidden sequence [vendors.get_quote -> payments.approve] completed within t_workorder_442; every call was individually authorized
  witness (6 events):
    e01    task_start   t_workorder_442  - WO-442: HVAC failure, Site 12
    e03    delegation   human:ops.manager -> agent:coordinator  [w_coord]  scope=6 tools  - root grant to coordinator
    e08    delegation   agent:coordinator -> agent:procurement  [w_proc]  scope=6 tools  - sub-delegate quote collection
    e13    tool_call    agent:procurement  vendors.get_quote  [w_proc]  - quote from acme-hvac: $8,400   <- forbidden[0]
    e28    delegation   agent:coordinator -> agent:finance  [w_fin]  scope=4 tools  - sub-delegate payment processing
    e33    tool_call    agent:finance      payments.approve  [w_fin]  - approve $8,400 to acme-hvac   <- forbidden[1]
  every event above passed its own Lifetime/Scope/Principal check; the composition is the violation

coverage: QUALIFIED - no enforcement point declared for this trace
families: Lifetime ok  |  Scope ok  |  Principal ok  |  Provenance n/a  |  Composition partial  |  Trajectory n/a
verdict: FAIL (1 finding)

Read that trace again. The coordinator was granted exactly what the envelope declares. Both sub-delegations narrowed scope. Every tool call sat inside its warrant. A per-call policy engine says yes 40 times. And the task still solicited vendor quotes and approved the payment to the winner with no human in between. That gap, agents composing past checks that each pass individually, is what Kagua exists to catch.

Why point-in-time authorization isn't enough

Cedar and OPA decide the point; Kagua verifies the trajectory. A policy engine answers "may this call proceed?", and that's precisely the layer composed abuse defeats, because every point answer is yes. Kagua evaluates the whole task DAG after the fact (or in CI, before deploy). The two are complementary: if you already run per-call policy, composition is the gap you have left.

Three claims, each testable in this repo:

  1. Point-in-time authorization cannot detect composed abuse.
  2. A deterministic, replayable check over a causally-ordered trace can, for declared invariants, at declared coverage.
  3. Nobody ships that artifact today. Gateways enforce, observability describes, evals score quality. None verify authority composition.

Quickstart

pip install kagua
git clone https://github.com/Dnakitare/kagua && cd kagua
kagua check fixtures/workorder/        # exits 1, prints the witness above

Three artifacts, all files, all diffable in git:

  • Trace (JSONL): a DAG of events. delegation, tool_call, task_start, task_end, token_issue, token_revoke, message. See fixtures/workorder/trace.jsonl.
  • Envelope (YAML): who the root principals are, what each agent is scoped to do, and which compositions are forbidden. See fixtures/workorder/envelope.yaml.
  • Verdict (exit code + JSON): findings with witness sets, a slice of the trace sufficient to demonstrate each violation, plus a coverage grade on every claim.

The rules Kagua checks (v0.1)

Family Check Status
Lifetime No event references a warrant outside its validity window; no activity after task_end (zombie authority) shipped
Scope Every call inside the transitive scope of its warrant chain; scope never widens across delegation hops shipped
Principal Every warrant chain terminates at a declared root principal; no orphaned authority shipped
Composition forbidden_composition sequences over the task DAG shipped (sequences only)
Provenance Cryptographically signed delegation hops (Muhuri) v0.2
Trajectory Plan subsumption v0.3+

v0.1 honestly covers three of the six families plus forbidden compositions. The general composition engine (budgets, conservation rules in CEL) is v0.2.

Design rules that won't bend:

  • Every check is deterministic and produces a replayable witness. No ML in the verifier. An anomaly score is a suspicion; a witness set is a proof.
  • Causal order beats wall clock. Ordering comes from parent links; timestamps are a fallback with a tolerance window, because distributed clocks lie.
  • Retries have identity. Events carry idempotency keys; a retried call can't count twice.
  • Lossy input never produces a silent pass.

Coverage grades: attested vs. qualified

Every verdict says what it can actually claim:

  • attested: the input source can prove completeness (all egress flowed through a declared enforcement point, like an MCP gateway).
  • qualified: violations found are real; the absence of violations proves nothing beyond the visible trace.

A pass on partial input is worse than no tool if it reads as a clean bill. Kagua states its own coverage boundary on every run.

Ingesting your traces

kagua ingest ./otel-export.json --adapter otel --out trace.jsonl

The OTel GenAI adapter converts tool-execution spans into canonical events and tells you exactly what it couldn't recover. This is real output over a real OpenLLMetry export (a LangChain tool loop instrumented with opentelemetry-instrumentation-langchain; the export is checked in at fixtures/otel/openllmetry-langchain.json, no hand-authored spans):

ingested 9 spans -> 4 events
  skipped 5: model/agent invocation spans (no authority semantics)
recovered: 0/4 warrants, 0 delegation records, 4/4 args digests (4 derived here from plaintext args, not attested by source)

this input cannot support:
  Principal   - no delegation records; warrant chains to a root principal cannot be verified
  Lifetime    - no warrants or task boundaries; validity windows unknowable
  Scope       - degraded to a point check of each call against the envelope's per-agent declarations
  Provenance  - not implemented until v0.2 (Muhuri-signed hops)

actor identity: 4 of 4 events have no per-agent identity (no gen_ai.agent.name); actor fell back to the service.name resource attribute, which cannot distinguish agents sharing a process.

task grouping: 4 events landed in 4 disjoint traces with no shared root span. Within-task checks (composition, lifetime) cannot correlate any of them. If these belong to one logical task, wrap the run in a workflow/root span or re-ingest with --task <id>.

verdicts over this trace will be QUALIFIED: findings are real, but a pass
covers only what this export saw. OTel sampling drops spans by design;
a sampled trace cannot prove the absence of a violation.

Even at this fidelity, the composition check works: group the calls into one task (--task, or a root span in your instrumentation) and the quote-then-approve pair in that export fails kagua check with a witness. When ordering rests on clocks instead of causal links, the finding says so rather than overclaiming.

Plain OTel GenAI data is authority-blind. If your instrumentation emits the kagua.* span attributes (kagua.warrant_id, kagua.delegation.subject, kagua.args_digest, ...), the adapter recovers full authority semantics; Datadog ignores them and nothing breaks.

CI

# .github/workflows/authority.yml
jobs:
  authority:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: Dnakitare/kagua@main
        with:
          trace: traces/recorded/
          fail-on: any

A prompt edit or tool-wiring change that widens effective authority turns the PR red with a Scope-family witness before it deploys. kagua-demo is the live version: a one-line PR gives the procurement agent payments.approve and CI fails on the exact granting event, plus the composition it enables. fixtures/scope-drift/ is the same story as a local fixture.

What Kagua is not

  • Not an eval framework. It never scores answer quality.
  • Not a gateway. It never sits in the request path.
  • Not an anomaly detector. If a check can't produce a replayable witness, it doesn't ship.

The problem is getting named from several directions at once; none of these ship this artifact, and each is worth reading:

Roadmap

  • v0.2: kagua infer (propose an envelope from observed traces, delivered as a PR, never auto-committed), the general composition engine (budget, conservation via CEL), pytest plugin, MCP gateway log adapter.
  • v0.3: Muhuri-signed delegation hops; Provenance moves from "trust the log" to "verify the chain". Replayable signed verdicts.
  • v0.4: kagua report with OWASP Agentic Top 10 and SOC 2 CC-series mappings. Findings and evidence language throughout, never "certified compliant".

License

Apache-2.0

Metadata

Release files for kagua 0.1.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for kagua 0.1.1
File Size Uploaded
kagua-0.1.1.tar.gz 39.5 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for kagua 0.1.1
File Interpreter ABI Platform
kagua-0.1.1-py3-none-any.whl Python 3 none any Details

Total release size: 71.9 kB

Release files / kagua-0.1.1.tar.gz

Download URL kagua-0.1.1.tar.gz
Size 39.5 kB
Tags Source
SHA-256 checksum
How to use checksums
7a4ea06d87d9a2d352924cf9c7d6d5004fd37b3efe57768fc9600a044d08a20e
BLAKE2b-256 checksum
How to use checksums
2c48e96751980adfc125b0f8268f8a6091c71a74cfe19df65db5385e6231de67
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.12

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Jul 3, 2026.

Transparency log

Release files / kagua-0.1.1-py3-none-any.whl

Download URL kagua-0.1.1-py3-none-any.whl
Size 32.5 kB
Tags Python 3
SHA-256 checksum
How to use checksums
0bf49164a820cf0d14680e218de8d185ae7fec39450f7774d7d66c6b41d0e121
BLAKE2b-256 checksum
How to use checksums
e1532f1ae3dfed9c632a5e26a3e09b0dbdb1be6a96ca620934147c11c9d5ae98
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.12

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Jul 3, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.1.1 This release

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page