recall searches local coding-agent sessions and explicit, durable memories from one command. It supports session data from Pi, Codex, OpenCode, Claude Code, and Grok Build.
Memory persistence is always manual. recall does not extract memories, summarize sessions, inject prompts, or write memory unless a user runs remember, edit, forget, or restore.
- Search sessions and memories together while keeping their results and scores separate.
- Search exact IDs, SQLite FTS5 text, character n-grams, and local Ollama embeddings.
- Keep durable memories as versioned JSON files.
- Rebuild the disposable local memory search index from canonical JSON.
- Scope memories to a normalized Git remote or make them global.
- Detect Syncthing conflict copies without changing them.
- Keep all data and embedding requests on the local machine.
Lexical and fuzzy search work without Ollama. Failed embeddings remain pending for a later indexing run.
- Go 1.25 or later
- Git for project-scoped memory and project-default searches
- Ollama for optional semantic search
- The
all-minilmmodel for the default embedding configuration
Install the default model:
ollama pull all-minilmBuild and install:
git clone https://github.com/Thelost77/recall.git
cd recall
make check
make installmake install installs recall to ~/.local/bin by default. Set PREFIX or INSTALL_DIR to use another path.
To install with Go:
go install github.com/Thelost77/recall/cmd/recall@latestIndex sessions and refresh memories:
recall indexSearch both sources. Each source receives its own result limit and ranking pass:
recall "database migration decision"Search sessions only. The short and long forms are equivalent:
recall -s "database migration decision"
recall session "database migration decision"Search memories only:
recall -m "database migration decision"
recall memory "database migration decision"Use -- when a bare query starts with a command word:
recall -- memorySearch output uses separate sections:
MEMORIES
1. m_ab12cd [project]
We avoided SQLite triggers because...
SESSIONS
1. [pi] Database investigation
2026-08-03
...
Combined JSON also keeps sources separate:
{
"query": "query",
"memories": { "results": [] },
"sessions": { "results": [] },
"warnings": []
}Common search options are:
--limit
--json
--explain
--lexical-only
--semantic-threshold
--all-projects
Session filters are:
--path
--harness
--role
--since
--before
Memory search supports --project PATH, --global, and --include-archived. Options that do not apply to the selected source are rejected. Put flags before the query; the CLI uses Go standard flag syntax.
Inside a Git repository, new recall session searches default to that repository path. Memory searches include the current project and global memories. Outside Git, memory searches include global memories by default. Use --all-projects to search every project.
Create a project memory in the current Git repository:
recall remember "We keep migrations reversible until the next release."Select another project, create a global memory, or include a source reference:
recall remember --project ~/work/api --source issue:481 "The API uses cursor pagination."
recall remember --global "Use UTC in operational runbooks."Memory content can come from arguments or standard input:
printf '%s\n' "The release job requires an annotated tag." | recall remember --globalInspect and revise memories:
recall list
recall list --all-projects --include-archived
recall show m_ab12cd
recall edit m_ab12cd "Updated content"
recall history m_ab12cd
recall forget m_ab12cd
recall restore m_ab12cdedit appends a revision and preserves prior content. forget archives without deleting. restore removes the archived state. List and search omit archived memories unless --include-archived is set. A unique memory ID prefix is accepted; an ambiguous prefix is rejected.
Project identity comes from Git. Common SSH and HTTPS origin forms normalize to the same key, such as github.com/owner/repository. A project without an origin uses a local/<repository-name> key rather than an absolute path. Outside Git, use --global or select a Git repository with --project.
Canonical memory records and local search data have different lifecycles:
Canonical records: ~/.local/share/recall/memories/records/*.json
Disposable memory index: ~/.local/share/recall/memory-index.sqlite
Disposable session index: ~/.local/share/recall/index.sqlite
Each canonical JSON file contains its schema version, opaque m_ ID, scope, project identity, timestamps, archive state, and complete revision history. Writes use a temporary file, file sync, and atomic rename. Embeddings and search data never enter canonical JSON.
The SQLite memory index is derived data. Delete it to rebuild search from JSON:
rm -f ~/.local/share/recall/memory-index.sqlite{,-wal,-shm}
recall indexIndex rebuilds never delete canonical records. recall index --rebuild rebuilds both derived indexes.
A Syncthing directory can hold canonical records:
memory_directory = "~/Sync/recall"
memory_index = "~/.local/share/recall/memory-index.sqlite"Do not put the SQLite memory index in Syncthing. SQLite databases, WAL and SHM files, FTS tables, embeddings, and caches are device-local derived data. Synchronizing a live SQLite database can corrupt it and create needless conflicts.
recall detects standard Syncthing conflict filenames. Search indexes only the canonical JSON file and reports the canonical path plus every conflict-copy path. edit, forget, and restore refuse to change an affected memory. status and doctor report conflicts as warnings. Resolve conflict files manually; recall never merges, renames, overwrites, or deletes them.
An invalid changed canonical file is reported and retried on the next refresh. If the local index contains an older valid version, search keeps that last good row. Canonical JSON remains the source of truth.
The preferred configuration file is ~/.config/recall/config.toml:
index = "~/.local/share/recall/index.sqlite"
memory_directory = "~/.local/share/recall/memories"
memory_index = "~/.local/share/recall/memory-index.sqlite"
[embedding]
url = "http://127.0.0.1:11434"
model = "all-minilm"
threshold = 0.60
[harnesses]
pi = true
codex = true
opencode = true
claude = true
grok = true
[sources]
pi = "~/.pi/agent/sessions"
codex = "~/.codex/sessions"
claude = "~/.claude/projects"
grok = "~/.grok/sessions"
# Leave empty to use `opencode db path`.
opencode = ""Configuration precedence is:
- command flags;
RECALL_CONFIG;~/.config/recall/config.toml;- defaults.
The embedding endpoint must use a loopback address. This prevents accidental uploads of private session or memory text. The default semantic threshold is 0.60.
recall status
recall doctorstatus reports session statistics, canonical records, active and archived memories, stored and pending embeddings, invalid records, conflicts, and storage paths.
doctor checks session adapters, both index schemas, canonical memory access, permissions, Ollama access, embedding dimensions, invalid records, and Syncthing conflicts. It reports conflicts without modifying them.
Application-created data directories use mode 0700. Canonical JSON and SQLite files use mode 0600. Existing user-selected Syncthing directories are not forcefully re-permissioned.
Session indexes contain derived copies of private session text. Memory indexes contain derived copies of explicit memory content. Ollama requests are restricted to loopback addresses. There is no cloud service, automatic prompt injection, automatic recall, or automatic memory write.
Recommended agent policy:
Agents may search recall when prior project knowledge may matter.
Agents must not add, edit, archive, or restore memories unless the user explicitly requests it.
The default adapters read:
| Harness | Default source |
|---|---|
| Pi | ~/.pi/agent/sessions/**/*.jsonl |
| Codex | ~/.codex/sessions/**/*.jsonl |
| OpenCode | The database returned by opencode db path |
| Claude Code | ~/.claude/projects/**/*.jsonl |
| Grok Build | ~/.grok/sessions/<encoded-cwd>/<session-id>/updates.jsonl |
Grok metadata comes from the sibling summary.json. When GROK_HOME is set and sources.grok is left unset, the default root is $GROK_HOME/sessions. A group directory whose encoded name was replaced by a hash uses the .cwd file in that group.
The session index includes user messages, assistant prose, compaction summaries, and useful metadata. It excludes tool output, reasoning, patches, snapshots, base64 data, and duplicate protocol events.
Run manual indexing first. The existing systemd user timer in contrib/systemd can run recall index; do not install a second timer for memory indexing.
mkdir -p ~/.config/systemd/user
cp contrib/systemd/recall-index.* ~/.config/systemd/user/
systemctl --user daemon-reload
systemctl --user enable --now recall-index.timerThe timer does not start Ollama. Lexical indexing still succeeds when Ollama is unavailable.
Run all checks and build:
make check
make buildTests use temporary directories and fake embedders. They do not inspect real sessions or require Ollama.
Recall uses SemVer tags with a leading v. Write notes in docs/releases/vX.Y.Z.md, commit them to main, then run:
./scripts/release.sh v0.2.1The script checks the worktree, creates an annotated tag, and pushes it. GitHub Actions runs GoReleaser, which attaches multi-platform archives and checksums to the GitHub Release. Dry-run locally with:
goreleaser release --snapshot --clean --skip=publish