recall.agents
Manage agents — named personas that own memories within a namespace. SyncAgents and AsyncAgents with identical method surfaces.
All methods below exist on both SyncAgents (via Recall) and AsyncAgents
(via AsyncRecall) with identical signatures. The only difference is await
on the async path. Each example shows both variants in tabs.
list()
def list(
self,
*,
limit: int = 20,
cursor: Optional[str] = None,
) -> dict: ...Return a paginated list of agents visible to the caller's org. Use cursor
for stable pagination on orgs with high agent churn.
Parameters
limitintoptionalNumber of agents per page. Server clamps to [1, 100].
cursorstroptionalOpaque cursor from the previous page's meta.nextCursor. Omit on the
first request.
Returns
{
"items": [
{
"id": "ag_01HEX…",
"name": "customer-support-v2",
"namespaceId": "ns_01HEX…",
"createdAt": "2026-05-01T10:00:00Z",
"updatedAt": "2026-05-09T14:22:00Z",
},
# …
],
"meta": {
"count": 3,
"limit": 20,
"nextCursor": None, # non-null when another page exists
},
}Examples
# Paginate all agents
cursor = None
all_agents = []
while True:
page = recall.agents.list(limit=50, cursor=cursor)
all_agents.extend(page["items"])
cursor = page["meta"].get("nextCursor")
if not cursor:
break
print(f"Total agents: {len(all_agents)}")cursor = None
all_agents = []
while True:
page = await recall.agents.list(limit=50, cursor=cursor)
all_agents.extend(page["items"])
cursor = page["meta"].get("nextCursor")
if not cursor:
break
print(f"Total agents: {len(all_agents)}")get()
def get(self, agent_id: str) -> dict: ...Fetch a single agent by its ID. The returned dict includes deletedAt,
which is null when the agent is active and an ISO 8601 timestamp when it
has been soft-deleted.
Parameters
agent_idstrrequiredThe id of the agent to fetch, e.g. 'ag_01HEX…'.
Examples
agent = recall.agents.get("ag_01HEX…")
print(agent["name"], "active:", agent["deletedAt"] is None)agent = await recall.agents.get("ag_01HEX…")
print(agent["name"], "active:", agent["deletedAt"] is None)Raises RecallNotFoundError when the ID does not exist or belongs to a
different org.
create()
def create(
self,
name: str,
*,
namespace_id: Optional[str] = None,
) -> dict: ...Create a new agent persona. The new agent immediately accepts memory writes scoped to it.
Parameters
namestrrequiredHuman-readable name for the agent, e.g. 'customer-support-v2'. Must be
unique within the org. Names are immutable post-creation — use patch()
to rename.
namespace_idstroptionalPin the agent to a specific namespace. When omitted, the agent is bound to the namespace derived from the API key.
Agent creation counts against the org's agentsLimit. Check
recall.org.plan() before bulk-creating agents to avoid hitting the cap
mid-loop.
Returns
Returns the full agent dict including id, name, namespaceId,
createdAt, updatedAt, and deletedAt (always null on creation).
Examples
agent = recall.agents.create("customer-support-v2")
print(agent["id"], agent["name"])
# ag_01HEX… customer-support-v2agent = await recall.agents.create("customer-support-v2")
print(agent["id"], agent["name"])patch()
def patch(
self,
agent_id: str,
*,
name: Optional[str] = None,
) -> dict: ...Partially update an agent. Only the kwargs you pass are sent on the wire — unspecified fields are left unchanged on the server.
Parameters
agent_idstrrequiredID of the agent to update.
namestroptionalNew display name. Must be unique within the org.
Returns
Returns the updated agent dict with the same shape as create().
Examples
updated = recall.agents.patch("ag_01HEX…", name="support-bot-v3")
print(updated["name"]) # support-bot-v3updated = await recall.agents.patch("ag_01HEX…", name="support-bot-v3")
print(updated["name"])delete()
def delete(self, agent_id: str) -> dict: ...Soft-delete an agent. The agent is flagged as deleted and can no longer accept memory writes, but its existing memories remain intact.
Parameters
agent_idstrrequiredID of the agent to delete.
Returns
{
"id": "ag_01HEX…",
"deletedAt": "2026-05-10T08:00:00Z",
"soft": True,
}Memories written by this agent are NOT deleted. The agent's memory history
remains fully accessible via recall.memories.list() and
recall.memories.search(). Call recall.memories.forget() to remove them
if needed.
Examples
result = recall.agents.delete("ag_01HEX…")
print("Deleted at:", result["deletedAt"])result = await recall.agents.delete("ag_01HEX…")
print("Deleted at:", result["deletedAt"])stats()
def stats(self, agent_id: str) -> dict: ...Fetch activity counters for a specific agent. Useful for monitoring agent health and detecting stale personas that can be pruned.
Parameters
agent_idstrrequiredID of the agent to inspect.
Returns
{
"memoryCount": 1_204,
"sessionCount": 87,
"lastActiveAt": "2026-05-09T22:11:00Z", # null if never used
}lastActiveAt is null for newly created agents that have never had a
memory written to them.
Examples
stats = recall.agents.stats("ag_01HEX…")
print(
f"Agent has {stats['memoryCount']:,} memories "
f"across {stats['sessionCount']} sessions."
)
if stats["lastActiveAt"] is None:
print("Agent has never been used.")stats = await recall.agents.stats("ag_01HEX…")
print(
f"Agent has {stats['memoryCount']:,} memories "
f"across {stats['sessionCount']} sessions."
)Errors
RecallAuthError401/403fatalAPI key missing, expired, or lacks admin scope.
RecallNotFoundError404fatalAgent ID does not exist or belongs to a different org.
RecallValidationError422fatalInvalid name (e.g. duplicate within org), malformed body.
RecallPlanLimitError402fatalagentsLimit reached. Upgrade the plan or delete unused agents.
RecallRateLimitError429fatalRate limit exceeded. Inspect .retry_after_ms.
RecallServerError5xxfatalServer-side failure. Retried automatically up to max_retries.
Was this page helpful?