<!-- Source: https://docs.khwan.ai/quickstart -->
<!-- The whole documentation in one file: https://docs.khwan.ai/llms-full.txt -->

# Quickstart

Get a Khwan brain running around your own model in a few minutes.

## Install

```bash
pip install khwan
```

The Python client is a thin HTTP wrapper — no engine code, no heavy dependencies.
It talks to the hosted Khwan API at `https://api.khwan.ai`. Both clients are open
source, so what a library holding your prompts actually sends is readable rather
than promised: [Python](https://github.com/khwanlabs/khwan-client-python) ·
[TypeScript](https://github.com/khwanlabs/khwan-client-ts).

## Get an API key

### Sign in to the dashboard

Create an account and open your Khwan dashboard.

### Create an API key

Generate a key — it looks like `kwk_live_xxxxxxxx`. Keep it secret; treat it like a
password.

### Pick an end-user id (optional)

Set a stable `user_id` for each of your end users (for example their internal
account id) to give each one an **isolated per-user sub-brain** — a private memory
per user, from a single API key. Omit it for one shared brain. It composes with
[cores](#isolate-a-core-optional) (`account::core::@user`). Per-user sub-brains are
a paid feature; the free plan includes a few so you can try it.

  Your Khwan API key (`kwk_...`) authenticates you to Khwan. It is **not**
  your model provider's key. Khwan never sees your Anthropic / OpenAI key in the
  BYOM flow.

## The three-step loop

Khwan's core is a `prepare` → *your model* → `record` loop:

```python
from khwan import Khwan

# 1. Connect. `user_id` identifies the end user on each request.
kw = Khwan(api_key="kwk_live_xxx", user_id="alice")

# Your own model + your own key — Khwan never sees this.
llm = anthropic.Anthropic(api_key="sk-ant-...")

def my_own_llm(messages):
    # messages is a standard [{role, content}] array from Khwan.
    system = next((m["content"] for m in messages if m["role"] == "system"), "")
    chat   = [m for m in messages if m["role"] != "system"]
    r = llm.messages.create(
        model="claude-sonnet-4-6",
        max_tokens=1024,
        system=system,
        messages=chat,
    )
    return r.content[0].text

# --- the loop ---

# STEP 1: prepare — Khwan builds the brief (memory + constitution + coherence). No LLM.
turn = kw.prepare("remember I prefer short answers in Thai")

# Optional: Khwan can gate a turn (e.g. a constitutional violation).
if not turn.allowed:
    print("blocked:", turn.reason)
else:
    # STEP 2: call YOUR model with the prepared messages.
    answer = my_own_llm(turn.messages)

    # STEP 3: record — hand the answer back so Khwan persists + learns.
    kw.record(turn, answer)

    print(answer)
```

That's the entire integration. Run it again with a follow-up input and Khwan
will already remember the preference it just learned.

## Next turn: memory in action

```python
turn   = kw.prepare("what did I ask you to remember?")
answer = my_own_llm(turn.messages)   # the system prompt now carries the Thai preference
kw.record(turn, answer)
```

## Isolate a core (optional)

A **core** is a fully isolated brain — its own memory, identity, and learning.
Point a client at one with `core`; omit it for the account's default core. Quota
stays pooled at the account level.

```python
client1 = Khwan(api_key="kwk_live_xxx", user_id="alice", core="client1")
```

The client sends this as the `X-Khwan-Core` header. Two clients on different cores
never share memory. Create and manage cores in the dashboard or via the
[API](/api-reference#cores).

## Point at another instance (on-prem)

Same code, different base URL:

```python
kw = Khwan(
    api_key="kwk_...",
    user_id="alice",
    base_url="https://khwan.internal.acme.com",
)
```

## Where to go next

- **[Bring Your Own Model](/byom)** — `turn.messages` in depth, plus OpenAI and
  Ollama examples.
- **[API Reference](/api-reference)** — the underlying REST endpoints.
