Local data, privacy and uninstall
What leaves your machine
Code navigation runs entirely on your machine. The embedded models compute the index, symbol graph, embeddings and summaries locally. greppy makes no network calls for code navigation, sends no telemetry and needs no account. It runs offline and air-gapped. The models are inside the binary; release packages download nothing at runtime.
Two optional features behave differently:
- The browser tool (beta) accesses no URLs except the ones an agent explicitly opens, searches or researches. It never uploads your repository.
- The built-in agent (beta) sends its conversation, including the code it reads, to the model gateway you set with
GREPPY_ENDPOINT(defaulthttp://127.0.0.1:8317). That gateway decides where the data goes from there. greppy ships no chat model and stores no provider credentials; you pass an API key withGREPPY_API_KEY.
What greppy stores
greppy keeps workspace paths, source spans, graph edges, embeddings and query-cache entries in a local, SQLite-backed cache outside your repository. It does not duplicate full source files there. On macOS, the data directory is ~/Library/Application Support/greppy. greppy cache status shows it as cache root, and with --json as data_root.
| Data | Contents |
|---|---|
Workspace store per repository (workspaces/v2/<id>/) |
paths, spans, graph relations, summaries, embeddings, query cache |
| Shared Base Stores and Deltas | the same, shared between linked worktrees and agent runs |
Inference cache (inference-cache/v1/) |
embeddings and summaries, keyed by exact model, prompt and input, reused user-wide |
Extracted models (models/v1/<model>/<sha256>/) |
both embedded models with their tokenizers, verified before loading |
Agent sessions (agent-sessions/<project>/) |
append-only JSONL transcripts; secrets and authorization headers are redacted |
| Agent workspaces | the captured baseline of the repository and each run's private changes; on macOS in ~/Library/Group Containers/group.ai.metricspace.greppy/workspace |
This is what it looks like in a separate, otherwise empty home directory after an installation with the installer and indexing serde. ~/.local/share/greppy/versions and ~/.greppy belong to the installer, the rest belongs to greppy.
$ find ~ -maxdepth 4 -type d
~
~/.local
~/.local/share
~/.local/share/greppy
~/.local/share/greppy/versions
~/.greppy
~/Library
~/Library/Application Support
~/Library/Application Support/greppy
~/Library/Application Support/greppy/locks
~/Library/Application Support/greppy/verified-base-digests-v1
~/Library/Application Support/greppy/inference-cache
~/Library/Application Support/greppy/trash
~/Library/Application Support/greppy/models
~/Library/Application Support/greppy/workspaces
~/Library/Group Containers
~/Library/Group Containers/group.ai.metricspace.greppy
~/Library/Group Containers/group.ai.metricspace.greppy/workspace
The store for serde (339 files, 4,573 symbols) takes 29 MiB. The two extracted models with their tokenizers take 777 MiB, and the installed version with CLI and browser runtime takes 1.1 GiB.
$ cd ~/Library/Application\ Support/greppy
$ du -sh workspaces/v2/6f9b5d25ed63b4d6 models inference-cache
29M workspaces/v2/6f9b5d25ed63b4d6
777M models
15M inference-cache
$ du -sh ~/.local/share/greppy/versions/v0.4.1
1.1G ~/.local/share/greppy/versions/v0.4.1
The data directory has mode 0700: other users cannot get in. greppy manages cache objects after it has checked owner, type and path. Cleanup therefore never walks directories that greppy does not own, and it never removes data a running reader is using.
All of this data is derived from the source code. Protect it like the repository itself.
Keep an eye on the cache
greppy cache status lists every managed entry with size, last use, lock and freshness, plus the unmanaged paths.
$ greppy cache status
cache root: ~/Library/Application Support/greppy
…
model ~/Library/Application Support/greppy/models/v1/qwen35-0.8b-mtp-q4km/5f9e4d4901a92b997e463c1f46055088b6cca5ca61a6522d1b9f64c4bb81cb42 12808179 bytes last_used=1791407430 locked=false orphaned=false freshness=unknown
model ~/Library/Application Support/greppy/models/v1/qwen35-0.8b-mtp-q4km/b36838d6969d415e08e7f91ab4aa069dcc260ec0801ea1d00bb5dab234181200 529297349 bytes last_used=1791407430 locked=false orphaned=false freshness=unknown
…
model ~/Library/Application Support/greppy/models/v1/embeddinggemma-300m-q4k/53f7d1c0d5c84a81e46f3bea8e0f17c94f459ffbaa8b06f7f52f1f09e58996f2 238991878 bytes last_used=1791407489 locked=false orphaned=false freshness=unknown
model ~/Library/Application Support/greppy/models/v1/embeddinggemma-300m-q4k/6852f8d561078cc0cebe70ca03c5bfdd0d60a45f9d2e0e1e4cc05b68e9ec329e 33385205 bytes last_used=1791407489 locked=false orphaned=false freshness=unknown
…
workspace ~/Library/Application Support/greppy/workspaces/v2/6f9b5d25ed63b4d6 29712704 bytes last_used=1791407625 locked=false orphaned=false freshness=fresh
unmanaged ~/Library/Application Support/greppy/inference-cache
unmanaged ~/Library/Application Support/greppy/verified-base-digests-v1
With --json, you also get the quota, the low-water mark for garbage collection and the TTL.
$ greppy cache status --json | jq '{data_root, quota_bytes, low_water_bytes, ttl_secs, unmanaged}'
{
"data_root": "~/Library/Application Support/greppy",
"quota_bytes": 10737418240,
"low_water_bytes": 9663676416,
"ttl_secs": 1209600,
"unmanaged": [
"~/Library/Application Support/greppy/inference-cache",
"~/Library/Application Support/greppy/verified-base-digests-v1"
]
}
Move it to a protected volume
GREPPY_STORE_DIR moves the entire data directory: workspace stores, extracted models and inference cache. Set it to an absolute directory on an encrypted or ephemeral volume before indexing, and use the same value for all later commands:
export GREPPY_STORE_DIR=/absolute/encrypted-volume/greppy-store
greppy index .
greppy doctor # store: now points into this directory
For the agent, put the workspace data directory on equally protected storage as well. Worktrees and shared indexes describes GREPPY_SHARED_INFERENCE_ROOT.
Inspect and clean up
greppy cache status --json # paths, sizes, locks, TTL and quota
greppy cache gc --dry-run # preview of the TTL/LRU cleanup
greppy cache gc # free eligible entries
greppy cache clear --root . --yes
greppy cache clear --all --yes # also removes managed shared agent Bases
The workspace caches have a TTL of 14 days and a quota of 10 GiB with garbage collection. cache status --json shows both as ttl_secs and quota_bytes. GREPPY_STORE_TTL_DAYS=0 turns aging off, and the quota stays. GREPPY_STORE_MAX_GIB sets the quota. cache clear keeps locked stores and reports them.
$ greppy cache status --json | jq -c '{ttl_secs, quota_bytes}'
{"ttl_secs":1209600,"quota_bytes":10737418240}
$ GREPPY_STORE_TTL_DAYS=0 greppy cache status --json | jq -c '{ttl_secs, quota_bytes}'
{"ttl_secs":0,"quota_bytes":10737418240}
$ GREPPY_STORE_MAX_GIB=20 greppy cache status --json | jq -c '{ttl_secs, quota_bytes}'
{"ttl_secs":1209600,"quota_bytes":21474836480}
cache status also lists unmanaged paths: data in the data directory that cache gc and cache clear do not touch. In the demo installation, these are inference-cache and verified-base-digests-v1; after agent runs, agent-sessions and agent-settings.json join them.
Daemons
The embedding and summary daemons run locally and per user. A loaded model stays in memory for 300 idle seconds, and a daemon process exits after 1,800 idle seconds. greppy doctor shows each daemon's socket; on macOS they live in /tmp/greppy-daemon-<uid>/, the directory with mode 0700, the sockets with 0600. The agent's control sockets live under short, hashed paths in a per-user runtime directory; greppy agent sessions list --json names the exact path.
Uninstall
If you set GREPPY_STORE_DIR, note the cache root from greppy cache status first. Then run:
curl -fsSL https://greppy.xyz/install.sh | sh -s -- --uninstall
The installer works in three steps and reports each one:
- It rolls back what it set up: the greppy blocks in your agents' instruction files, the link
~/.local/bin/greppy(when it points into its version directories),~/.local/share/greppy/versionsand~/.greppy. The*.greppy-backupfiles stay. - It clears the caches with
greppy cache clear --all --yes. Entries that a running greppy locks stay; idle daemons exit within 30 minutes. - It lists the system-wide parts it does not touch: a package installed with
--system, the login item fromgreppy workspace setupand every othergreppyon yourPATH.
For a complete removal, you clean up the rest yourself afterwards:
| Leftover | How to remove it |
|---|---|
| unmanaged paths in the data directory | rm -rf "$HOME/Library/Application Support/greppy" (macOS) or the cache root you noted |
| agent workspaces (macOS) | rm -rf "$HOME/Library/Group Containers/group.ai.metricspace.greppy" |
login item from greppy workspace setup |
macOS: LaunchAgent ~/Library/LaunchAgents/ai.metric-space.greppy.workspace.plist; Linux: systemd user unit |
macOS package from --system |
delete /Applications/GreppyWorkspaceFS.app and /usr/local/bin/greppy, then sudo pkgutil --forget ai.metric-space.greppy |
| Debian package | sudo apt remove greppy |
| RPM package | sudo rpm -e greppy |
You find all installer options under Install and uninstall.
Data for bug reports
For an issue, greppy doctor --json helps; redact private paths first. You report security vulnerabilities through GitHub's private vulnerability reporting; see Security and verification.