Quick Start
Add Configure to an existing agent with the same shape as the packaged agent template: hosted auth, profile context, model tool calling, hosted UI surfaces, and background profile updates. Configure does not host the model; bring an Anthropic, OpenAI, OpenRouter, or equivalent provider key.
Stable install
Install configure from npm latest.
Prerequisites
bash
npm init -y # if this folder does not already have a package.json
npm install configure
npx configure setupYour environment needs Configure keys plus one model provider key:
bash
CONFIGURE_API_KEY=sk_...
CONFIGURE_PUBLISHABLE_KEY=pk_...
CONFIGURE_AGENT=your-agent-name
MODEL_PROVIDER=anthropic
MODEL_NAME=claude-sonnet-4-6
ANTHROPIC_API_KEY=sk-ant-...Only the selected provider key is required. For OpenAI use OPENAI_API_KEY; for OpenRouter use OPENROUTER_API_KEY.
Canonical starter
Start from the template that ships with the package:
node_modules/configure/template/— canonical packaged Atlas-derived shell
Treat it as the default shell. Do not invent a new layout unless the existing app already has a strong shell worth preserving. Keep hosted Configure surfaces inline where the template places them and change only .env, public/brand.css, public/brand.js, and backend prompt/tool behavior.
Agent-driven setup
If a coding agent is wiring this up for you, point it at configure.dev/skill.md and tell it to use configure.
API-only profile path
If you only need profile reads and writes, you do not have to put hosted auth or UI components in the chat hot path. Use Server-Side Users with userId / X-User-Id from your server to create an unlinked developer-scoped profile, then link it later with Configure.auth({ externalId }) when you need connected tools or cross-agent sharing.
1. Authenticate in the browser
Use the hosted auth surface from https://configure.dev/js/configure.js. Phone OTP and approval happen inside a Configure-owned iframe. Your app receives only an agent-scoped token.
html
<div id="configure-auth"></div>
<script src="https://configure.dev/js/configure.js"></script>
<script>
Configure.auth({
el: "#configure-auth",
publishableKey: "pk_...",
agent: "your-agent",
agentName: "Your Agent",
theme: "light"
});
document.addEventListener("configure:authenticated", (event) => {
const { token, userId } = event.detail;
// Send token + userId to your backend chat route.
});
</script>2. Load profile context server-side
typescript
import {
ConfigureClient,
CONFIGURE_TOOLS,
UI_TOOLS,
parseUIToolCall,
toOpenAIFunctions,
} from 'configure';
const client = new ConfigureClient(process.env.CONFIGURE_API_KEY, {
agent: process.env.CONFIGURE_AGENT,
});
const profile = await client.profile.get(token, userId, {
sections: ['identity', 'summary', 'integrations'],
});
const context = profile.format({ guidelines: true });
const systemPrompt = `You are my agent.\n\n${context}`;
const tools = [...CONFIGURE_TOOLS, ...UI_TOOLS];CONFIGURE_TOOLS covers profile reads/writes and connected tool search. UI_TOOLS adds show_ui_component so the model can ask your frontend to render hosted Configure surfaces.
3. Stream your model with tools
Anthropic accepts Configure's tool definitions directly:
typescript
const stream = anthropic.messages.stream({
model: process.env.MODEL_NAME || 'claude-sonnet-4-6',
max_tokens: 4096,
system: systemPrompt,
tools,
messages,
});OpenAI-compatible providers use the converter:
typescript
const response = await fetch('https://api.openai.com/v1/chat/completions', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${process.env.OPENAI_API_KEY}`,
},
body: JSON.stringify({
model: process.env.MODEL_NAME || 'gpt-4o',
stream: true,
messages: [{ role: 'system', content: systemPrompt }, ...messages],
tools: toOpenAIFunctions(tools),
tool_choice: 'auto',
}),
});4. Route tool calls
When the model calls a normal Configure tool, execute it with the SDK. When it calls show_ui_component, send a UI event to the browser instead of mounting raw <configure-*> tags.
typescript
async function executeTool(call, token, userId, sendEvent) {
if (call.name === 'show_ui_component') {
const ui = parseUIToolCall(call.name, call.input);
sendEvent({ type: 'ui_component', ...ui });
return ui;
}
switch (call.name) {
case 'get_profile':
return client.profile.get(token, userId);
case 'search_emails':
return client.tools.searchEmails(token, userId, call.input.query);
case 'search_files':
return client.tools.searchFiles(token, userId, call.input.query);
case 'search_web':
return client.tools.searchWeb(token, userId, call.input.query);
case 'remember':
return client.profile.remember(token, userId, call.input.fact || call.input.content);
default:
return { error: `Unhandled tool: ${call.name}` };
}
}The full template handles every Configure tool in node_modules/configure/template/server.mjs or the mirrored examples/quickstart/server.mjs.
5. Render hosted UI surfaces
The browser maps ui_component events to hosted methods from configure.js:
js
const mounts = {
connection_list: Configure.connections,
single_connector: Configure.singleConnector,
memory_import: Configure.memoryImport,
profile_editor: Configure.profileEditor,
memory_card: Configure.memoryCard,
confirmation: Configure.confirmation,
};
function renderConfigureSurface(event) {
const mount = mounts[event.component];
if (!mount) return;
const row = document.createElement("div");
row.className = "message-row assistant";
const shell = document.createElement("div");
shell.className = "surface-shell";
const el = document.createElement("div");
shell.appendChild(el);
row.appendChild(shell);
document.querySelector("#messages").appendChild(row);
mount({
el,
publishableKey,
agent,
token,
userId,
...event.props,
});
}This keeps the production path honest: your app calls Configure.*() and Configure owns the iframe-rendered browser surfaces. In the packaged template, these surfaces are appended inline into the main thread instead of a detached side area.
6. Save profile updates after each turn
After the assistant responds, fire-and-forget ingestion so future sessions improve without blocking the user:
typescript
client.profile.ingest(
token,
userId,
[
{ role: 'user', content: userMessage },
{ role: 'assistant', content: assistantResponse },
],
{ sync: false },
).catch(() => {});Reference starter
Use the packaged template (node_modules/configure/template/) when you want the whole compact loop:
- one Express server
- one HTML file
- hosted auth with
Configure.auth() - SSE streaming
- Anthropic, OpenAI, and OpenRouter provider paths
CONFIGURE_TOOLS+UI_TOOLS- hosted Configure surfaces
- background profile ingestion
Next:
- Tool Calling — Full tool routing implementation
- Inline UI Components — Hosted UI methods and
show_ui_component - Profiles — Profile structure and update patterns
- Connected Tools — Gmail, Calendar, Drive, Notion integration