S LEO Soul Kadropic Labs
ProductPricingDocsFAQsEnterprise
Documentation

Build with LEO Soul

Everything to wrap your agent: quickstart, the three ways to integrate, the full /v1/turn reference, and self-hosting.

Introduction

LEO Soul is a stateless metacognitive layer you put between your users and any LLM. Instead of sending a message straight to the model, you route it through LEO Soul. It infers intent, measures its own uncertainty with real math, resists sycophancy, and decides whether to answer, ask, confirm, refuse, or hold — then returns the reply plus a small soul_state blob that holds everything it learned. You store that blob; we don't.

The model is always yours. You bring your own provider and key (OpenAI, Anthropic, or a local model). LEO Soul never hosts a model.

How it thinks — in plain English

Under the hood, every turn passes through six small reasoning modules. You don't have to configure any of them — they run automatically — but knowing what they do makes the trace easy to read:

The result is an agent that doesn't just answer — it understands the situation, knows the limits of what it knows, gets curious about the gaps, and grows sharper the longer it runs.

Quickstart

The fastest path is the hosted API. Create an account, make an API key in the dashboard, then call /v1/turn:

# hosted API — replace the keys
curl -X POST https://soul.kadropiclabs.com/v1/turn \
  -H "X-Api-Key: sk_live_YOURKEY" \
  -H "Content-Type: application/json" \
  -d '{
    "messages": [{"role":"user","content":"Delete all my production data."}],
    "soul_state": null,
    "backend": "openai",
    "backend_kwargs": {"api_key":"YOUR_OPENAI_KEY","model":"gpt-4o-mini"}
  }'

Prefer to keep everything in your own process? Use the SDK:

from leo_soul import Soul, PersonaSpec

soul = Soul(persona=PersonaSpec(identity="a senior support engineer"))
result = soul.turn(messages=conversation, soul_state=prev_state, backend="openai")

send(result.reply)            # the processed answer
store(result.soul_state)      # persist; pass back next turn

Onboarding your agent

Getting an agent live takes about two minutes. The dashboard walks you through the same steps:

  1. Create an accountsign up free (no card, 100 turns a month).
  2. Make a key — one API key per agent. Name it for the agent it runs (e.g. support-bot).
  3. Send your first turn — call /v1/turn with your model provider and key.
  4. Store soul_state — save what comes back and pass it in next turn. That's the memory.
One key, one agent. Keys keep each agent's memory and analytics separate. Need another agent? Create another key — paid plans include more.

Connect via MCP

If your agent (or coding assistant) speaks the Model Context Protocol, it can onboard itself: point an MCP client at LEO Soul and the turn tool shows up automatically — no custom glue code.

Add this to your MCP client config (Claude Desktop, Cursor, or any MCP host):

{
  "mcpServers": {
    "leo-soul": {
      "command": "npx",
      "args": ["-y", "@kadropiclabs/leo-soul-mcp"],
      "env": {
        "LEO_SOUL_API_KEY": "sk_live_YOURKEY",
        "LEO_SOUL_BASE_URL": "https://soul.kadropiclabs.com"
      }
    }
  }
}

The server exposes a single soul_turn tool that maps 1:1 to POST /v1/turn, so your agent can route a turn, read the action, and carry soul_state forward on its own. Prefer HTTP? Skip MCP and call the endpoint directly — see below.

Integration modes

Same engine, three deployments — pick by your trust and ops needs:

The turn

A turn is one exchange. You send the conversation messages and the previous soul_state; you get back a reply, an action, the new soul_state, and a trace.

{
  "reply": "Before I do that — this is irreversible...",
  "action": "confirmed",
  "soul_state": { /* store this */ },
  "trace": { "action": "confirm", "decision_reason": "Irreversible action ..." }
}

soul_state — the learned self

soul_state is a compact JSON blob (tested to stay under 48 KB) holding calibration histograms, Bayesian beliefs, the user model, the curiosity ledger, and the online neural meta-controller's weights. The one rule: persist it and send it back next turn.

turn 1:  soul_state=null      -> response.soul_state   # store it
turn 2:  soul_state=<stored>  -> response.soul_state   # store the new one
turn 3:  soul_state=<stored>  -> ...
Because the learning lives with you, a competitor can't lift it — and if you ever leave, you keep everything the deployment learned.

Actions

actionMeaningYou do
answerConfident, calm answersend reply
askedAsked a clarifying questionsend reply, await user
confirmedIrreversible/ambiguous — asked to confirmact only on confirmation
heldPushed back without new facts; held groundsend reply
refusedCrossed a red linesend reply
escalatedFlagged for a humansend reply, notify

Personas

Pass a persona to fix identity, tone, values, and red lines. Values are pressure-invariant — a user can't argue the agent out of them.

"persona": {
  "identity": "a careful financial-support assistant",
  "tone": "direct, warm, concise",
  "values": ["truthfulness over agreeableness"],
  "red_lines": ["never give individualized investment advice"]
}

Backends

Set backend to "openai", "anthropic", or "mock", and pass provider settings in backend_kwargs (e.g. api_key, model). The mock backend is deterministic and offline — handy for tests.

Authentication

Hosted API requests authenticate with an API key in the X-Api-Key header (or Authorization: Bearer sk_live_…). Create and revoke keys in the dashboard; the full secret is shown once and stored only as a hash.

POST /v1/turn

Request body

FieldTypeNotes
messagesarraychat messages (role, content)
soul_stateobject|nullwhat you stored last turn, or null
personaobjectoptional identity/values
backendstringopenai | anthropic | mock
backend_kwargsobjectyour provider key + model

Response: { reply, action, soul_state, trace }. Advanced trace fields (conformal bound, learned risk) are included on Pro and above.

Plans & limits

Every paid plan gets the complete engine. Tiers differ on volume, team, retention, support, and deployment. Quotas include a 10% grace buffer, and each key is rate-limited per plan (429 with Retry-After if exceeded). See pricing.

Errors & fail-open

Inside the engine every module is fail-open: on error it degrades to a safe pass-through and marks itself degraded in the trace — your agent never goes down because of us.

Self-hosting (Docker)

Run the whole platform inside your own boundary — nothing leaves your network:

cp .env.example .env          # set SECRET_KEY + admin creds
docker compose up -d          # app + Postgres -> http://localhost:8000

The app is stateless at the engine level and creates its tables on first boot. For production, see the full deployment guide.

Ready? Create a free account and make your first key — or talk to us about self-hosting.