Your first policy
Kite Logik policies are OPA/Rego files. You can either write them directly, or write them in a constrained YAML DSL and let kitelogik compile generate the Rego for you. Most teams start with YAML and drop into hand-written Rego when they need delegation cascades, plan evaluation, or data-classification flow control — features the YAML compiler intentionally doesn't cover.
Option A — YAML
The YAML DSL covers the common cases: action allowlists/denylists, argument thresholds, role and scope checks, risk tier assignment, deny reasons.
# policies/policy.yaml
version: 1
package: kitelogik.main
rules:
- name: allow_read_ops
when:
action: [get_customer, list_transactions]
scope: read_customer
then: allow
risk_tier: INFORMATIONAL
- name: allow_small_refund
when:
action: approve_refund
role: [support_agent, manager]
scope: approve_refund
args:
amount: { lte: 200 }
then: allow
risk_tier: TRANSACTIONAL_LOW
- name: block_large_refund
when:
action: approve_refund
args:
amount: { gt: 200 }
then: deny
reason: "Refunds over $200 require manager approval"
- name: block_shell_access
when:
action: run_shell_command
then: deny
reason: "Shell access is prohibited"Supported argument operators
The args: block compares fields on input.args. Five operators:
| YAML | Rego operator |
|---|---|
gt | > |
gte | >= |
lt | < |
lte | <= |
eq | == |
Compile
kitelogik compile policies/policy.yamlWrites policies/policy.rego next to the source. With -o path/to.rego you can override the destination, and with --check you can validate the YAML without writing output.
Validate the generated Rego
kitelogik validateRuns opa check on every *.rego file in policies/ (excluding *_test.rego).
What the YAML compiler will not generate
By design, complex interactions stay in hand-written Rego:
- Delegation cascades (
agent.spawn/agent.delegaterules that referenceparent_token_idanddelegation_depthgraph relationships) - Plan evaluation (
agent.planrules that count step types or check cross-step invariants) - Data classification flow (
data_classificationfield rules and cross-event flow constraints)
For those, see Option B.
Option B — Hand-written Rego
Every policy file starts with default allow := false (deny-by-default), imports the if and in keywords, and lives in kitelogik/policies/<name>.rego (or your project's policies/ for kitelogik init projects).
package kitelogik.financial
import future.keywords.if
import future.keywords.in
default allow := false
# Allow refunds under $100 for support agents with the right scope
allow if {
input.action == "approve_refund"
"approve_refund_under_100" in input.context.session_scopes
input.context.user_role in {"support_agent", "manager"}
input.args.amount <= 100
}The same pattern works for agent lifecycle policies — just match on input.event_type:
package kitelogik.agent_lifecycle
import future.keywords.if
import future.keywords.in
import future.keywords.every
default allow := false
default deny := false
allow if {
input.event_type == "agent.spawn"
input.context.delegation_depth <= 2
every cap in input.requested_capabilities {
cap in input.context.session_scopes
}
}
deny if {
input.event_type == "agent.spawn"
input.context.delegation_depth > 2
}See kitelogik/policies/examples/ in the source for annotated templates, and kitelogik/policies/library/ for ready-to-use starter policies (financial, security, RBAC, tool allowlists).
Test policies with opa test
Rego has first-class unit testing. Drop a *_test.rego file alongside your policy and run:
kitelogik testInternally this calls opa test policies/. Use kitelogik test -v for verbose output.
# policies/financial_test.rego
package kitelogik.financial_test
import data.kitelogik.financial
test_small_refund_is_allowed if {
financial.allow with input as {
"action": "approve_refund",
"args": {"amount": 50},
"context": {
"user_role": "support_agent",
"session_scopes": ["approve_refund_under_100"],
},
}
}
test_large_refund_is_denied if {
not financial.allow with input as {
"action": "approve_refund",
"args": {"amount": 5000},
"context": {
"user_role": "support_agent",
"session_scopes": ["approve_refund_under_100"],
},
}
}Dry-run a single event with kitelogik check
Useful for "would this event be allowed?" debugging without spinning up an agent. Pass the event payload as JSON:
kitelogik check '{
"action": "read_file",
"resource_path": "/etc/passwd",
"context": {
"session_id": "s1",
"user_role": "support",
"session_scopes": ["read_customer"]
}
}'Returns the full PolicyDecision as JSON.
Iterate
OPA's --watch flag (set on the kitelogik init Docker Compose) means edits to policies/*.rego hot-reload. Edit, save, re-run your agent — the new rules are live without restarting OPA.
Next
- Governance events — the full event schema your policies decide on
- Risk tiers & HITL — how to assign tiers and trigger human review
- Adapters → Overview — wire your policies into the framework you're using