klieo-workflow-api 3.8.1

Embeddable Axum run-service router fronting klieo-workflow (submit / poll declarative workflows).
Documentation
# klieo-workflow-api

Embeddable [axum](https://github.com/tokio-rs/axum) router that fronts
[`klieo-workflow`](../klieo-workflow) over REST. A caller submits a declarative
`WorkflowDef` as JSON; the service compiles it against a host-supplied `Registry`
allow-list, runs it on the klieo runtime, and reports status — so workflows can be
authored in any language (Python, Java) while all execution stays in Rust.

## Endpoints

| Method | Path | Purpose |
|--------|------|---------|
| `GET`  | `/health` | Unauthenticated liveness probe (`200`, body `ok`) — for an orchestrator with no credential to present. |
| `POST` | `/runs` | Submit a `WorkflowDef` + input envelope. Compiles synchronously (invalid → `400` with a typed error), then runs it in the background. Returns `202 { run_id }`. |
| `GET`  | `/runs/{id}` | Poll run status + result (`404` if unknown). |
| `GET`  | `/registry` | Enumerate the palette (registered model / tool / subflow ids) a workflow may reference. |
| `GET`  | `/runs/{id}/events` | Server-Sent Events stream of live run progress (live-tail; best-effort). |

## Mounting

```rust
let router = WorkflowRunRouterBuilder::new()
    .with_authenticator(auth)   // required
    .with_app(app)              // klieo App — supplies bus/memory/tools/context
    .with_registry(registry)    // the allow-list of models/tools/subflows
    .with_run_store(run_store)  // KvStore-backed run state
    .build()?;
```

The host constructs the `App` and `Registry`; the service reads neither secrets
nor an LLM of its own (each agent node swaps in its registry-resolved model, so
`App.llm` is unused by workflow runs).

## Contract

- **Auth:** every request is authenticated; `POST /runs` requires the
  `klieo.workflow.run` scope, reads (`GET /runs/{id}`, `GET /runs/{id}/events`)
  require `klieo.workflow.read`. The run's `author` is stamped server-side from
  the caller identity — never client-supplied. `klieo.workflow.read` alone only
  authorizes reading runs the caller itself authored; a read for a
  different-author run returns `404` (not `403`) so a run's existence is never
  disclosed to a non-owner. `klieo.workflow.read.all` additionally grants
  cross-author reads, for an operator/support identity.
- **Idempotency:** a submit is keyed by the canonical hash of the definition plus
  its input; a retried submit collapses to the original run rather than starting a
  second.
- **Bounded:** concurrent runs are capped (excess → `429` with `Retry-After`); the
  request body is size-limited; every run has a wall-clock timeout.
- **Terminal-write guarantee:** a run always reaches a terminal status
  (`succeeded` / `failed` / `aborted`) — a panicking or timed-out flow is recorded
  as failed/aborted, never left `running`.

## Limits (v1)

Run status is a volatile poll cache (durable run outcome lives in the provenance
chain). No stored/named workflows — the definition travels in every request. No
HITL suspend/resume. Single global registry.

## Deploying

`klieo-workflow-api` — not [`klieo-server`](../klieo-server) — is the
deployable run-service surface: `klieo-server` is a `publish = false`
reference demo, not meant to serve real traffic. Embed this crate's router
in your own binary (see Mounting, above), then deploy that binary using the
`klieo-compliance` repo's `deploy/` tree (Docker Compose, Helm, Terraform)
as the topology reference — swap its compliance-server container image for
yours; the reverse proxy, secrets, and networking shape carry over
unchanged. klieo is pre-production: `deploy/` does not itself prescribe
autoscaling or canary rollout — add those only if your deployment needs
them.