Build with a coding agent

The fastest path for Cursor, Claude Code, Codex, Devin, and other coding agents.

LoreOS docs are designed to be read by both humans and coding agents. If you are using an agent, give it the resources below in this order.

API key status

For local testing, issue a short-lived sandbox key directly from the API:

$export LOREOS_KEY="$(curl -sS -X POST https://api.loreos.app/v1/demo/sandbox-key \
> | jq -r '.data.api_key')"
$export LOREOS_BASE="https://api.loreos.app"

Demo keys are intentionally narrow: five characters, fifteen sessions, 150 messages, 2,000 input characters, no image generation, no managed Telegram, no webhook delivery, no budget changes, no app creation, and no extra API keys. They are for copy-paste testing only.

For persistent apps, use self-serve account access when it is enabled for your workspace: a human verifies identity in the console, approves the agent’s requested scopes, and the agent receives a short-lived account access token. The agent then issues a runtime API key for your app. Keep every runtime LOREOS_KEY server-side.

Initial demo issuance does not require a browser challenge, so terminal coding agents can call it directly. If abuse appears, LoreOS may temporarily pause issuance or add a challenge to the public route.

Agent resource order

  1. Integration guideGET https://api.loreos.app/v1/llms.txt
    • Short, live API usage guide.
    • Best first context for an agent that needs to make calls.
  2. Docs and API indexhttps://docs.loreos.app/llms.txt
    • Compact index of the docs site and public API reference.
    • Best when the agent needs to choose the right guide or endpoint page.
  3. Page markdown — append .md to any docs page URL.
    • Use this when the agent is focused on one topic.
    • Examples: /getting-started/quickstart.md, /getting-started/build-with-a-coding-agent.md, /getting-started/self-serve-access.md, /getting-started/full-developer-e-2-e-path.md, /platform/character-state.md, or an API Reference page URL plus .md.
  4. API discoveryhttps://docs.loreos.app/.well-known/api-catalog
    • Machine-readable API discovery.
  5. OpenAPIhttps://api.loreos.app/v1/openapi.json
    • Public /v1-only schema source of truth (point your SDK generator here). The raw https://api.loreos.app/openapi.json is the whole server (includes internal admin/cbt) — do not generate against it.

Only call /v1/*. Generate against https://api.loreos.app/v1/openapi.json (the public, /v1-only schema). The raw https://api.loreos.app/openapi.json describes the whole server, including internal /admin/* (operator cockpit) and /cbt/* (internal chat) surfaces. Those are not for tenant apps — they are unversioned, not app-scoped, and may change without notice. Instruct your agent to use only /v1 routes. /v1 itself is in preview and is versioned via the schema_version field; pin generated clients to the OpenAPI schema and re-check it when schema_version changes.

Golden path

Ask the agent to do this first:

Use LoreOS to create one character, start one session, send one message,
poll session events, and print the first character reply. Use only the /v1 API.

The minimal flow is:

POST /v1/characters
POST /v1/sessions
POST /v1/sessions/{session_id}/messages
GET /v1/sessions/{session_id}/events?since={cursor}
GET /v1/sessions/{session_id}/relationship-snapshot

For a production-shaped integration that imports an authored character bundle, migrates prior chat, publishes playable-character and NPC graphs, sends a reply, and checks score opt-in, use Full developer E2E path after the minimal flow works.

Use relationship-snapshot, memories, open-loops, life-feed, and identity-continuity for user-facing relationship evidence. Use GET /v1/sessions/{session_id}/relationship-scores only when your app explicitly needs numeric dimensions such as affection_toward_user or romantic_interest; numeric relationship scores are empty/redacted until you opt in with PATCH /v1/apps/{app_id} { "expose_relational_numerics": true }. The score response includes score_contract, updated_at, and version; scores are not monotonic and are not a universal cross-app leaderboard.

For dashboard sync, use GET /v1/characters/{slug}/relationship-scores?limit=50 to export all session score meters for one character, or GET /v1/external-users/{external_user_ref}/relationship-scores?character={slug}&limit=50 to export one user’s score meters. These export endpoints return final per-session state only: session_id, character, external_user_ref, updated_at, version, and relationship_scores[]. They do not expose raw model traces or conversation text.

If your app needs to inject app-owned relationship context such as “founding friend” or “inner circle”, use PATCH /v1/sessions/{session_id}/relationship-context. This writes a planning-guarded session context event. Add relationship_context_key plus write_mode="replace_key" to replace one active app-owned row, and use GET|DELETE /v1/sessions/{session_id}/relationship-context to audit or remove it. It does not overwrite character canon, persona, or learned relational scores.

After the app opts into relationship numerics, relationship_score.changed arrives on the same session event log and webhook transport as chat events. For app-wide operations, use GET|PATCH /v1/apps/{app_id}/proactive-policy and GET /v1/apps/{app_id}/observability/metrics?window_hours=24.

For docs validation, run this in a clean workspace where the agent cannot inspect the LoreOS repository. The agent should be able to build a tiny server-side app from the public docs, a self-issued demo key, and the machine-readable resources listed above.

Persistent setup without giving the agent your login

When the agent needs to create a persistent app, issue runtime API keys, or manage per-user caps, do not hand it Google credentials, Clerk credentials, browser cookies, or a human session token. Use the account device flow:

POST /v1/account/device/start (include client_label and an opaque client_fingerprint)
human opens verification_uri and approves in the console
POST /v1/account/device/token
GET /v1/account/me
POST /v1/account/apps
POST /v1/account/api-keys
GET /v1/account/apps/{app_id}/api-keys
POST /v1/account/apps/{app_id}/api-keys/{prefix}/rotate
POST /v1/account/apps/{app_id}/api-keys/{prefix}/revoke

The token returned by POST /v1/account/device/token starts with lat_. It is an account access token and works only with /v1/account/* routes. It is not a runtime API key. After the agent issues an app runtime key, use that ck_... runtime key as LOREOS_KEY for POST /v1/characters, POST /v1/sessions, and all normal Character OS calls. Clerk Account API keys start with ak_...; they are not LoreOS keys and should never be used against api.loreos.app.

Runtime key list calls are prefix-only. They show safe metadata such as auth_status, environment, last-used time, quota/rate-limit hints, and whether revoke/rotate is available. The full ck_... secret is returned only by issue/rotate and should be stored immediately by the developer’s backend or secret manager.

Production app keys are blocked until production activation. If GET /v1/me returns detail.code = "production_not_active", use the account token to check GET /v1/account/apps/{app_id}/production-readiness, fix billing/cap blockers, then call POST /v1/account/apps/{app_id}/production-activation. A production runtime key is ready only when GET /v1/me returns data.production_state = "production_active".

Use Self-serve access for the exact scope list, request bodies, rate-limit behavior, and revocation flow. Account routes are preview guide routes, not the generated runtime SDK surface yet.

The reply is asynchronous. POST /messages returns accepted and a cursor, not the reply text. Poll events until you see:

1{
2 "type": "message.created",
3 "role": "character",
4 "payload": {
5 "text": "...",
6 "bubbles": ["..."]
7 }
8}

Render on the committed event above. Do not block the UI on any separate delivered status: in LoreOS docs, delivery status means a webhook or managed-channel push attempt has settled. It is useful for observability, but it is not the readiness gate for showing a reply that is already present in the session event log.

Reliability contract

LoreOS APIs are structured so agents can call, recover, and continue.

  • Every success response is wrapped as { "schema_version", "data", "next_actions" }.
  • Errors use { "detail": { "code", "message", "fix" } }.
  • next_actions tells the agent what to call next.
  • Retry-safe sends: pass Idempotency-Key: <unique-per-message> on POST /messages. A same-key re-call (common on serverless/Vercel) returns the original cursor + { "idempotent_replay": true } instead of creating a duplicate turn/reply. Dedupe event delivery by the monotonic cursor.
  • Long-running work is exposed through session events, runs, and delivery state.
  • Usage caps return 402 budget_exceeded before expensive model work starts.
  • Unknown or cross-app resources return 404, never tenant-identifying details.
  • Clients should ignore unknown additive fields.

Common mistakes

  1. Expecting a reply from POST /messages. The reply arrives later on the event log.
  2. Reading top-level response fields. Use response.data, not response.session_id or response.cursor.
  3. Dropping the cursor. Save data.cursor, then poll with since=<cursor>.
  4. Treating external_user_ref as LoreOS auth. It is your own opaque end-user id. Your app owns end-user auth.
  5. Putting LOREOS_KEY in the browser. Keep the key server-side. Proxy browser requests through your backend.
  6. Testing images before readiness. Upload an identity image and check visual readiness before image probes.
  7. Using a demo key as production auth. Demo keys are short-lived and capped. Use a self-serve-issued runtime key for real apps.
  8. Using a production key before activation. production_not_active means the key is valid but the production app is still pending. Activate the app from the account plane, then retry GET /v1/me.
  9. Assuming a failed sandbox-key call means the API is unavailable. 429 means the issuance rate limit was reached. 503 demo_sandbox_disabled means public issuance is temporarily paused; persistent runtime keys still work.
  10. Using numeric relationship scores without app opt-in. Read qualitative relationship evidence by default. If you need score values, first call GET /v1/me to get app_id, then opt in with PATCH /v1/apps/{app_id}.
  11. Waiting for delivered before rendering a reply. Render when the session log contains message.created or character.initiated with role: "character". delivered is push-delivery bookkeeping, not the visible-reply readiness signal.
  12. Using an account token as the runtime key. lat_... account tokens are for /v1/account/* setup only. Runtime calls use the ck_... app runtime API key issued by the account plane.
  13. Using Clerk’s Account API key as a LoreOS key. ak_... keys come from Clerk’s own Account/API Keys UI. They are never accepted by LoreOS. Issue a LoreOS Runtime API Key from /console or POST /v1/account/api-keys.

What a successful agent integration proves

A clean agent integration should prove:

  • the app keeps LOREOS_KEY server-side;
  • the app creates or reuses a character;
  • the app starts a session for an external_user_ref;
  • the app sends a user message;
  • the app polls session events with the returned cursor;
  • the app displays a message.created event with role: "character".
  • the app reads relationship-snapshot or memories when it needs product evidence for continuity, offscreen life, open loops, or reach-out reasons.

If an agent cannot reach that result from the docs alone, the docs need another pass.

When to use LoreOS

Use LoreOS when you need persistent AI characters with memory, relationships, world continuity, daily-life context, visual identity, delivery, metering, and observability.

Do not use LoreOS if you only need a single stateless chatbot response and want to own all memory, delivery, and usage infrastructure yourself.