Metadata-Version: 2.4
Name: olympus-council
Version: 0.24.0
Summary: OLYMPUS — a controlled-autonomy, self-improving multi-agent AI assistant with a built-in hallucination controller
Author: maadjiba24-afk
License-Expression: MIT
Project-URL: Homepage, https://github.com/maadjiba24-afk/Olympus-
Project-URL: Repository, https://github.com/maadjiba24-afk/Olympus-
Project-URL: Issues, https://github.com/maadjiba24-afk/Olympus-/issues
Keywords: ai,agent,assistant,multi-agent,llm,anthropic,claude,controlled-autonomy,byok,self-improving,hallucination-controller
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: Intended Audience :: End Users/Desktop
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
Classifier: Topic :: Communications :: Chat
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: anthropic>=0.92.0
Requires-Dist: youtube-transcript-api>=1.0.0
Requires-Dist: cryptography>=41.0.0
Dynamic: license-file

# ⚡ OLYMPUS

[![CI](https://github.com/maadjiba24-afk/Olympus-/actions/workflows/ci.yml/badge.svg)](https://github.com/maadjiba24-afk/Olympus-/actions/workflows/ci.yml)
[![License: MIT](https://img.shields.io/badge/License-MIT-d9b44a.svg)](LICENSE)
[![Python 3.10+](https://img.shields.io/badge/python-3.10%2B-blue.svg)](pyproject.toml)

A self-sufficient, self-recurring, **self-improving** multi-agent AI system
built on frontier LLM APIs. A main agent
commands a supervised council of specialists, answers the supervisor flags as
factual pass through a hallucination controller, and the system continuously
scans the world, learns from YouTube, and upgrades itself.

Out of the box Olympus ships <!--cap:agents-->13<!--/cap--> specialist agents,
<!--cap:tools-->62<!--/cap--> agent tools, and <!--cap:commands-->79<!--/cap-->
CLI commands. Every count here is generated from the code
(`olympus capabilities`) and verified in CI, so the numbers can't drift from
what's actually built.

**Headless-first and lightweight.** Olympus installs with three pure-Python
dependencies and runs anywhere Python does — a server, a droplet, WSL, a CI job,
an SSH session — with no bundled browser or media stack and no OAuth dance to
get started (the optional operator harness can attach your own Chrome). Web access is server-side (with a client-side fallback),
the sandbox is confined and approval-gated, and every command is screened by a
[security gate](docs/THREAT_MODEL.md) before it can run. What you get for that
small footprint is a *verified* council (every answer fact-checked before you
see it), a pool that composes several models by strength and price, and a system
that measurably improves at working with you over time — trust and adaptation
over breadth.

> **Status:** the full architecture is implemented and covered by a
> comprehensive passing test suite. The test suite covers architecture, gates,
> and security logic; AI-output quality is measured separately by
> `olympus eval` / `olympus scores`, not by `pytest`. Install with the
> one-liner below, type `olympus`, and you're chatting; `olympus scores` shows
> each specialist's measured quality.

## Install

Pick your OS, paste one line, then type `olympus`. The first run asks which API
key you're bringing (Anthropic, OpenAI, or any compatible provider), saves it
securely, and drops you into chat. Requires **Python 3.10+**.

**Linux / macOS**

```bash
curl -fsSL https://raw.githubusercontent.com/maadjiba24-afk/Olympus-/main/install.sh | sh
```

**Windows** (PowerShell)

```powershell
irm https://raw.githubusercontent.com/maadjiba24-afk/Olympus-/main/install.ps1 | iex
```

**Any OS, via pip/pipx:**

```bash
pipx install olympus-council     # isolated; gives the `olympus` command
# or:  pip install olympus-council
```

Then just:

```bash
olympus
```

**Stay up to date.** New versions are one command away — Olympus updates itself
in place whichever way you installed it:

```bash
olympus upgrade          # update to the latest release
olympus version          # show the installed version
```

(On Windows, open a **new** terminal after installing so the `olympus` command
is on your PATH. Uninstall anytime: `rm -rf ~/.olympus ~/.local/bin/olympus`,
or on Windows remove `%USERPROFILE%\.olympus` and the `olympus.cmd` shim.)

## Architecture

```
                              user
                               │
                               ▼
                ┌─────────────────────────────┐
                │   ZEUS · Main Agent          │  routes or answers directly
                └──────────────┬──────────────┘
                               │ delegates
                               ▼
                ┌─────────────────────────────┐
                │   ATHENA · Supervisor        │  plans precise sub-tasks
                └──────────────┬──────────────┘
                               │ dispatches
        ┌──────────┬──────────┼──────────┬──────────────┐
        ▼          ▼          ▼          ▼              ▼
   PLUTUS     PEITHO    HEPHAESTUS    AEGIS          IRIS
   Financial  Marketing  Coding      Cybersecurity  Social Network
        ▼          ▼          ▼          ▼              ▼
   CHIRON     CHRONOS     ARGUS      MNEMOSYNE     PROMETHEUS
   Coaching   Scheduling  Opportunity YouTube       Evolution /
                          Scout 🌐    Learner 🎥    Self-Upgrade 🔧
          ANGELOS · Inbox & Calendar 📬      METIS · Learning Synthesizer 🧠
                 (daily cycle: experience → skill library)
        └──────────┴──────────┴──────────┴──────────────┘
                               │ outputs
                               ▼
                ┌─────────────────────────────┐
                │  ALETHEIA · Hallucination    │  verifies flagged claims with
                │  Controller                  │  web search, flags/corrects,
                └──────────────┬──────────────┘  records lessons
                               │ verified findings
                               ▼
                  ZEUS composes the final answer
                               │
                               ▼
                              user
```

### The council

**Orchestration pipeline.** These three run every request — they route, plan,
and verify — and are **not** counted among the <!--cap:agents-->13<!--/cap-->
specialists.

| Stage | Role |
|---|---|
| **Zeus** | Main agent — the user's single interface; routes or answers |
| **Athena** | Supervisor — plans a **dependency graph** of specialist steps (parallel where independent, serial where one step needs another's output) and gates quality |
| **Aletheia** | Hallucination controller — verifies claims, fixes/flags, learns from mistakes |

**The <!--cap:agents-->13<!--/cap--> specialists.** The permanent domain experts
registered in `olympus/specialists.py` (names and titles below come straight
from that registry):

| Agent | Role |
|---|---|
| **Plutus** | Financial Specialist |
| **Peitho** | Marketing Specialist |
| **Hephaestus** | Coding Specialist — polyglot (Python, Go, Rust, TypeScript, Java, SQL, …), idiomatic per language; executes code under an approval-gated action spine (opt-in Docker isolation) |
| **Aegis** | Cybersecurity Specialist (strictly defensive) |
| **Iris** | Social Network Assistant |
| **Chiron** | Coaching Specialist |
| **Chronos** | Scheduling Manager |
| **Angelos** | Inbox & Calendar Manager |
| **Argus** | Opportunity Scout — surfs the internet via Anthropic's **server-side web search** (no MCP connections required) for business opportunities and world events |
| **Mnemosyne** | YouTube Learner — watches videos via transcript, summarizes what it understood, stores lessons |
| **Metis** | Learning Synthesizer — runs the **daily learning cycle**, distilling lessons, corrections, and user feedback into the self-built skill library |
| **Prometheus** | Evolution Specialist — audits Olympus, finds what's missing inside it, upgrades agent prompts (`gate_prompt`: **applied only if a before/after benchmark shows no regression, else auto-rolled-back**), files improvement proposals |
| **Hermes** | Operator — acts on your behalf on **explicitly authorized** sites: logs in with vaulted credentials and operates declarative site profiles. Never browses the open web; credentialed actions are scope/approval-gated and off by default (`OLYMPUS_OPERATOR`). See [docs/DESIGN_OPERATOR.md](docs/DESIGN_OPERATOR.md) |

### Self-* properties

- **Self-sufficient** — web access is built in through Anthropic's server-side
  `web_search` / `web_fetch` tools; no MCP servers or external connectors.
- **Self-recurring** — `python -m olympus heartbeat` runs an autonomous loop:
  opportunity scans every 6 h, the YouTube watch-queue hourly, a full
  self-audit weekly.
- **Self-improving** — three feedback loops:
  1. Aletheia records every correction as a lesson in persistent memory.
  2. Specialists recall lessons before answering (`recall_memory`).
  3. Prometheus reads recurring corrections + Olympus's own source and rewrites
     agent prompts. For benchmarked specialists it uses `gate_prompt`, which
     applies a rewrite only if a before/after benchmark shows no regression and
     rolls it back automatically otherwise (raw `update_prompt` — auto-backup,
     measure-by-hand — remains for un-benchmarked agents), and files
     `propose_upgrade` notes for changes that need code.
- **Evolves with you** — beyond the shared loops above, Olympus adapts to *each
  person*: every few exchanges it distills your own history (facts, 👍/👎,
  corrections) into a private, evolving **working model** that tailors every
  answer to you, with a growth level that deepens the more you use it
  (`olympus growth`). It's per-user and never leaks across people.

  Prometheus runs weekly via the heartbeat **and** automatically after every
  N conversations (`OLYMPUS_AUDIT_EVERY_CHATS`, default 20 — counted across
  CLI, web, and Telegram; the audit runs in the background on the server's
  own credentials, never on a visitor's BYOK key). With `GITHUB_TOKEN` +
  `GITHUB_REPO` set, his upgrade proposals are **auto-filed as GitHub
  issues** — and the optional Auto-Upgrade workflow
  (`.github/workflows/auto-upgrade.yml`) lets a coding agent implement them as
  pull requests automatically.

### Reasoning over serial problems (dependency-graph planning)

Most orchestrator-worker systems (Hermes included) fan tasks out in parallel
and stitch the pieces together — which breaks on problems where one step needs
another's result first. Olympus's Athena instead plans a **dependency graph**:

- Independent steps run **concurrently** (fast — latency is the slowest branch).
- A step that genuinely depends on another runs **after** it and **receives its
  output as input**, so it builds on the result instead of guessing.

So "research the market → price it from the findings → write copy for that
price" executes as a real chain (each step fed the last), while anything that
*can* run in parallel still does. The executor is cycle-safe and isolates
per-step failures. You get parallel speed *and* correct serial reasoning.

### Cross-model learning (opt-in) — the best of every frontier model

Olympus runs on whatever model a user brings (Claude, GPT, Gemini, …). Each
frontier model knows different things — so Olympus can distill the best of all
of them into one shared, quality-gated knowledge layer that lifts every model,
including the cheap ones.

It is **opt-in and privacy-first** (off by default):

- A user explicitly enables contribution (web ⚙ checkbox, `/contribute on` on
  Telegram/CLI). Only then is anything shared.
- What's shared is **anonymized at write time** — emails, phone numbers, long
  ID/account numbers, and API-key-shaped strings are stripped before a short
  snapshot (tagged with the source model) enters the shared queue. Raw user
  data never enters the pool.
- Metis's daily cycle reads the queue **grouped by source model** and distills
  genuinely cross-model insights — knowledge one model surfaced that helps
  every specialist regardless of model — into **provisional** skills.
- The **benchmark gate** then keeps only the skills that measurably help and
  reverts the rest, so a weak model's output can't pollute the shared library.

The result is something neither Hermes nor OpenClaw has: a system that gets
collectively smarter by distilling the best of every frontier model its users
bring — with consent, anonymization, and quality-gating built in.

### Keeping all <!--cap:agents-->13<!--/cap--> specialists strong (systematic training)

A specialist only improves at what's *measured* — so Olympus measures every
user-facing specialist and trains the weakest on a cadence:

- **Full coverage.** Every user-facing specialist (Plutus, Peitho, Hephaestus,
  Aegis, Iris, Chiron, Chronos, Angelos, Argus, Mnemosyne) has benchmark items; any gap
  is auto-filled with a generated one. (Metis, Prometheus, and Hermes are
  internal — Hermes is the operator/browser actuator, the other two the
  planner and self-improver — so their quality is their effect on the system,
  not a benchmarked answer.)
- **`python -m olympus scores`** shows every specialist's current score,
  lowest first. **`python -m olympus train`** scores them all, then has
  Prometheus focus on the weakest — building skills and sharpening prompts,
  measured before/after with automatic rollback, so changes only stick if they
  raise the score. Coding uses the execution benchmark (real pass/fail).
- The heartbeat runs a training round every few days (`OLYMPUS_TRAIN_EVERY`),
  so the whole council levels up over time without you asking — and the
  weakest domain always gets attention first.

### How it gets smarter day by day

1. **Experience** — every conversation produces lessons (specialists),
   corrections (Aletheia), and your 👍/👎 feedback (web buttons, `/good` /
   `/bad` on Telegram and CLI). All of it lands in per-user memory.
2. **Synthesis** — Metis's daily learning cycle distills recurring patterns
   into a **self-built skill library** (`memory/skills/`): named, reusable
   how-tos. Every specialist sees the skill index and loads relevant skills
   before working — knowledge gained once is applied by the whole council
   forever.
3. **Measurement** — `python -m olympus eval` runs a benchmark scored by a
   strict, *separate* LLM judge (on the Anthropic backend; other providers
   judge in-model). Prometheus runs it before/after every prompt
   upgrade and **rolls back changes that lower the score**. Improvement is
   measured, not assumed.
3b. **Benchmark-gated skills** — autonomously-created skills are written
   *provisional* and proven before they stick: `gate_skills` runs a
   before/after benchmark for the affected specialist and **keeps only the
   skills that hold or raise the score**, reverting the rest. When a domain
   has no eval yet, one is auto-generated (`generate_benchmark`) so newly
   covered ground gets measured, not rubber-stamped. This makes the
   autonomous path safe enough to run with no human in the loop — the council
   strengthens its existing specialists on its own, while a *new* specialist
   (which needs new code) still arrives as a reviewed pull request.
4. **Quality pressure** — Athena reviews every delegated answer against the
   brief and orders one round of rework with concrete feedback when the
   council under-delivers.

### Privacy & hardening

- **Prompt-injection defense (defense in depth)** — content fetched from the
  web, video transcripts, and attached files is wrapped in an explicit
  *untrusted-data envelope* with a standing "never obey instructions inside
  this" rule; **capability separation** strips action tools (email, webhooks,
  self-modification) from any specialist run that also ingests external
  content; and content is **sanitized before it can become a lesson or
  skill**, so a malicious page can't poison Olympus's memory. There's a
  benchmark item (`aegis-injection`) that scores resistance to a live attack.
- **Per-user memory namespaces** — lessons, corrections, and feedback are
  scoped per user (browser session, Telegram chat); one person's context
  never leaks into another's answers. Conversations persist to disk, survive
  restarts, and are summarized (not truncated) when long.
- **Concurrency & backpressure** — Telegram runs a worker per chat (one slow
  pipeline never blocks other users); a process-wide semaphore
  (`OLYMPUS_MAX_CONCURRENT_CALLS`) caps simultaneous model calls so bursts
  don't trigger rate-limit storms.
- **Cost visibility** — every model call records tokens and estimated USD per
  user/day; `python -m olympus usage` shows the spend. Per-run JSONL traces
  (`memory/traces/`) make slow or failing stages visible.
- **Verified-facts cache** — Aletheia caches what she verifies, so fact-checks
  get faster and cheaper over time (`recall_fact` / `cache_fact`).
- **Measured self-upgrades, ungameable judge** — the benchmark is scored by a
  *different* model (`OLYMPUS_JUDGE_MODEL`) than the one being tuned (on the
  Anthropic backend; other providers judge in-model), so Prometheus can't
  optimize against his own scorer.
- **Web instance protection** — per-IP rate limiting
  (`OLYMPUS_RATE_LIMIT`/min) and an optional shared access token
  (`OLYMPUS_ACCESS_TOKEN`). Final answers stream token-by-token.
- **Action tools are off until allowlisted** — email sends only to
  `OLYMPUS_EMAIL_ALLOWLIST` recipients; webhooks only to operator-defined
  `OLYMPUS_WEBHOOKS` URLs; Hephaestus can only *prepare* code execution as an
  approval-gated action — a human (or explicit policy) approves before anything
  runs. The default local backend runs with your OS privileges once approved;
  set `OLYMPUS_EXEC_BACKEND=docker` for OS-level isolation of untrusted code.
- **Accurate by design** — answers the supervisor flags as factual pass through
  the hallucination controller before you see them; uncertain claims are
  flagged, never laundered.

## Why Olympus vs Hermes / OpenClaw

| | Hermes | OpenClaw | **Olympus** |
|---|---|---|---|
| Hallucination control | none | none | **built-in verification gate** — factual answers are web-checked (the supervisor flags what needs checking) before you see them |
| Specialists | generic per-task workers | one assistant + plug-in skills | **<!--cap:agents-->13<!--/cap--> permanent domain experts** with crafted identities |
| Self-improvement | memory + skills | memory files | memory **plus a dedicated evolution agent** that audits the system and rewrites its own prompts |
| Internet access | via tools/skills | via skills/browser | server-side web search on Claude (zero connectors, zero MCP); built-in DuckDuckGo fallback on every other provider |
| Parallelism | yes | n/a | **yes** — specialists run concurrently |
| Models | model-agnostic | model-agnostic | **model-agnostic** — Claude first-class, plus any OpenAI-compatible endpoint (OpenAI, Gemini, Groq, OpenRouter, Ollama/local) with **bring-your-own-key in the web UI** |
| Footprint | full server stack | persistent Node.js service | **single Python package · 3 runtime deps · stdlib-only interfaces** |

## Setup

Installation is covered in [Install](#install) above — the one-liner creates a
private Python environment, installs Olympus, and puts an `olympus` command on
your PATH. The first run asks one question (which API key you're bringing —
Anthropic, OpenAI, or any compatible provider like Groq, OpenRouter, or a local
Ollama), saves it securely (`~/.olympus/config.env`, owner-only), and drops you
into chat. From then on it's just:

```
olympus
you ▸ find me 30 minutes with Sarah next week and draft the invite
```

Plain English. No bash, no pip, no environment variables. Add more keys anytime
with `olympus setup` — Olympus composes multiple models into one brain.

<details>
<summary>Manual install (developers)</summary>

```bash
pip install -r requirements.txt        # or: pip install .
export ANTHROPIC_API_KEY=sk-ant-...
python -m olympus
```
</details>

Or with Docker:

```bash
docker build -t olympus .
docker run -p 8484:8484 -e ANTHROPIC_API_KEY=sk-ant-... olympus
```

### Hosting a public instance (HTTPS)

**Turnkey:** [`deploy/`](deploy/) has a one-command Docker Compose + Caddy setup
(automatic HTTPS, no certificate steps) — see [`deploy/README.md`](deploy/README.md).
The manual reverse-proxy recipe below is the alternative if you'd rather wire it
yourself.

The built-in web server speaks plain HTTP — fine on `localhost`, **not** safe
to expose directly, because bring-your-own-key API keys and file contents
would travel unencrypted. Put it behind a TLS-terminating reverse proxy:

```nginx
server {
  listen 443 ssl;
  server_name olympus.example.com;
  ssl_certificate     /etc/letsencrypt/live/olympus.example.com/fullchain.pem;
  ssl_certificate_key /etc/letsencrypt/live/olympus.example.com/privkey.pem;
  location / {
    proxy_pass http://127.0.0.1:8484;
    proxy_buffering off;            # required for token streaming
    proxy_read_timeout 600s;        # pipeline runs can be minutes long
  }
}
```

Run Olympus bound to localhost (`--host 127.0.0.1`, the default) so only the
proxy can reach it, and set `OLYMPUS_ACCESS_TOKEN`, `OLYMPUS_RATE_LIMIT`, and
`OLYMPUS_MAX_CONCURRENT_CALLS` for a shared deployment. Caddy or a cloud load
balancer with managed certificates works equally well — the only hard
requirement is `proxy_buffering off` (or the equivalent) so streamed answers
aren't held back.

**Built-in hardening for shared use.** Each browser gets its own unguessable,
`HttpOnly` session cookie, so users never collide or read each other's memory
and actions — no manual session strings. Request bodies are capped (1 MB), the
expensive chat endpoint and the cheap write endpoints have separate per-IP rate
limits, and per-user memory, the relationship graph, and playbooks are all
bounded (weakest memories are pruned past the cap) so storage and prompt size
stay in check. **Monitoring.** `GET /healthz` is an unauthenticated liveness probe for load
balancers and uptime checks; `GET /api/metrics` (behind the access token)
reports uptime, per-path request counts, process-wide error counts, and today's
spend vs budget.
From a shell, `olympus status` shows the provider, whether a key is configured,
the daily budget, the account mode, and recent usage.

The access token gates entry to the instance; for per-person identity, set
`OLYMPUS_REQUIRE_LOGIN=1` to require **accounts**: users register/log in, and
each account's memory, actions, playbooks, graph, and connected services are
namespaced to their account — not a shared cookie. Passwords are hashed with
PBKDF2 (stdlib, no new dependency) and sessions are server-side tokens. Accounts
are opt-in, so local single-user runs need nothing.

## Usage

```bash
python -m olympus                  # interactive chat (default)
python -m olympus web              # browser chat UI at http://localhost:8484
python -m olympus serve            # HTTP API incl. OpenAI-compatible /v1/* endpoints
python -m olympus telegram         # Telegram gateway (zero extra deps)
python -m olympus whatsapp         # WhatsApp Cloud API gateway (webhook)
python -m olympus profile "I run a bakery called Crumb; keep replies short"
python -m olympus ask "Find me 3 business opportunities in AI tooling"
python -m olympus scan             # Argus: world/opportunity scan now
python -m olympus watch <youtube-url>   # Mnemosyne: watch + learn now
python -m olympus queue <youtube-url>   # queue a video for the heartbeat
python -m olympus audit            # Prometheus: self-audit + self-upgrade now
python -m olympus learn            # Metis: distill experience into skills now
python -m olympus eval             # run the judge-scored quality benchmark
python -m olympus code-eval        # run Hephaestus's code against real tests
python -m olympus scores           # per-specialist benchmark scores (weakest first)
python -m olympus train            # strengthen the weakest specialists now
python -m olympus skills           # list the self-built skill library
python -m olympus gate             # benchmark-gate provisional skills now
python -m olympus usage --days 7   # estimated token/cost spend
python -m olympus heartbeat        # run the autonomous recurring loop
```

(`pip install .` also gives you a plain `olympus` command.)

### Use Olympus from any OpenAI client

Olympus exposes an **OpenAI-compatible inbound endpoint**, so any existing
OpenAI client, IDE, or app can drive the full council by changing only
`base_url`, `model`, and `api_key` — every request runs the same
route → plan → dispatch → verify → review → synthesize pipeline.

```bash
export OLYMPUS_API_KEYS=sk-my-secret-key   # comma-separated; gates /v1/*
python -m olympus serve --host 127.0.0.1 --port 8484
```

```python
from openai import OpenAI

client = OpenAI(base_url="http://127.0.0.1:8484/v1", api_key="sk-my-secret-key")
resp = client.chat.completions.create(
    model="olympus-council",
    messages=[{"role": "user", "content": "Say hello in one sentence."}],
)
print(resp.choices[0].message.content)
```

`GET /v1/models`, non-streaming and streaming (`stream=true`)
`POST /v1/chat/completions` are all supported. When `OLYMPUS_API_KEYS` is unset
the `/v1/*` routes answer on **loopback only** (never a silent open relay). Full
details, `curl` examples, and the auth/loopback notes live in
[docs/OPENAI_ENDPOINT.md](docs/OPENAI_ENDPOINT.md).

### Sovereignty: provable zero-egress mode

Set `OLYMPUS_SOVEREIGN=1` and Olympus runs **fully local with an enforced,
fail-closed guarantee**: remote models are excluded from selection entirely,
every model call / tool fetch funnels through a single egress check
(`security.assert_egress_allowed`) that raises rather than leaking, and routing
honors a `public` / `internal` / `restricted` data class (a `restricted` request
stays local even when sovereign mode is off). If no local model is configured it
**fails closed** instead of downgrading to a remote one.

```bash
export OLYMPUS_SOVEREIGN=1
export OLYMPUS_PROVIDER=openai OLYMPUS_BASE_URL=http://localhost:11434/v1 OLYMPUS_MODEL=qwen2.5
olympus status          # shows sovereign=ON, allowlist, eligible local models
```

This is application-layer enforcement at Olympus's own egress choke — not an OS
firewall (pair it with one for a host-wide guarantee). The threat model, the
fully-local recipe (Ollama/vLLM), the data-class policy table, and an honest
statement of the boundary are in
[docs/SOVEREIGNTY.md](docs/SOVEREIGNTY.md).

### Every decision is replayable and signed — verify it yourself

Olympus records every orchestration decision, freezes the exact model responses
that produced it, and **signs the decision path** with an Ed25519 key. Anyone can
re-execute a past run against those frozen responses and confirm the reasoning is
**byte-identical**, and check the signature against a pinned public key — no trust
in us required:

```bash
olympus verify --run <RUN_ID>        # replays the decision path AND checks the signature
#   replay    : PASS — N decision(s) replayed byte-identically
#   signature : PASS — decision-log signature valid
#   RESULT    : PASS — replay-identical and signed by the trusted production key.
```

A run id comes back in the `X-Olympus-Run-Id` header of every *non-streaming*
`/v1` answer (a streamed response can't carry it — the run id is only assigned
once the run completes; use `/api/status` or a non-streaming request to get it),
and `/api/status` reports the signing posture. **Honesty about trust:** with no secret
signing seed configured, runs are signed by a *public default key* — verification
still passes but is loudly labeled `DEV / UNVERIFIED` (integrity, not
authenticity), and `olympus verify --run … --require-production` rejects it. Set a
real `OLYMPUS_SIGNING_SEED` (HSM/KMS recommended) and pin the derived key to make
it a genuine guarantee. Step-by-step for a skeptical evaluator:
[docs/VERIFY.md](docs/VERIFY.md); key custody and rotation:
[docs/SIGNING.md](docs/SIGNING.md).

### Connectors: MCP servers & custom plugins

Olympus connects to external tools and data two ways, both governed by the
same security model as its built-in tools:

**MCP servers (the ecosystem).** Olympus speaks the Model Context Protocol
natively on the Anthropic backend — plug in any of the hundreds of community
MCP servers (GitHub, Notion, Postgres, Slack, Tavily, Linear, …). Tools run
server-side on Anthropic's infrastructure.

```bash
# attach a server (tokens read from an env var, never stored on disk)
python -m olympus add-mcp tavily https://mcp.tavily.com/mcp/ \
       --type data --auth-env TAVILY_MCP_TOKEN --specialists argus,aletheia
export TAVILY_MCP_TOKEN=tvly-...
python -m olympus connectors          # list everything configured
```

Or drop a `memory/connectors.json` (see `examples/connectors.json.example`).

**Custom plugins (your own connectors).** A plugin is a plain Python function
that runs locally and works on **every** backend — the simplest way to wire
Olympus to your own REST API or internal system:

```python
from olympus.connectors import plugin

@plugin("crm_lookup", "Look up a customer by email",
        schema={"type": "object",
                "properties": {"email": {"type": "string"}},
                "required": ["email"]},
        specialists=["plutus"], action=False)
def crm_lookup(email: str) -> str:
    ...   # call your API, return a string
```

Put the file in a `plugins/` directory (or point `OLYMPUS_PLUGINS_DIR` at one;
see `examples/plugins/`). See `examples/plugins/example_rest_connector.py` for
a working template.

**The security edge nobody else has.** Hermes and OpenClaw let you plug in MCP
servers with no quality gate and no injection defense — a malicious or buggy
connector runs unchecked. Olympus gates connectors in two tiers:

- **Tier 1 — data connectors** (read-only): wired into specialists like any
  other tool. Output is wrapped as untrusted content, sanitized before it can
  touch memory, and **fact-checked by Aletheia** like any other claim.
- **Tier 2 — action connectors** (change the world): treated exactly like the
  email/webhook actuators, behind a **double gate** — defining one in
  `connectors.json` is not enough; it stays **inert** until the operator also
  names it in `OLYMPUS_MCP_ACTION_ALLOWLIST`. And capability separation still
  applies: action connectors are stripped from any specialist run that also
  ingests external content, so a poisoned page or document can never trigger
  one. Assign them to a non-web specialist like Chronos.

You get the whole MCP ecosystem *plus* the safety the others skip.

> MCP runs server-side on the Anthropic backend; custom plugins work on every
> backend. On OpenAI-compatible providers, use plugins for connectors.

### Coding that's *measurably* good — execution-scored

Hephaestus isn't graded on whether his code *looks* right — his code is **run
against real tests** and scored on whether it actually passes. `python -m
olympus code-eval` has him solve real tasks (merge intervals, an LRU cache, a
bug fix, debounce, deep flatten, Go word-count, …); each solution is extracted,
executed in an isolated temp directory with a wall-clock timeout, and scored
pass/fail. (This runs Olympus's *own* generated code in a dev/eval context, never
user input; for OS-level isolation of untrusted code use the docker exec
backend.) Languages whose runtime isn't installed are skipped, not failed.

This objective signal feeds the self-improvement loop: Prometheus runs
`run_code_benchmark` before and after changing Hephaestus's prompt or coding
skills and keeps only changes that raise the **pass rate** — so his coding
ability improves against ground truth, not a judge's guess. It's the closest
thing to genuinely training a coding agent, and it's a coding edge neither
Hermes nor OpenClaw has.

### Controlled-autonomy actions — prepare, approve, execute, undo

Olympus doesn't just advise — it can *do* things, safely. The rule is absolute:
**agents prepare actions; they never execute them.** A prepared action is queued
with a preview; you approve it explicitly before it runs, and every step is
logged to an immutable audit trail.

```bash
python -m olympus actions          # see actions awaiting your approval (with preview)
python -m olympus approve <id>     # execute a prepared action
python -m olympus edit <id> to=... # fix the content first — stays awaiting approval
python -m olympus reject <id> ...  # decline it (teaches future behavior)
python -m olympus undo <id>        # reverse a reversible, executed action
python -m olympus autonomy 2       # set the autonomy dial (0–4)
python -m olympus grant email      # grant a permission scope
python -m olympus revoke all       # kill switch — revoke every scope
python -m olympus budget 5         # cap your API spend at $5/day (0 = off)
python -m olympus limit gmail_send 5  # max 5 sends/day (runaway guard)
```

In the **browser UI**, prepared actions appear as **cards** under a "📋 actions"
button with a count badge — each shows the full preview, *why* Olympus prepared
it, and one-click **Approve / Edit / Reject / Undo**. Edit lets you correct the
exact content (a recipient, a subject line) before approving — the action stays
held until you say go. The panel auto-opens when a reply prepares something for
you to review, so approving is a click, not a command.

The safety model is structural, not hopeful:

- **Risk classes** — every action is `trivial` / `notable` / `irreversible` /
  `financial-legal`. **Irreversible and financial actions can NEVER auto-run**,
  at any autonomy level — they always require an explicit approval.
- **Autonomy dial (L0–L4)** — L1 (default) prepares and stops; only L3+ may
  auto-run *trivial, reversible* actions, and only within policy.
- **Two independent gates** — an action needs both its permission scope granted
  *and* its approval satisfied before it executes.
- **Injection-safe by construction** — because agents only *prepare*, a
  malicious email that tricks an agent into preparing a bad action is harmless:
  you see the preview and reject it. Reading can never become acting without you.

### Safety limits — your bill and your contacts, both capped

Two guards protect you from a runaway or prompt-injected agent — neither has
anything to do with Olympus charging you (it never does; you bring your own key):

- **Budget guard.** Olympus is bring-your-own-key, so every model call bills
  *your* provider account. Set `olympus budget 5` and Olympus pauses new
  requests — chat *and* unattended background work — once today's estimated
  spend reaches $5, instead of silently running your bill up. Spending money is
  itself irreversible, so the same principle that gates sending an email gates
  spending a dollar. The browser action panel shows today's spend against the
  cap, and turns amber when it's reached.
- **Action rate limits.** A daily cap on how many times each action type may
  actually *execute*, so even fast-clicked approvals (or an injected agent)
  can't flood your contacts. Irreversible actions default to a generous runaway
  guard (50/day) and financial/legal ones to 10/day; trivial and reversible
  actions are unlimited. Tune any of them with `olympus limit <type> <n>`
  (`0` = unlimited). Drafting and rejecting never count — only real execution.

New capabilities (calendar, files, payments-prep) are just new action types
registered on this same spine — they inherit the gate automatically.

**First real integration — Gmail.** Connect a Google account and **Angelos**,
the correspondence manager, triages your inbox and *prepares* replies, drafts,
and archives — but **sending always goes through the approval gate**. Because
Angelos reads untrusted email, the capability-separation rule strips its direct
action tools automatically: it can only `prepare_action`, never send on its own.
So a malicious email that tries to make it wire money or leak data produces, at
worst, a prepared action you preview and reject. Set `GMAIL_ACCESS_TOKEN` (see
`.env.example`) to connect.

**Calendar too.** Angelos also reads your Google Calendar to propose genuinely
free times and *prepares* invitations — but creating an event emails the
attendees, so it's classed irreversible and **always waits for your approval**
(with undo that cancels). That completes the **email + calendar assistant**:
connect one Google account and Olympus triages your inbox, drafts replies,
proposes meeting times, and prepares the invites — you approve, it acts.

**Self-serve connect + encrypted credentials.** Users link Google with a click
("Connect Google" in the web UI → Google consent → done) via a standard OAuth
flow; tokens are stored **encrypted at rest** in a secrets vault (Fernet,
keyed by `OLYMPUS_SECRET_KEY`) and refreshed automatically — never in plaintext.
Set `OLYMPUS_GOOGLE_CLIENT_ID`/`SECRET` to enable it.

**Runs anywhere, database when you want it.** Storage defaults to the local
filesystem (zero setup). Set `OLYMPUS_DATABASE_URL` to a Postgres URL and the
same data — including the encrypted vault — persists there instead, no code
changes. Database-ready is a config switch, not a rewrite.

### Multilingual — native in any language

Olympus answers in the user's own language, generated natively rather than
translated. The council coordinates internally in English (cheaper, more
reliable JSON), but every word the user sees — direct replies, synthesized
answers, and marketing/social copy from Peitho and Iris — is authored in the
user's language with its cultural and idiomatic norms.

- By default it **matches the language of your message** (and the conversation,
  so short follow-ups stay in language).
- Set a **persistent preference** when you want it fixed:
  - Web UI: the ⚙ panel's *Language* field (`Spanish`, `日本語`, `auto`, …)
  - Telegram: `/lang French` (or `/lang auto`)
  - CLI chat: `/lang Arabic`
- A benchmark item (`peitho-multilingual`) scores native-quality output in
  another language, so the self-improvement loop measures multilingual quality
  too.

### Use several keys together — best of each, as one

Give Olympus more than one frontier key and it uses them **together**, not as a
switch: each part of the pipeline runs on whichever model is strongest for it.
With Claude + GPT, for example, reasoning and verification run on one while
coding runs on the other — composed into a single system.

- **Web UI:** the ⚙ panel has a "+ Model 2" row — add a second provider/model/key.
- **Env / CLI:** `OLYMPUS_MODELS=[{"provider":"openai","model":"gpt-5","api_key":"..."}]`
  alongside your primary key. `python -m olympus models` shows the assignment.

How it decides: a built-in capability ranking scores each model per role
(reasoning, coding, verification). The strongest model wins a role outright;
when two are comparable, the work is **split across keys** so both are actually
used. One key still works exactly as before — it just becomes "every role on
that model."

### Use any model (bring your own key)

Anthropic/Claude is the default and the most capable path (server-side web
search, adaptive thinking). But Olympus runs on **any OpenAI-compatible
endpoint** — OpenAI, Gemini, DeepSeek, Groq, Mistral, OpenRouter, Ollama,
LM Studio, vLLM — with zero extra dependencies:

```bash
# OpenAI
export OLYMPUS_PROVIDER=openai OLYMPUS_MODEL=gpt-4o OLYMPUS_API_KEY=sk-...

# Groq
export OLYMPUS_PROVIDER=openai OLYMPUS_MODEL=llama-3.3-70b-versatile \
       OLYMPUS_API_KEY=gsk_... OLYMPUS_BASE_URL=https://api.groq.com/openai/v1

# Fully local with Ollama (no API key at all)
export OLYMPUS_PROVIDER=openai OLYMPUS_MODEL=llama3 \
       OLYMPUS_BASE_URL=http://localhost:11434/v1
```

On non-Claude providers, web access automatically falls back to a built-in
client-side DuckDuckGo search — the architecture (and the hallucination
gate) works identically everywhere.

**Run on a Claude subscription instead of API credits (`claude-code`).** If you
have a Claude Pro/Max plan and the [Claude Code](https://claude.com/claude-code)
CLI installed and logged in, point Olympus at it and pay nothing per token — it
runs on your subscription:

```bash
export OLYMPUS_PROVIDER=claude-code      # uses the local `claude` CLI; no API key
# optional: OLYMPUS_MODEL=sonnet         # else Claude Code's default (Opus on Max)
python -m olympus
```

Each model call is one stateless, single-turn `claude -p` completion, so it
never runs tools/bash on your machine during the pipeline (the trade-off:
specialists reason from the model's own knowledge — no live web_search on this
provider). It's for **personal, single-user** use on your own subscription —
not for serving a multi-user public instance (that would breach the plan terms
and its rate limits; use API keys there). Needs the `claude` CLI on `PATH`
(`OLYMPUS_CLAUDE_BIN` overrides).

**In the web UI**, each visitor can click **⚙ model** and enter their own
provider, model, and API key. Keys live in the visitor's browser
(localStorage), travel only with their own requests, are used in-memory, and
are never stored or logged by the server — that's what makes a public
Olympus instance feasible without burning your own key.

### Telegram in 2 minutes

1. Message **@BotFather** on Telegram → `/newbot` → copy the token.
2. `export TELEGRAM_BOT_TOKEN=123456:ABC...`
3. `python -m olympus telegram`

Optional environment variables:

- `TELEGRAM_ALLOWED_CHAT_IDS=12345,67890` — restrict who can use the bot
  (open to everyone by default).
- `TELEGRAM_NOTIFY_CHAT_ID=12345` — the heartbeat proactively pushes
  opportunity scans and self-audit reports to this chat, so Olympus reaches
  *you* instead of waiting to be asked.

### WhatsApp (official Cloud API)

Talk to Olympus from WhatsApp — same dependency-free style (raw Cloud API, no
Twilio, no `whatsapp-web.js`). Because the Cloud API is webhook-based, this runs
a small HTTP server that Meta calls.

1. In the [Meta developer console](https://developers.facebook.com/), create an
   app, add the **WhatsApp** product, and copy the **phone number ID** and an
   **access token**.
2. Set the env vars and start the gateway:
   ```bash
   export WHATSAPP_ACCESS_TOKEN=EAAG...
   export WHATSAPP_PHONE_NUMBER_ID=123456789
   export WHATSAPP_VERIFY_TOKEN=any-secret-you-choose
   python -m olympus whatsapp            # serves the webhook on :8485
   ```
3. Put it behind HTTPS (same reverse-proxy note as the web UI — Meta requires a
   public `https://` URL) and register `https://your-host/webhook` as the
   webhook, using the same verify token.

Optional: `WHATSAPP_ALLOWED_NUMBERS=15551234567,...` restricts who may talk to
it; `WHATSAPP_APP_SECRET=...` makes Olympus verify Meta's payload signatures.
Each sender gets a private memory namespace, and the same `/scan`, `/audit`,
`/watch`, `/good`, `/lang`, `/contribute` commands as Telegram work.

### Discord, Slack, and Signal

The same council answers on Discord, Slack, and Signal — all zero-dependency
(raw HTTP over `urllib`, stdlib request-signing), all sharing one command set
(`/scan`, `/audit`, `/watch`, `/good`, `/lang`, `/contribute`, `/growth`) and a
private per-user memory namespace.

- **Discord** — create an app, copy its **public key**, and point the
  *Interactions Endpoint URL* at `https://your-host/`.
  ```bash
  export DISCORD_PUBLIC_KEY=...            # verifies inbound (Ed25519)
  export DISCORD_WEBHOOK_URL=...           # optional: heartbeat push to a channel
  python -m olympus discord               # interactions endpoint on :8486
  ```
  Discord gives an interaction only ~3 seconds to answer, far less than a full
  council turn takes, so Olympus **acks immediately with a deferred response**
  and then edits in the real reply through the interaction follow-up webhook.

- **Slack** — create an app with the Events API, copy its **signing secret**,
  and set the *Request URL* to `https://your-host/`.
  ```bash
  export SLACK_BOT_TOKEN=xoxb-...
  export SLACK_SIGNING_SECRET=...          # verifies inbound (HMAC-SHA256)
  export SLACK_NOTIFY_CHANNEL=C0123        # optional: heartbeat push
  python -m olympus slack                 # events endpoint on :8487
  ```
  Slack retries any event it doesn't hear back on within ~3 seconds, so Olympus
  **acks the webhook instantly** and runs the pipeline on a background worker;
  Slack's `event_id` is de-duplicated so a retry never produces a second reply.

- **Signal** — talk to a `signal-cli` daemon (no cloud account).
  ```bash
  export SIGNAL_NUMBER=+15551234567             # your registered Signal number
  export SIGNAL_CLI_REST_URL=http://localhost:8080   # signal-cli-rest-api endpoint
  python -m olympus signal
  ```

All three webhook servers are multi-threaded (`ThreadingHTTPServer`) and, like
WhatsApp and Telegram, use one serial worker per user — ordered within a
conversation, concurrent across users — so one slow answer never blocks anyone
else. Put the Discord/Slack endpoints behind HTTPS (both platforms require a
public `https://` URL), the same reverse-proxy note as the web UI.

### Remembering you — the profile card

Olympus keeps a small, editable **profile card** — who you are and how you like
things done — and rides it (cached) on every turn, so you stop re-explaining
yourself and the agent gets cheaper the longer you use it:

```bash
olympus profile "I run a bakery called Crumb; keep replies short"
olympus profile --set timezone CET     # structured facts
olympus profile                        # show the card
olympus profile --clear                # forget it
```

The card is deliberately tiny and only states what you've actually set (an empty
profile costs zero tokens), it's plain text you can read and edit, and it's
never auto-written from untrusted content — the first, minimal slice of a larger
memory system. Under the hood, Olympus also caches the system prompt **and** the
tool definitions on every model call, so repeated agent turns bill the big,
stable parts of the prompt once and read them from cache after that. And instead
of replaying the whole conversation each turn, once the history crosses a token
budget Olympus folds the older turns into a compact running **state** block
(facts, decisions, preferences, open threads) and replays only the most recent
turns verbatim — so cost tracks what matters, not how long you've been talking.

### Durable memory — it remembers across sessions

Beyond the single conversation, Olympus builds a **typed, per-user memory** over
time. After each substantive turn, a cheap model runs in the background and
extracts durable facts — identity, preferences, projects, recurring tasks,
important people, procedures — as candidate memories. A **write gate** decides
what's kept:

- below a confidence floor → discarded; a duplicate → reinforces the existing
  memory (raising its confidence); a conflict → supersedes the old one (keeping
  history) when clearly confident, else asks you;
- **anything sensitive (health, finances, legal, identifiers) is never
  auto-saved** — it waits in an approval queue, exactly like a risky action.

Memories **decay** unless reused, so stale facts fade. On each turn Olympus
retrieves only the memories relevant to what you're asking (lexical match, ranked
by importance × decayed-confidence × recency, under a token budget, with a
relevance floor so junk never enters the prompt). Everything is inspectable and
yours to edit or forget:

```bash
olympus memory                 # list what Olympus remembers (with confidence)
olympus memory candidates      # sensitive/uncertain items awaiting your approval
olympus memory approve <id>    # approve a held memory   (reject <id> to dismiss)
olympus memory forget <id>     # tombstone a memory
olympus memory search "..."    # what would Olympus recall for this query?
```

It's an event-sourced design (an append-only log is the source of truth; the
typed memory is a projection), stored on the same backend as everything else —
local files by default, Postgres when `OLYMPUS_DATABASE_URL` is set. Turn the
whole thing off with `OLYMPUS_MEMORY=0`.

In the **browser UI**, a "🧠 memory" button opens a full **knowledge panel** —
your editable profile, held candidates awaiting **Approve / Dismiss**, saved and
proposed **playbooks**, the **people-and-companies graph**, what Olympus
remembers (one-click **Forget** on anything), and its **track record** with
growth insights (below). Everything the agent knows about you, visible and
editable in one place.

Retrieval is lexical by default. Point `OLYMPUS_EMBED_MODEL` at any
OpenAI-compatible `/embeddings` endpoint (OpenAI, a local Ollama/LM Studio
server, …) and Olympus adds a **semantic fallback**: when keyword matching comes
back thin, it embeds the query and finds memories by meaning, not just words.
It's optional and off by default — and the fallback only fires when lexical
search misses, so the hot path stays free in the common case.

### Playbooks — save a workflow once, run it by name

The retention engine: when you repeat a multi-step task, save it as a **named
procedure** and next time one phrase loads the steps — with every action in them
still flowing through the approval gate. Month-6 stops re-explaining what
month-1 had to spell out.

```bash
olympus playbook save "weekly investor update" "pull the metrics; draft in my voice; CC my cofounder"
olympus playbook run "weekly investor update"   # loads the steps; actions still gated
olympus playbook list                           # your saved workflows
olympus playbook proposed                        # ones Olympus suggested, awaiting approval
olympus playbook approve "<name>"   |  forget "<name>"
```

When a turn matches a saved playbook's name, Olympus follows its steps
automatically. Playbooks are **versioned** (re-saving bumps the version, keeps
its usage stats) and **approval-gated to create**: a specialist may *propose* a
procedure when it notices you repeating one, but it stays inert until you
approve it — Olympus never invents a workflow and runs it on you.

### Relationship graph — who do you know at Acme?

Flat memories answer "what do I know about Sarah?"; a graph answers "who do I
know at **Acme**?" — which needs edges, not rows. As you mention people and
companies, the same background extractor records them as a small per-user graph
of entities and typed relations (`works_at`, `cofounder_of`, `competitor_of`,
…). When a turn names a known entity, Olympus traverses one hop **in both
directions** and injects the connections — so "who's at Acme?" surfaces everyone
you've told it works there.

```bash
olympus graph                  # all entities and how many connections each has
olympus graph "Acme"           # describe one entity and its relationships
olympus graph --forget "Acme"  # remove an entity and its edges
```

It's the same store and the same rules — inspectable, per-user, and nothing it
learns ever acts without the approval gate.

### Growth loop — it learns from what you approve, edit, and reject

Every time you approve a prepared action as-is, fix it first, or decline it,
that's ground-truth feedback. Olympus logs those **outcomes** per action type and
keeps a track record:

```bash
olympus outcomes   # e.g. "42 actions: 75% approved as-is, 18% after edit, 7% rejected"
```

When you keep changing or declining a particular kind of action, it surfaces an
**insight** — *"you've edited 4 of the last 5 emails before sending; consider
setting a preference or editing the playbook."* Crucially, Olympus **suggests,
never silently changes**: improvement is something you confirm, not something
done to you. No engagement optimization, no dark-pattern retention — the agent
earns its keep by being useful, and the track record is yours to see.

## Layout

```
olympus/
├── config.py        # model + cadence settings
├── llm.py           # streamed Claude calls (adaptive thinking, caching, retries)
├── agent.py         # the shared agentic tool loop
├── tools.py         # client-side tools + server-side web tool declarations
├── memory.py        # persistent memory (lessons, corrections, reports, upgrades)
├── youtube.py       # transcript fetching for Mnemosyne
├── specialists.py   # the council registry (add a specialist = prompt + 1 entry)
├── orchestrator.py  # Zeus → Athena → specialists → Aletheia pipeline
├── heartbeat.py     # the self-recurring loop (+ Telegram push notifications)
├── web.py           # zero-dependency browser chat UI
├── telegram.py      # zero-dependency Telegram gateway
├── cli.py           # command-line interface
└── prompts/*.md     # every agent's mind — editable, and upgradable by Prometheus
```

Memory lives in `./memory/` (gitignored): `lessons/`, `corrections/`,
`reports/`, `upgrades/`, `prompt_backups/`, plus the YouTube `watchlist.txt`.

## Safety rails

- Aegis is defensive-only by constitution; Prometheus is forbidden from
  weakening safety rules in any prompt.
- Prometheus can modify **prompts only** — code changes become written
  proposals in `memory/upgrades/` for a human (or coding agent) to apply.
- Every prompt rewrite is automatically backed up to `memory/prompt_backups/`.

## Releases, support & security

- [`CHANGELOG.md`](CHANGELOG.md) — notable changes per version (Keep a Changelog).
- [`RELEASING.md`](RELEASING.md) — how a signed release is cut (tag → sign → publish → verify).
- [`SECURITY.md`](SECURITY.md) — how to report a vulnerability privately, and the blast-radius guarantees.
- [`docs/SUPPORT.md`](docs/SUPPORT.md) — SemVer, the 6-month LTS window, and release-integrity policy.
- [`docs/BACKUPS.md`](docs/BACKUPS.md) — encrypted, signed, off-droplet data backups and disaster recovery.

Verify any published release with `olympus verify` (recomputes every file hash
and checks the signature against the pinned key); verify a recorded run's audit
trail with `olympus verify --log <run_id>`.
