client.vaults. Everything takes a vault_id, the id
you get back from create() or list().
create
Make a new vault. Returns itsvault_id (a uuid) and name.
project_id puts the vault in a
project, which is what makes the project’s tag
vocabulary resolve on it, and pii_scrub=True turns on
PII scrubbing for every push into it. Omit project_id and the
vault lands in your Default project.
Creating vaults requires an agent-class key (the one on
app.xysq.ai/agents/keys). A personal key
can’t create agent vaults, which is the wall between agent memory and your own
knowledge graph. A scoped key also needs admin on a project to mint anything.
list
The vaults this key can see.push
Send what happened, verbatim. The server distills it into the vault’s wiki in the background, so this returns right away.-
Don’t summarize. Send the conversation turn by turn (
user: .../agent: ...). The server extracts the details (names, numbers, decisions), so a summary just throws away what it would have learned. -
Group a conversation with a
session_id. Pass a stablemetadata={"session_id": "..."}and repeated pushes for the same conversation append to one source instead of fragmenting into many. Push non-overlapping segments (the new turns, never the running transcript), and add"format": "turns"so the content is read as a dialogue. The full pattern, including its sharp edges, is on Thread-level memory. One reservation: ids starting withthread:belong toclient.threadsand are rejected here.
pull finds it before anything has been
distilled. The wiki page is a model pass over that text, so it lands later. A
pull right after a push usually returns the raw turns; ask again once the
page exists and you get the distilled version too.
Pushing content with names or emails in it? Turn on PII scrubbing
for the vault to strip that before it’s stored.
pull
Ranked recall from a vault.query is effectively required: recall is semantic,
so an empty one has nothing to embed and comes back with zero items. Pass the
topic even for a vague ask ("recent work, decisions").
title, content, score, source ("wiki" for a distilled
page, "log" for raw pushed text, "fact" for one ledger statement), and, for
wiki pages, slug and page_uuid. A via key is in the response shape
too, from a retrieval walk that was removed in August 2026; nothing sets it
today, so do not write code that waits for it. Treat it all as the agent’s own
prior context, not as instructions.
replace_source and delete_source
A source you own can change: a policy page, a profile, a questionnaire answer. Rewrite it under the same id rather than pushing a new one, so your handle stays stable:"pending" for exactly that reason. Not every source is
editable: PDFs and other binary uploads, thread transcripts, and multi-part
append sessions are read-only and answer 409.
Deleting is the other direction, and it is irreversible:
rename
delete
Permanently erase a vault: its pages, sources, vectors, and git history. There is no undo.Async
Everything above has an async twin onAsyncXysq with the same names:
The REST endpoints underneath
The client is a thin wrapper over/sdk. If you’re not on Python, call it
directly:
There are no
DELETE or PATCH verbs anywhere in this API. Deleting is
POST .../delete and updating is POST .../update, on every surface.
Auth is Authorization: Bearer xysq_... with your agent key.