Skip to content
Menu

Product

Solutions

Integrations

Developers

Language

Product

What it stores, and what leaves your machine

A default install listens only on your machine and has no telemetry. It redacts recognized credentials before storing captured text, but filtering can miss sensitive information. Remote servers and optional cloud providers change where data goes.

The default is local.

Install it, run it, and the only thing that can talk to it is your own machine.

  • Loopback only

    The server binds 127.0.0.1:49374. No process outside the machine can reach it. A fresh install still mints a bearer token into an owner-only file, which the hooks and the CLI read, so nothing is open even on loopback.

  • No telemetry

    The ai-memory binary has no analytics, crash reporting or usage tracking. Default local capture and search do not send project content to external model providers.

  • One directory you own

    Wiki pages and the SQLite file live under one data directory. New directories are created 0700 and new files 0600 on Unix.

  • No encryption at rest

    Stored data relies on filesystem permissions. Existing installs are not chmodded for you. Use disk encryption if you need protection when the machine is off.

Captured text is filtered before storage.

Hook payloads are untrusted text. They pass through a sanitizer that redacts recognized credentials and caps their size. It can miss sensitive information.

Hook payload

sanitize()

Secrets dropped

Stored

Size capped

The sanitizer is the only path from a hook payload into the store.
  • One way in

    The stored type can only be built by sanitize(). Code that skips the privacy strip does not compile.

  • Secrets are replaced

    Matches become typed markers such as [REDACTED:github_token] or [REDACTED:jwt]. That covers secrets inside JSON and Windows credential paths, and terminal escape sequences are stripped. The strip is best effort.

  • Sizes are capped

    Tool excerpts stop at 2 KB and prompts at 16 KiB. A 16 KiB backstop applies to every stored body after redaction.

  • Tool inputs are not kept

    PreToolUse events never retain commands, arguments, paths or input bodies. Observations are an audit trail, never a full transcript. The opt-in [ingest] index_file_paths adds one field: the checkout-relative path of the single file a kept file tool named, never its content, and an ignored path still sends nothing.

Keep a path or a repository out

  • A [capture] block in .ai-memory.toml lists paths to ignore. Matching events are dropped on your machine, before the spool, the network and the logs.
  • Allowlist mode inverts it: a repository without the file emits no events at all.
  • An invalid rule set falls back to metadata only. It never applies half a policy.
  • File paths and recognized shell arguments are checked lexically. Symlinks, shell variables and scripts read from files can evade matching; prompts are not path-filtered. This is best-effort capture filtering, not complete DLP.
  • Assistant output is never stored by default. It takes a server flag and a client flag together.
  • Backfill and managed-workstream imports apply the same capture rules to tool calls and results. Excluded calls are omitted; calls the policy cannot prove safe keep only tool-family metadata.
per-repository capture rules
# .ai-memory.toml in the repository
[capture]
ignore_paths = ["private/**", "~/personal-notes/**"]

# Or capture only repositories that opt in
ai-memory install-hooks --apply --capture-mode allowlist

Match protection to your deployment

Remote access needs both authentication and TLS, including on a LAN. Apply every requirement that matches your setup before connecting clients.

  1. One person, one machine

    Loopback, a token in a file

    ai-memory init creates the token at <data_dir>/auth-tokens/default and the hooks, the CLI and the MCP bridge read it from there. An install from before 3.0 keeps running without auth until you run ai-memory auth enable, which mints the token and re-registers every client.

  2. A homelab box or a second machine

    Bearer token for the LAN

    Create a token with ai-memory generate-auth-token and set AI_MEMORY_AUTH_TOKEN. It is compared in constant time and protects /mcp, /hook, /handoff and the admin and API routes. Set AI_MEMORY_ALLOWED_HOSTS as well; it blocks DNS rebinding and does not replace the token.

  3. Anything beyond loopback

    TLS through a reverse proxy

    ai-memory does not terminate TLS, by design. Bearer tokens are not encrypted on the wire, so put Caddy, nginx or a Cloudflare Tunnel in front. The repo ships compose templates for Caddy and cloudflared. Set AI_MEMORY_AUTH__SECURE_COOKIE=true when people sign in from other machines.

  4. More than one person writes

    Accounts and API keys

    Passwords are stored as Argon2id hashes. Each machine gets an aim_ key that is printed once and never shown again. ai-memory api-key rotate <id> makes the old key return 401 at once. The first account turns every /admin/* route root only.

  5. Your team already has Keycloak, Okta or Entra ID

    OIDC device auth for hooks

    Native hooks and the CLI can carry a token from ai-memory auth login oidc-device. The server does not validate OIDC tokens itself, so this needs an OIDC-aware gateway in front of it. It is hook and CLI auth through a gateway, and the server has no built-in SSO login.

What leaves the machine, and when.

These settings can send memory content to a model provider; they are off by default. Remote-server hooks, configured admission webhooks and your own backup destinations are separate data paths to review.

PathWhat is sentHow it is turned onDefault
Remote embeddingsThe full text of every stored page. Switching later also backfills the existing corpus. This path is not sanitized the way the others are.embedding_provider = openai | voyage | google | openai-compatOff
Assistant output captureThe assistant’s final-turn text, and only if you have also configured a cloud LLM. Global to the install, Claude Code and Codex only.capture_assistant on the server and install-hooks --capture-assistant on the clientOff
LLM rerankEach live query plus up to 30 bounded page titles and snippets. The query is not redacted, because redaction could change its meaning.AI_MEMORY_RERANKER=llmOff
LLM consolidation and lintPrompts built from stored observations and pages go to whichever provider you chose. Point it at a local model and nothing leaves.AI_MEMORY_LLM_PROVIDEROff

Your machine

Hooks

Wiki and index

Local embedder

Third parties

Wiki and index

Cloud embeddings

Cloud LLM

LLM rerank

Opt-in, off by default

Solid lines stay inside. Dashed lines exist only after you change a setting.

Default local capture and search send no project content to a model provider. If you choose a cloud provider, review its terms and data handling. See the project’s data-handling notes.

Who wrote it, and how to remove it.

Attribution and audit

  • With accounts on, each write carries its author. Pages record author_id and a last_modified_by block in the frontmatter.
  • Every mutation lands in an audit_log table, with the user’s identity on attributed rows.
  • The wiki is a git repository, so every page change is also a commit you can diff and restore.
  • Admission webhooks receive the actor and can reject an operation.
  • There is no audit log screen yet. The rows are in SQLite.

What a purge removes

Purge logically deletes data from the selected project. History and earlier backups can retain copies. Separately, retention rules can remove unused session pages, and explicit expiry dates can remove other pages. Without --confirm, a purge only previews what it would remove.

purge
# Remove one session
ai-memory purge-session --workspace default --project my-app --session-id <uuid> --confirm

# Remove a whole project
ai-memory purge-project --project experimental --confirm
After a purgeDefaultWith --compact
Reachable through the API or MCP toolsNoNo
Returned by searchNoNo
Live markdown file in the wikiNo, best effortNo, best effort
Bytes still inside memory.sqliteYes, in free pagesNo
Text still in the wiki git historyYesYes
Present in backups taken earlierYesYes

--compact is not forensic erasure. To remove text from history you rewrite the wiki’s git history and rotate your backups yourself. Lifecycle operations has the full procedure.

Where it stops.

Reporting a vulnerability

  • Do not open a public issue. Open a private security advisory on GitHub.
  • You get a response within 7 days. The target for a patch is 30 days, with credit in the changelog unless you decline.
  • Only the latest release receives security fixes.
  • Release assets ship with SHA-256 files, and CI actions are pinned to reviewed commits.

Threat model and policy in SECURITY.md

Questions and answers

Does ai-memory send my code or prompts anywhere?

By default, ai-memory keeps captured project content on your machine. If you connect to a shared server, it sends that content there. Optional cloud embeddings or language-model features send data to the providers you configure. Your coding agent has its own data settings and provider connections.

Does the local embedder need the network?

On first start, the local embedder downloads about 87 MB of model files from Hugging Face and verifies their checksums. No project content is sent for that download. Set embedding_provider = "none" or supply the model files yourself to avoid it.

Are secrets stored?

Every hook payload passes a sanitizer before storage. Recognized credentials are replaced with typed [REDACTED:kind] markers and bodies are size capped. The sanitizer is a best-effort credential strip and gives no guarantee.

Can I delete a session for good?

Purge is a logical delete. The content stops being reachable and searchable, but the text stays in the wiki git history and in earlier backups. The --compact flag clears the SQLite free pages and is not forensic erasure.

Is ai-memory multi-tenant?

No. Project-level grants can restrict database-user accounts, but this remains a single-tenant service. Root has access to every project, and trusted-proxy deployments enforce access at the proxy. Use separate servers for teams that need independent isolation.

Try it on loopback first.

Start with a local, non-sensitive project. Review what is captured before connecting a shared server or a cloud provider.