Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ vscode-extension/*.vsix
ehthumbs.db
Thumbs.db

# ── DevMem runtime data ───────────────────────────────────────────────────────
# ── Recall runtime data ───────────────────────────────────────────────────────
# Local data directory — never commit user activity data
*.db
*.db-wal
Expand Down
10 changes: 5 additions & 5 deletions Dockerfile.sandbox
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ USER devuser
WORKDIR /home/devuser

# Copy the project into the container
COPY --chown=devuser:devuser . /home/devuser/devmem/
COPY --chown=devuser:devuser . /home/devuser/dev-recall/

# Install deps in separate layers so Docker caches each one.
# sentence-transformers/PyTorch (~800 MB) is omitted — embeddings fail
Expand All @@ -32,15 +32,15 @@ RUN /home/devuser/.venv/bin/pip install --quiet --timeout 60 --retries 3 \
RUN /home/devuser/.venv/bin/pip install --quiet --timeout 60 --retries 5 \
pytest pytest-cov pytest-mock ruff

# Install devmem itself (no ML deps)
# Install dev-recall itself (no ML deps)
RUN /home/devuser/.venv/bin/pip install --quiet --no-deps \
-e "/home/devuser/devmem"
-e "/home/devuser/dev-recall"

ENV PATH="/home/devuser/.venv/bin:$PATH"

# Pre-configure a fake git identity (required for git hooks to fire)
RUN git config --global user.email "sandbox@devmem.test" && \
RUN git config --global user.email "sandbox@dev-recall.test" && \
git config --global user.name "Sandbox User"

# Default: drop into an interactive shell so you can run devmem commands manually
# Default: drop into an interactive shell so you can run recall commands manually
CMD ["/bin/zsh"]
101 changes: 51 additions & 50 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,25 +1,26 @@
# DevMem
# Recall

**Local-first developer memory layer.** Captures every developer activity — terminal commands, git commits, file edits, repo opens, AI chat sessions — into a structured SQLite database with a FAISS vector index. Enables natural language recall:

```
devmem ask "what did I work on last Tuesday?"
devmem ask "how did I fix the auth bug?"
devmem today
devmem timeline
recall ask "what did I work on last Tuesday?"
recall ask "how did I fix the auth bug?"
recall today
recall timeline
```

---

## Quick Start

```bash
pip install devmem
devmem init
pip install dev-recall
recall init
source .zshrc # or .bashrc
```

`devmem init` will:
1. Create `~/.local/share/devmem/` and `~/.config/devmem/`
`recall init` will:
1. Create `~/.local/share/recall/` and `~/.config/recall/`
2. Initialize the SQLite database + FAISS vector index
3. Install the zsh/bash shell hook (appends `source` line to your rc file)
4. Set `git config --global core.hooksPath` to capture all commits
Expand All @@ -31,21 +32,21 @@ devmem init

| Command | Description |
|---------|-------------|
| `devmem init` | First-time setup |
| `devmem ask "<query>"` | Natural language search with LLM answer |
| `devmem today` | Summary of today's activity |
| `devmem week` | Summary of this week's activity |
| `devmem timeline` | Chronological event list for a day |
| `devmem search "<query>"` | Raw hybrid search (no LLM) |
| `devmem repos` | List all tracked repos |
| `devmem stats` | Capture statistics |
| `devmem export` | Export events as JSON or CSV |
| `devmem config` | View/edit configuration |
| `devmem privacy list` | Show what's captured |
| `devmem privacy delete` | Delete captured events |
| `devmem privacy ignore --cmd "pattern"` | Add a privacy filter |
| `devmem daemon start/stop/status/logs` | Manage the background daemon |
| `devmem mcp-serve` | Start MCP server (for Claude Code / Copilot) |
| `recall init` | First-time setup |
| `recall ask "<query>"` | Natural language search with LLM answer |
| `recall today` | Summary of today's activity |
| `recall week` | Summary of this week's activity |
| `recall timeline` | Chronological event list for a day |
| `recall search "<query>"` | Raw hybrid search (no LLM) |
| `recall repos` | List all tracked repos |
| `recall stats` | Capture statistics |
| `recall export` | Export events as JSON or CSV |
| `recall config` | View/edit configuration |
| `recall privacy list` | Show what's captured |
| `recall privacy delete` | Delete captured events |
| `recall privacy ignore --cmd "pattern"` | Add a privacy filter |
| `recall daemon start/stop/status/logs` | Manage the background daemon |
| `recall mcp-serve` | Start MCP server (for Claude Code / Copilot) |

---

Expand All @@ -68,18 +69,18 @@ CLI + MCP Server
## Data Sources

### Shell commands (zsh / bash)
Add to `~/.zshrc` (done automatically by `devmem init`):
Add to `~/.zshrc` (done automatically by `recall init`):
```bash
source ~/.config/devmem/hook.zsh
source ~/.config/dev-recall/hook.zsh
```

### Git commits
`devmem init` sets `core.hooksPath` globally — all future commits in any repo are captured.
`recall init` sets `core.hooksPath` globally — all future commits in any repo are captured.

### VS Code activity
Install the extension:
```bash
code --install-extension devmem.devmem-vscode
code --install-extension recall.recall-vscode
```

### AI chat sessions
Expand All @@ -93,27 +94,27 @@ Automatically scanned from:

## LLM Integration

DevMem uses [OpenRouter](https://openrouter.ai) for the `ask` command and daily summaries.
Recall uses [OpenRouter](https://openrouter.ai) for the `ask` command and daily summaries.

```bash
export OPENROUTER_API_KEY=sk-or-...
devmem ask "what was I debugging yesterday?"
recall ask "what was I debugging yesterday?"
```

Without an API key, `devmem ask` falls back to `--no-llm` mode (shows retrieved events directly). All other commands work fully offline.
Without an API key, `recall ask` falls back to `--no-llm` mode (shows retrieved events directly). All other commands work fully offline.

---

## MCP Server

Use DevMem as a context source in Claude Code or VS Code Copilot:
Use Recall as a context source in Claude Code or VS Code Copilot:

**Claude Code** (`~/.config/claude/mcp.json`):
```json
{
"mcpServers": {
"devmem": {
"command": "devmem",
"dev-recall": {
"command": "dev-recall",
"args": ["mcp-serve"]
}
}
Expand All @@ -124,9 +125,9 @@ Use DevMem as a context source in Claude Code or VS Code Copilot:
```json
{
"servers": {
"devmem": {
"dev-recall": {
"type": "stdio",
"command": "devmem",
"command": "dev-recall",
"args": ["mcp-serve"]
}
}
Expand All @@ -146,21 +147,21 @@ Available MCP tools: `recall`, `today_summary`, `recent_repos`, `find_command`,
- Default retention: **90 days** (configurable)

```bash
devmem privacy list # see what's captured
devmem privacy delete --before 2026-01-01
devmem privacy ignore --cmd "*mycompany*"
recall privacy list # see what's captured
recall privacy delete --before 2026-01-01
recall privacy ignore --cmd "*mycompany*"
```

---

## Configuration

Config file: `~/.config/devmem/config.json`
Config file: `~/.config/dev-recall/config.json`

```bash
devmem config # show all settings
devmem config daemon_port 8080 # change port
devmem config retention_days 30 # shorter retention
recall config # show all settings
recall config daemon_port 8080 # change port
recall config retention_days 30 # shorter retention
```

Key settings:
Expand All @@ -179,14 +180,14 @@ Key settings:
## Data Storage

```
~/.local/share/devmem/
~/.local/share/dev-recall/
├── events.db # SQLite (events + FTS5 + sessions + daily_summaries)
├── vectors.faiss # FAISS vector index
├── shell.tsv # shell hook ring buffer
├── git.tsv # git hook ring buffer
└── daemon.pid # running daemon PID

~/.config/devmem/
~/.config/dev-recall/
├── config.json
├── hook.zsh / hook.bash
└── git-hooks/post-commit + post-checkout
Expand All @@ -198,14 +199,14 @@ Key settings:

```bash
git clone <repo>
cd devmem
cd dev-recall
pip install -e ".[dev]"
pytest
```

### Sandbox testing

`devmem init` makes system-wide changes (modifies `~/.zshrc`, sets a global `git config core.hooksPath`, starts a background daemon). Use the provided Docker sandbox to test safely without touching your host environment.
`recall init` makes system-wide changes (modifies `~/.zshrc`, sets a global `git config core.hooksPath`, starts a background daemon). Use the provided Docker sandbox to test safely without touching your host environment.

**Prerequisites:** Docker

Expand All @@ -216,11 +217,11 @@ pytest
# Run the full test suite
./sandbox.sh test

# Run `devmem init` and inspect every file it creates
# Run `recall init` and inspect every file it creates
./sandbox.sh init

# Run any arbitrary command
./sandbox.sh "devmem --help"
./sandbox.sh "recall --help"
```

What the sandbox isolates:
Expand All @@ -233,7 +234,7 @@ What the sandbox isolates:
| Network calls to OpenRouter | Blocked via `--network none` |
| Privilege escalation | `--cap-drop ALL --security-opt no-new-privileges` |

Alternatively, use a throwaway VM: `multipass launch --name devmem-test`
Alternatively, use a throwaway VM: `multipass launch --name dev-recall-test`

---

Expand Down
3 changes: 0 additions & 3 deletions devmem/__init__.py

This file was deleted.

6 changes: 3 additions & 3 deletions git-hooks/post-checkout
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
#!/bin/sh
# DevMem git post-checkout hook
# Recall git post-checkout hook
# $1=prev ref, $2=new ref, $3=flag (1=branch, 0=file checkout)

# Only record branch switches, not file checkouts
[ "$3" = "1" ] || exit 0

__devmem_dir="${DEVMEM_DATA_DIR:-$HOME/.local/share/devmem}"
__devrecall_dir="${DEV_RECALL_DATA_DIR:-$HOME/.local/share/devmem}"
REPO_PATH=$(git rev-parse --show-toplevel 2>/dev/null) || exit 0
NEW_BRANCH=$(git rev-parse --abbrev-ref HEAD 2>/dev/null)
OLD_BRANCH=$(git name-rev --name-only "$1" 2>/dev/null || echo "unknown")
TS=$(date -u +%Y-%m-%dT%H:%M:%SZ)

printf '%s\tbranch\t%s\t%s\t%s\n' \
"$TS" "$REPO_PATH" "$OLD_BRANCH" "$NEW_BRANCH" \
>> "$__devmem_dir/git.tsv" 2>/dev/null
>> "$__devrecall_dir/git.tsv" 2>/dev/null

exit 0
6 changes: 3 additions & 3 deletions git-hooks/post-commit
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
#!/bin/sh
# DevMem git post-commit hook
# Recall git post-commit hook
# Installed globally via: git config --global core.hooksPath ~/.config/devmem/git-hooks/

__devmem_dir="${DEVMEM_DATA_DIR:-$HOME/.local/share/devmem}"
__devrecall_dir="${DEV_RECALL_DATA_DIR:-$HOME/.local/share/devmem}"
REPO_PATH=$(git rev-parse --show-toplevel 2>/dev/null) || exit 0
HASH=$(git rev-parse HEAD 2>/dev/null) || exit 0
MSG=$(git log -1 --format="%s" 2>/dev/null)
Expand All @@ -13,6 +13,6 @@ TS=$(date -u +%Y-%m-%dT%H:%M:%SZ)

printf '%s\tcommit\t%s\t%s\t%s\t%s\t%s\t%s\n' \
"$TS" "$REPO_PATH" "$HASH" "$BRANCH" "$MSG" "$FILES" "$AUTHOR" \
>> "$__devmem_dir/git.tsv" 2>/dev/null
>> "$__devrecall_dir/git.tsv" 2>/dev/null

exit 0
6 changes: 3 additions & 3 deletions git-hooks/post-merge
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
#!/bin/sh
# DevMem git post-merge hook
# Recall git post-merge hook
# Installed globally via: git config --global core.hooksPath ~/.config/devmem/git-hooks/
# Arguments: $1=1 if squash merge, 0 otherwise

IS_SQUASH="${1:-0}"
__devmem_dir="${DEVMEM_DATA_DIR:-$HOME/.local/share/devmem}"
__devrecall_dir="${DEV_RECALL_DATA_DIR:-$HOME/.local/share/devmem}"
REPO_PATH=$(git rev-parse --show-toplevel 2>/dev/null) || exit 0
BRANCH=$(git rev-parse --abbrev-ref HEAD 2>/dev/null)
TS=$(date -u +%Y-%m-%dT%H:%M:%SZ)
Expand All @@ -15,6 +15,6 @@ MERGED_BRANCH=$(git reflog show --format="%gs" -1 HEAD 2>/dev/null \

printf '%s\tmerge\t%s\t%s\t%s\t%s\n' \
"$TS" "$REPO_PATH" "$BRANCH" "$MERGED_BRANCH" "$IS_SQUASH" \
>> "$__devmem_dir/git.tsv" 2>/dev/null
>> "$__devrecall_dir/git.tsv" 2>/dev/null

exit 0
6 changes: 3 additions & 3 deletions git-hooks/pre-push
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
#!/bin/sh
# DevMem git pre-push hook
# Recall git pre-push hook
# Installed globally via: git config --global core.hooksPath ~/.config/devmem/git-hooks/
# Arguments: $1=remote_name $2=remote_url
# Stdin: lines of "local_ref local_sha remote_ref remote_sha"

REMOTE="$1"
__devmem_dir="${DEVMEM_DATA_DIR:-$HOME/.local/share/devmem}"
__devrecall_dir="${DEV_RECALL_DATA_DIR:-$HOME/.local/share/devmem}"
REPO_PATH=$(git rev-parse --show-toplevel 2>/dev/null) || exit 0
BRANCH=$(git rev-parse --abbrev-ref HEAD 2>/dev/null)
TS=$(date -u +%Y-%m-%dT%H:%M:%SZ)
Expand All @@ -26,6 +26,6 @@ done

printf '%s\tpush\t%s\t%s\t%s\t%d\n' \
"$TS" "$REPO_PATH" "$REMOTE" "$BRANCH" "$COMMIT_COUNT" \
>> "$__devmem_dir/git.tsv" 2>/dev/null
>> "$__devrecall_dir/git.tsv" 2>/dev/null

exit 0
14 changes: 11 additions & 3 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ requires = ["setuptools>=42", "wheel"]
build-backend = "setuptools.build_meta"

[project]
name = "devmem"
name = "dev-recall"
version = "0.1.0"
description = "Local-first developer memory layer"
readme = "README.md"
Expand All @@ -25,14 +25,22 @@ dependencies = [
]

[project.scripts]
devmem = "devmem.cli:cli"
recall = "recall.cli:cli"

[project.optional-dependencies]
dev = ["pytest>=7.0", "pytest-cov", "pytest-mock", "ruff"]
# Optional collectors — install only the ones you want
linux = [
"psutil>=5.9", # process/port tracking
"dbus-next>=0.2", # session lock/sleep events (Linux D-Bus)
"docker>=7.0", # Docker/Podman container events
]
# PyGObject (gi/Wnck) for X11 window tracking is a system package;
# install via: sudo apt install python3-gi gir1.2-wnck-3.0

[tool.setuptools.packages.find]
where = ["."]
include = ["devmem*"]
include = ["recall*"]

[tool.ruff]
line-length = 100
Expand Down
3 changes: 3 additions & 0 deletions recall/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
"""Recall — Local-first developer memory layer."""

__version__ = "0.1.0"
Loading
Loading