Build with Emily.
What you get without building it.
Most of the work in a useful AI assistant is memory: what to keep, what to drop and how to stay consistent. Emily does that part.
Memory you do not have to build
Emily keeps context across conversations, so your app picks up where the last session left off instead of starting from zero.
Learning with guardrails
Before anything is stored, three protocols remove duplicates, block unreliable thoughts and protect her identity.
How the Epistemic Firewall worksMemory you can inspect
In Emily Brain, people can see what Emily remembers, how memories connect, and ask her why she holds one.
Not tied to one model
Emily works with leading AI models, and her memory is separate from the model, so you are not tied to a single provider.
AI models Emily can run on
How Emily behaves in your app.
First conversations
Emily starts learning what matters to the people using your app. Only information that passes her three checks becomes a memory.
Over weeks and months
Conversations build on each other. Emily recalls earlier decisions and context without your app resending them.
At any time
People can open a memory and ask Emily why she holds it, what it connects to and how confident she is.
Web, email, MCP, SDK or API.
Start with the one that matches how your people work. They all reach the same Emily and the same memory.
Web
Available todayChat with Emily in the browser, with voice and files. Register with Google; no code needed.
Create an accountMCP
Available todayConnect compatible AI tools to Emily, so they share her memory.
MCP connection guideEmail Emily or forward a thread, and she replies with the context she already holds.
Email setup guideSDK
Available todayEmilyRemote on npm: a terminal CLI and a JavaScript and TypeScript SDK. Sign in and talk to your Emily in a few lines.
EmilyRemote on npmAPI
Available todayCall Emily over HTTPS from your own backend: device sign-in, a streaming chat endpoint and turn recovery, for your own interface.
Read the API referenceCompanion Developer: $179 CAD a month, coming soon
The planned developer tier adds capacity for building on Emily, with 25,000,000 tokens monthly, and bring your own key when it arrives. Planned pricing, not yet available to purchase.
EmilyRemote: the CLI and SDK.
EmilyRemote signs you in to your own Emily and streams conversations, from a terminal or from JavaScript and TypeScript. Sign-in is OAuth device authorization with browser approval, handled by Robson.
1. Install and sign in
npm install -g @robsonai/emilyremote
emilyremote setup
emilyremote self-check
emilyremote login --email you@example.com
emilyremote ask "What should I focus on today?"Open the approval link and approve with the same account. On a headless server, add --no-browser --credential-store file and approve on another computer.
2. Call Emily from your code
import { EmilyClient } from '@robsonai/emilyremote';
const account = new EmilyClient();
const signedIn = await account.login({ headless: true,
onEvent(e) {
if (e.type === 'login_required')
console.error(e.verification_url, e.user_code);
} });
const personal = account.withProfile(signedIn.profile);
for await (const e of personal.ask({ text: 'Help me plan today.' })) {
if (e.type === 'result') console.log(e.result.response_text);
}ES modules and CommonJS, with TypeScript declarations. Credentials stay in the native credential store; the API never returns a token.
Requirements: Node.js 22 or later. Runtimes included for Linux x64 (glibc 2.38+) and Apple Silicon (macOS 26+). Intel Mac, Linux ARM and Windows are not supported yet.
@robsonai/emilyremote on npmThe inbox you already use.
Email is how most work arrives, so it is a way into Emily that needs nothing new. Send her a question or forward a thread, and she answers with the context she already holds.
- What she learns from an email joins the same memory as your chats, MCP tools and apps
- Pick up on the web where an email thread left off, without re-explaining
- Works from any mail client, on any device
Email access is included with Emily.
Your front end. Your Emily.
Build any interface you like on Emily: a web app, a widget inside your product, or a mobile app. Your backend holds each person's connection and streams Emily's replies to your screens.
A branded coaching app
A web front end in your stack. Your backend calls Emily and streams each reply to the page.
A help widget on your website
Embed Emily in a product you already run. Sessions and sign-in stay with your app.
A voice-first mobile app
Native apps talk to your backend, never to Emily directly, so credentials stay on your server.
How the pieces fit
You build
Your interface
The screens, branding and workflow your people see.
Robson runs
Sign-in and access
Every request is authenticated by Robson, wherever your interface runs.
Emily provides
Memory and reasoning
Long-term memory, the Epistemic Firewall and the AI model configured for the account.
Want to offer Emily to your own customers under your brand? See white label. Where your interface runs, for example on a developer's laptop while you build or on your own server in production, is agreed when we issue your access. Sign-in always goes through Robson.
From request to live.
Anyone can register with Google and use Emily today, on the web, by email, through MCP or with the SDK. For a custom interface or a white-label build, this is how it works.
Request access
Tell us what you want to build and who will use it.
Agree scope and credentials
We agree how your app will connect, where it will run, and issue your credentials.
Build and test
You build against Emily with the API reference and examples we share with you.
Go live
We confirm your production setup, and your people start using it.
The Emily Companion API.
For a custom interface connecting each person to their own Emily Companion. Your backend makes every call; the browser never holds an Emily token.
Connection model
Browser interface → your per-user backend → Emily HTTPS API
│
└─ stores this person's Emily SDK tokens
Person's browser → Emily sign-in and approval page (Robson)- Never put Emily access or refresh tokens in browser JavaScript, storage, URLs, analytics or logs.
- Resolve whose connection to use from your own authenticated session, never from an ID the browser sends.
- Protect your routes with secure HTTP-only cookies and CSRF checks; keep each person's data separate.
- The chat endpoint is a streaming POST, so your backend makes the request and streams it to the browser.
Base URL
https://emily.robsonai.com
Use the Robson-approved origin for your environment. Emily's CORS allowlist is not open to arbitrary domains: agree your hosting origin with Robson and call Emily server to server.
Tokens
- Access token: Bearer, about 15 minutes (use
expires_in) - Refresh token: rotates on every refresh
- Connection: up to 30 days, then reconnect
- Scoped: other routes return 403; expired or revoked return 401
1. Connect an account (device approval with PKCE)
Your backend creates a PKCE verifier and S256 challenge, starts a device request, and shows the person the verification link. They approve on Emily's hosted page; your backend polls for the tokens.
POST /auth/sdk/device
Content-Type: application/json
{
"code_challenge": "{BASE64URL_SHA256_OF_VERIFIER}",
"code_challenge_method": "S256",
"device_name": "Example Companion Web"
}
→ device_code, user_code, expires_in,
interval, verification_uri,
verification_uri_completePOST /auth/sdk/device/token
Content-Type: application/json
{
"device_code": "{DEVICE_CODE}",
"code_verifier": "{ORIGINAL_PKCE_VERIFIER}"
}
→ access_token, refresh_token, token_type,
expires_in, expires_at, issuer,
user { id, email, name }While the person has not answered, polling returns authorization_pending; on slow_down, wait the returned interval. Stop on denial or expiry, and respect Retry-After. After the exchange, call GET /auth/status and check its user_id matches the token response before binding the connection to your app session.
2. Select the personal Emily
List targets with GET /api/sdk/clones and select only the one entry whose target_kind is account_self and whose clone_id matches account_id. Confirm it with POST /api/sdk/clones/resolve. Keep clone_id as an opaque string; never convert it to a number.
3. Send a message and stream the reply
POST /chat/v3
Authorization: Bearer {ACCESS_TOKEN}
Content-Type: application/json
Accept: text/event-stream
{
"message": "Hello Emily",
"session_id": "{SESSION_ID}",
"client_turn_id": "{CLIENT_TURN_ID}",
"clone_id": "{ACCOUNT_SELF_CLONE_ID}",
"history_scope": "continuity"
}Send with Authorization: Bearer, Content-Type: application/json and Accept: text/event-stream. Use one session ID per conversation and a new UUID client_turn_id for each message, saved before you send.
The reply streams as Server-Sent Events: metadata, segment, done, error and duplicate. Replace segments by segment_id rather than appending them.
An HTTP 200 is not proof a turn completed: read the events. A done with reattach or error is not a finished answer. Treat streamed Markdown and tool output as untrusted and sanitize it.
Endpoints
| Method and path | Use | Credential |
|---|---|---|
| POST /auth/sdk/device | Start S256 PKCE device approval | None |
| GET /auth/sdk/device/verify | Emily-hosted sign-in and consent page | Emily browser session |
| POST /auth/sdk/device/token | Exchange the approved device code | Device code and PKCE verifier |
| POST /auth/sdk/refresh | Rotate the token pair | Refresh token in body |
| POST /auth/sdk/logout | Revoke the connection (returns 204) | Refresh token in body |
| GET /auth/status | Check the token's account status | Bearer access token |
| GET /api/sdk/capabilities | SDK contract and supported chat routes | Bearer access token |
| GET /api/sdk/clones | List targets; select account_self | Bearer access token |
| POST /api/sdk/clones/resolve | Confirm the personal target | Bearer access token |
| POST /chat/v3 | Send a message, receive SSE | Bearer + clone_id |
| GET /chat/last-turn | Look up an exact completed turn | Bearer + clone_id |
| GET /chat/turn/client/{client_turn_id} | Look up an exact submitted turn | Bearer + clone_id |
| GET /chat/turn/{turn_id}/stream | Reattach to or replay a turn | Bearer + clone_id |
| GET /chat/session/{session_id}/active-turn | Find a session's active turn | Bearer + clone_id |
| POST /chat/turn/cancel | Stop an active turn | Bearer + clone_id |
Recover, never resend
If a connection drops, keep the same session and client_turn_id and look the turn up before doing anything else. The send may already be running. Never automatically replay a chat request after a network failure or a token refresh.
Errors
- 401 Refresh once on your backend; if that fails, ask the person to reconnect.
- 403 Outside this connection's scope. Never try a wider credential.
- 400 Request or target-selection error; keep the pending turn.
- 429 Wait for Retry-After or the device-flow interval.
- 503 From last-turn: history unavailable; keep the turn unresolved and retry.
Scope
This API covers each person's own Emily Companion only. Administrator tools, other people's or organizations' Emily, dashboards, conversation history, and memory or model settings are not part of it; they need a separate agreement with Robson. Messages from a custom interface are software-sent and are not treated as typed in Emily's own app.
Tell us what you want to build.
Describe your app and the people who will use it, and we will set up developer access.
Or email sales@robsoninc.com