CLI
Add, search and manage memory from your terminal, with a JSON mode built for AI agents and exit codes a script can branch on.
Install
The CLI is published for both toolchains. Pick whichever is already on your machine — the two are interchangeable, so you only need one.
npm install -g memorysync-cli
Or run it without installing, which is the easier path inside a container or a one-off script:
npx memorysync-cli help
Needs Node 18 or newer, or Python 3.9 or newer. Both packages have no dependencies, so there is no transitive tree to audit and nothing is compiled at install time.
Both installs provide memorysync and the shorter msync. Every command, flag, output format and exit code on this page behaves the same in either, and the two are compared against each other in CI, down to identical help --json output and identical shell completion scripts.
Authenticate
init asks for a key, verifies it against the API before saving anything, and records a default user and project.
memorysync init
For CI or any non-interactive shell, pass the values instead. Without a terminal there is no prompt, and the command fails with the flag to add rather than hanging on stdin.
memorysync init --api-key ms_live_xxx --user alice --force
Or skip stored credentials entirely and set MEMORYSYNC_API_KEY, which takes precedence over anything on disk.
Get a key without signing up
init --agent mints an evaluation key instead of asking for one. No email, no verification code, nobody signing anything. It is meant for the case where a coding agent is setting itself up and there is no human in the loop to go and create an account.
memorysync init --agent --agent-caller claude-code
The key is stored exactly the way a pasted one is, so every later command works with no further setup. It arrives with a generated end-user id such as swift-otter-4821, because a key created by an agent has nobody to name it after. identify replaces it.
memorysync identify alice
That changes the default only. Memories already stored under the generated id keep it, so read them back by passing that id: --user <the old id>. identify prints the exact value, so take it from the command's own output rather than from the example above — every key gets a different one.
Quick start
# Store a factmemorysync add "I prefer TypeScript over JavaScript" --user alice# Search it backmemorysync search "language preference" --user alice# Recent memories, as a tablememorysync list --user alice -o table# Pipe something inecho "Ships on Fridays" | memorysync add --user alice
Commands
Twenty-two commands. Every one accepts every output format, and memorysync help <command> prints the same flags and examples shown here — both are generated from one declaration inside the CLI, so this page cannot describe a flag the parser rejects.
Each command below is its own anchor, so you can link someone straight to the one you mean.
memorysync init
Store a credential and pick a default user and project.
memorysync init [--api-key <key> | --agent | --email <address>] [--user <id>] [--project <id>] [--force]
Prompts for an API key, verifies it against the API, then writes a profile. The key is never written to the config file in plain text: it goes to the OS keychain where one is reachable, and otherwise to an encrypted file readable only by you. With --agent it mints an evaluation key instead of asking for one, so a coding agent can get working memory with no email, no verification code and no human. That key expires after seven days and nobody owns it until somebody claims it with --email.
| Flag | What it does |
|---|---|
--api-key <key> | Skip the prompt and use this key. |
--agent | Mint an evaluation key with no signup. Expires in 7 days unless claimed. |
--agent-caller <name> | Which tool is minting the key, e.g. claude-code. Attribution only. |
--email <address> | Claim the current evaluation account. Sends a code, then pass it with --code. |
--code <code> | The claim code from the email. |
--password <password> | Set a dashboard password while claiming. Optional. |
-u, --user <id> | Default end user for later commands. |
--project <id> | Default project. |
-p, --profile <name> | Profile to create. Default "default". |
--force | Overwrite an existing profile without asking. |
memorysync initmemorysync init --api-key ms_live_xxx --user alice --forcememorysync init --agent --agent-caller claude-codememorysync init --email you@example.commemorysync init --email you@example.com --code K7MP-3XQR
memorysync identify
Name the end user that later commands default to.
memorysync identify <name> [--profile <name>]
An evaluation key starts with a generated end-user id like swift-otter-4821, because a key minted by an agent has nobody to name it after. This replaces it with something meaningful. Only changes the local default: memories already stored under the old id keep that id, so pass --user explicitly to read them back.
| Flag | What it does |
|---|---|
-p, --profile <name> | Profile to change. Default "default". |
memorysync identify alicememorysync identify alice@example.com
memorysync add
Store a durable fact about a user.
memorysync add [text] [--user <id>] [--metadata <json>]
Text is run through extraction, so filler is discarded and near-duplicates are merged. A "skipped" result is normal and not an error. Reads stdin when no text argument is given, so it composes with pipes.
| Flag | What it does |
|---|---|
-u, --user <id> | End user this memory belongs to. Falls back to the configured default. |
-m, --metadata <json> | Labels to store alongside the memory. |
-f, --file <path> | Read the text from a file. |
--source <name> | Where this came from. Default "cli". |
--no-dedupe | Store even when similar content already exists. |
--wait | Poll until the memory is searchable before exiting. |
--dry-run | Report what would be stored, and store nothing. |
memorysync add "Prefers TypeScript over JavaScript" --user aliceecho "Ships on Fridays" | memorysync add --user alicememorysync add --file note.txt --user alice --wait
Consumes plan quota: add_requests. See memorysync quota for headroom.
memorysync search
Search memory in natural language.
memorysync search <query> [--user <id>] [--limit <n>]
| Flag | What it does |
|---|---|
-u, --user <id> | End user this memory belongs to. Falls back to the configured default. |
-k, --limit <n> | Maximum results, 1 to 50. Default 5. |
--no-rerank | Skip the rerank pass. Faster, less precise. |
--context | Print the assembled context block instead of a result list. |
--explain | Include scoring detail for each result. |
memorysync search "language preference" --user alicememorysync search "open questions" --user alice -o json | jq '.data[].text'
Consumes plan quota: retrieval_requests. See memorysync quota for headroom.
memorysync list
List a user's memories, newest first.
memorysync list [--user <id>] [--limit <n>]
| Flag | What it does |
|---|---|
-u, --user <id> | End user this memory belongs to. Falls back to the configured default. |
--limit <n> | Maximum memories to return. Default 20. |
memorysync list --user alice --limit 50 -o table
Consumes plan quota: retrieval_requests. See memorysync quota for headroom.
memorysync get
Fetch one memory by id.
memorysync get <memory-id> [--user <id>]
| Flag | What it does |
|---|---|
-u, --user <id> | End user this memory belongs to. Falls back to the configured default. |
--history | Include the revision history. |
memorysync get m_60632 --user alice
memorysync update
Change a memory's labels or importance.
memorysync update <memory-id> [--metadata <json>] [--importance <n>]
| Flag | What it does |
|---|---|
-u, --user <id> | End user this memory belongs to. Falls back to the configured default. |
-m, --metadata <json> | Replace the metadata with this JSON. |
--importance <n> | Importance from 0 to 1. |
--dry-run | Show the change without applying it. |
memorysync update m_60632 --metadata '{"priority":"high"}' --user alice
memorysync delete
Delete memories.
memorysync delete <memory-id...> [--user <id>] [--all] [--yes]
Deleting is two-step by design: without --yes it previews and exits without changing anything, so an ambiguous command cannot clear a scope. Only memories are ever affected. No form of this command can delete an account, a project or an API key.
| Flag | What it does |
|---|---|
-u, --user <id> | End user this memory belongs to. Falls back to the configured default. |
--all | Delete every memory for that one user, and nothing else. Needs --yes. |
-y, --yes | Confirm the deletion. |
--dry-run | Preview only. Implied when --yes is absent. |
memorysync delete m_60632 --user alice --yesmemorysync delete --all --user alice # previews, deletes nothing
memorysync import
Bulk load memories from a JSON or JSONL file.
memorysync import <file> [--user <id>] [--batch-size <n>] [--resume] [--async]
Each record needs a text field, and may carry metadata, tags, source, event_type and importance. Every record in one import belongs to the same end user, from --user or your configured default. Validates the whole file before sending anything, and reports per-row errors with line numbers rather than failing on the first bad row. Pass --resume to make re-running the same file safe: each record is sent with an identifier the server remembers, so rows that already landed are reported as skipped instead of being stored a second time. Pass --async for a large file: the file is uploaded once and processed in the background, and you get a job id to poll with `memorysync import-status`.
| Flag | What it does |
|---|---|
-u, --user <id> | End user this memory belongs to. Falls back to the configured default. |
--batch-size <n> | Records per request. Default 50. |
--resume | Send a per-record identifier so re-running the same file skips rows already stored. |
--ref-field <name> | Field holding each record’s own id, used by --resume. Default: id, then _id, then uuid. |
--async | Upload the file and return a job id instead of waiting. Use for large files. |
--wait | With --async, poll until the job finishes. |
--continue-on-error | Keep going after a failed batch. |
--dry-run | Validate the file and report what would be sent. |
memorysync import memories.jsonl --user alice --dry-runmemorysync import memories.jsonl --user alice --resumememorysync import memories.jsonl --user alice --resume --async --wait
Consumes plan quota: add_requests. See memorysync quota for headroom.
memorysync migrate
Move an account from Mem0, Supermemory or Zep into MemorySync.
memorysync migrate <provider> [--file <path> | --key <key>] [--dry-run]
Reads an export from disk, or pulls the account from the provider directly with their API key, maps every record onto a MemorySync memory, and writes each one into the end-user scope it belongs to. The source id becomes a client reference, so re-running the same migration recognises what already landed instead of storing it twice — a run interrupted halfway is finished by running it again. Labels become tags, and the original id and timestamp are kept in metadata so the two systems stay reconcilable. Anything whose owner cannot be determined stops the run rather than being guessed at, because a record written into the wrong scope is unreachable by the person it belongs to. Always start with --dry-run: it reports the per-user breakdown and every unusable record without writing anything.
| Subcommand | What it does |
|---|---|
mem0 | Mem0 memories, grouped by their user_id. |
supermemory | Supermemory documents, grouped by their scope container tag. |
zep | Zep episodes, grouped by the user graph they came from. |
| Flag | What it does |
|---|---|
--file <path> | An export from the provider, on disk. Use instead of --key. |
--key <key> | The provider’s API key, to pull directly. Falls back to MEM0_API_KEY, SUPERMEMORY_API_KEY or ZEP_API_KEY. |
--source-user <id> | Migrate only this user from the source provider, and use it as the scope for records that name no user. |
--scope-tag-prefix <prefix> | supermemory: the container-tag prefix that identifies an end user. Default "user_". |
--include-source <list> | zep: also migrate these episode sources, comma separated. json, fact_triple. |
--role <type> | zep: only migrate episodes with this role type, such as user. |
--batch-size <n> | Records per request. Default 50. |
--dry-run | Report what would be written, and write nothing. |
--continue-on-error | Migrate the usable records instead of refusing the whole file. |
memorysync migrate mem0 --file mem0_export.json --dry-runmemorysync migrate supermemory --key sm-xxxx --dry-runmemorysync migrate zep --key z-xxxx --role user
Consumes plan quota: add_requests. See memorysync quota for headroom.
memorysync import-status
Check a background import, or list recent ones.
memorysync import-status [<job-id>] [--wait] [--cancel]
With a job id, reports progress and per-outcome counts. Without one, lists recent imports newest first. Pass --wait to poll until the job finishes, and --cancel to ask the worker to stop between batches — records already imported stay imported.
| Flag | What it does |
|---|---|
--wait | Poll until the job reaches a final state. |
--cancel | Ask the worker to stop between batches. |
--limit <n> | How many recent jobs to list. Default 20. |
memorysync import-statusmemorysync import-status 3f9a1c7e-0b2d-4a51-9e88-1c2d3e4f5a6b --wait
memorysync export
Write a user's memories to a file or stdout.
memorysync export [--user <id>] [--out <path>]
| Flag | What it does |
|---|---|
-u, --user <id> | End user this memory belongs to. Falls back to the configured default. |
--out <path> | Write here instead of stdout. |
--format <json|jsonl|csv> | Serialization. Default jsonl. |
memorysync export --user alice --format jsonl --out backup.jsonl
Consumes plan quota: retrieval_requests. See memorysync quota for headroom.
memorysync quota
Show plan usage and when the cycle resets.
memorysync quota
Worth checking when writes appear to succeed but nothing is stored. Over a plan limit the API returns success with an empty result rather than an error, so an assistant never reports billing state to an end user. This command is how you see that from the outside.
memorysync status
Check the credential, the API and the active scope.
memorysync status
memorysync doctor
Diagnose setup problems and say how to fix them.
memorysync doctor
Checks credential storage and file permissions, DNS, TLS, API reachability, clock skew, quota headroom, project binding and Node version, then prints the first thing worth fixing.
memorysync whoami
Print the identity and scope in use.
memorysync whoami
memorysync project
List and select projects.
memorysync project <list|use> [id]
| Subcommand | What it does |
|---|---|
list | List projects in the tenant. |
use | Set the default project for this profile. |
memorysync project listmemorysync project use proj_8de0eb70b4f64e10
memorysync source
Inspect and control connected knowledge sources.
memorysync source <list|status|sync|pause|resume> [id]
GitHub, Slack, Notion, Google Drive, OneDrive, Granola, Amazon S3 and crawled sites. No competitor exposes connectors from a CLI, so this has no equivalent elsewhere.
| Subcommand | What it does |
|---|---|
list | List connected sources. |
status | Show sync state and last run for one source. |
sync | Trigger a sync now. |
pause | Pause syncing. |
resume | Resume syncing. |
memorysync source listmemorysync source status github
memorysync event
Track asynchronous ingestion.
memorysync event <status|wait> <memory-id>
| Subcommand | What it does |
|---|---|
status | Report where a memory is in the pipeline. |
wait | Block until a memory is searchable or the timeout passes. |
memorysync event wait m_60632 --timeout 60000
memorysync config
Read and edit local configuration and profiles.
memorysync config <show|get|set|unset|profiles|use-profile|delete-profile|path>
| Subcommand | What it does |
|---|---|
show | Print the active config with secrets redacted. |
get | Print one value. |
set | Set one value. |
unset | Remove one value. |
profiles | List profiles. |
use-profile | Switch the active profile. |
delete-profile | Remove a profile and its stored key. |
path | Print the config file location. |
memorysync config showmemorysync config use-profile staging
memorysync mcp
Connect MemorySync MCP to your AI clients.
memorysync mcp <install|list|remove>
Delegates to memorysync-mcp-install, so one tool sets up both the API and MCP.
| Subcommand | What it does |
|---|---|
install | Write MCP config for every detected client. |
list | Show which clients were detected. |
remove | Remove the MemorySync MCP entries again. |
memorysync mcp listmemorysync mcp install
memorysync completion
Print a shell completion script.
memorysync completion <bash|zsh|fish|powershell>
| Subcommand | What it does |
|---|---|
bash | Bash completion script. |
zsh | Zsh completion script. |
fish | Fish completion script. |
powershell | PowerShell completion script. |
memorysync completion zsh > "${fpath[1]}/_memorysync"
memorysync help
Show help. With --json, print the whole command tree.
memorysync help [command] [--json]
memorysync version
Print the version.
memorysync version
Use it inside an agent
Put --json (or --agent) before the command name. Every command then answers with one envelope on stdout, whether it succeeded or failed, with no colour and no spinners.
memorysync --json search "preferences" --user alice | jq '.data[].text'
{"status": "success","command": "search","duration_ms": 134,"scope": { "user": "alice", "profile": "default" },"count": 2,"data": [{ "id": "m_60632", "text": "Prefers TypeScript", "score": 0.97 }],"quota": {"metric": "retrieval_requests","used": 12,"limit": 1000,"exhausted": false}}
Results are always an array under data, for every command, so .data[] works everywhere. Failures use the same envelope with status: "error" and a non-zero exit, so one code path handles both outcomes.
memorysync help --json returns the entire command tree, so an agent can discover the surface for itself rather than being told about it in a prompt.
Exit codes
Distinct per cause, so a script can branch without parsing stderr.
| Code | Meaning | Retry? |
|---|---|---|
0 | Success. | — |
1 | Unclassified failure. | Maybe |
2 | Usage: unknown command, bad flag, missing argument. | No |
3 | Authentication: missing, wrong, expired or revoked key. | No |
4 | Plan limit reached. Nothing was stored or returned. | Not until reset |
5 | Network: unreachable, or timed out. | Yes |
6 | Not found. | No |
130 | Interrupted. | — |
memorysync add "$FACT" --user "$USER_ID"case $? in0) echo "stored" ;;3) echo "credential problem"; exit 1 ;;4) echo "out of quota - nothing was stored"; exit 1 ;;5) echo "network problem, retrying"; sleep 5 ;;esac
Output formats
Set with -o. Every command accepts all five, so a script never has to remember which command refuses which format.
text- Human-readable, with colour when the terminal supports it. The default.
table- Aligned columns, with long values truncated to keep rows on one line.
json- The raw structured result, for piping to jq.
yaml- The same data, easier to read at a glance for nested objects.
quiet- Nothing on stdout. Use the exit code.
Profiles
For more than one environment or account, without juggling exported variables in separate shells.
memorysync init --profile staging --api-key ms_live_xxx --user alicememorysync config profilesmemorysync config use-profile stagingmemorysync --profile production status
Precedence, highest first: explicit flags, environment variables, the profile, then defaults. Environment beats the profile deliberately, so a CI image cannot be steered by a config file that happens to be baked into it.
Deleting
delete previews by default and changes nothing until you pass --yes. The preview is the server's own dry run, so what it lists is exactly what a confirmed run removes.
memorysync delete m_60632 --user alice # previews, deletes nothingmemorysync delete m_60632 --user alice --yes # performs itmemorysync delete --all --user alice # previews the whole scope
Connected sources
Inspect and drive the connectors feeding memory — GitHub, Slack, Notion, Google Drive, OneDrive, Granola, Amazon S3 and crawled sites — without opening the dashboard.
memorysync source listmemorysync source status githubmemorysync source sync githubmemorysync source pause slack
Connecting a new source needs a browser round trip for OAuth, so that stays in the dashboard. A CLI that half-connected a source would be worse than one that does not try.
Shell completion
# bashmemorysync completion bash > /etc/bash_completion.d/memorysync# zshmemorysync completion zsh > "${fpath[1]}/_memorysync"# fishmemorysync completion fish > ~/.config/fish/completions/memorysync.fish# PowerShell — add to your profilememorysync completion powershell | Out-String | Invoke-Expression
Start a new shell afterwards for it to take effect.
When something is wrong
Start with doctor. It checks the credential and where it is stored, file permissions, DNS, API reachability, quota headroom, the project binding and your runtime version — Node or Python, whichever package you installed — then prints what to fix. It exits 0 even when checks fail, because diagnosing is what it was asked to do.
memorysync doctor
| Symptom | Cause | Fix |
|---|---|---|
| "command not found", right after a successful install | npm's or pipx's bin directory is not on PATH. | See Install. Or use npx memorysync-cli and skip PATH entirely. |
| Exit 3, "No API key found" | No credential in the environment, the keychain or the config directory. | Run memorysync init, or set MEMORYSYNC_API_KEY. |
| Exit 2, "This command needs an end user" | Memory is scoped per user and none was given. | Pass --user, or set a default during init. |
| Exit 4, or writes that store nothing | A plan limit is reached, and the API degrades silently by design. | Run memorysync quota to see usage and the reset date. |
| add succeeds but search finds nothing | Embedding is asynchronous, so a new memory is briefly not searchable. | Use add --wait, or memorysync event wait <id>. |
| add returns a status of skipped | Extraction discarded it as filler, or merged it into a near-duplicate. | Not a failure and not worth retrying. Store a concrete, durable statement. |
| Exit 5 on every command | The API is unreachable: DNS, a proxy, or an egress rule. | memorysync doctor separates DNS from the API call. |
Environment variables
| Variable | Effect |
|---|---|
MEMORYSYNC_API_KEY | Credential. Overrides anything stored. |
MEMORYSYNC_BASE_URL | API base URL. |
MEMORYSYNC_USER_ID | Default end user. |
MEMORYSYNC_PROJECT_ID | Default project. |
MEMORYSYNC_PROFILE | Profile to use. |
MEMORYSYNC_OUTPUT | Default output format. |
MEMORYSYNC_TIMEOUT | Per-request timeout, in milliseconds. |
MEMORYSYNC_CONFIG_DIR | Config location. Defaults to ~/.memorysync for both packages. |
NO_COLOR | Disable colour. Wins over the next one. |
MEMORYSYNC_FORCE_COLOR | Keep colour when stdout is not a terminal, for a CI runner that renders ANSI. |
Every variable here is read by both packages, under the same name. --user and --project also accept the shorter MEMORYSYNC_USER and MEMORYSYNC_PROJECT as aliases; the _ID forms above take precedence and are the ones to use.
Where to go next
- MemorySync MCP
- Give an assistant the same memory through the Model Context Protocol, instead of shelling out.
- SDKs
- Call the API from your own code, in Python or TypeScript.
- API reference
- Every endpoint the CLI wraps, with request and response shapes.