# https://github.com/purmemo-ai/purmemo-mcp Project Manual

Generated at: 2026-07-18 21:19:50 UTC

## Table of Contents

- [Installation, Sign-in & Auth Recovery](#page-1)
- [MCP Tools, Hooks & Slash Commands](#page-2)
- [Architecture & Key Design Decisions](#page-3)
- [Cross-Platform Integrations, iOS & Distribution](#page-4)

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

## Installation, Sign-in & Auth Recovery

### Related Pages

Related topics: [MCP Tools, Hooks & Slash Commands](#page-2), [Architecture & Key Design Decisions](#page-3)

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

The following source files were used to generate this page:

- [README.md](https://github.com/purmemo-ai/purmemo-mcp/blob/main/README.md)
- [scripts/install.sh](https://github.com/purmemo-ai/purmemo-mcp/blob/main/scripts/install.sh)
- [scripts/install.ps1](https://github.com/purmemo-ai/purmemo-mcp/blob/main/scripts/install.ps1)
- [src/cli/init.ts](https://github.com/purmemo-ai/purmemo-mcp/blob/main/src/cli/init.ts)
- [src/auth/oauth-manager.ts](https://github.com/purmemo-ai/purmemo-mcp/blob/main/src/auth/oauth-manager.ts)
- [src/auth/token-store.ts](https://github.com/purmemo-ai/purmemo-mcp/blob/main/src/auth/token-store.ts)
- [src/auth/key-derivation.ts](https://github.com/purmemo-ai/purmemo-mcp/blob/main/src/auth/key-derivation.ts)
- [src/cli/recover.ts](https://github.com/purmemo-ai/purmemo-mcp/blob/main/src/cli/recover.ts)
- [docs/ADR/039-token-storage-fallback.md](https://github.com/purmemo-ai/purmemo-mcp/blob/main/docs/ADR/039-token-storage-fallback.md)
</details>

# Installation, Sign-in & Auth Recovery

pūrmemo's installation and authentication layer is designed around a single principle: a new user should reach a working memory in one command, and a returning user should never see a stack trace when their token goes stale. This page documents the install path, the OAuth/sign-in flow, and the recovery mechanisms that keep the CLI self-healing across hostile environments (macOS hostname drift, stale tokens, unreadable disk state).

## Installation

The repository ships platform-specific installer scripts that bootstrap the CLI and register it with supported MCP clients (Claude Code, Codex, Gemini CLI). On POSIX systems the entry point is `scripts/install.sh`; on Windows it is `scripts/install.ps1`. Both scripts resolve dependencies, write the configured MCP entry into the host agent, and emit a short next-step hint `Source: [README.md:1-80]()`. New users see a README that "gets out of their way" — the happy path is a single shell invocation that ends with the browser sign-in window already opening `Source: [scripts/install.sh:1-120]()`.

For users who already have a partial install, the install scripts are idempotent: re-running them does not clobber an existing token, only refreshes the binary and hook configuration `Source: [scripts/install.sh:120-200]()`. The PowerShell variant mirrors this contract `Source: [scripts/install.ps1:1-150]()`.

## Sign-in & OAuth Flow

After install, `purmemo init` triggers the sign-in path. The CLI delegates to `oauth-manager.ts`, which starts a local callback listener, opens the browser to the pūrmemo authorization page, and exchanges the returned code for an OAuth token `Source: [src/auth/oauth-manager.ts:1-180]()`. The token is then handed to `token-store.ts` for at-rest encryption before persisting to disk `Source: [src/auth/token-store.ts:1-90]()`.

Since v15.7.20, the CLI is no longer the only entry into this flow. If any later command detects a stale or missing token, it auto-launches the same browser sign-in with a one-line explanation instead of erroring out `Source: [src/cli/init.ts:1-140]()`. This change collapsed two user-visible states ("installed but not signed in" and "was signed in, token expired") into one self-healing path.

## Token Storage & Encryption Key

Tokens are encrypted with an OpenSSL symmetric cipher whose key is derived from local host identifiers via `SHA-256(os.hostname() + os.userInfo().username)` in legacy mode, or read from a persisted key file in current mode `Source: [src/auth/key-derivation.ts:1-110]()`. The persisted-key mode was introduced in v15.7.18 to fix silent token corruption on macOS: when users switched Wi-Fi networks, toggled a VPN (NordVPN, etc.), or sleep/woke the laptop, `os.hostname()` flipped because of DHCP and Bonjour re-advertisement, producing a different key and an unreadable token `Source: [docs/ADR/039-token-storage-fallback.md:1-60]()`.

The fallback strategy (ADR-039) lets the store try the persisted key first, then the legacy hostname-derived key, so a single hostname change does not brick the install `Source: [src/auth/token-store.ts:90-180]()`.

## Auth Recovery

Two distinct failure modes each have a dedicated recovery path, surfaced through `recover.ts`:

| Failure | Trigger | Recovery action | Introduced |
|---|---|---|---|
| Bad decrypt (recoverable) | hostname/key mismatch on a still-valid token store | re-derive with legacy key, keep going | v15.7.20 |
| Bad decrypt (unrecoverable) | both persisted and legacy keys fail, hostname drifted past the fallback window | auto-launch browser sign-in, replace token | v15.7.19 |

Before v15.7.19, an unrecoverable decrypt surfaced as a raw OpenSSL error (`error:1C80006...`) and left the user effectively bricked, with no path back except a manual uninstall `Source: [src/cli/recover.ts:1-160]()`. The current implementation catches that error class, deletes the unreadable ciphertext, and re-enters the OAuth flow without requiring the user to type `purmemo init` again `Source: [src/cli/recover.ts:160-260]()`.

The same recovery entry point is reused by the install scripts, so a user who upgrades a bricked install gets the browser sign-in automatically on the next tool call instead of seeing an exception in their MCP client `Source: [src/auth/oauth-manager.ts:180-260]()`.

## Operational notes

- **Idempotent installs**: re-running `scripts/install.sh` or `scripts/install.ps1` preserves the token store; only binary and hook assets are refreshed.
- **Self-healing CLI**: every command that needs the token funnels through `token-store.ts`, which is the single integration point for all three recovery paths above.
- **macOS users**: prefer a stable hostname (disable Bonjour name randomization) if you cannot rely on the persisted-key file being readable across sessions.
- **Debug signal**: a visible browser window opening unprompted means the recovery path fired — this is expected behavior, not a regression.

---

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

## MCP Tools, Hooks & Slash Commands

### Related Pages

Related topics: [Installation, Sign-in & Auth Recovery](#page-1), [Architecture & Key Design Decisions](#page-3)

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

The following source files were used to generate this page:

- [src/server.ts](https://github.com/purmemo-ai/purmemo-mcp/blob/main/src/server.ts)
- [src/tools/handlers.ts](https://github.com/purmemo-ai/purmemo-mcp/blob/main/src/tools/handlers.ts)
- [src/tools/handoff.ts](https://github.com/purmemo-ai/purmemo-mcp/blob/main/src/tools/handoff.ts)
- [src/intelligent-memory.ts](https://github.com/purmemo-ai/purmemo-mcp/blob/main/src/intelligent-memory.ts)
- [src/workflows/engine.ts](https://github.com/purmemo-ai/purmemo-mcp/blob/main/src/workflows/engine.ts)
- [src/hooks/purmemo_first_message.ts](https://github.com/purmemo-ai/purmemo-mcp/blob/main/src/hooks/purmemo_first_message.ts)
</details>

# MCP Tools, Hooks & Slash Commands

## Overview

Pūrmemo MCP integrates a persistent memory backend with AI coding agents through three coordinated surfaces: **MCP tools** callable from the model, **session-start hooks** injected into agent runtimes, and **slash commands** surfaced to the user. Together they let the agent read prior context at the start of a session, write new memory mid-session, and hand off work across sessions.

The MCP server registers its tool surface in `src/server.ts`, dispatches incoming tool calls to a handler registry in `src/tools/handlers.ts`, and delegates the heavier memory orchestration to `src/intelligent-memory.ts` and `src/workflows/engine.ts`. Hook installation for each supported agent (Claude Code, Gemini CLI, OpenAI Codex) and the first-message priming logic live under `src/hooks/`.

Source: [src/server.ts:1-80]()

## MCP Tools

### Tool registry and dispatch

`src/server.ts` exposes a list of tool definitions via the standard MCP `tools/list` method and routes `tools/call` requests through `src/tools/handlers.ts`. Each handler is responsible for parameter validation, telemetry, and delegating to a domain module. The domain modules split naturally along the data they touch: conversation storage (`save_conversation`), workflow lifecycle (`src/workflows/engine.ts`), semantic recall (`src/intelligent-memory.ts`), and cross-agent handoff (`src/tools/handoff.ts`).

Source: [src/tools/handlers.ts:1-120]()

### Read and write tools

The write path centers on `save_conversation`, which as of v15.7.17 accepts an explicit `mode` parameter — either `replace` (default, one-shot snapshots) or `append` (true living document with timestamped separators). This change was formalized as ADR-036 to remove ambiguity for callers. Source: [src/tools/handlers.ts:120-220]()

The read path was expanded in v15.7.21 with three new tools: `get_test_results`, `get_artifacts`, and `get_investigations`. These close a "write-only telemetry gap" — prior to that release the server could record test outcomes, artifact references, and investigation narratives but offered no native way for the model to recall them. Source: [src/tools/handlers.ts:220-360]()

Both `get_test_results` and `get_investigations` previously truncated long string fields (200-character clips of `failure_details` and `root_cause_analysis` respectively). v15.7.22 and v15.7.23 lifted those caps and print the full body with wrapped-line indentation so the model can see complete failure traces and root-cause narratives. Source: [src/tools/handlers.ts:260-340]()

### Handoff tool

`src/tools/handoff.ts` implements the cross-session handoff primitive. A handoff bundles the current task state, open todos, and the memory IDs that should be reactivated in the next session, so a new agent invocation can resume without rediscovering context. Source: [src/tools/handoff.ts:1-140]()

### Intelligent memory and workflows

`src/intelligent-memory.ts` provides the semantic layer behind recall — chunking conversations, computing embeddings, and ranking hits during a `search_memories` call. `src/workflows/engine.ts` runs multi-step memory workflows (consolidation, summarization, dedup) that the agent can trigger explicitly via tools. Source: [src/intelligent-memory.ts:1-160](), [src/workflows/engine.ts:1-200]()

## Session-Start Hooks

Hooks are installed per-agent so that the moment a new session begins the agent is primed with a brief from Pūrmemo. The brief is injected via the agent's native hook system rather than the MCP tool surface, so it runs even before the model issues its first tool call.

| Agent | Hook entry point | Notes |
|---|---|---|
| Claude Code | `SessionStart` hook in settings | v15.7.24 fixed JSONL sniffing that miscounted user messages |
| Gemini CLI | `SessionStart` equivalent | Parity target since v15.7.15 |
| OpenAI Codex | `hooks.json` under `[features] codex_hooks` | Feature flag enabled in v15.7.16 |

Source: [src/hooks/purmemo_first_message.ts:1-160]()

The hook emits a single-line header of the form `pūrmemo v15.7.15 · email · tier · memories · cycle usage`, followed by a conversation-first recall ranking so the most recent relevant thread surfaces first. v15.7.24 repaired a JSONL sniffing bug where Claude transcripts were parsed as a single JSON document (which threw on line 2 and silently fell back, yielding a user-message count of zero) and stopped counting tool-result turns as user prompts. Source: [src/hooks/purmemo_first_message.ts:60-140]()

Hook installation is wired through the `installCodexHooks()`, `installClaudeHooks()`, and `installGeminiHooks()` helpers. The Codex installer calls `enableCodexHooksFeatureFlag()` to write `[features] codex_hooks = true` into `config.toml`; without that flag Codex silently ignores `hooks.json`. Source: [src/hooks/purmemo_first_message.ts:160-240]()

## Slash Commands

Slash commands are exposed to the user inside the agent's input box and translate 1:1 to tool calls under the hood — `/remember`, `/recall`, `/handoff`, `/test-results`, `/artifacts`, `/investigations`. Each command resolves to the corresponding MCP tool in `src/tools/handlers.ts`, so slash commands inherit the same parameter validation, telemetry, and error handling as direct tool invocations. The list is registered in `src/server.ts` alongside the tool definitions so a UI client can render the available commands from the same source of truth. Source: [src/server.ts:80-160](), [src/tools/handlers.ts:1-120]()

---

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

## Architecture & Key Design Decisions

### Related Pages

Related topics: [MCP Tools, Hooks & Slash Commands](#page-2), [Cross-Platform Integrations, iOS & Distribution](#page-4)

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

The following source files were used to generate this page:

- [ARCHITECTURE.md](https://github.com/purmemo-ai/purmemo-mcp/blob/main/ARCHITECTURE.md)
- [CLAUDE.md](https://github.com/purmemo-ai/purmemo-mcp/blob/main/CLAUDE.md)
- [src/index.ts](https://github.com/purmemo-ai/purmemo-mcp/blob/main/src/index.ts)
- [src/types.ts](https://github.com/purmemo-ai/purmemo-mcp/blob/main/src/types.ts)
- [src/lib/api-client.ts](https://github.com/purmemo-ai/purmemo-mcp/blob/main/src/lib/api-client.ts)
- [src/lib/logger.ts](https://github.com/purmemo-ai/purmemo-mcp/blob/main/src/lib/logger.ts)
- [src/lib/auth.ts](https://github.com/purmemo-ai/purmemo-mcp/blob/main/src/lib/auth.ts)
- [src/lib/hooks.ts](https://github.com/purmemo-ai/purmemo-mcp/blob/main/src/lib/hooks.ts)
- [docs/adr/ADR-036-save-conversation-modes.md](https://github.com/purmemo-ai/purmemo-mcp/blob/main/docs/adr/ADR-036-save-conversation-modes.md)
- [docs/adr/ADR-039-auth-key-fallback.md](https://github.com/purmemo-ai/purmemo-mcp/blob/main/docs/adr/ADR-039-auth-key-fallback.md)
</details>

# Architecture & Key Design Decisions

`purmemo-mcp` is a Model Context Protocol (MCP) server that gives coding assistants persistent, queryable memory across sessions. It exposes a small, opinionated tool surface to MCP-aware clients (Claude Code, OpenAI Codex, Gemini CLI) and runs side processes that hook into those clients' lifecycle events to keep memory fresh without requiring the user to remember a command.

## System Overview

The project is structured as a TypeScript MCP server with a companion CLI. The MCP entry point registers tools with the host client, while the CLI installs and maintains hooks and configuration for each supported agent runtime. Authentication is handled locally so the user does not have to sign in on every launch.

| Layer | Responsibility | Notable modules |
|-------|---------------|-----------------|
| MCP server | Tool registry, request dispatch, schema validation | `src/index.ts`, `src/types.ts` |
| API client | Authenticated calls to the pūrmemo backend | `src/lib/api-client.ts` |
| Auth | Token storage, decryption key derivation, fallback | `src/lib/auth.ts` |
| Hooks | Lifecycle event handlers for Claude/Codex/Gemini | `src/lib/hooks.ts` |
| Telemetry | Read-side tools (`get_test_results`, `get_artifacts`, `get_investigations`) | server tool definitions |

The MCP entry point is intentionally thin: it parses incoming JSON-RPC requests, dispatches them to typed handlers, and returns results. Source: [src/index.ts]().

## Core Design Decisions

### ADR-driven change management

Significant behavioral changes are recorded as Architecture Decision Records under `docs/adr/`. Two ADRs are directly referenced in release notes and shape the public API:

- **ADR-036** introduces an explicit `mode` parameter on `save_conversation` so callers can choose between `replace` (default, one-shot snapshot) and `append` (living document with timestamped separators). This removes the previous ambiguity where the same call could overwrite or extend depending on internal heuristics. Source: [docs/adr/ADR-036-save-conversation-modes.md]().
- **ADR-039** defines the auth key fallback window for users whose hostname drifts (e.g., macOS users toggling VPN or switching Wi-Fi), allowing a legacy-key decrypt path before declaring the token unrecoverable. Source: [docs/adr/ADR-039-auth-key-fallback.md]().

Recording these as ADRs rather than scattered README prose makes the trade-offs reviewable in one place.

### Persisted encryption key with hostname fallback

Token storage was originally keyed off `SHA-256(os.hostname() + os.userInfo().username)`. On macOS, `os.hostname()` flips when the user switches networks, toggles a VPN, or sleeps/wakes the laptop, which silently corrupted stored OAuth tokens. The fix in v15.7.18 persists the encryption key to disk, with ADR-039 providing a fallback path so that brief hostname drift does not brick the install. Source: [src/lib/auth.ts](). When both the persisted and legacy decrypt paths fail, the CLI auto-launches a browser sign-in flow with a one-line explanation rather than surfacing an OpenSSL error to the user. Source: [src/lib/auth.ts](); [CLAUDE.md]().

### Multi-CLI hook parity

Claude Code was the first supported host. Codex and Gemini CLI were added later as first-class hook surfaces. Each runtime uses a different installation path:

- Claude Code: writes a `hooks.json` consumed by its session lifecycle.
- Codex: same hook payload, but only fires if `[features] codex_hooks = true` is set in `config.toml`; `installCodexHooks()` now flips that flag for the user. Source: [src/lib/hooks.ts]().
- Gemini CLI: receives a `SKILL.md` plus equivalent session-start wiring.

The session-start handler emits a compact header (`pūrmemo v<version> · email · tier · memories · cycle usage`) so the user always sees their account state. v15.7.24 fixed a JSONL-sniffing bug that miscounted user messages in Claude transcripts and switched the brief to conversation-first recall ranking. Source: [src/lib/hooks.ts](); [CHANGELOG entry for v15.7.24]().

### Symmetric read/write telemetry

Earlier releases only had write-side telemetry tools. v15.7.21 added three read tools — `get_test_results`, `get_artifacts`, `get_investigations` — to close the loop. Subsequent patches removed field-level truncation in the listing output (200-character clip on `failure_details` and `root_cause_analysis`) so callers could see the full record body. Source: [src/types.ts](); [src/index.ts]().

## Data Flow

```mermaid
sequenceDiagram
    participant Host as MCP Host (Claude/Codex/Gemini)
    participant MCP as purmemo-mcp server
    participant Auth as auth.ts
    participant API as api-client.ts
    participant Backend as pūrmemo backend

    Host->>MCP: tools/call (save_conversation, get_*, ...)
    MCP->>Auth: readToken()
    Auth-->>MCP: OAuth token (persisted key, fallback if needed)
    MCP->>API: request(method, path, body, token)
    API->>Backend: HTTPS request
    Backend-->>API: JSON response
    API-->>MCP: typed result
    MCP-->>Host: JSON-RPC result
```

## Module Boundaries and Configuration

`src/index.ts` is the only entry point the MCP host loads. It registers a fixed set of tools whose schemas are declared in `src/types.ts` and dispatched to handler functions that delegate to `src/lib/api-client.ts`. The logger (`src/lib/logger.ts`) is the only allowed output channel for diagnostic messages; raw `console.log` is reserved for tool results that the host should display.

Configuration lives alongside the user's local install rather than in the repository. Hooks are installed into the host's config directory (`~/.claude/hooks.json`, `~/.codex/config.toml`, etc.) by the CLI, not by the server itself. The server treats these files as read-only inputs to its session-start handlers.

This separation is deliberate: the server is portable across hosts, while the CLI owns the messy work of patching per-runtime configuration files and recovering from drift in those files.

---

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

## Cross-Platform Integrations, iOS & Distribution

### Related Pages

Related topics: [MCP Tools, Hooks & Slash Commands](#page-2), [Architecture & Key Design Decisions](#page-3)

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

The following source files were used to generate this page:

- [purmemo-ios/README.md](https://github.com/purmemo-ai/purmemo-mcp/blob/main/purmemo-ios/README.md)
- [purmemo-ios/purmemo-ios/PurmemoApp.swift](https://github.com/purmemo-ai/purmemo-mcp/blob/main/purmemo-ios/purmemo-ios/PurmemoApp.swift)
- [purmemo-ios/purmemo-ios/Services/PurmemoAPI.swift](https://github.com/purmemo-ai/purmemo-mcp/blob/main/purmemo-ios/purmemo-ios/Services/PurmemoAPI.swift)
- [purmemo-ios/purmemo-ios/Services/AuthService.swift](https://github.com/purmemo-ai/purmemo-mcp/blob/main/purmemo-ios/purmemo-ios/Services/AuthService.swift)
- [purmemo-ios/purmemo-ios/Services/KeychainService.swift](https://github.com/purmemo-ai/purmemo-mcp/blob/main/purmemo-ios/purmemo-ios/Services/KeychainService.swift)
- [purmemo-ios/purmemo-ios/Services/ClaudeChannelStream.swift](https://github.com/purmemo-ai/purmemo-mcp/blob/main/purmemo-ios/purmemo-ios/Services/ClaudeChannelStream.swift)
</details>

# Cross-Platform Integrations, iOS & Distribution

## Scope and Purpose

The `purmemo-ios/` module is the native iOS companion to the pūrmemo MCP server, exposing the same memory primitives (conversations, investigations, artifacts, recall) to iPhone and iPad clients. While the CLI/MCP server targets terminal-first agents (Claude Code, Codex, Gemini CLI), the iOS app targets human-facing use: an on-device shell that authenticates against the pūrmemo backend, persists the OAuth token in the iOS Keychain, and streams Claude channel responses into SwiftUI views.

The `purmemo-ios/README.md` (Source: [purmemo-ios/README.md:1-40]()) frames the iOS target as a first-class surface that mirrors the MCP toolset rather than a thin web wrapper. Auth, API, and streaming concerns are split into dedicated services so that the SwiftUI layer stays declarative.

## App Entry and Service Layer

`PurmemoApp.swift` is the SwiftUI `App` struct that wires environment-level services into the view hierarchy. Services are constructed once at launch and injected as `@EnvironmentObject` values, so views can subscribe to auth state, API state, and stream state without re-instantiating them on every navigation. This matches the pattern used by the CLI's lazy service container, where HTTP clients and auth stores live for the process lifetime.

The `Services/` directory groups the four cross-cutting concerns:

| Service | Responsibility |
|---|---|
| `PurmemoAPI.swift` | HTTP client that maps Swift methods onto the MCP REST surface |
| `AuthService.swift` | OAuth sign-in flow, refresh, and signed-out transitions |
| `KeychainService.swift` | Wraps `SecItem*` APIs for token persistence |
| `ClaudeChannelStream.swift` | Server-sent / chunked stream consumer for Claude responses |

Source: [purmemo-ios/purmemo-ios/PurmemoApp.swift:1-30](), [purmemo-ios/purmemo-ios/Services/PurmemoAPI.swift:1-20]()

## Networking and Authentication

`PurmemoAPI.swift` is the only module that talks HTTP. It centralises base URL, header injection, JSON encoding/decoding, and error mapping so individual feature views do not duplicate request-building logic. Authenticated calls read the bearer token from `KeychainService` and attach it as `Authorization: Bearer …`; unauthenticated calls (sign-in, refresh) skip the header.

`AuthService.swift` orchestrates the OAuth dance: it launches the system browser via `ASWebAuthenticationSession`, captures the callback URL, exchanges the code with the backend, and hands the resulting token pair to `KeychainService` for storage. On subsequent launches it rehydrates the token from the Keychain and validates it lazily on first authenticated call — the same "no work until needed" stance that the CLI's `purmemo init` adopted in v15.7.20 (Source: [purmemo-ios/purmemo-ios/Services/AuthService.swift:1-40](), [purmemo-ios/purmemo-ios/Services/KeychainService.swift:1-25]()).

`KeychainService.swift` is the iOS analogue of the CLI's persisted encryption key introduced in v15.7.18. Where the CLI moved off `SHA-256(hostname + userInfo.username)` because macOS network changes silently re-keyed stored tokens, the iOS app sidesteps the problem by leaning on the Keychain's `kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly` semantics — the key survives app reinstalls but is bound to the device. This is the right trade-off for a personal-memory product: portable enough for restores, hostile to cross-device token theft.

Source: [purmemo-ios/purmemo-ios/Services/KeychainService.swift:1-40](), [purmemo-ios/purmemo-ios/Services/AuthService.swift:20-60]()

## Streaming Channel and Conversation Recall

`ClaudeChannelStream.swift` is the iOS counterpart to the CLI's session-start hooks. The CLI surfaces a one-line header on SessionStart (`pūrmemo v15.7.15 · email · tier · memories · cycle usage`, per the v15.7.15 release notes); the iOS app instead drives a live, scrollable chat surface. `ClaudeChannelStream` consumes the chunked response from the Claude channel endpoint, exposes a published `@Published var tokens: [String]`, and lets SwiftUI views append each chunk as it arrives.

```mermaid
flowchart LR
  A[SwiftUI View] --> B[ClaudeChannelStream]
  B --> C[PurmemoAPI]
  C --> D[(pūrmemo backend)]
  D --> C
  C --> B
  B --> A
  K[KeychainService] --> C
  AS[AuthService] --> K
```

The stream layer also writes completed turns back through `PurmemoAPI.saveConversation`, mirroring the v15.7.17 ADR-036 explicit `mode` parameter: callers default to `replace` for one-shot snapshots and switch to `append` for living documents. The iOS app uses `replace` for free-form chats and `append` for investigation threads that accumulate over multiple Claude calls.

Source: [purmemo-ios/purmemo-ios/Services/ClaudeChannelStream.swift:1-50](), [purmemo-ios/purmemo-ios/Services/PurmemoAPI.swift:40-90]()

## Distribution Considerations

The `purmemo-ios/` tree is structured as an Xcode project (`purmemo-ios.xcodeproj` implied by the directory layout), which is the canonical distribution surface for App Store and TestFlight. The README calls out the build steps (open in Xcode, select a development team, run on simulator or device) and notes that no CocoaPods or SwiftPM external dependencies are required — the app uses only first-party Apple frameworks (`SwiftUI`, `Foundation`, `Security`, `AuthenticationServices`), which keeps the binary small and the review process simple.

For non-iOS surfaces, distribution flows through the CLI tool (`npx purmemo` or `purmemo init`), the MCP server registration in Claude Code / Codex / Gemini, and the web app. The iOS app is therefore one of four first-class clients and shares the same backend contract as the MCP tools, which is why `PurmemoAPI` can be a thin REST mapping rather than a bespoke SDK.

Source: [purmemo-ios/README.md:1-80]()

---

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

---

## Pitfall Log

Project: purmemo-ai/purmemo-mcp

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

## 1. Installation risk - Installation risk requires verification

- Severity: medium
- Evidence strength: source_linked
- Finding: Developers should check this installation risk before relying on the project: v15.7.15 — Codex hook parity
- User impact: Upgrade or migration may change expected behavior: v15.7.15 — Codex hook parity
- Evidence: failure_mode_cluster:github_release | https://github.com/purmemo-ai/purmemo-mcp/releases/tag/v15.7.15

## 2. Installation risk - Installation risk requires verification

- Severity: medium
- Evidence strength: source_linked
- Finding: Developers should check this installation risk before relying on the project: v15.7.16 — enable Codex hooks feature flag
- User impact: Upgrade or migration may change expected behavior: v15.7.16 — enable Codex hooks feature flag
- Evidence: failure_mode_cluster:github_release | https://github.com/purmemo-ai/purmemo-mcp/releases/tag/v15.7.16

## 3. Installation risk - Installation risk requires verification

- Severity: medium
- Evidence strength: source_linked
- Finding: Developers should check this installation risk before relying on the project: v15.7.19 — Auto-recover from unrecoverable token decrypt
- User impact: Upgrade or migration may change expected behavior: v15.7.19 — Auto-recover from unrecoverable token decrypt
- Evidence: failure_mode_cluster:github_release | https://github.com/purmemo-ai/purmemo-mcp/releases/tag/v15.7.19

## 4. Installation risk - Installation risk requires verification

- Severity: medium
- Evidence strength: source_linked
- Finding: Developers should check this installation risk before relying on the project: v15.7.20 — Zero-friction install + auto-recover from sign-in drift
- User impact: Upgrade or migration may change expected behavior: v15.7.20 — Zero-friction install + auto-recover from sign-in drift
- Evidence: failure_mode_cluster:github_release | https://github.com/purmemo-ai/purmemo-mcp/releases/tag/v15.7.20

## 5. 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/purmemo-ai/purmemo-mcp

## 6. Configuration risk - Configuration risk requires verification

- Severity: medium
- Evidence strength: source_linked
- Finding: Developers should check this configuration risk before relying on the project: v15.7.18 — auth: persisted encryption key
- User impact: Upgrade or migration may change expected behavior: v15.7.18 — auth: persisted encryption key
- Evidence: failure_mode_cluster:github_release | https://github.com/purmemo-ai/purmemo-mcp/releases/tag/v15.7.18

## 7. 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/purmemo-ai/purmemo-mcp

## 8. Runtime risk - Runtime risk requires verification

- Severity: medium
- Evidence strength: source_linked
- Finding: Developers should check this runtime risk before relying on the project: v15.7.22 — get_test_results no longer truncates failure body
- User impact: Upgrade or migration may change expected behavior: v15.7.22 — get_test_results no longer truncates failure body
- Evidence: failure_mode_cluster:github_release | https://github.com/purmemo-ai/purmemo-mcp/releases/tag/v15.7.22

## 9. 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/purmemo-ai/purmemo-mcp

## 10. 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/purmemo-ai/purmemo-mcp

## 11. 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/purmemo-ai/purmemo-mcp

## 12. Runtime risk - Runtime risk requires verification

- Severity: low
- Evidence strength: source_linked
- Finding: Developers should check this performance risk before relying on the project: v15.7.17 — ADR-036: explicit replace/append semantics for save_conversation
- User impact: Upgrade or migration may change expected behavior: v15.7.17 — ADR-036: explicit replace/append semantics for save_conversation
- Evidence: failure_mode_cluster:github_release | https://github.com/purmemo-ai/purmemo-mcp/releases/tag/v15.7.17

## 13. Runtime risk - Runtime risk requires verification

- Severity: low
- Evidence strength: source_linked
- Finding: Developers should check this performance risk before relying on the project: v15.7.24
- User impact: Upgrade or migration may change expected behavior: v15.7.24
- Evidence: failure_mode_cluster:github_release | https://github.com/purmemo-ai/purmemo-mcp/releases/tag/v15.7.24

## 14. 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/purmemo-ai/purmemo-mcp

## 15. 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/purmemo-ai/purmemo-mcp

## 16. Maintenance risk - Maintenance risk requires verification

- Severity: low
- Evidence strength: source_linked
- Finding: Developers should check this maintenance risk before relying on the project: v15.7.21 — close write-only telemetry gap
- User impact: Upgrade or migration may change expected behavior: v15.7.21 — close write-only telemetry gap
- Evidence: failure_mode_cluster:github_release | https://github.com/purmemo-ai/purmemo-mcp/releases/tag/v15.7.21

## 17. Maintenance risk - Maintenance risk requires verification

- Severity: low
- Evidence strength: source_linked
- Finding: Developers should check this maintenance risk before relying on the project: v15.7.23 — get_investigations no longer truncates root cause
- User impact: Upgrade or migration may change expected behavior: v15.7.23 — get_investigations no longer truncates root cause
- Evidence: failure_mode_cluster:github_release | https://github.com/purmemo-ai/purmemo-mcp/releases/tag/v15.7.23

<!-- canonical_name: purmemo-ai/purmemo-mcp; human_manual_source: deepwiki_human_wiki -->
