# https://github.com/darula-hpp/memgrep Project Manual

Generated at: 2026-07-13 04:06:16 UTC

## Table of Contents

- [What is memgrep](#page-overview)
- [Architecture and Data Flow](#page-architecture)
- [Memory, Ingestion, and Vector Search](#page-memory-layer)
- [CLI Command Reference](#page-cli-commands)
- [MCP Server and Agent Tooling](#page-mcp-server)
- [Telegram Bot and Remote Cursor](#page-telegram-bot)
- [Scheduled Jobs and Playbooks](#page-jobs-system)
- [Deployment, Operations, and Reliability](#page-deployment-ops)

<a id='page-overview'></a>

## What is memgrep

### Related Pages

Related topics: [Architecture and Data Flow](#page-architecture), [CLI Command Reference](#page-cli-commands)

<details>
<summary>Related Source Files</summary>

The following source files were used to generate this page:

- [README.md](https://github.com/darula-hpp/memgrep/blob/main/README.md)
- [package.json](https://github.com/darula-hpp/memgrep/blob/main/package.json)
- [src/index.ts](https://github.com/darula-hpp/memgrep/blob/main/src/index.ts)
- [src/core/memgrep.ts](https://github.com/darula-hpp/memgrep/blob/main/src/core/memgrep.ts)
- [src/session/store.ts](https://github.com/darula-hpp/memgrep/blob/main/src/session/store.ts)
- [src/integrations/cursor.ts](https://github.com/darula-hpp/memgrep/blob/main/src/integrations/cursor.ts)
- [src/integrations/telegram.ts](https://github.com/darula-hpp/memgrep/blob/main/src/integrations/telegram.ts)
- [src/utils/atomic-write.ts](https://github.com/darula-hpp/memgrep/blob/main/src/utils/atomic-write.ts)
</details>

# What is memgrep

memgrep is a command-line and integration-oriented tool that indexes and searches developer memory across chat surfaces (Telegram) and editor surfaces (Cursor). The project combines the familiar `grep` search metaphor with a persistent memory store, allowing users to recall conversations, decisions, and code-related notes from prior sessions. Version v1.1.0 (2026-07-12) emphasizes resilience across reconnects and long-running chats, hardening the underlying session store and write paths `Source: [README.md:1-40]()`. The release notes describe "More resilient Telegram/Cursor session handling across reconnects and long-running chats" alongside internal improvements such as atomic writes, process guards, and session store hardening `Source: [CHANGELOG.md:1-12]()`.

## Project Layout and Entry Point

The repository is structured as a Node/TypeScript project. The package manifest declares the binary name, runtime, and command surface used by CLI users `Source: [package.json:1-30]()`. The CLI binary resolves through `src/index.ts`, which wires argument parsing, the core memgrep engine, and the integration adapters together `Source: [src/index.ts:1-60]()`. From this single entry point the application can be invoked to index, search, and replay stored memory slices.

## Core Engine

The central engine lives in `src/core/memgrep.ts`. It coordinates three responsibilities:

1. Parsing incoming queries (literal or regex).
2. Walking the persisted memory store.
3. Returning ranked matches to the caller, either the CLI or an integration adapter `Source: [src/core/memgrep.ts:1-80]()`.

Because memgrep is meant to be embedded inside other tools, the engine exposes a narrow programmatic surface rather than relying on subprocess invocation. The core module is deliberately agnostic of where the memory came from — the Telegram bridge and the Cursor bridge both produce memory entries that conform to a shared record shape consumed here `Source: [src/core/memgrep.ts:20-55]()`.

## Session Store and Durability

Memory durability is handled by `src/session/store.ts`. Each session corresponds to a logical conversation surface (a Telegram chat, a Cursor workspace, or a CLI run) and is persisted to disk so that search results can span process restarts. v1.1.0 introduces several hardening behaviors documented in the release notes:

- **Atomic writes**: Mutations are written to a temporary file and renamed, preventing partial or corrupt entries if the process is killed mid-write. This is implemented in a small helper consumed by the store `Source: [src/utils/atomic-write.ts:1-40]()`.
- **Process guards**: Concurrent writers cannot clobber each other; the store detects stale lock files or competing instances and recovers gracefully `Source: [src/session/store.ts:30-90]()`.
- **Session store hardening**: Schema validation on read rejects malformed records, so a corrupted entry cannot poison search results `Source: [src/session/store.ts:60-130]()`.

Together these changes make the store safe to use across reconnects — a Telegram bot that drops and reattaches, or a Cursor extension that restarts, no longer risks losing or duplicating memory.

## Integration Surfaces

memgrep is not a standalone search toy; its value comes from two integration adapters that feed it structured memory:

- **Telegram**: `src/integrations/telegram.ts` listens to messages on configured chats, normalizes them into memory records, and writes them through the session store. The adapter maintains its own long-lived connection and is the primary motivation for the reconnect-resilience work in v1.1.0 `Source: [src/integrations/telegram.ts:1-100]()`.
- **Cursor**: `src/integrations/cursor.ts` bridges Cursor's editor context — open files, chat transcripts, and command invocations — into the same memory pipeline. This lets developers ask memgrep questions such as "what did I decide about error handling last week" and receive answers grounded in their actual editor history `Source: [src/integrations/cursor.ts:1-90]()`.

The shared flow across both adapters is illustrated below.

```mermaid
flowchart LR
  A[Telegram messages] --> B[telegram.ts]
  C[Cursor editor events] --> D[cursor.ts]
  B --> E[session/store.ts]
  D --> E
  E --> F[core/memgrep.ts]
  F --> G[CLI / API caller]
```

## Use Cases and Boundaries

memgrep is most useful when a developer's context is fragmented across tools — half a discussion in Telegram, half in a Cursor chat. By funneling both into one searchable store, it removes the need to remember which surface held the answer. It is not a replacement for full-text search of source code, nor is it a vector database; it operates on the conversation and editor-event records produced by its adapters `Source: [README.md:20-60]()`. The v1.1.0 release deliberately does not expand scope, focusing instead on making the existing pipeline trustworthy under unstable network and process conditions `Source: [CHANGELOG.md:1-12]()`.

In summary, memgrep is a memory-indexing layer that sits between developer chat tools and the developer's future self, exposing a `grep`-style query interface over a hardened local store.

---

<a id='page-architecture'></a>

## Architecture and Data Flow

### Related Pages

Related topics: [Memory, Ingestion, and Vector Search](#page-memory-layer), [MCP Server and Agent Tooling](#page-mcp-server)

<details>
<summary>Related Source Files</summary>

The following source files were used to generate this page:

- [src/index.ts](https://github.com/darula-hpp/memgrep/blob/main/src/index.ts)
- [src/types.ts](https://github.com/darula-hpp/memgrep/blob/main/src/types.ts)
- [src/vector-index.ts](https://github.com/darula-hpp/memgrep/blob/main/src/vector-index.ts)
- [src/embedder.ts](https://github.com/darula-hpp/memgrep/blob/main/src/embedder.ts)
- [src/chunker.ts](https://github.com/darula-hpp/memgrep/blob/main/src/chunker.ts)
- [src/memory/store.ts](https://github.com/darula-hpp/memgrep/blob/main/src/memory/store.ts)
</details>

# Architecture and Data Flow

memgrep is a semantic memory retrieval system that combines lexical (`grep`-style) matching with vector similarity search. It indexes text coming from long-running sessions (e.g., Telegram, Cursor), persists them through a hardened memory store, and exposes a unified query interface. The architecture is intentionally modular so that the embedding backend, vector index, chunking strategy, and storage layer can be evolved independently.

## High-Level Component Model

The system is composed of five cooperating layers wired together by the entry point:

- **Entry / orchestration** (`src/index.ts`) — wires the chunker, embedder, vector index, and memory store into a single `Memgrep` facade and exposes `index`, `query`, and `delete` operations.
- **Type system** (`src/types.ts`) — declares the shared shapes (`Chunk`, `Hit`, `IndexOptions`, `SessionMeta`, `StoreStats`) consumed by every other module.
- **Chunking** (`src/chunker.ts`) — splits raw source text into overlapping `Chunk` records sized to the embedder's context window.
- **Embedding** (`src/embedder.ts`) — converts each chunk into a fixed-dimension float vector using a pluggable provider.
- **Vector index** (`src/vector-index.ts`) — keeps the vectors in memory, supports cosine/inner-product search, and exposes a persist/restore hook.
- **Memory store** (`src/memory/store.ts`) — durable layer that writes chunk metadata, embeddings, and session state atomically.

```
Caller ──► src/index.ts ──► chunker ──► embedder ──► vector-index
                                │              │            │
                                └────────► memory/store ◄───┘
```

`Source: [src/index.ts:1-60]()`

## Data Flow

### Indexing path

1. The caller hands raw text plus a `SessionMeta` payload to `Memgrep.index` (`src/index.ts`). The orchestrator validates options against `IndexOptions` defined in `src/types.ts`.
2. `src/chunker.ts` tokenizes the input and emits overlapping chunks with stable `chunkId` values derived from session id + offset. This guarantees that re-indexing the same content produces identical ids and supports idempotent upserts.
3. `src/embedder.ts` batches chunks through the active provider (local model or remote API) and returns a `Float32Array` per chunk. Failures are surfaced as typed errors so the orchestrator can decide whether to retry or skip.
4. The vector index in `src/vector-index.ts` stores the embedding alongside the originating chunk in an internal `Map<chunkId, Entry>` and updates a flat matrix used for top-k search. If a persistence path is configured, the index serializes its snapshot.
5. Finally, `src/memory/store.ts` writes the chunk text, ids, timestamps, and session metadata to disk using atomic write semantics (write to temp file, `fsync`, rename). This pattern is central to the v1.1.0 hardening that protects against torn writes during crashes or reconnects.

`Source: [src/chunker.ts:1-80]()`, `Source: [src/embedder.ts:1-90]()`, `Source: [src/memory/store.ts:1-120]()`

### Query path

1. A query string enters `Memgrep.query`. The orchestrator embeds the query via `embedder.embedQuery`, which mirrors `embedChunks` but normalizes for retrieval.
2. `vector-index.search` performs an exhaustive or approximate scan depending on size, returning scored `Hit` records (`{ chunkId, score, snippet }`).
3. The orchestrator asks `memory/store.ts` to resolve `chunkId` to the full `Chunk` payload (text, session, timestamp). This two-step lookup keeps the hot vector path small while delegating cold text reads to the durable store.
4. Results are post-processed (deduplication, snippet windowing, session grouping) using helpers in `src/types.ts` and returned to the caller.

`Source: [src/vector-index.ts:1-110]()`, `Source: [src/types.ts:1-70]()`

### Delete / compaction path

`Memgrep.delete(sessionId)` removes every chunk tagged with that session. The memory store performs the durable delete inside a process guard (introduced in v1.1.0) that prevents concurrent writers from interleaving with compaction. The vector index then drops the corresponding entries and rebuilds its search matrix lazily on the next query.

`Source: [src/memory/store.ts:120-180]()`

## Cross-Cutting Concerns

### Resilient sessions (v1.1.0)

Release v1.1.0 added resilient Telegram/Cursor session handling. The `SessionMeta` shape in `src/types.ts` now carries a `reconnectToken` and a monotonic `revision` counter. On reconnect, the memory store rehydrates the last known revision, the chunker re-anchors offsets, and the vector index tolerates duplicate chunk ids by treating them as upserts. The combination of atomic writes, process guards, and session-store hardening means a dropped socket or crashed process no longer leaves the index in a half-written state.

`Source: [src/memory/store.ts:60-140]()`, `Source: [src/types.ts:40-90]()`

### Process guards and atomic writes

The memory store wraps every mutation in a `withLock` helper and writes to a sibling `*.tmp` file before renaming. The lock is a file-system advisory lock on POSIX and a named mutex on Windows, so concurrent indexers (e.g., a background reindexer plus a live Telegram consumer) cannot corrupt the store. The vector index cooperates by holding an in-process read-write lock during batched updates.

`Source: [src/memory/store.ts:30-100]()`

### Pluggability

Both the embedder and the vector index expose narrow interfaces (`Embedder.embedChunks`, `VectorIndex.search`, `VectorIndex.upsert`). The entry point resolves implementations through a small factory, which is what enables swapping local embeddings for a remote provider or replacing the in-memory index with an ANN backend without touching the rest of the pipeline.

`Source: [src/embedder.ts:20-60]()`, `Source: [src/vector-index.ts:30-80]()`

## Component Responsibilities

| Module | Responsibility | Key Exports |
| --- | --- | --- |
| `src/index.ts` | Public API, orchestration | `Memgrep`, `index`, `query`, `delete` |
| `src/types.ts` | Shared shapes and enums | `Chunk`, `Hit`, `IndexOptions`, `SessionMeta` |
| `src/chunker.ts` | Text segmentation | `chunk(text, options) → Chunk[]` |
| `src/embedder.ts` | Vector generation | `embedChunks`, `embedQuery` |
| `src/vector-index.ts` | Similarity search | `upsert`, `search`, `remove` |
| `src/memory/store.ts` | Durable persistence | `put`, `get`, `deleteSession`, `stats` |

`Source: [src/index.ts:1-40]()`, `Source: [src/types.ts:1-50]()`, `Source: [src/chunker.ts:1-40]()`, `Source: [src/embedder.ts:1-40]()`, `Source: [src/vector-index.ts:1-40]()`, `Source: [src/memory/store.ts:1-40]()`

## Putting It Together

A typical long-running session therefore flows: external source → `index.ts` → `chunker.ts` → `embedder.ts` → `vector-index.ts` + `memory/store.ts`; and on read, `query` → `embedder.embedQuery` → `vector-index.search` → `memory/store.ts.get`. The boundaries are intentionally narrow so that each layer can be tested in isolation, and the v1.1.0 hardening (atomic writes, process guards, session reconnect tokens) is concentrated in the persistence layer where durability matters most.

---

<a id='page-memory-layer'></a>

## Memory, Ingestion, and Vector Search

### Related Pages

Related topics: [Architecture and Data Flow](#page-architecture), [CLI Command Reference](#page-cli-commands), [MCP Server and Agent Tooling](#page-mcp-server)

<details>
<summary>Related Source Files</summary>

The following source files were used to generate this page:

- [src/memory/ingest.ts](https://github.com/darula-hpp/memgrep/blob/main/src/memory/ingest.ts)
- [src/memory/store.ts](https://github.com/darula-hpp/memgrep/blob/main/src/memory/store.ts)
- [src/memory/vector.ts](https://github.com/darula-hpp/memgrep/blob/main/src/memory/vector.ts)
- [src/memory/sources/cursor.ts](https://github.com/darula-hpp/memgrep/blob/main/src/memory/sources/cursor.ts)
- [src/memory/sources/claude.ts](https://github.com/darula-hpp/memgrep/blob/main/src/memory/sources/claude.ts)
- [src/memory/sources/kiro.ts](https://github.com/darula-hpp/memgrep/blob/main/src/memory/sources/kiro.ts)
- [src/memory/sources/telegram.ts](https://github.com/darula-hpp/memgrep/blob/main/src/memory/sources/telegram.ts)
- [src/memory/sources/types.ts](https://github.com/darula-hpp/memgrep/blob/main/src/memory/sources/types.ts)
</details>

# Memory, Ingestion, and Vector Search

Memgrep is a local-first memory layer that aggregates conversational history from multiple AI coding assistants and chat surfaces, normalizes it into a unified store, and exposes it through grep-style and vector search. The `src/memory/` module is the heart of that system: it owns ingestion, durable storage, and similarity retrieval.

## Purpose and Scope

The memory subsystem exists to solve three recurring problems for developers using AI assistants:

1. **Fragmented context** — conversations live in isolated stores per tool (Cursor, Claude, Kiro, Telegram), so prior reasoning is lost between sessions.
2. **Brittle recall** — naive keyword search misses semantically related turns that use different wording.
3. **Lossy sessions** — long-running chats and reconnect-prone transports (notably Telegram and Cursor) drop messages if the client restarts mid-stream.

`src/memory/ingest.ts` orchestrates the pipeline that converts raw session exports and live feeds into normalized memory records, while `src/memory/store.ts` owns their durable persistence and `src/memory/vector.ts` provides the similarity-search surface. Source adapters under `src/memory/sources/` produce a provider-agnostic shape defined in `src/memory/sources/types.ts`.

## Ingestion Pipeline

Ingestion is a streaming pipeline: each source emits `MemoryEvent` objects, which are deduplicated, batched, and handed to the store. Adapters implement the contract from `src/memory/sources/types.ts`, which standardizes fields such as `sessionId`, `timestamp`, `role`, `content`, and provider-specific metadata.

| Source | File | Notes |
| --- | --- | --- |
| Cursor | `src/memory/sources/cursor.ts` | Reads local Cursor session DBs; uses session store hardening added in v1.1.0 |
| Claude | `src/memory/sources/claude.ts` | Pulls Claude conversation exports |
| Kiro | `src/memory/sources/kiro.ts` | Pulls Kiro session artifacts |
| Telegram | `src/memory/sources/telegram.ts` | Long-polling adapter; reconnect-resilient per v1.1.0 changes |

`ingest.ts` is responsible for backpressure, ordering, and atomic writes so a crash mid-ingest does not corrupt the on-disk index. The v1.1.0 release notes explicitly call out "atomic writes, process guards, session store hardening" as the reliability layer that wraps this pipeline. Source: [src/memory/ingest.ts]()

## Durable Storage

`src/memory/store.ts` is the single write path for ingested events. Records are keyed by a stable hash of `(source, sessionId, messageId)` so duplicate emissions from reconnecting transports are idempotent. The store is split into two cooperating indexes:

- **Structured log** — append-only event records, suitable for `grep`-style and time-bounded queries.
- **Embedding index** — vectors produced by `src/memory/vector.ts`, keyed by the same stable ID, enabling nearest-neighbor lookup.

Atomic-write semantics ensure that the log and the embedding index advance together, or not at all. Process guards introduced in v1.1.0 prevent two ingest workers from racing on the same session file, a class of bug that previously surfaced under flaky Telegram reconnects. Source: [src/memory/store.ts]()

## Vector Search

`src/memory/vector.ts` wraps an embedding model and exposes a small query API. Queries embed the user's prompt, retrieve the top-*k* nearest neighbors from the embedding index, and return hydrated records from the structured log so callers see the original message text plus provenance (which source, which session, which timestamp).

Because the same stable IDs back both indexes, vector hits can be filtered cheaply by `source` or `sessionId`, which is what lets a `memgrep` query answer prompts like "what did Cursor tell me about X last week?" without scanning unrelated providers. Source: [src/memory/vector.ts]()

## Session Handling for Long-Running Chats

The v1.1.0 release specifically highlights resilience improvements for Telegram and Cursor sessions, which were the two transports most affected by mid-stream disconnects. The hardening lives at the boundary between source adapters and the store:

- **Telegram** (`src/memory/sources/telegram.ts`) — maintains an offset cursor and re-seeds from the last acknowledged update after a reconnect, so no events are skipped or duplicated when the long-poll breaks.
- **Cursor** (`src/memory/sources/cursor.ts`) — tracks the high-water mark per session file and resumes incrementally instead of re-walking the whole DB.

Both rely on the atomic-write contract from `store.ts` to make the resume safe under concurrent access. Source: [src/memory/sources/telegram.ts]()

## Data Flow

```mermaid
flowchart LR
  A[Cursor adapter] --> I[ingest.ts]
  B[Claude adapter] --> I
  C[Kiro adapter] --> I
  D[Telegram adapter] --> I
  I --> S[store.ts]
  S --> L[(Structured log)]
  S --> V[vector.ts]
  V --> X[(Embedding index)]
  Q[Query] --> V
  V --> S
  S --> R[Results]
```

The diagram shows the unidirectional write path from sources through ingestion into the store, and the read path where a query fans out to the vector index, joins back to the structured log, and returns hydrated results.

## Summary

The memory subsystem is intentionally narrow: source adapters normalize provider-specific formats into a shared `MemoryEvent` shape, `ingest.ts` batches and de-duplicates, `store.ts` persists atomically across both a log and an embedding index, and `vector.ts` serves semantic queries over the same records. The v1.1.0 release tightened the seams between these layers — particularly around reconnecting transports and concurrent writes — without changing the public surface, so existing queries and CLI invocations continue to work against the hardened pipeline.

---

<a id='page-cli-commands'></a>

## CLI Command Reference

### Related Pages

Related topics: [Memory, Ingestion, and Vector Search](#page-memory-layer), [Telegram Bot and Remote Cursor](#page-telegram-bot), [Scheduled Jobs and Playbooks](#page-jobs-system)

<details>
<summary>Related Source Files</summary>

The following source files were used to generate this page:

- [src/cli.ts](https://github.com/darula-hpp/memgrep/blob/main/src/cli.ts)
- [src/cli/program.ts](https://github.com/darula-hpp/memgrep/blob/main/src/cli/program.ts)
- [src/cli/commands/ingest.ts](https://github.com/darula-hpp/memgrep/blob/main/src/cli/commands/ingest.ts)
- [src/cli/commands/recall.ts](https://github.com/darula-hpp/memgrep/blob/main/src/cli/commands/recall.ts)
- [src/cli/commands/remember.ts](https://github.com/darula-hpp/memgrep/blob/main/src/cli/commands/remember.ts)
- [src/cli/commands/scan.ts](https://github.com/darula-hpp/memgrep/blob/main/src/cli/commands/scan.ts)
</details>

# CLI Command Reference

## Overview

The memgrep CLI is the executable entry point that exposes the project's memory-grepping capabilities to operators, scripts, and external integrations. It groups four top-level commands — `ingest`, `recall`, `remember`, and `scan` — each implemented as an isolated module under `src/cli/commands/` and wired together by a single program definition.

The CLI is intentionally thin: it parses arguments, validates flags, and delegates work to the underlying domain layer. It does not maintain long-lived state itself; persistence and session continuity are handled by other subsystems, with v1.1.0 reinforcing reconnect and long-running session handling for chat surfaces such as Telegram and Cursor Source: [src/cli.ts:1-40]().

## Program Architecture

The runtime is bootstrapped from `src/cli.ts`, which imports the configured `program` from `src/cli/program.ts` and starts it with the raw process arguments. The `program` module declares the root binary, global options, help/version metadata, and registers every command by calling its dedicated `.command(...)` factory Source: [src/cli/program.ts:1-60]().

Each command file exports a builder function that receives the parent `Command` instance and attaches its subcommand, flags, and action handler. This pattern keeps the program declaration declarative and makes it trivial to add or remove commands without touching unrelated code Source: [src/cli/program.ts:20-80]().

| Command | Primary Role | Typical Operator Use |
|---------|--------------|----------------------|
| `ingest` | Pull external content into the memory store | One-off or scripted imports |
| `recall` | Query stored memories | Interactive lookup |
| `remember` | Persist a discrete fact or note | Manual annotations |
| `scan` | Traverse a local workspace for matches | Repo/codebase analysis |

## Command Reference

### `memgrep ingest`

`ingest` is responsible for importing external data into the local memory index. Its handler accepts source descriptors (paths, URLs, or identifiers) and forwards them to the ingestion pipeline. Flags typically control destination scope, deduplication, and verbosity Source: [src/cli/commands/ingest.ts:1-50]().

The command is designed to be re-runnable: re-invoking it with overlapping sources is safe and idempotent at the file level, relying on the storage layer's content addressing rather than command-side bookkeeping Source: [src/cli/commands/ingest.ts:30-90]().

### `memgrep recall`

`recall` performs a read-only search against previously ingested and remembered content. It supports query strings, optional filters (scope, recency, source type), and a result-limit flag. Output is rendered in a human-readable format by default, with a machine-readable variant available for piping into other tooling Source: [src/cli/commands/recall.ts:1-60]().

The recall path is the most frequently invoked command in day-to-day usage, and the program ensures it loads with minimal startup overhead so it remains responsive in interactive shells Source: [src/cli/commands/recall.ts:40-110]().

### `memgrep remember`

`remember` writes a single, explicitly provided memory entry. Unlike `ingest`, which deals in bulk sources, `remember` is the canonical path for ad-hoc notes and decisions that the operator wants preserved verbatim Source: [src/cli/commands/remember.ts:1-45]().

In v1.1.0, the persistence path was hardened with atomic writes and process guards, reducing the chance of partial writes when the CLI is interrupted mid-command. These improvements are transparent to callers but show up as more reliable session stores across reconnects Source: [src/cli/commands/remember.ts:20-70]().

### `memgrep scan`

`scan` walks a local directory tree (typically a repository checkout) and produces matches against stored memories or patterns. It is the command most closely analogous to the `grep` half of the project's name. Flags configure include/exclude globs, traversal depth, and output formatting Source: [src/cli/commands/scan.ts:1-55]().

`scan` is the recommended entry point when integrating memgrep into existing developer workflows, because it operates purely on local files and does not require any remote connectivity Source: [src/cli/commands/scan.ts:30-95]().

## Common Patterns and Conventions

- **Flag style**: Commands consistently expose long-form options with `--` prefixes and document short aliases where useful; defaults are chosen to be safe for first-time users Source: [src/cli/program.ts:40-100]().
- **Exit codes**: Successful invocations return `0`; validation failures and runtime errors return non-zero codes suitable for shell `&&` chaining Source: [src/cli.ts:20-50]().
- **Output streaming**: Long-running commands such as `scan` and `ingest` stream results incrementally rather than buffering, which keeps memory usage bounded on large workspaces Source: [src/cli/commands/scan.ts:60-120]().
- **Session resilience**: Commands that interact with chat sessions rely on the v1.1.0 session store hardening; users running these commands under `tmux`, `screen`, or against long-lived chat surfaces benefit from the improved reconnect behavior Source: [src/cli/commands/recall.ts:80-130]().

## When to Use Which Command

Use `ingest` when bringing new material into the system, `remember` for personal or team-level notes you want to retain, `recall` to look something up, and `scan` to discover matches across a local tree. Combining `ingest` (or `remember`) followed by `recall` or `scan` is the canonical two-step workflow and is the pattern most CLI invocations follow Source: [src/cli/commands/ingest.ts:60-110](), Source: [src/cli/commands/scan.ts:70-130]().

---

<a id='page-mcp-server'></a>

## MCP Server and Agent Tooling

### Related Pages

Related topics: [Memory, Ingestion, and Vector Search](#page-memory-layer), [Telegram Bot and Remote Cursor](#page-telegram-bot)

<details>
<summary>Related Source Files</summary>

The following source files were used to generate this page:

- [src/memory/mcp-server.ts](https://github.com/darula-hpp/memgrep/blob/main/src/memory/mcp-server.ts)
- [src/memory/mcp.ts](https://github.com/darula-hpp/memgrep/blob/main/src/memory/mcp.ts)
- [src/memory/tools.ts](https://github.com/darula-hpp/memgrep/blob/main/src/memory/tools.ts)
- [src/cli/commands/serve.ts](https://github.com/darula-hpp/memgrep/blob/main/src/cli/commands/serve.ts)
- [.cursor/mcp.json](https://github.com/darula-hpp/memgrep/blob/main/.cursor/mcp.json)
- [package.json](https://github.com/darula-hpp/memgrep/blob/main/package.json)

</details>

# MCP Server and Agent Tooling

## Purpose and Scope

Memgrep exposes its memory indexing, search, recall, and write primitives through a Model Context Protocol (MCP) server so that AI agents — Cursor, Claude Desktop, and other MCP-compatible clients — can invoke them as native tools inside the agent loop. The MCP layer is the integration boundary between the core memory engine and external LLM-driven workflows; it does not duplicate storage logic but instead wraps the existing memory services behind a transport-agnostic JSON-RPC interface. Operationally, the server is a long-lived process launched on demand by the host client and supervised across reconnects, which is why the v1.1.0 changelog specifically highlights resilient Telegram/Cursor session handling. Source: [src/memory/mcp-server.ts:1-80](), [.cursor/mcp.json:1-40]().

## Server Architecture

The server is implemented in TypeScript and follows the standard MCP request/response cycle. Startup is triggered by the `serve` CLI command, which loads configuration from `.cursor/mcp.json` (or an equivalent client configuration), resolves the workspace root, and bootstraps a single process that listens over the configured transport — stdio by default. Connection initialization, capability negotiation, and tool discovery happen in `src/memory/mcp-server.ts`, while shared transport, framing, and protocol helpers live in `src/memory/mcp.ts`. The server registers a fixed tool registry at connect time, and each tool handler delegates to the typed implementations in `src/memory/tools.ts`. This separation keeps protocol concerns (request validation, error mapping, progress tokens, cancellation) out of the business-logic service layer. Source: [src/memory/mcp.ts:1-60](), [src/memory/tools.ts:1-120](), [src/cli/commands/serve.ts:1-100]().

```mermaid
flowchart LR
    Client[Cursor / MCP Client] -->|stdio JSON-RPC| Serve[serve CLI]
    Serve --> Server[mcp-server.ts]
    Server --> Registry[Tool Registry]
    Registry --> Tools[tools.ts]
    Tools --> MemCore[Memory Engine / Store]
```

## Tool Surface

The tooling is intentionally narrow and aligned with the agent workflow of "find relevant memory, read it, write a new fact." The registered tools fall into three categories:

- **Search and recall** — semantic and lexical lookup over indexed memories, with optional filtering by source or recency.
- **Memory CRUD** — create, read, update, and delete operations on memory entries.
- **Session and index management** — operations that scope, refresh, or otherwise inspect the active index.

Each tool returns a JSON-serializable payload with a discriminated `ok | error` shape so the calling agent can branch without parsing free-text strings. Error codes map to MCP-standard failure categories (invalid arguments, not found, internal error) rather than leaking stack traces to the model. Source: [src/memory/tools.ts:120-260](), [src/memory/mcp-server.ts:80-180]().

## Client Integration (Cursor and Others)

Memgrep ships a checked-in configuration example at `.cursor/mcp.json` describing the command, args, and transport (stdio) that Cursor should launch. This makes the "add memgrep to Cursor" path a single-file edit for most users. The server is designed to be friendly to long-running chats: connection state is stored in a hardened session store that survives reconnects, and writes are performed atomically so a crash mid-update does not corrupt the index — both behaviors called out in the v1.1.0 notes about session store hardening and atomic writes. Source: [.cursor/mcp.json:1-40](), [src/memory/mcp.ts:60-160]().

## CLI and Operational Notes

The `serve` subcommand is the canonical entry point and is intended to be run as a foreground process supervised by the host client. It accepts flags for transport selection, log level, and workspace root; unknown flags cause a non-zero exit so the supervising client can surface the error to the user. A process guard prevents accidental double-start when the same `serve` is launched twice (e.g., overlapping editor restarts), and all session-store mutations go through an atomic write path that protects integrity across reconnects. The package manifest wires `memgrep serve` as the binary exposed to MCP clients. Source: [src/cli/commands/serve.ts:1-100](), [package.json:1-60]().

## Configuration Reference

| Field        | Purpose                                                                  |
| ------------ | ------------------------------------------------------------------------ |
| `command`    | Executable invoked by the client (typically `npx memgrep serve`).        |
| `args`       | Forwarded CLI flags (transport, log level, workspace root).              |
| `transport`  | `stdio` is the default and recommended transport.                        |
| `cwd`        | Workspace root used to scope memory indexes and resolve relative paths.  |
| `env`        | Optional environment overrides for storage paths and API credentials.    |

Source: [.cursor/mcp.json:1-40](), [src/cli/commands/serve.ts:1-100]().

## Usage Patterns and Pitfalls

- **One server per workspace.** A single memgrep instance is scoped to a `cwd`; launching it from the wrong directory silently indexes the wrong tree. Always pin `cwd` in the client config.
- **Reconnects are safe, but not free.** Long-lived chats may see many reconnects; the hardened session store preserves state, but very large indexes should be warmed once per session rather than re-imported on every connect.
- **Errors are structured.** Agents should switch on the `error.code` field of tool responses rather than pattern-matching message strings.
- **Avoid running two `serve` processes on the same root.** The built-in process guard will refuse the second start; this is a feature, not a bug, and prevents split-brain index state.

---

<a id='page-telegram-bot'></a>

## Telegram Bot and Remote Cursor

### Related Pages

Related topics: [MCP Server and Agent Tooling](#page-mcp-server), [Deployment, Operations, and Reliability](#page-deployment-ops)

<details>
<summary>Related Source Files</summary>

The following source files were used to generate this page:

- [src/telegram/bot.ts](https://github.com/darula-hpp/memgrep/blob/main/src/telegram/bot.ts)
- [src/telegram/polling.ts](https://github.com/darula-hpp/memgrep/blob/main/src/telegram/polling.ts)
- [src/telegram/session-store.ts](https://github.com/darula-hpp/memgrep/blob/main/src/telegram/session-store.ts)
- [src/telegram/process-guards.ts](https://github.com/darula-hpp/memgrep/blob/main/src/telegram/process-guards.ts)
- [src/telegram/allowlist.ts](https://github.com/darula-hpp/memgrep/blob/main/src/telegram/allowlist.ts)
- [src/telegram/router.ts](https://github.com/darula-hpp/memgrep/blob/main/src/telegram/router.ts)
</details>

# Telegram Bot and Remote Cursor

## Purpose and Scope

The Telegram Bot and Remote Cursor subsystem in memgrep provides a chat-based interface for interacting with the project's grep/memory-search functionality from a mobile or remote client. It bridges Telegram's long-polling API with an internal "remote cursor" abstraction that streams intermediate and final results back to the originating chat, so users can issue search/lookup commands without running memgrep locally.

The subsystem is organized into a small set of cooperating modules:

- `bot.ts` — the entrypoint that constructs the bot, wires dependencies, and starts the polling loop.
- `polling.ts` — encapsulates the long-poll loop, backoff, and reconnect logic against the Telegram Bot API.
- `router.ts` — dispatches incoming updates (commands and free-text messages) to handlers.
- `session-store.ts` — persists per-chat session state (cursor positions, last query, idempotency keys) durably across reconnects.
- `process-guards.ts` — provides single-instance enforcement and graceful-shutdown handling for the bot process.
- `allowlist.ts` — gates incoming updates to a configured set of chat IDs/users.

The v1.1.0 release explicitly hardened this subsystem: "More resilient Telegram/Cursor session handling across reconnects and long-running chats" and "Internal code quality improvements (atomic writes, process guards, session store hardening)." `Source: [CHANGELOG.md:1-10]()`

## Architecture and Data Flow

The bot follows a thin entrypoint → polling → router → handler → session-store pipeline. The remote cursor is implemented as a stateful handle kept inside the session record, so a reconnect or crash does not lose the user's place in a streamed result.

```mermaid
flowchart LR
  TG[Telegram Bot API] -->|updates| POL[polling.ts]
  POL -->|normalized Update| RTR[router.ts]
  ALW[allowlist.ts] -->|allow/deny| RTR
  RTR -->|command| HND[command handlers]
  RTR -->|free-text| HND
  HND -->|open/advance| CUR[Remote Cursor]
  CUR --> SS[session-store.ts]
  SS -->|atomic write| FS[(session.json)]
  PG[process-guards.ts] --> POL
  PG --> SS
```

Key invariants enforced across modules:

- Only one bot process may run at a time; `process-guards.ts` raises a duplicate-instance error otherwise. `Source: [src/telegram/process-guards.ts:1-40]()`
- Every incoming update is checked against `allowlist.ts` before any handler runs. `Source: [src/telegram/allowlist.ts:1-30]()`
- Cursor state is written via atomic write helpers so partial flushes cannot corrupt the session file. `Source: [src/telegram/session-store.ts:1-60]()`

## Session Store and Cursor Hardening (v1.1.0)

The session store is the heart of long-running chat reliability. Each chat has an associated record containing the user identity, the active cursor (if any), the last delivered message id (for pagination/replay), and metadata for idempotency. Writes are performed atomically: a temp file is written in the same directory and then `rename`d over the target, so a crash or power loss cannot leave a half-written session.

`process-guards.ts` installs SIGINT/SIGTERM handlers that flush pending writes, close the polling loop cleanly, and remove the single-instance lockfile. Together with the polling backoff, this is what makes "reconnects and long-running chats" resilient in v1.1.0. `Source: [src/telegram/process-guards.ts:40-90]()`

The remote cursor itself is a thin object that pairs a backend query handle with a delivery position. Handlers advance the cursor as new results arrive, and the router uses the cursor to format and send Telegram messages. Because cursor state lives in the session record, the bot can resume a partially delivered result after a restart rather than re-running the underlying query.

## Routing, Polling, and Allowlist

`router.ts` separates two update classes: slash commands (e.g. `/search`, `/status`) and free-text messages. Commands are matched by a small dispatch table; free-text falls through to a default handler that interprets the message as a query, opening a new cursor. `Source: [src/telegram/router.ts:1-80]()`

`polling.ts` runs the long-poll loop, normalizes Telegram `Update` objects into an internal shape, and applies exponential backoff on network errors. Offsets are persisted via the session store so a reconnect does not re-deliver old messages or skip messages that arrived while the bot was down. `Source: [src/telegram/polling.ts:1-70]()`

`allowlist.ts` reads a list of permitted chat IDs from configuration and silently drops any update whose `chat.id` is not present. This is the primary access-control boundary; handlers can assume every update they receive is authorized. `Source: [src/telegram/allowlist.ts:30-60]()`

## Operational Notes

- **Single instance:** always run the bot under a supervisor or wrap it so that `process-guards.ts` can enforce uniqueness; starting a second instance will exit fast.
- **Reconnects:** the polling loop resumes from the last persisted offset; no manual intervention is required after transient network loss.
- **Long chats:** cursor state survives process restarts, so partially delivered result sets continue from the right position instead of restarting.
- **Atomic durability:** session writes use rename-based atomic replacement; never edit `session.json` by hand while the bot is running.

Together, these properties make the Telegram Bot and Remote Cursor subsystem a stable remote front-end for memgrep's search capabilities, with the v1.1.0 hardening specifically targeting the reconnect and long-running-chat scenarios that earlier versions handled less gracefully.

---

<a id='page-jobs-system'></a>

## Scheduled Jobs and Playbooks

### Related Pages

Related topics: [Telegram Bot and Remote Cursor](#page-telegram-bot), [Deployment, Operations, and Reliability](#page-deployment-ops)

<details>
<summary>Related Source Files</summary>

The following source files were used to generate this page:

- [src/jobs/daemon.ts](https://github.com/darula-hpp/memgrep/blob/main/src/jobs/daemon.ts)
- [src/jobs/executor.ts](https://github.com/darula-hpp/memgrep/blob/main/src/jobs/executor.ts)
- [src/jobs/cursor-executor.ts](https://github.com/darula-hpp/memgrep/blob/main/src/jobs/cursor-executor.ts)
- [src/jobs/schedule.ts](https://github.com/darula-hpp/memgrep/blob/main/src/jobs/schedule.ts)
- [src/jobs/service.ts](https://github.com/darula-hpp/memgrep/blob/main/src/jobs/service.ts)
- [src/jobs/store.ts](https://github.com/darula-hpp/memgrep/blob/main/src/jobs/store.ts)
</details>

# Scheduled Jobs and Playbooks

## Overview

The `src/jobs/` module implements memgrep's background scheduling layer for recurring automation tasks, including the "playbook" runs that drive long-lived Telegram and Cursor sessions. A central daemon supervises timed triggers, hands them off to specialized executors, and persists state in a hardened session/job store. The module is intentionally split so that the scheduling policy, execution runtime, and persistence concerns can evolve independently.

`Source: [src/jobs/daemon.ts]()`  
`Source: [src/jobs/schedule.ts]()`  
`Source: [src/jobs/service.ts]()`

## Component Architecture

The job subsystem is organized as a pipeline of single-responsibility units that cooperate through the `service` facade.

```mermaid
flowchart LR
  Scheduler[schedule.ts<br/>trigger logic] --> Daemon[daemon.ts<br/>process guard & loop]
  Daemon --> Service[service.ts<br/>orchestration]
  Service --> Exec[executor.ts<br/>generic runner]
  Service --> CursorExec[cursor-executor.ts<br/>Cursor session runner]
  Exec --> Store[store.ts<br/>persistent state]
  CursorExec --> Store
  Store --> Service
```

Key responsibilities:

- `daemon.ts` — Owns the long-running process, enforces a single-instance lock, and recovers after crashes or reconnects. The v1.1.0 release notes call out "process guards" here.
- `schedule.ts` — Defines when jobs fire (intervals, cron-like expressions, one-shot delays) and is the only module that decides *what should run next*.
- `service.ts` — Acts as the public API surface and coordinator between schedule, executor, and store.
- `executor.ts` — Generic executor used for non-Cursor playbooks and for shared concerns such as retries and timeouts.
- `cursor-executor.ts` — Specialized executor that bridges the scheduler with Cursor sessions; coupled to the Telegram/Cursor resilience work shipped in v1.1.0.
- `store.ts` — Persistence layer that records playbook runs, session metadata, and last-known state; hardened with atomic writes per the release notes.

`Source: [src/jobs/daemon.ts]()`  
`Source: [src/jobs/service.ts]()`  
`Source: [src/jobs/executor.ts]()`  
`Source: [src/jobs/cursor-executor.ts]()`  
`Source: [src/jobs/store.ts]()`

## Scheduling and Trigger Flow

`schedule.ts` produces the next due job by inspecting registered playbooks and their timing rules. The daemon wakes on a tick interval, queries the scheduler for due entries, and forwards them to the service. The service resolves the correct executor (generic or Cursor-specific), runs the job, and writes results back through the store.

For Cursor-driven playbooks, `cursor-executor.ts` re-establishes or resumes the existing Cursor session before invoking the underlying agent. This is the integration point that received the most attention in v1.1.0, where "more resilient Telegram/Cursor session handling across reconnects and long-running chats" was added.

The flow is intentionally idempotent at the scheduling boundary: if the daemon is restarted mid-run, `schedule.ts` re-derives due jobs from persisted state rather than relying on in-memory timers alone. `store.ts` is the source of truth that makes this recovery possible.

`Source: [src/jobs/schedule.ts]()`  
`Source: [src/jobs/daemon.ts]()`  
`Source: [src/jobs/cursor-executor.ts]()`  
`Source: [src/jobs/store.ts]()`

## Execution and Persistence

### Executors

`executor.ts` provides the baseline execution contract: accept a job descriptor, run the playbook body, capture stdout/stderr or structured results, and surface errors as typed outcomes. `cursor-executor.ts` extends that contract with Cursor-specific session lookup, retry-on-reconnect behavior, and cleanup of orphaned sessions when a run terminates abnormally. The split lets non-Cursor playbooks avoid carrying Cursor-only dependencies.

### Store and atomicity

`store.ts` is the only module allowed to mutate durable job state. In line with the v1.1.0 changelog ("atomic writes, process guards, session store hardening"), writes are committed through atomic file operations so that partial updates never leave the store in an inconsistent state. The store also tracks per-job run history so that retries can resume from the last successful step rather than restarting from scratch.

`Source: [src/jobs/executor.ts]()`  
`Source: [src/jobs/cursor-executor.ts]()`  
`Source: [src/jobs/store.ts]()`

## Operational Notes

- **Single instance:** The daemon relies on a process lock so that two schedulers do not race to execute the same playbook. Operators should treat this lock as authoritative and avoid launching duplicate daemons.
- **Recovery:** After a crash, restarting the daemon re-reads due jobs from the store; long-running Cursor sessions are reattached rather than abandoned, matching the v1.1.0 resilience improvements.
- **Extending playbooks:** New automated tasks should be registered through `service.ts`, which routes them to `executor.ts` unless they explicitly require Cursor integration, in which case `cursor-executor.ts` is used.
- **State inspection:** All authoritative state lives in `store.ts`; logs and ad-hoc files outside the store are not considered durable for scheduling purposes.

`Source: [src/jobs/service.ts]()`  
`Source: [src/jobs/daemon.ts]()`  
`Source: [src/jobs/store.ts]()`

---

<a id='page-deployment-ops'></a>

## Deployment, Operations, and Reliability

### Related Pages

Related topics: [Telegram Bot and Remote Cursor](#page-telegram-bot), [Scheduled Jobs and Playbooks](#page-jobs-system)

<details>
<summary>Related Source Files</summary>

The following source files were used to generate this page:

- [src/jobs/launchd.ts](https://github.com/darula-hpp/memgrep/blob/main/src/jobs/launchd.ts)
- [src/telegram/launchd.ts](https://github.com/darula-hpp/memgrep/blob/main/src/telegram/launchd.ts)
- [src/fs/atomic-write.ts](https://github.com/darula-hpp/memgrep/blob/main/src/fs/atomic-write.ts)
- [src/telegram/process-guards.ts](https://github.com/darula-hpp/memgrep/blob/main/src/telegram/process-guards.ts)
- [src/telegram/session-store.ts](https://github.com/darula-hpp/memgrep/blob/main/src/telegram/session-store.ts)
- [.env.example](https://github.com/darula-hpp/memgrep/blob/main/.env.example)
</details>

# Deployment, Operations, and Reliability

This page documents how `memgrep` is deployed, supervised, and kept reliable at runtime. It covers the launchd-based process orchestration for scheduled jobs and the Telegram/Cursor integration, the atomic-write primitives used for durable storage, the process-guard utilities that protect long-running sessions, and the configuration surface exposed through the environment file.

## Process Supervision via launchd

The repository uses `launchd` (macOS) as the supervisor for two distinct workload classes: periodic background jobs and the persistent Telegram bot runtime.

- `src/jobs/launchd.ts` registers periodic job execution with the system launcher, ensuring background work (such as indexing, cleanup, or scheduled searches) runs reliably across reboots and user sessions. `Source: [src/jobs/launchd.ts]()`
- `src/telegram/launchd.ts` keeps the Telegram integration alive as a long-running daemon, restarting it on crash and surviving logout. This is the foundation of the "resilient Telegram/Cursor session handling across reconnects and long-running chats" introduced in v1.1.0. `Source: [src/telegram/launchd.ts]()`

Together these modules decouple the scheduler from the application logic: launchd owns lifecycle, while the TypeScript modules own registration, environment loading, and signal handling.

## Atomic Writes for Durable State

To prevent corruption from crashes, power loss, or concurrent writers, `memgrep` routes all critical file mutations through the helper in `src/fs/atomic-write.ts`.

Typical guarantees provided by this module:

- Writes are staged to a temporary file in the same directory, then renamed atomically into place.
- Partial or truncated files are never observed by readers.
- The pattern is used by the session store to persist Telegram session data without risking a half-written JSON or sqlite file.

`Source: [src/fs/atomic-write.ts]()`

This pattern is one of the "internal code quality improvements (atomic writes, …)" called out in the v1.1.0 changelog, and is a prerequisite for the session-store hardening described below.

## Process Guards and Session Store Hardening

Two Telegram-specific modules implement the reliability layer for the chat runtime.

### Process Guards

`src/telegram/process-guards.ts` provides defensive utilities that prevent the daemon from running in degenerate states, such as:

- Refusing to start a second instance (single-instance lock).
- Detecting stale PID files left by a previous crash and recovering gracefully.
- Cleaning up child resources on `SIGTERM` / `SIGINT`.

`Source: [src/telegram/process-guards.ts]()`

These guards are the second half of the v1.1.0 "process guards" improvement and complement the supervisor in `src/telegram/launchd.ts`.

### Session Store

`src/telegram/session-store.ts` persists Telegram session state (auth keys, dialog offsets, Cursor chat context) so that reconnects do not lose conversation continuity. Combined with atomic writes and process guards, this delivers the "more resilient Telegram/Cursor session handling across reconnects and long-running chats" promised in the release notes. `Source: [src/telegram/session-store.ts]()`

## Configuration Surface

Runtime configuration is supplied through environment variables documented in `.env.example`. Operators are expected to copy this file to `.env` and populate it before launching either of the launchd-managed daemons. The launchd wrappers read the environment on startup and pass it to supervised processes, which means restarts triggered by launchd automatically pick up changes only after a reload of the plist. `Source: [.env.example]()`

## Reliability Workflow

```mermaid
flowchart LR
  A[launchd] --> B[jobs/launchd.ts]
  A --> C[telegram/launchd.ts]
  C --> D[process-guards.ts]
  D --> E[session-store.ts]
  E --> F[atomic-write.ts]
  C --> G[.env]
  B --> G
```

This diagram summarizes the runtime topology: launchd supervises both daemons, the Telegram daemon is gated by process guards, and its persistent state is written atomically to disk.

## Operational Notes

- Always restart through `launchctl` rather than killing the process directly; the process-guards module assumes it owns the PID file.
- After editing `.env`, reload the corresponding plist so the new environment is picked up by the next supervised launch.
- Treat the session store file as opaque binary or JSON state — manual edits bypass the atomic-write guarantee and can corrupt long-running chats.

---

<!-- evidence_pipeline_checked: true -->
<!-- evidence_injected: true -->

---

## Pitfall Log

Project: darula-hpp/memgrep

Summary: Found 8 structured pitfall item(s), including 0 high/blocking item(s). Top priority: Configuration risk - Configuration risk requires verification.

## 1. Configuration risk - Configuration risk requires verification

- Severity: medium
- Evidence strength: source_linked
- Finding: Project evidence flags a configuration risk. Review the linked source before relying on this workflow.
- User impact: May increase setup, validation, or first-run risk for the user.
- Evidence: capability.host_targets | https://github.com/darula-hpp/memgrep

## 2. Capability evidence risk - Capability evidence risk requires verification

- Severity: medium
- Evidence strength: source_linked
- Finding: README/documentation is current enough for a first validation pass.
- User impact: May increase setup, validation, or first-run risk for the user.
- Evidence: capability.assumptions | https://github.com/darula-hpp/memgrep

## 3. Maintenance risk - Maintenance risk requires verification

- Severity: medium
- Evidence strength: source_linked
- Finding: Project evidence flags a maintenance risk. Review the linked source before relying on this workflow.
- User impact: May increase setup, validation, or first-run risk for the user.
- Evidence: evidence.maintainer_signals | https://github.com/darula-hpp/memgrep

## 4. Security or permission risk - Security or permission risk requires verification

- Severity: medium
- Evidence strength: source_linked
- Finding: no_demo
- User impact: May increase setup, validation, or first-run risk for the user.
- Evidence: downstream_validation.risk_items | https://github.com/darula-hpp/memgrep

## 5. Security or permission risk - Security or permission risk requires verification

- Severity: medium
- Evidence strength: source_linked
- Finding: no_demo
- User impact: May increase setup, validation, or first-run risk for the user.
- Evidence: risks.scoring_risks | https://github.com/darula-hpp/memgrep

## 6. Maintenance risk - Maintenance risk requires verification

- Severity: low
- Evidence strength: source_linked
- Finding: issue_or_pr_quality=unknown。
- User impact: May increase setup, validation, or first-run risk for the user.
- Evidence: evidence.maintainer_signals | https://github.com/darula-hpp/memgrep

## 7. Maintenance risk - Maintenance risk requires verification

- Severity: low
- Evidence strength: source_linked
- Finding: release_recency=unknown。
- User impact: May increase setup, validation, or first-run risk for the user.
- Evidence: evidence.maintainer_signals | https://github.com/darula-hpp/memgrep

## 8. Maintenance risk - Maintenance risk requires verification

- Severity: low
- Evidence strength: source_linked
- Finding: Developers should check this maintenance risk before relying on the project: v1.1.0
- User impact: Upgrade or migration may change expected behavior: v1.1.0
- Evidence: failure_mode_cluster:github_release | https://github.com/darula-hpp/memgrep/releases/tag/v1.1.0

<!-- canonical_name: darula-hpp/memgrep; human_manual_source: deepwiki_human_wiki -->
