Raw capture โ€” raw/memento.md


url: https://github.com/latentsignal-org/memento date_fetched: 2026-07-05 backfilled: true


Memento turns years of email into source-attributed living documents. It is a local-first knowledge layer over a msgvault email archive, built for the long-term signal that ordinary inboxes and keyword search leave buried. Memento is not an email client and does not rebuild your inbox. It organizes long-term email history into memory surfaces:

Memento depends on kenn-io/msgvault for mail acquisition, archive storage, full-text search, semantic/vector search, and sync.

Watch the demo: https://www.youtube.com/watch?v=Ms1KeAYCN2A

Memento combines deterministic extraction with agents that know where to look.

Memento runs locally as a single Go process. The binary embeds the statically built web UI and serves it together with the API on one localhost origin, reading your msgvault archive while writing only Memento-owned tables. No Node.js is needed at runtime โ€” only for building or developing the frontend.

flowchart LR
  Browser["Browser<br/>http://127.0.0.1:8787"]
  Go["memento (Go)<br/>embedded web UI + API<br/>rollups + durable agents"]
  Store[("SQLite<br/>msgvault tables read-only<br/>memento_* tables owned")]
  Msgvault["msgvault<br/>archive acquisition, FTS, sync"]
  LLM["Configured LLM provider<br/>Gemini or OpenAI-compatible"]
  Browser --> Go
  Go --> Store
  Msgvault --> Store
  Go -. optional generation .-> LLM
Key design choices:

For release binaries:

For building from source:

Install references:

Start with the demo mode:

./memento app --demoIt uses a populated synthetic archive, requires no real email, and opens the main People, Projects, Newsletters, Concepts, and Home surfaces at http://127.0.0.1:8787. It is the safest way to review the product shape before connecting a real msgvault archive.

Download the archive for your platform from GitHub Releases, extract it, and:

./memento app --demoThis starts a populated synthetic archive and opens http://127.0.0.1:8787 in your browser. It does not touch your real msgvault data, so it is the safest first run.

When you are ready to use your own archive, confirm msgvault can see it:

msgvault statsThen start Memento normally:

./memento appIf the archive has not been initialized for Memento yet, the app opens the first-run onboarding wizard at /onboard. The wizard verifies the archive, collects your identity, configures the AI provider, and builds the local memory indexes.

Run commands from the repository root.

pnpm install
pnpm package        # builds the UI, embeds it, compiles ./memento
./memento app --demo

pnpm package runs next build (static export to out/), stages the output into backend/internal/webui/dist, and compiles the Go binary with the UI embedded.

If msgvault already has a configured archive:

./memento appIf the database has not completed onboarding, Memento routes you to /onboard.

For the best retrieval behavior, also run msgvault's local HTTP API in another terminal:

msgvault serveThen point Memento at it with MEMENTO_MSGVAULT_API_URL. The exact URL depends on your msgvault configuration; use the local URL printed by msgvault serve. Memento still works without this API by reading SQLite directly and shelling out to the msgvault CLI, but the HTTP API path avoids repeated subprocesses and lets Memento run more read-only agent tools concurrently.

You can also initialize from the terminal:

./memento init``init is safe to re-run after pulling new mail into msgvault.

Copy the sample env file when you want to configure values before running ./memento init or ./memento serve:

cp .env.sample .envFor most local setups, these are the important entries:

Variable Required? Purpose
MEMENTO_MODEL_PROVIDER Yes for LLM features gemini,openai_compatible, orfakefor tests/demo simulation.
MEMENTO_AGENT_MODEL Yes for LLM features Default model used by Go agents.
MEMENTO_MODEL_API_KEY Provider-dependent API key for Gemini or an OpenAI-compatible provider.
MEMENTO_MODEL_BASE_URL OpenAI-compatible only /v1API base URL for Ollama, vLLM, LM Studio, Cerebras, OpenCode Zen, OpenAI, or another compatible gateway.
MEMENTO_BACKEND_URL Dev only Backend URL the next devproxy targets, normallyhttp://127.0.0.1:8787.
MEMENTO_WEB_DIR Optional Serve the web UI from a directory on disk instead of the embedded copy (frontend iteration).
MEMENTO_MSGVAULT_DB Optional Direct path to a msgvaultSQLite database.
MEMENTO_MSGVAULT_HOME Optional Directory containing msgvault.dbwhen not using the default msgvault config.
MEMENTO_MSGVAULT_API_URL Optional, recommended Local msgvault serveURL for API-backed search and message fetches.
MEMENTO_MSGVAULT_API_KEY Optional Bearer token for the msgvault HTTP API when configured.

The backend resolves the archive database in this order:

MEMENTO_MODEL_PROVIDER=gemini
MEMENTO_MODEL_API_KEY=your-key
MEMENTO_AGENT_MODEL=gemini-3.5-flash
MEMENTO_MODEL_PROVIDER=openai_compatible
MEMENTO_MODEL_BASE_URL=http://127.0.0.1:11434/v1
MEMENTO_MODEL_API_KEY=ollama
MEMENTO_AGENT_MODEL=your-tool-calling-model

The selected model must support tool calls. Official OpenAI API usage is also routed through openai_compatible; when MEMENTO_MODEL_BASE_URL points at api.openai.com and MEMENTO_MODEL_REASONING_EFFORT is set, Memento uses the Responses API reasoning path.

Variable Default Purpose
MEMENTO_<NAME>_MODEL unset Per-agent model override for COLLECTOR,PROJECT,CONCEPT,PERSON, orMEMENTO.
MEMENTO_AGENT_STEP_LIMIT 20 Maximum model/tool loop steps per run.
MEMENTO_AGENT_CONTEXT_LIMIT_TOKENS 128000 Context budget denominator reported by context_status.
MEMENTO_AGENT_STALE_AFTER_MS 120000 Stale non-terminal run timeout.
MEMENTO_AGENT_DECISION_TIMEOUT_MS 90000 Human backfill decision timeout.
MEMENTO_MODEL_REASONING_EFFORT unset OpenAI Responses reasoning effort, or DeepSeek V4 effort normalization. Generic compatible gateways ignore it.
MEMENTO_MODEL_THINKING unset DeepSeek V4 thinking toggle, enabledordisabled.
MEMENTO_MODEL_REPLAY_REASONING off Replays provider reasoning_contentwhen required.
MEMENTO_AGENT_VERBOSE_LOGS off Extra provider request logs and raw SSE lines.

Other optional settings in .env.sample:

Variable Purpose
MEMENTO_ALLOWED_DEV_ORIGINS Additional comma-separated origins accepted by Next.js during local development.
MEMENTO_REFRESH_TRACE Print refresh-stage timing traces to stderr.

See docs/agent-runtime.md for the full runtime contract, docs/agent-loop-and-prompts.md for the current agent workflows, and docs/agent-tools-reference.md for the tool catalog.

Memento uses msgvault as its archive substrate rather than implementing its own mail search engine.

./memento doctor
./memento stats

doctor checks archive resolution, schema state, provider configuration, and common env mistakes. stats prints the resolved archive path plus table counts.

./memento refreshIndex pages read from materialized rollup tables:

Use this after changing person-resolution logic, bot filtering, classifier thresholds, or after a large archive update.

./memento person-resolve --persist
./memento people-candidates --persist
./memento refresh --people
./memento person-show --email someone@example.com
./memento person-link --email alias@example.com --person 42 --note "same person"
./memento person-split --email newsletter@example.com --name "Newsletter Name"
./memento refresh --people

Manual links are locked overrides and survive later resolver runs.

./memento person-merge-suggest
./memento person-merge --from 3656 --into 3100
./memento refresh --people

person-merge transfers emails, notes, AI facets, narratives, and project memberships from --from into --into.

Projects are user-confirmed. Memento should not auto-create them from a cluster or thread without user confirmation.

./memento project create --name "Heat Pump Install" --slug heat-pump --started 2025-06-11
./memento project add-messages --slug heat-pump --search '"2270 Faircrest"'
./memento project add-person --slug heat-pump --email contractor@example.com --role contractor
./memento project generate --slug heat-pump --llm
./memento refresh --projects

The web app also supports draft-based project creation through /projects/new.

Concepts are opt-in evergreen topics.

./memento concept create \
  --name "AI / LLMs" \
  --slug ai-llms \
  --scope "Generative AI, LLMs, agents, evals, RAG, fine-tuning." \
  --seed "LLM,GPT,Claude,Anthropic,OpenAI"
./memento concept add-messages --slug ai-llms --seed --limit 80
./memento concept generate --slug ai-llms --llm
./memento refresh --concepts

The web app also supports draft-based concept creation through /concepts/new.

./memento newsletter-detect --persist
./memento newsletter-generate --slug the-pragmatic-engineer --llm
./memento refresh --newsletters

The agent runtime lives in Go under backend/internal/agentrunner; the browser talks to it directly over same-origin SSE endpoints. Agent runs are durable: status, steps, tool calls, human decisions, and replayable SSE events are stored in memento_agent_* tables. Browser reloads replay existing events and then tail live events.

Supported provider modes:

Read docs/agent-runtime.md before changing prompts, tools, provider behavior, or run lifecycle code. For a workflow-level guide, read docs/agent-loop-and-prompts.md; for tool parameters and availability, read docs/agent-tools-reference.md.

# Setup
./memento init
./memento reset [--force]
# Diagnostics
./memento doctor
./memento stats
./memento inspect-schema
# Schema and rollups
./memento migrate
./memento refresh [--people] [--projects] [--newsletters] [--concepts]
# Identity pipeline
./memento person-resolve [--persist] [--fuzzy] [--jaro F] [--jaccard F]
./memento people-candidates [--limit N] [--include-excluded] [--persist]
./memento newsletter-detect [--persist] [--min-messages N]
# Person review and overrides
./memento person-show --email E
./memento person-show --id N
./memento person-link --email E --person ID [--note "..."]
./memento person-split --email E [--name N] [--note "..."]
./memento person-merge-suggest [--limit N] [--json]
./memento person-merge --from ID --into ID [--yes]
# Projects
./memento project create --name N --slug S [--started YYYY-MM-DD]
./memento project add-messages --slug S [--search Q | --label L | --thread T | --message-id N]
./memento project add-person --slug S --email E [--role R]
./memento project show --slug S
./memento project generate --slug S --llm
# Newsletters
./memento newsletter-generate --slug S --llm
# Concepts
./memento concept create --name N [--slug S] [--scope "..."] [--seed "k1,k2"]
./memento concept add-messages --slug S [--search Q | --seed | --message-id N] [--limit N]
./memento concept generate --slug S --llm
# Server
./memento app [--port N] [--db PATH] [--no-open]
./memento app --demo
./memento serve [--port N] [--db PATH]
./memento serve --demo
./memento onboard --demo

Common flags:

For frontend work, run the backend and the Next.js dev server side by side:

pnpm build:backend       # once, or after Go changes
./memento serve --demo   # terminal 1: API on :8787
pnpm dev                 # terminal 2: UI on :3000, /api proxied to :8787

Hot reload applies to frontend code through Next.js HMR on :3000. Go changes are not hot reloaded by this repo; rebuild ./memento with pnpm build:backend and restart ./memento serve --demo.

This repo does not currently use Vite. The development server is next dev --webpack, and the production UI is a Next.js static export embedded in the Go binary. A future Vite migration could simplify the frontend if Memento commits to being a pure React SPA, but it would require replacing Next routing, font/image handling, and App Router conventions. Do not mix Vite into the current Next.js app incrementally.

Production builds use the static export served by the Go binary, so verify release-facing changes with pnpm package && ./memento app --demo before shipping.

Checks:

cd backend && go test ./...
pnpm lint
pnpm build

The Playwright E2E suite under tests/ runs against the built binary. Build first, seed the fixture database, then run:

pnpm package        # build binary with embedded UI
pnpm e2e:seed       # create /tmp/memento-e2e.sqlite
pnpm e2e            # run the suite

Confirm the server is running and healthy:

curl http://127.0.0.1:8787/api/healthIn frontend development (pnpm dev), make sure ./memento serve is running and MEMENTO_BACKEND_URL matches its port.

Check the archive path precedence in the Configuration section. If needed, set one explicit value:

MEMENTO_MSGVAULT_DB=/absolute/path/to/msgvault.dbLLM-backed generation needs a configured provider. Either enter a key during ./memento init or edit .env. Local OpenAI-compatible providers may accept a placeholder API key such as ollama.

Rebuild the rollups:

./memento refreshThen hard-refresh the browser.

Split it out and re-run newsletter detection:

./memento person-split --email sender@example.com --name "Newsletter Name"
./memento newsletter-detect --persist
./memento refresh

Use a locked manual link or merge:

./memento person-link --email other@example.com --person 42 --note "same human"
./memento person-merge-suggest
./memento person-merge --from 123 --into 42
./memento refresh --people

reset drops Memento-owned tables only. It does not delete msgvault messages, threads, attachments, labels, or sync state.

./memento reset
./memento init

Use --force only in scripts:

./memento reset --forceMemento is local-first: the server binds to 127.0.0.1, your archive is read locally, and Memento writes only its own memento_* tables. When you configure an LLM provider, excerpts of archive content are sent to that provider during generation. See SECURITY.md.