# Architecture

The one canonical execution path Kaji uses to run a capability, and the boundaries it does and does not own.

## Execution Path

`kaji.execute(capability, request)` is the only way a capability runs. There
is no second path, so no caller can accidentally skip a safety boundary. For
one request, the executor:

1. Validates `principalId` and `idempotencyKey` are non-empty strings.
2. Validates `input` against the capability's `input.parse()`.
3. Claims the idempotency key in the execution store. An existing claim
   returns the same recorded or in-flight outcome instead of running
   `execute` again; a conflicting claim (same key, different input,
   capability, or principal) settles `failed`.
4. Calls `authorize({ principalId, input })`. A `false` result or a thrown
   error settles `denied`.
5. If `approval({ principalId, input })` returns `true`, calls the
   configured `approve` handler. A missing handler, an invalid decision, a
   rejected decision, or a handler error settles `rejected`.
6. Calls `execute(input, context)` at most once.
7. Records the outcome in the execution store and returns it.

Cancellation is checked before each step that hasn't yet started a side
effect; once `execute` has been called, Kaji can no longer prove the action
didn't begin, so every failure path from that point settles `unknown` rather
than an ordinary failure.

```text
request
  → validate input
  → claim idempotency key
  → authorize
  → approve (if required)
  → execute            (side effects may begin here)
  → record outcome
```

## Boundaries

Kaji owns the execution boundary; it does not own what's on either side of
it.

- **Capability code is ordinary application code.** `execute`,
  `authorize`, and `approval` are functions your application supplies. Kaji
  never contains business logic, and it never calls a capability's
  functions outside `kaji.execute()`.
- **The execution store is a narrow contract.** It claims idempotency keys
  atomically and records terminal outcomes. It is not a general event log,
  and v0 ships only `memoryStore()`, a process-local, non-durable
  implementation. A production deployment supplies its own durable
  `ExecutionStore`.
- **Approval is a decision, not a UI.** Kaji calls the `approve` handler you
  configure and enforces its decision; it does not implement a review queue,
  notification system, or audit UI.
- **Cancellation and timeout use native `AbortSignal`.** Kaji combines the
  caller's signal with its own `timeoutMs` into one effective signal; it
  does not invent a Kaji-specific cancellation token.

## Footnotes

Kaji has no agent loop, model provider, tool registry, session or event
store, CLI, or hosted control plane. An agent framework, MCP server, or
direct application code decides what action to request; Kaji only governs
how that one action is safely executed. See `docs/product.md` in the
repository for the complete non-goal list.

## Further Reading

- [Capabilities](/docs/concepts/capability)
- [Execution](/docs/concepts/executor)
- [Approval](/docs/concepts/approval)
- [Idempotency](/docs/concepts/idempotency)
- [Timeout](/docs/concepts/cancellation)