Privacy-first CLI that turns shell history into searchable memory
Project description
mem
Your shell, remembered.
A privacy-first CLI that captures, searches, and organizes your terminal history
with on-device AI. Nothing ever leaves your machine.
What mem does
mem silently captures every command you type, then lets you search, save, and replay them — scoped to the git repo you're in.
mem deploy # search your history
mem save "cmd" -g ops # save a command to a group
mem run ops # run the group interactively
mem vars set API_KEY # store a secret for saved commands
Unlike Ctrl+R, mem ranks results by frequency, recency, and the repo you're currently in. Unlike cloud-based tools, everything stays on your machine as plain text files in ~/.mem/.
Install
# Homebrew (recommended)
brew install matinsaurralde/tap/mem
# pip
pip install cli-mem
# With AI features (pattern extraction + credential detection)
pip install "cli-mem[ai]"
Then activate the shell hook for your shell:
# zsh
echo 'eval "$(mem init zsh)"' >> ~/.zshrc
source ~/.zshrc
# bash
echo 'eval "$(mem init bash)"' >> ~/.bashrc
source ~/.bashrc
# fish
echo 'mem init fish | source' >> ~/.config/fish/config.fish
source ~/.config/fish/config.fish
That's it. Every command you type is now silently captured with full context (directory, git repo, exit code, duration).
Search
Just type mem followed by any keyword. Results are ranked by your current repo.
mem kubectl # search by keyword
mem "docker compose" # search by phrase
mem deploy -n 20 # more results
mem deploy --json # machine-readable output
1 kubectl apply -f deployment.yaml infra 2h ago
2 docker compose up -d backend 1d ago
3 fly deploy api 3d ago
Patterns
mem automatically learns structural patterns from your history using on-device AI. No manual step needed — extraction runs in the background every 20 commands.
mem kubectl -p
Patterns for "kubectl":
kubectl get <resource>
kubectl describe <resource> <name>
kubectl logs <pod> [--tail=<n>]
kubectl apply -f <file>
Groups
Groups are named collections of commands — like runbooks you can execute.
Save commands to a group
mem save "kubectl get pods -n production" --group k8s --comment "list pods"
mem save "docker compose up -d" -g deploy -c "start services"
Save the last command you ran:
mem save "!" -g troubleshooting
List groups
mem list # show all groups and saved commands
mem list k8s # show commands in a specific group
mem list -g # global scope only
mem list -r # current repo only
mem list --json # JSON output
Run a group
mem run k8s # run interactively (pick one or all)
mem run deploy -y # run all without prompts
Manage groups
mem group rename old new # rename a group
mem group remove k8s # delete a group
mem group copy k8s --global # copy from repo to global scope
mem group edit k8s # open in $EDITOR
Export and import
mem export k8s # copy JSON to clipboard
mem export k8s --format markdown # copy as markdown
mem export k8s --stdout # print instead of clipboard
mem import # import from clipboard (auto-detect format + group name)
mem import -g renamed # import from clipboard with custom group name
mem import runbook.json -g ops # import from file (auto-detects format)
mem import runbook.md -g ops # markdown works too
Variables
Saved commands can contain $VAR_NAME placeholders that get resolved at runtime. Values never get stored in group files.
Save commands with variables
# Variables are detected automatically from $VAR_NAME tokens
mem save "ssh -i ~/.ssh/\$KEY_NAME ubuntu@\$BASTION_HOST" -g ssh
# Set a default value with --var
mem save "kubectl get pods -n \$NAMESPACE" -g k8s --var NAMESPACE=production
# AI detects hardcoded credentials and suggests variables
mem save "curl -H 'Authorization: Bearer eyJhbGci...' https://api.example.com/users" -g api
# Detected possible credential: Bearer token
# Suggested: curl -H 'Authorization: Bearer $API_TOKEN' ...
# Variable name [API_TOKEN]: █
Resolution priority
When mem run encounters variables, it resolves them in this order:
- Inline arguments —
mem run api API_TOKEN=abc123 - Shell environment —
export API_TOKEN=abc123 - Persistent store —
mem vars set API_TOKEN - Default value — from
--var NAME=defaultat save time - Interactive prompt — asks you, only as a last resort
All prompts are collected upfront before any command runs. With --yes, unresolved variables cause an immediate error listing what's missing.
Variable store
For values that persist across sessions but shouldn't be in .zshrc:
mem vars set API_TOKEN # hidden input (like sudo)
mem vars set DB_HOST staging.db # inline for non-sensitive values
mem vars list # shows names only, never values
mem vars remove API_TOKEN
mem vars clear
Variable status in listings
mem list shows whether each variable is ready:
● backend / api
──────────────────────────────────────────────────────
1. curl -H 'Authorization: Bearer $API_TOKEN' .../users/$USER_ID
✓ $API_TOKEN resolved from environment
⚠ $USER_ID unset — pass inline: mem run api USER_ID=42
Scoping
Every group and saved command lives in either repo scope (tied to the current git repo) or global scope (available everywhere).
- Inside a git repo: defaults to repo scope
- Outside a git repo: defaults to global scope
- Use
--global/-gto force global scope - A repo group shadows a global group with the same name
Sessions
mem groups your commands into work sessions (based on 5-minute idle gaps and repo changes) so you can recall exactly what you did.
mem session "api outage" # search sessions by keyword
mem session debug --json # machine-readable output
┌ [1] Session: 2026-03-07 14:30 myapp ──────────────────┐
│ 1 kubectl logs api-7f9b --tail=100 │
│ 2 kubectl get pods -n production │
│ 3 kubectl rollout restart deploy api │
│ 4 curl -s localhost:8080/health │
└─────────────────────────────────────────────────────────┘
Replay a session? [number/n]: _
Replaying a session executes each command with per-command confirmation.
Other commands
mem stats # top commands, repos, totals
mem stats --json # machine-readable stats
mem forget "API_KEY=sk-..." # permanently delete matching commands
mem forget "password" --yes # skip confirmation
mem init zsh # print shell hook code (also: bash, fish)
How it works
You type a command
│
▼
Shell hook (preexec/precmd)
│
▼
mem _capture ← runs in background, <5ms
│
├─→ Append to ~/.mem/repos/<repo>.jsonl
└─→ Every 20 captures: background pattern extraction
Search scoring:
score = (frequency × 0.4) + (recency × 0.4) + (context × 0.2)
- Frequency — how often you've run this command
- Recency — exponential decay, 7-day half-life
- Context — 1.0 same repo, 0.5 same directory prefix, 0.0 otherwise
AI features use Apple Foundation Models running entirely on your Mac's neural engine. No API keys, no cloud, no data leaves the machine. If Apple Intelligence isn't available, everything still works — you just don't get pattern extraction or credential detection.
Storage
All data lives in ~/.mem/ as human-readable plain text:
~/.mem/
repos/
myapp.jsonl # commands captured in this git repo
_global.jsonl # commands outside any repo
sessions/
2026-03-07.jsonl # work sessions by date
patterns/
kubectl.json # AI-extracted command patterns
docker.json
groups/
repos/
myapp.json # repo-scoped groups and saved commands
_global.json # global groups and saved commands
vars.json # persistent variable store (0600 permissions)
Inspect anything:
cat ~/.mem/repos/myapp.jsonl
tail -f ~/.mem/repos/myapp.jsonl # watch commands arrive in real-time
grep "docker" ~/.mem/repos/*.jsonl # search across repos
Data rotation happens automatically in the background:
| Data | Retention |
|---|---|
| Commands | 90 days |
| Sessions | 30 days |
| Patterns | Forever |
Privacy
- Zero network requests — not even update checks
- Zero telemetry — no analytics, no crash reports
- Zero cloud dependencies — fully offline, always
- On-device AI only — runs on your Mac's neural engine
- Plain text storage — no proprietary formats, you own your data
Read more in PHILOSOPHY.md.
Requirements
| Requirement | Version |
|---|---|
| macOS | 26.0+ |
| Python | 3.10+ |
| Apple Intelligence | Optional (for patterns + credential detection) |
Uninstall
brew uninstall mem # or: pip uninstall cli-mem
rm -rf ~/.mem # remove all captured data
Remove the shell hook line from your shell config (~/.zshrc, ~/.bashrc, or ~/.config/fish/config.fish).
Contributing
git clone https://github.com/matinsaurralde/mem.git
cd mem
pip install -e ".[dev]"
pytest
Read PHILOSOPHY.md first.
License
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file cli_mem-0.4.1.tar.gz.
File metadata
- Download URL: cli_mem-0.4.1.tar.gz
- Upload date:
- Size: 73.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.10
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
15810962a9bc09fb765b3ec82f9ec56a29587b28bc92b4288e459db453bc7cd1
|
|
| MD5 |
57c5aa9095c67fe7f2fc52aee290dac1
|
|
| BLAKE2b-256 |
36228007b9b4e579e63e0c66d8ab0621e3de8f5a7ff3625a0f634760f3e2dcfc
|
File details
Details for the file cli_mem-0.4.1-py3-none-any.whl.
File metadata
- Download URL: cli_mem-0.4.1-py3-none-any.whl
- Upload date:
- Size: 41.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.10
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
0e2d10f4c75e1197e47a02052be148300fd802ab8a58b8328b2e74ddd1522315
|
|
| MD5 |
0ba1eb86c7116574a62a9978ed2997f7
|
|
| BLAKE2b-256 |
2697e12fb1c163335d51aefc7e1fb77ad8c36d0b2fb3072106a45fc299f9262a
|