Build with a coding agent
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:
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
- Integration guide —
GET https://api.loreos.app/v1/llms.txt- Short, live API usage guide.
- Best first context for an agent that needs to make calls.
- Docs and API index —
https://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.
- Page markdown — append
.mdto 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.
- API discovery —
https://docs.loreos.app/.well-known/api-catalog- Machine-readable API discovery.
- OpenAPI —
https://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.jsonis the whole server (includes internal admin/cbt) — do not generate against it.
- Public /v1-only schema source of truth (point your SDK generator here). The raw
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:
The minimal flow is:
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:
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:
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_actionstells the agent what to call next.- Retry-safe sends: pass
Idempotency-Key: <unique-per-message>onPOST /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 monotoniccursor. - Long-running work is exposed through session events, runs, and delivery state.
- Usage caps return
402 budget_exceededbefore expensive model work starts. - Unknown or cross-app resources return
404, never tenant-identifying details. - Clients should ignore unknown additive fields.
Common mistakes
- Expecting a reply from
POST /messages. The reply arrives later on the event log. - Reading top-level response fields.
Use
response.data, notresponse.session_idorresponse.cursor. - Dropping the cursor.
Save
data.cursor, then poll withsince=<cursor>. - Treating
external_user_refas LoreOS auth. It is your own opaque end-user id. Your app owns end-user auth. - Putting
LOREOS_KEYin the browser. Keep the key server-side. Proxy browser requests through your backend. - Testing images before readiness. Upload an identity image and check visual readiness before image probes.
- Using a demo key as production auth. Demo keys are short-lived and capped. Use a self-serve-issued runtime key for real apps.
- Using a production key before activation.
production_not_activemeans the key is valid but the production app is still pending. Activate the app from the account plane, then retryGET /v1/me. - Assuming a failed sandbox-key call means the API is unavailable.
429means the issuance rate limit was reached.503 demo_sandbox_disabledmeans public issuance is temporarily paused; persistent runtime keys still work. - Using numeric relationship scores without app opt-in.
Read qualitative relationship evidence by default. If you need score values, first call
GET /v1/meto getapp_id, then opt in withPATCH /v1/apps/{app_id}. - Waiting for
deliveredbefore rendering a reply. Render when the session log containsmessage.createdorcharacter.initiatedwithrole: "character".deliveredis push-delivery bookkeeping, not the visible-reply readiness signal. - Using an account token as the runtime key.
lat_...account tokens are for/v1/account/*setup only. Runtime calls use theck_...app runtime API key issued by the account plane. - 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/consoleorPOST /v1/account/api-keys.
What a successful agent integration proves
A clean agent integration should prove:
- the app keeps
LOREOS_KEYserver-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.createdevent withrole: "character". - the app reads
relationship-snapshotormemorieswhen 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.