Skip to main content

Operator CLI: intents and grants

Since v0.12.0 the korvun binary carries the operator's authority tools: intent contracts (what you authorize, with limits) and authority grants (who may act under an intent, with less). They work against the same local database the server uses, with brief, WAL-safe access — you can run them while Korvun is serving.

Every mutation leaves an identified receipt in the action ledger: you as the principal, in-process loopback evidence, and a finite audit rule — operator for your acts, attenuation_violated for a delegation the wall refused. Refusals are recorded too: the trail says why.

Intents​

An intent contract states an authorized outcome and its limits: a purpose in words, an operation set, a coarse resource set, an optional action budget and an optional validity window.

korvun intent create --config korvun.json \
--purpose "test week" \
--operations calc,time \
--max-actions 10 \
--expires 2026-09-06T20:00:00Z

Prints the new id (int_…) in DRAFT. Flags: --purpose and --operations (comma-separated) are required; --resources defaults to *; --max-actions 0 means unlimited; --valid-from defaults to now; no --expires means no expiry.

korvun intent activate --config korvun.json int_…
korvun intent revoke --config korvun.json int_…
korvun intent list --config korvun.json
korvun intent show --config korvun.json int_…

The lifecycle is fail-closed and walked from the STORED state: DRAFT → ACTIVE → EXPIRED | REVOKED. Terminal is terminal — re-activating a revoked intent fails honestly, and the failed attempt leaves its receipt. show includes the contract digest: a deterministic hash of the TERMS (status excluded — revoking closes a contract's life, it does not rewrite its identity).

Grants​

A grant gives one principal bounded authority under an intent.

korvun grant issue --config korvun.json \
--intent int_… \
--subject principal_brain_default \
--operations calc \
--max-actions 5 \
--depth 1

The intent must be IN FORCE at the issuing instant: a DRAFT intent denies with intent_inactive, an expired window with intent_expired — the clock wins over a stale status, and the refusal is recorded.

korvun grant delegate --config korvun.json \
--parent grant_… \
--subject principal_ch_telegram \
--operations calc

Delegation passes authority on — and authority can only shrink. The child inherits the parent's intent, expiry and budget unless narrowed by flags, is issued by the parent's subject with depth parent − 1, and must be a subset of its parent in EVERY dimension: operations, resources, budget, expiry, validity window, depth. A widening child is denied naming the widened dimension and never touches the disk. The same wall governs the kernel itself — the operator's CLI holds no special power here.

korvun grant revoke --config korvun.json grant_…

A revoked grant delegates nothing anymore (authority_revoked).

Effect ceilings (v0.13.0)​

A grant can carry an effect ceiling: the highest consequence class its authority may reach, on the ladder pure < read_external < write_reversible < write_compensatable < write_irreversible < critical.

korvun grant issue --config korvun.json \
--intent int_… \
--subject principal_brain_default \
--operations calc \
--effect-ceiling read_external

Delegation must shrink here too: the child inherits the parent's ceiling unless narrowed, and a child reaching ABOVE it is denied naming effect_ceiling — the tenth attenuation dimension, judged by the same validator everywhere. Under a ceilinged (bounded) grant, write_irreversible and critical actions also require human approval — which, until the approval workflow ships, dies with the honest approval_unavailable. Grants without a ceiling (the root's standing authority and the config-derived grants) behave exactly as before.

The verifier (v0.14.0)​

Since v0.14.0 every terminal outcome leaves a signed receipt on an append-only hash chain, and the CLI carries the judge.

korvun receipt verify --config korvun.json rcpt_…

One receipt (or every receipt of an act_… id), re-judged offline against the store file with seven named checks: canonical roundtrip, hash recompute, Ed25519 signature against the REGISTERED public key, the key's validity window, the chain link to the predecessor, and coherence with the action row. Every failure carries its name (hash_mismatch, signature_invalid, custody_mismatch, …) — never a generic "invalid".

korvun ledger check --config korvun.json

The whole chain, structure first: a deleted receipt is denounced by its hole (chain_seq_gap with the missing position), a cloned position as chain_seq_duplicate, then every link through the same seven checks — the FIRST broken link stops the verdict with its receipt id and reason.

korvun receipt rotate-key --config korvun.json

Atomic retire-and-activate rotation of the profile's signing key. The rotation act leaves its OWN receipt sealed with the NEW key; retired keys are kept forever, so each era of the chain verifies with the key of its era. Verification is read-only; the honest scope is documented: the ledger is tamper-evident, never "immutable" — the operator controls storage and keys.

Reading the trail​

Receipts live in the action ledger next to every other recorded action. Each row carries its identity columns — principal, intent, authority — and its per-attempt evidence (provider, credential kind, subject). No secret material is ever stored: credential KINDS are a finite enum by construction.