diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md index 29ce2fd..a43eb40 100644 --- a/ARCHITECTURE.md +++ b/ARCHITECTURE.md @@ -58,7 +58,7 @@ work around it. Stability of the public surface is governed by | `gateway` | Surface 1 — OpenAI/Anthropic-compatible proxy; meters + governs every call. | | `mcp` | MCP gateway — intercepts `tools/call` for allowlist + approval + audit. | | `memory` | Git-native memory reader (user-owned md/yaml; path-traversal-safe; keyword search). | -| `otel` | Surface 3 — OpenTelemetry GenAI span export. | +| `otel` | Surface 3 — OpenTelemetry GenAI span export + an OTLP/HTTP trace ingress (`POST /v1/traces`) that meters consumed spans. | | `httpapi` | HTTP server: mounts the proxy, the `/v1` run-control API, the memory + approval endpoints, and the local admin page. | | `config` | Config from env + `.env`. Secrets only from here; never stored/logged. | | `httpx`, `id`, `version`, `app` | Small shared helpers: JSON responses, UUIDs, build identity, bootstrap wiring. | @@ -96,5 +96,5 @@ work around it. Stability of the public surface is governed by SQLite (WAL) is the default store — one file the user owns. Tables: `runs`, `steps`, `tool_calls`, `cost_ledger`, `checkpoints`, `approvals`, `memory_facts`. Migrations are embedded and **forward-only** (the daemon refuses to start if the -on-disk schema is newer than the binary). Postgres is a future opt-in behind the -same `Store` interface. +on-disk schema is newer than the binary). Postgres is an opt-in backend behind the +same `Store` interface (`RISKKERNEL_DATABASE_URL`), for multi-instance / HA. diff --git a/README.md b/README.md index 8180925..10b1935 100644 --- a/README.md +++ b/README.md @@ -37,15 +37,17 @@ It is **not** another gateway (LiteLLM/Portkey own routing), **not** another obs | 🔁 **Hard loop-iteration cap** | No more infinite agent loops. | | ⏱️ **Hard wall-clock budget** | Runs that exceed their time budget halt. | | 💾 **Crash-resumable checkpoints** | `kill -9` the daemon mid-run; it reloads with the budget already spent and resumes from the last checkpoint — without re-spending. [Guide](docs/RESUME.md) · [demo](examples/kill-9-resume). | -| ✋ **Framework-agnostic approval gates** | Side-effecting tool calls pause for human approval — CLI, local web, or webhook. | -| 🧠 **Memory you own** | Git-native markdown/YAML on your disk; episodic state in your SQLite. | -| 📡 **OpenTelemetry GenAI** | Emits `gen_ai.*` spans to *your* backend (Grafana/SigNoz/Datadog/Langfuse). | +| ✋ **Framework-agnostic approval gates** | Side-effecting tool calls pause for human approval — CLI, local web, webhook, or **Slack**. | +| 📜 **Policy-as-code** | Reusable budget / tool-allowlist / approval bundles via `POST /v1/policies` or a reviewed `riskkernel.yaml`, dry-run against recorded runs ([the policy guide](docs/POLICY.md)). | +| 📊 **Spend attribution & compliance** | Roll cost up across runs by team/user/feature (`riskkernel audit summary --by metadata.team`), plus a tamper-evident OWASP / EU AI Act evidence export ([compliance](docs/COMPLIANCE.md)). | +| 🧠 **Memory you own** | Git-native markdown/YAML on your disk; episodic state in your SQLite (or opt-in Postgres for HA — [docs](docs/POSTGRES.md)). | +| 📡 **OpenTelemetry GenAI (both ways)** | Emits `gen_ai.*` spans to *your* backend (Grafana/SigNoz/Datadog/Langfuse) **and ingests** them, to meter apps it never proxied ([ingress](docs/OTLP_INGRESS.md)). | ## Three ways to adopt — pick the one that fits -1. **Proxy (zero code).** Set one env var: `OPENAI_BASE_URL=http://localhost:7070/v1`. Every call is intercepted, budgeted, logged, checkpointed, and forwarded to the real provider with your key. -2. **Python SDK (deep control).** Install the SDK (from source today — see the [Quickstart](#quickstart-60-seconds)), then `@governed_run` / `@governed_tool` / `runtime.budget(...)` / `ApprovalGate`. Adapters for the Claude Agent SDK, OpenAI Agents SDK, and LangChain. -3. **OpenTelemetry (universal).** RiskKernel is an OTLP endpoint *and* emitter — govern apps already instrumented with OpenLLMetry / the OpenAI Agents SDK, and export to the backend you already run. +1. **Proxy (zero code).** Set one env var: `OPENAI_BASE_URL=http://localhost:7070/v1` (or `ANTHROPIC_BASE_URL` for `/v1/messages`). Every call — streaming or not — is intercepted, budgeted, logged, checkpointed, and forwarded to the real provider with your key. Native providers: Anthropic, OpenAI, and Ollama (local). +2. **SDK (deep control).** `pip install riskkernel` (Python) or `npm install @riskkernel/sdk` (TypeScript), then governed runs, per-step loop/time budgets, checkpoints, and approval gates. Framework adapters for the Claude Agent SDK, OpenAI Agents SDK, LangChain, LlamaIndex, CrewAI, AutoGen, and PydanticAI (Python), and the Vercel AI SDK (TypeScript). +3. **OpenTelemetry (universal).** RiskKernel is an OTLP endpoint *and* emitter — ingest GenAI spans (`POST /v1/traces`) to meter apps already instrumented with OpenLLMetry / the OpenAI Agents SDK / the Vercel AI SDK, and export cost/halt/tool spans to the backend you already run. ## Quickstart (60 seconds) @@ -87,9 +89,11 @@ curl -s -D- http://localhost:7070/v1/chat/completions \ Inspect and audit, all on your disk: ```bash -riskkernel runs list # every governed run -riskkernel audit export # the cost ledger as JSON -riskkernel audit tools # governed tool calls as JSON +riskkernel runs list # every governed run +riskkernel audit export # the cost ledger as JSON +riskkernel audit tools # governed tool calls as JSON +riskkernel audit summary --by metadata.team # spend rolled up across runs +riskkernel audit compliance # OWASP / EU AI Act evidence export ``` Prefer a native binary to Docker? Install the CLI with one command — no clone @@ -109,14 +113,16 @@ riskkernel completion zsh > "${fpath[1]}/_riskkernel" # zsh riskkernel completion fish > ~/.config/fish/completions/riskkernel.fish # fish ``` -Deeper control (loops, checkpoints, approval gates) is the Python SDK: +Deeper control (loops, checkpoints, approval gates) is the SDK — Python or +TypeScript: ```bash -pip install riskkernel +pip install riskkernel # Python → sdks/python +npm install @riskkernel/sdk # TypeScript → sdks/typescript ``` -See [`sdks/python`](sdks/python). Trace every run in your own backend: -[`examples/otel`](examples/otel). +See [`sdks/python`](sdks/python) and [`sdks/typescript`](sdks/typescript). Trace +every run in your own backend: [`examples/otel`](examples/otel). Want to *see* the headline feature? [`examples/codebase-qa`](examples/codebase-qa) is a runnable agent that loops over a codebase until the governor kills it on its diff --git a/ROADMAP.md b/ROADMAP.md index f807a74..4a1af38 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -16,46 +16,47 @@ The core runtime is built and released: that halt a run *before* it overspends ([`docs/BUDGETS.md`](docs/BUDGETS.md)). - **Crash-resume** — `kill -9` a run mid-flight and resume it without re-spending ([`docs/RESUME.md`](docs/RESUME.md)). -- **OpenAI-compatible proxy** — point one env var at RiskKernel and every call is - metered, priced, and budget-enforced (BYO key). +- **OpenAI- and Anthropic-compatible proxy** — point one env var at RiskKernel and + every call (streaming or not) is metered, priced, and budget-enforced (BYO key). + Native providers: Anthropic, OpenAI, and Ollama (local, key-free). - **Human-in-the-loop approval** — gate side-effecting tools; resolve from the CLI, a local web page, a webhook, or **Slack** ([`docs/APPROVALS_SLACK.md`](docs/APPROVALS_SLACK.md)). -- **Policy-as-code** — named policy bundles via `POST /v1/policies` or a reviewed - `riskkernel.yaml`, with a dry-run against recorded runs ([`docs/POLICY.md`](docs/POLICY.md)). -- **OpenTelemetry GenAI export** — cost/halt/tool spans into your existing backend, - with a ready-made Grafana + Tempo dashboard. +- **Policy-as-code, enforced per-run** — named policy bundles via `POST /v1/policies` + or a reviewed `riskkernel.yaml`, with a dry-run against recorded runs; a run created + under a bundle is governed by its tool allowlist and approval rules, not just its + budget ([`docs/POLICY.md`](docs/POLICY.md)). +- **OpenTelemetry GenAI — export and ingress** — emit cost/halt/tool spans into your + existing backend (ready-made **Grafana + Tempo** and **SigNoz** dashboards), *and* + ingest GenAI spans (`POST /v1/traces`) to meter apps RiskKernel never proxied + ([`docs/OTLP_INGRESS.md`](docs/OTLP_INGRESS.md)). +- **Spend attribution** — roll cost up across runs by team/user/feature + (`riskkernel audit summary --by metadata.team`), with the run name and tags also on + the OTel spans so the same grouping works in your backend. - **MCP gateway** — govern an agent's `tools/call` (allowlist + approval + audit). - **Compliance evidence export** — controls mapped to OWASP / EU AI Act references with a tamper-evident, hash-chained event log ([`docs/COMPLIANCE.md`](docs/COMPLIANCE.md)). - **Git-native memory** — markdown/YAML the agent reads, that you own. +- **Storage** — zero-config SQLite by default; an opt-in **Postgres** backend for + multi-instance / HA behind the same `Store` interface ([`docs/POSTGRES.md`](docs/POSTGRES.md)). - **SDKs** — Python (`pip install riskkernel`) and TypeScript (`@riskkernel/sdk`), - with LangChain, OpenAI Agents, and Vercel AI SDK adapters. + with adapters for the Claude Agent SDK, OpenAI Agents, LangChain, LlamaIndex, + CrewAI, AutoGen, and PydanticAI (Python), and the Vercel AI SDK (TypeScript). +- **Operability** — a Prometheus `/metrics` endpoint, a `riskkernel doctor` setup + check, shell completions, and a one-command `docker compose` quickstart. - **Measured, low overhead** — the enforcement decision is ~150 ns and zero - allocations per call ([`docs/PERFORMANCE.md`](docs/PERFORMANCE.md)). + allocations per call, with a reproducible cost benchmark and a timed `kill -9` + recovery benchmark (exact-once spend) behind the claims ([`docs/PERFORMANCE.md`](docs/PERFORMANCE.md)). ## Next Where the work is heading near-term: -- **Per-run policy enforcement** — a referenced policy bundle applies its budget to a - run today; extend that to enforce the bundle's tool allowlist and approval rules - per-run, not just globally. -- **More framework adapters** — CrewAI ([#83](https://github.com/prashar32/riskkernel/issues/83)), - AutoGen ([#84](https://github.com/prashar32/riskkernel/issues/84)), - PydanticAI ([#85](https://github.com/prashar32/riskkernel/issues/85)), - LlamaIndex ([#86](https://github.com/prashar32/riskkernel/issues/86)). -- **More native providers** — AWS Bedrock ([#24](https://github.com/prashar32/riskkernel/issues/24)) - and local Ollama ([#23](https://github.com/prashar32/riskkernel/issues/23)). -- **Streaming proxy** — SSE pass-through with mid-stream budget enforcement - ([#22](https://github.com/prashar32/riskkernel/issues/22)). -- **OTLP ingress** — consume GenAI spans to govern apps RiskKernel didn't instrument - ([#90](https://github.com/prashar32/riskkernel/issues/90)). -- **Postgres storage backend** — behind the same `Store` interface, SQLite stays the - default ([#25](https://github.com/prashar32/riskkernel/issues/25)). -- **Operability** — a `/metrics` endpoint ([#91](https://github.com/prashar32/riskkernel/issues/91)), - a `riskkernel doctor` setup check ([#94](https://github.com/prashar32/riskkernel/issues/94)), - shell completions ([#93](https://github.com/prashar32/riskkernel/issues/93)), - and a Homebrew tap ([#97](https://github.com/prashar32/riskkernel/issues/97)). +- **More native providers** — AWS Bedrock ([#24](https://github.com/prashar32/riskkernel/issues/24)); + the long tail via LiteLLM-as-upstream. +- **More backend dashboards** — a Datadog dashboard to join the Grafana and SigNoz + examples. +- **Easier install** — a Homebrew tap for `brew install riskkernel` + ([#97](https://github.com/prashar32/riskkernel/issues/97)). ## Exploring