Profiles and memory
configure.profile(...) creates a per-user server object for reading and writing memory.
If your client already speaks MCP, connect https://mcp.configure.dev instead: the same configure_profile_* tools surface natively with zero code. This guide is the SDK power path for in-process control.
These examples assume a server-side client from Installation; apiKey and agent come from npx configure setup:
ts
import { Configure } from "configure";
const configure = new Configure({
apiKey: process.env.CONFIGURE_API_KEY, // sk_… developer secret key
agent: process.env.CONFIGURE_AGENT, // your agent handle
});
const token = /* Configure access token from the Continue with Configure exchange */;
const profile = configure.profile({ token });token is the agent-scoped Configure token from the Continue with Configure exchange (or the inline Link fallback); pass it, or externalId for an unlinked user, not both. For an app-local user that has not linked Configure yet, use configure.profile({ externalId: "customer-123" }); the SDK maps that to the developer-scoped X-User-Id path.
Read
ts
const read = await profile.read({
sections: ["identity", "preferences", "summary"],
});
const approvedContext = read.profile.format({ guidelines: false });profile.read() returns composed profile context. It does not accept raw file paths. Choose sections when the app knows the packet it wants, or omit sections when the app genuinely needs the broad approved overview. Use read.profile.format() only for an app-owned display or context path. Keep profile.tools() in the model loop so the model can call the four default tools (configure_profile_read, configure_profile_search, configure_profile_remember, configure_profile_forget) for overview, concrete memories, source-specific views, saves, and targeted deletes. Do not pass browser tokens or user IDs to the model.
profile.read() also accepts box and page: box opens one box from the read's table of contents (a category like "work", a source like "agents/parry", or a shared project tag "projects/<slug>"), and page (starting at 1) continues a long box. profile.search() accepts box too, and it composes with query. profile.remember() takes an optional box to file the fact onto a named shelf.
read returns { profile, portable, filtered, hiddenSources }. The subsections live on read.profile: read.profile.imports contains user-directed ChatGPT, Claude, Gemini, Grok, or other memory imports, and read.profile.integrations contains connected tools such as Gmail, Calendar, Drive, and Notion. read.profile.format() renders the approved context for a prompt.
Search
ts
const results = await profile.search({
query: "meeting preferences",
source: "tempo",
from: "2026-05-01",
to: "2026-05-05",
limit: 8,
});
const chatgptImportedMemories = await profile.search({
query: "*",
source: "imports/chatgpt",
limit: 50,
});profile.search() performs deterministic retrieval over permitted attributed profile data. Compact results are the default and include readable memory text plus source attribution. Pass detail: "full" only when you need safe inspectable metadata such as CFS path, markers, provenance, or updated_at.
source accepts an agent handle ("tempo" or "agents/tempo") or an import handle ("imports/chatgpt" or "import:chatgpt"). The prefixed forms are exact filters and match the source labels that read and search results print. A bare provider name (chatgpt, claude, gemini, grok, other) matches both the connected agent of that name and the matching import shelf, because both can exist.
This is the retrieval path for concrete questions. Use it for prompts like "what did I say about Japan travel?", "what does ChatGPT remember about me?", or broader tasks that need relevant preferences beyond an optional overview packet.
Remember
ts
await profile.remember("User prefers SMS for urgent billing issues.");profile.remember() accepts one explicit fact string. It rejects message arrays and raw transcripts. New memories are stored as typed CFS entries at /agents/{agent}/memories/{YYYY-MM-DD}/{mem_id}.json.
Forget
ts
await profile.forget(saved.memory.id, { reason: "user_request" });profile.forget(id, options?) deletes one memory this agent wrote. It only reaches your own saves: an id another agent wrote returns a clean not-found result, never an error. The id (and optional date, which makes the delete a direct lookup) come from the remember response or from a search hit. reason: "user_request" is for the user asking you to remove something for good: it also suppresses the same fact across every source and blocks it from being re-saved. The default reason, correction, just retracts your own copy. REST apps can call POST /v1/profile/forget with the same fields.
Commit
ts
// messages, response, toolResults: what the just-finished model turn produced
await profile.commit({
messages,
response,
toolResults,
});profile.commit() submits bounded turn material after a model turn, especially after profile reads. Bounded messages or tool results clear read-backed obligations; explicit memories are optional and should only contain durable user facts, preferences, or intentions. It is server-side write-back, not a default model tool and not a bulk import API.
Existing agent flow
For an existing agent, keep your current model loop and add these steps:
- Create
const profile = configure.profile({ token })after Link. - Merge
profile.tools({ connectors, actions })with your existing tool list when the hosted/product surface requested connector/action capabilities and the app supports them. - Route
configure_*tool calls toprofile.executeTool(). - Let the model call the default tools (
configure_profile_read,configure_profile_search,configure_profile_remember,configure_profile_forget) through the tool router. - Pass tool results back to the model for the final assistant answer.
- Call
profile.commit()after the turn.
Action tools change external state. Expose the actions your app supports when your hosted/product surface requested those capabilities; execution still fails closed if linked state, connector state, permissions, scopes, approval state, clear user intent, or runtime policy are missing.