# Reported issues for Engram by devinmlowe

Pod holds 13 of 13 GitHub reports that passed its relevance review. This can include external user reports, maintainer-confirmed bugs, and concrete feature gaps. Treat them as evidence to inspect, not a count of distinct defects.

Back to [Engram by devinmlowe](/mcp/engram-by-devinmlowe).

## Most discussed

### [mcp] forget's scope: "global" bypasses assertScope for every caller — an env-pinned tenant can delete another tenant's memories

**Evidence**

`src/semantic/forget.ts:229-236`:

```ts
function assertScope(row: MemoryRow, gate: ScopeGate): void {
  if (gate.scope === GLOBAL_SCOPE) return;
  ...
}
```

`ScopeGate.scope` doc (`forget.ts:62-66`): `"global"` is the documented override: it acts on a memory in any scope even when `readScopes` would hide it. The MCP `forget` tool passes it straight through — `server.ts:1900-1906` `scope: params.scope` — and the query path likewise widens the candidate search: `server.ts:1926`…

[Read the thread](https://github.com/devinmlowe/engram/issues/109) · 2026-09-21 · closed · 4 comments

### [semantic] memory_suppressions is keyed on content_hash alone — one tenant's forget suppresses (and one tenant's remember lifts) re-extraction of the same sentence for every tenant

**Evidence**

`src/semantic/forget.ts:368-370` — `forgetMemory` records the tenant scope of the forgotten row:

```ts
db.prepare(
  "INSERT OR REPLACE INTO memory_suppressions (content_hash, memory_id, scope, created_at) VALUES (?, ?, ?, ?)",
).run(contentHash(row.content), row.id, row.scope ?? GLOBAL_SCOPE, now);
```

but every reader keys on `content_hash` alone:

- `forget.ts:169-174` `isSuppressed` — `SELECT 1 FROM memory_suppressions WHERE content_hash = ?`
- `forget.ts:177-180`…

[Read the thread](https://github.com/devinmlowe/engram/issues/106) · 2026-09-21 · closed · 4 comments

### [mcp] resolveCallScoping lets client read_scopes / scope replace ENGRAM_READ_SCOPES / ENGRAM_SCOPE instead of intersecting — an env-pinned stdio child can read and write any tenant

**Evidence**

`src/interfaces/mcp/scoping.ts:73-92` `resolveCallScoping`:

```ts
const base = getTenantScoping(env);
const writeScope = params.scope !== undefined ? requireScope(params.scope, "scope") : base.writeScope;
let readScopes = base.readScopes;
if (params.read_scopes !== undefined) {
  ...
  readScopes = params.read_scopes.map((s) => requireScope(s, "read_scopes"));
} else if (params.scope !== undefined && !env.ENGRAM_READ_SCOPES?.trim()) {
  readScopes = ["global", writeScope as…

[Read the thread](https://github.com/devinmlowe/engram/issues/108) · 2026-09-21 · closed · 3 comments

### [mcp] stdio start bridges to the daemon and silently drops ENGRAM_SCOPE / ENGRAM_READ_SCOPES / ENGRAM_DB_PATH from its own env — Hermes stdio profile isolation is bypassed

**Evidence**

`interfaces/hermes-plugin/provider.py:278-297` — the stdio transport scopes its child purely through the environment and passes no per-call `scope` / `read_scopes` arguments (`mcp_client.py:156` sends `{"name", "arguments"}` verbatim):

```python
def _child_env(self) -> Dict[str, str]:
    env: Dict[str, str] = {
        "ENGRAM_SCOPE": self._write_scope(),
        "ENGRAM_READ_SCOPES": self._config.get("read_scopes", f"global,{self._write_scope()}"),
    }
    if…

[Read the thread](https://github.com/devinmlowe/engram/issues/87) · 2026-09-18 · closed · 2 comments

### [PRD] Plugin-marketplace + MCP-registry distribution

> Auto-generated from research findings. DECISION NEEDED items and LOW-confidence sections require your judgment.

**Tier:** Must-have #4 · **Confidence:** HIGH · **Research:** insights 3, 10

## Problem statement

In 2026 developers discover memory servers through the MCP registry and plugin marketplaces, not READMEs: `server-memory` sees ~390K npm downloads/month via registry discovery ([Mnemoverse comparison](https://mnemoverse.com/docs/library/memory-mcp-servers-compared)); the official…

[Read the thread](https://github.com/devinmlowe/engram/issues/58) · 2026-09-17 · closed · 2 comments

### Decision: plugin: MCP transport — npx stdio or HTTP daemon?

Plugin MCP transport: `npx` stdio (zero-setup) vs HTTP (needs the daemon). Recommendation: ship stdio in the plugin; `engram mcp install claude` (PRD 1) upgrades it to HTTP.

**Parent PRD:** #58

This decision blocks implementation of the parent PRD. Close it by recording the choice (and the reason) in a comment, then updating the PRD issue body if the requirements change.

[Read the thread](https://github.com/devinmlowe/engram/issues/60) · 2026-09-17 · closed · 1 comment

### engram update: start step uses launchctl load, which registers but never runs the job (mcp did not answer within 90s)

## What happened

`engram update --yes` on macOS (git-checkout install, 0.4.0 -> 0.4.0 re-run on 2026-09-21) failed at the restart step:

```
start mcp: mcp did not answer on its port within 90s
```

The automatic code-only rollback then failed at the same step, leaving `/Users/devinmlowe/git/engram` detached at the previous sha with all three services loaded but not running.

## Root cause

The supervisor adapter in `src/interfaces/cli/services.ts` starts a launchd job with `launchctl load…

[Read the thread](https://github.com/devinmlowe/engram/issues/147) · 2026-09-21 · open · 0 comments

### [hermes-plugin] test_stdio_e2e_real_server.py spawns server.js without --standalone, so it bridges to the live daemon and writes through it

Found while verifying #119 (PR #137).

`interfaces/hermes-plugin/tests/test_stdio_e2e_real_server.py` starts `dist/interfaces/mcp/server.js` without `--standalone`. Since decision #60 a stdio start probes `http://127.0.0.1:9907/health` and, when the daemon answers, becomes a bridge. On a machine with the daemon running, the test's `remember` call therefore goes to the production database (observed: `Updated existing memory` on an already-present fixture memory) and the assertion on a fresh…

[Read the thread](https://github.com/devinmlowe/engram/issues/138) · 2026-09-21 · closed · 0 comments

## Most recent

### [search] recall sessions do not pin read_scopes — a refine with different scopes merges other tenants' results into the session, and recall_drill re-checks nothing

**Evidence**

`src/_core/search/session.ts:42-52` `RecallSession` has no scope field; `SessionStore.create` (`session.ts:76-99`) stores `query`, `results`, budgets only. `src/interfaces/shared/search.ts:195-235` refines an existing session with the scopes of the *current* call:

```ts
const response = await searchMultiSource(db, {
  query: params.query, sources, mode: "hybrid", budget: remainingBudget,
  scopes: params.scopes,   // from this call, not the session
}, config);…

[Read the thread](https://github.com/devinmlowe/engram/issues/110) · 2026-09-21 · open · 0 comments

### [hermes-plugin] provider.py replaces a client whose reader thread died without stop() — the still-running node child (model loaded) is orphaned, an exited one is never wait()ed

**Evidence**

`interfaces/hermes-plugin/mcp_client.py:51-58`:

```python
@property
def alive(self) -> bool:
    # A child whose stdout reader has ended (EOF or reader crash) can
    # never answer again, so it counts as dead even if the PID lingers
    return (self._proc is not None and self._proc.poll() is None and not self._reader_dead)
```

`interfaces/hermes-plugin/provider.py:305-312`:

```python
if self._client is None or not self._client.alive:
    client =…

[Read the thread](https://github.com/devinmlowe/engram/issues/105) · 2026-09-18 · open · 0 comments

### [mcp] HTTP daemon session map only shrinks on DELETE /mcp — clients that disconnect without terminating their session leak a Server + transport per session forever

**Evidence**

`src/interfaces/mcp/http.ts:61-70` (only removal path) and `:85-95`:

```ts
if (req.method === "DELETE" && sessionId) {
  const transport = sessions.get(sessionId);
  if (transport) { sessions.delete(sessionId); await transport.close(); }
  ...
}
...
const transport = new StreamableHTTPServerTransport({ sessionIdGenerator: () => randomUUID() });
const sessionServer = new Server(serverInfo, { capabilities: { tools: {} } });
options.registerHandlers(sessionServer);
await…

[Read the thread](https://github.com/devinmlowe/engram/issues/104) · 2026-09-18 · open · 0 comments

### [mcp] bridge retries a failed tools/call after reconnect with identical params — at-least-once execution for non-idempotent tools (forget succeeds, then the host is told "not found")

**Evidence**

`src/interfaces/mcp/bridge.ts:228-247` (`forward`):

```ts
try {
  return await op(client);
} catch (err) {
  if (err instanceof McpError) throw new McpError(err.code, bareMessage(err), err.data);
  try {
    const again = await reconnect(`${what} failed: ${errMsg(err)}`);
    const result = await op(again);          // same req.params (bridge.ts:250)
```

**Why it's a bug**

A transport failure after the daemon has committed the call but before the response reaches the bridge…

[Read the thread](https://github.com/devinmlowe/engram/issues/103) · 2026-09-18 · open · 0 comments

### [windows] Supervise the MCP HTTP daemon across system restarts

## Problem

After a Windows system restart on **September 16, 2026**, the engram visualizer recovered through its Windows Task Scheduler task, but the engram MCP HTTP daemon did not restart automatically.

The MCP daemon was not listening on its configured local port and no MCP server process was running. The database, compiled runtime, and visualizer were healthy; manually starting the MCP daemon restored service.

## Context

The visualizer and MCP daemon currently have different lifecycle…

[Read the thread](https://github.com/devinmlowe/engram/issues/12) · 2026-09-16 · closed · 0 comments

The remaining reports are on [the project's issue tracker](https://github.com/devinmlowe/engram/issues).
