Skip to content
Menu

Product

Solutions

Integrations

Developers

Language

Product

What it stores, and what leaves your machine

A default install listens on your machine only, strips secrets before anything is written, and has no telemetry. Every path that sends data out is off until you turn it on. This page also lists what the project does not defend against.

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, which is why the default needs no password.

  • No telemetry

    The binary has no analytics, crash reporting or usage tracking. Capture and search make zero network calls.

  • 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

    Version 1 relies on filesystem permissions. Existing installs are not chmodded for you. Use disk encryption if the laptop needs it.

Nothing is stored before it is sanitized.

Hook payloads are untrusted text. They reach the store through one function, and the type system enforces it.

Diagram: a raw hook payload containing keys and passwords enters a single gate labelled sanitize(). Secrets drop out below the gate. A smaller, size-capped observation comes out the other side and is stored.
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.

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.
  • Matching is lexical. Symlinks are not resolved, and prompts and shell commands cannot be tied to a path. This is a capture boundary. It is not complete DLP.
  • Assistant output is never stored by default. It takes a server flag and a client flag together.
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

Add one rung at a time.

Each step exists for a specific situation. Stop at the one that matches yours.

  1. One person, one machine

    Loopback, no auth

    The default. Nothing to configure, because nothing else can connect.

  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. 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.

  4. 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.

  5. 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.

What leaves the machine, and when.

Four paths can send data out. All four are off by default.

Diagram: hooks, the wiki and index, and the local embedder sit inside an enclosure labelled Your machine, joined by solid lines. Dashed lines to cloud embeddings, a cloud LLM and LLM rerank cross the wall through open switches labelled Opt-in, off by default.
Solid lines stay inside. Dashed lines exist only after you change a setting.
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

With none of these enabled there is no third party in the data path. Once you configure a cloud provider, that provider is your processor under your own agreement with it. DATA_HANDLING.md covers the GDPR framing. It is not legal advice.

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 is a logical delete, scoped so that project A can never remove files from project B. Data has no expiry unless a page sets one.

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?

No. There is no telemetry, and capture and search make no network calls. Data leaves the machine only if you turn on remote embeddings, assistant output capture with a cloud LLM, LLM rerank, or a cloud LLM provider for consolidation. All are off by default.

Does a default install make any network request?

One. Since 2.0 the default local embedder downloads an all-MiniLM-L6-v2 model of about 87 MB from Hugging Face on first start. No user data is sent. Set embedding_provider = "none" or place 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. It is a single-tenant service. Accounts give attribution, and every authenticated user can read every project on that server. Run separate servers for people who must not see each other’s data.

Try it on loopback first.

No account and no API key. Nothing can reach it but your own machine.