Skip to content

Repository files navigation

memgrep

Local agent memory, a coding loop, Cursor from your phone, and playbooks you can schedule.

Docs: https://memgrep.gitwork.dev

memgrep is a local control plane for Cursor. It started as searchable agent memory. The scope is larger now:

Pillar What it does
Memory Ingest Cursor / Claude Code / Kiro chats. Hybrid recall (vector + keyword). remember playbooks and decisions. Fully local (SQLite + HNSW + on-device embeddings).
Loop Per-project coding loops: task in, exit conditions, exit actions (including github_pr). Runs until PASS, then optional PR / follow-ups. Editable config in <cwd>/.memgrep/; named pointer under ~/.memgrep/loops/<name>/.
Telegram Allowlisted bot drives a real local Cursor agent (@cursor/sdk) in a real cwd, with memgrep MCP attached mid-task.
Jobs Cron + remembered playbook + Cursor. Schedule the workflows you already trust.
MCP One server for agents: memory + jobs + loop + docs (Word templates) + optional suites (Cursor, Jira, Neon, gcloud, PostHog, Upstash, Product Hunt, …).

The point: lock workflows you already figured out. Store once (remember / ingest). Recall mid-task instead of reinventing steps every chat. Loop until done. Schedule what should run on a clock. Drive it from the IDE or from your phone.

Demo

memgrep demo

Why

Agent gateways can vibe a workflow every session. That burns tokens on steps you already solved.

memgrep is for the opposite:

  1. Durable playbooks - store the procedure, attach it via MCP, cron it if needed.
  2. Memory across tools - a fix from last month's Cursor chat is recallable in today's agent.
  3. Remote coding without a second platform - Telegram is the channel; Cursor is the runtime; memgrep is memory, loop, and scheduler.
  4. Loops that finish work - not a one-shot prompt: implement, verify exits, run exit actions.

Quickstart

Requires Node.js 18+. Native addons build on install. The embedding model (~25 MB) downloads once; memory search is offline after that. Cursor / Telegram / jobs / loop need network and a CURSOR_API_KEY.

1. Memory

npm install -g memgrep
memgrep ingest
memgrep recall "how did we fix the auth race?"
memgrep copy

2. Coding loop

memgrep loop init my-app --cwd ~/dev/my-app
memgrep loop use my-app
memgrep loop run --task "Add health check endpoint and tests"
memgrep loop status
memgrep loop runs

3. Cursor from your phone

memgrep telegram           # BotFather token + Cursor API key + project cwd
memgrep telegram install   # or: memgrep telegram install --all
memgrep telegram service   # Loaded: yes?

4. Scheduled playbooks (notify mode needs Telegram)

memgrep remember "Smoke: reply with one line ok + time. Do not edit files." --title smoke-playbook
memgrep jobs add --name smoke-5m --cron "*/5 * * * *" \
  --playbook-query "smoke playbook" --cwd ~/dev/project \
  --prompt "Reply with one line: smoke ok and the current time. Do not edit files." \
  --mode notify --profile default
memgrep jobs install
memgrep jobs run smoke-5m
memgrep jobs service

One-shot local stack (Telegram --all, jobs LaunchAgent, loopback MCP):

npm run build
node dist/cli.js cursor setup   # once
node dist/cli.js loop init default --cwd ~/dev/project   # or loop setup
npm start
npm stop

MCP stays on http://127.0.0.1:3921/mcp. Public tunnels are opt-in (any vendor); see Optional public MCP.

Always-on on macOS

Service Install Status Logs
Telegram bots + MCP memgrep telegram install / --all memgrep telegram service ~/.memgrep/logs/telegram-launchd.log
Jobs scheduler memgrep jobs install memgrep jobs service ~/.memgrep/logs/jobs-launchd.log
Background ingest memgrep ingest install memgrep ingest service ~/.memgrep/logs/ingest-launchd.log
Edge node (cloud hub) memgrep edge pair then edge install memgrep edge service ~/.memgrep/logs/edge-*.log

After upgrade: stop foreground pollers, re-run telegram install / jobs install / ingest install / edge install, confirm Loaded: yes. Restart:

launchctl kickstart -k gui/$(id -u)/com.memgrep.telegram
launchctl kickstart -k gui/$(id -u)/com.memgrep.jobs
launchctl kickstart -k gui/$(id -u)/com.memgrep.ingest
launchctl kickstart -k gui/$(id -u)/com.memgrep.edge

These pause while the Mac sleeps; missed job ticks beyond a 6h grace window are skipped.

Command map

# Memory
memgrep scan | ingest | ingest install | remember | list | recall | show | copy | delete

# Edge node ↔ cloud hub (macOS / Linux / Windows)
memgrep edge token | pair | install | service | status

# Loop (per-project profiles)
memgrep loop init <name> [--cwd <path>]
memgrep loop use <name>
memgrep loop setup|status [--profile <name>]
memgrep loop run --task "..." [--profile <name>]
memgrep loop runs [runId]
memgrep loop input|exit|action set|rm ...

# Cursor agent (MCP suite)
memgrep cursor setup|status

# Telegram
memgrep telegram | telegram setup|list|status|install|service|uninstall

# Jobs
memgrep jobs add|list|show|run|logs|daemon|install|service|...

# MCP server
memgrep serve [--http] [--host 127.0.0.1] [--port 3921] [--token <token>] [--allowed-host <host>]

# Docs (Word templates → .memgrep/docs; MCP docs_* always on)
memgrep docs setup|status|list|fill|edit

# Optional suites (tools omitted until configured)
memgrep jira|neon|gcloud|posthog|upstash|producthunt setup|status
# Loop: use `loop init` / `loop setup` (not `<suite> setup`)

# File search (offline semantic grep)
memgrep index <dir>
memgrep search "query"

Full walkthroughs: docs.

Agent memory

In: ingest (Cursor, Claude Code, Kiro) or remember (your own note / playbook).
Out: recall (hybrid by default: vector + FTS5/BM25 via RRF), list, show, copy.

memgrep scan [--source kiro] [--new] [--last <n>]
memgrep ingest [--source cursor,claude,kiro]
memgrep ingest --pick 2,5
memgrep ingest --last [n]
memgrep ingest <file...>
memgrep remember "we chose X over Y because Z" --title decision
memgrep recall "<query>" [-k <n>] [--mode hybrid|vector|keyword]

Memory lives in ~/.memgrep (MEMGREP_HOME to override). Re-ingest is idempotent by content hash.

Tool Source Notes
Cursor ~/.cursor/projects/*/agent-transcripts/ Full user + assistant turns
Claude Code ~/.claude/projects/*/*.jsonl Full user + assistant turns
Kiro IDE Kiro globalStorage workspace sessions User turns and titles (assistant output is opaque)
Antigravity Not yet Encrypted protobuf; agents can still query via MCP
Anything else memgrep remember "<text>" Manual notes, decisions, postmortems

New sources: implement TranscriptSource and pass it to ingestTranscripts.

Give agents access (MCP)

One MCP server. Register once per client.

No global install (recommended):

{
  "mcpServers": {
    "memgrep": {
      "command": "npx",
      "args": ["-y", "memgrep", "serve"]
    }
  }
}

Global install:

{
  "mcpServers": {
    "memgrep": {
      "command": "memgrep",
      "args": ["serve"]
    }
  }
}

Config: Cursor ~/.cursor/mcp.json, Claude Code claude mcp add memgrep -- npx -y memgrep serve, Kiro ~/.kiro/settings/mcp.json.

Always on the wire: recall, get_chat, list_chats, remember, resolve_open, jobs_*, docs_*.
When configured: loop_*, cursor_*, plus optional suites below.

Optional MCP suites

Unconfigured credential suites are omitted from the tool list. Docs is always registered.

Suite Configure Purpose
docs memgrep docs setup (optional; creates dirs) Jinja-style Word fill (docs_fill, docs_serve, …) under .memgrep/templates.memgrep/docs
cursor memgrep cursor setup Local @cursor/sdk agent (cursor_workspaces, cursor_status, cursor_run)
loop memgrep loop init / loop setup Coding loop (loop_run, loop_status, upsert defaults)
jira memgrep jira setup Issues, comments, transitions
neon memgrep neon setup Read-only Neon project / branch metadata
gcloud memgrep gcloud setup Logs + GCE inspect (ADC / service account)
posthog memgrep posthog setup Analytics queries / flags
upstash memgrep upstash setup Redis REST helpers
producthunt memgrep producthunt setup PH read APIs

Optional public MCP (agnostic tunnel)

  1. npm start or memgrep serve --http on 127.0.0.1:3921
  2. Point any tunnel at that port
  3. Allow the public Host and require a bearer token:
export MEMGREP_MCP_TOKEN="$(cat ~/.memgrep/mcp-token)"
export MEMGREP_PUBLIC_URL=https://your-tunnel.example/mcp
# or MEMGREP_PUBLIC_HOST / MEMGREP_ALLOWED_HOSTS / ~/.memgrep/mcp-public-url

Coding loop

Agnostic loop: free-text task, optional inputs, exit conditions, exit actions. The loop implements, verifies exits, then runs builtins (e.g. github_pr) and any remaining agent actions. Completion can notify via Telegram.

memgrep loop init prepaid --cwd ~/dev/prepaid
memgrep loop use prepaid
memgrep loop setup                    # edit cwd / git defaults
memgrep loop status --profile prepaid
memgrep loop run --task "Ship refunds health check" --profile prepaid   # foreground (CLI)
memgrep loop runs

Config lives in the project at <cwd>/.memgrep/ (edit in your IDE; safe to commit), including AGENTS.md (how to add inputs/exits/actions for agents). Home keeps a thin pointer at ~/.memgrep/loops/<name>/project.json and the template at ~/.memgrep/loop.base/. Active: ~/.memgrep/loop.active or MEMGREP_LOOP_PROFILE. Legacy home-only loops/<name>/loop.json still works until you re-init.

MCP: loop_run starts detached in the background; also loop_run_status, loop_status, loop_upsert_* / loop_remove_*. Requires Cursor; Jira optional for jiraKey context only.

Scheduled playbooks (jobs)

A job is cron + pointer to a remembered playbook. The daemon fires Cursor in the job cwd with memgrep MCP; the agent get_chats the playbook and runs your prompt.

memgrep jobs add \
  --name email-scan-am \
  --cron "30 8 * * 1-5" \
  --playbook-query "email scan" \
  --cwd ~/dev/career-ops \
  --prompt "Scan unread mail and summarize; do not send replies" \
  --mode auto

memgrep jobs list
memgrep jobs run email-scan-am
memgrep jobs logs email-scan-am
memgrep jobs install              # LaunchAgent com.memgrep.jobs

Stored under ~/.memgrep/jobs/. Default mode is notify (Telegram summary). Use --mode auto carefully for read-only jobs. Same jobs are manageable from Cursor or Telegram via MCP.

Cursor from your phone (Telegram)

Chat with a local Cursor agent from Telegram. You do not need the same Wi-Fi. Usage bills against your Cursor plan. Needs a CURSOR_API_KEY.

memgrep telegram
memgrep telegram setup career
memgrep telegram --profile career
memgrep telegram --all
memgrep telegram install --all
memgrep telegram service

Profiles: ~/.memgrep/telegram/<profile>.json. The bot embeds loopback MCP so Cursor can call memory, jobs, loop, and configured suites mid-task.

On your phone: free text / /ask, /ws workspaces, /cwd, /new, /model, /mode, /status, /recall, /list, /show, /open, /help. Only allowlisted Telegram user ids get answers.

Env overrides: TELEGRAM_BOT_TOKEN, TELEGRAM_ALLOWED_USER_IDS, CURSOR_API_KEY, MEMGREP_TELEGRAM_CWD, MEMGREP_TELEGRAM_MODEL, MEMGREP_TELEGRAM_PROFILE.

Split processes: memgrep serve --http + memgrep telegram --no-server (MEMGREP_MCP_URL to override).

File search

Semantic grep over any folder, fully offline:

npx memgrep index ./docs
npx memgrep search "how do I configure auth?"

index options: --out (default .memgrep), --model (any Transformers.js-compatible embedding model).
search options: --index (default .memgrep), -k for the number of results.

Library usage

Same engine as an embeddable library (SQLite for semantic search, not a hosted DB):

import { VectorIndex } from 'memgrep';

const index = await VectorIndex.create({ model: 'Xenova/all-MiniLM-L6-v2' });

await index.add([
  { id: 'doc1', text: 'To reset your password, click the forgot password link.' },
  { id: 'doc2', text: 'Our refund policy allows returns within 30 days.', metadata: { url: '/refunds' } },
]);

const hits = await index.search('I forgot my login', { k: 5 });
await index.save('./my-index');
const loaded = await VectorIndex.load('./my-index');

Also exported: Embedder, chunkText, MemoryStore, ingestTranscripts, and the per-tool parsers. Use Embedder + chunkText if you already have pgvector / LanceDB / Qdrant and only want local embeddings.

How it works

Chunks are searched; chats are returned.

  1. Transcripts parse to clean User: / Assistant: dialogue (tool noise stripped).
  2. Text is chunked (~1000 chars, 200 overlap) and embedded locally (384-dim, Transformers.js).
  3. Vectors go to HNSW; chats + chunk text to SQLite; FTS5/BM25 kept in sync via triggers.
  4. Queries run vector + keyword in parallel; RRF merges. Exact ids ride keyword; meaning rides vectors.
  5. Ingest is idempotent by content hash. Vector index is a rebuildable cache; SQLite is source of truth. Next recall / ingest / serve self-heals a divergent index.

Limitations, honestly

  • Hybrid search helps exact ids; very short or heavily punctuated strings can still miss.
  • Kiro ingestion is partial. Antigravity cannot be ingested today.
  • delete is not permanent against re-ingest if the source transcript still exists.
  • One writer at a time; no cross-process lock yet (self-heal repairs loss on next open).
  • Recall quality tracks what was said in dialogue; signal that lived only in tool output searches poorly. A one-line remember often wins.
  • Telegram and jobs need a host that stays awake. LaunchAgents pause while the Mac sleeps.
  • Loop and Cursor suites need a valid Cursor API key and allowlisted cwd.

Roadmap

  • Tombstones so delete survives re-ingest
  • More transcript sources (Antigravity if the format opens, Codex CLI, Windsurf)
  • File-watch ingest (--watch) on top of the interval daemon
  • Linux systemd units alongside macOS LaunchAgents
  • Telegram /jobs slash shortcuts (MCP already covers manage-from-chat)
  • Browser / WASM HNSW for the library

Development

npm install
npm run build
npm test

Docs site: cd docs && npm install && npm run dev (port 4401). Live: memgrep.gitwork.dev.

License

MIT

About

Local memory + cron scheduling for Cursor agents. Recall past sessions, schedule playbooks, MCP-native.

Topics

Resources

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages