apocryphx/ES-Archive

Persistent memory for Claude, ChatGPT and LM Studio via MCP. Local, iCloud-synced, Objective-C.

Objective-C

1

56 commits

updated Sep 22, 2026

See the code

See what people are saying

README

ES Archive

An AI-first archive server for Claude, ChatGPT, LM Studio, and any other MCP-compatible client.

Persistent archive that the AI owns: store, retrieve, organize, curate, and forget across sessions. The Archive is the collection; an entry is what a session writes into it. Built natively in Objective-C with Core Data, on-device multilingual Core ML embeddings, and optional CloudKit sync. Designed and optimized for Claude; Claude Desktop, ChatGPT desktop, and LM Studio all connect to the same server over stdio, each as its own persona, in one shared archive.

ES Archive was known as ES Memory through version 3.3.3. The rename was a clean cut, no aliases: the MCP tools (memory_*archive_*), bundle identifiers, and app group all changed. The CloudKit container and sync schema did not, so a synced archive re-downloads on first launch, and legacy .esmemory backups still open.

Read more about the technology and philosophy behind ES Archive on alpharecursion.com.

Two ways to run it

ES Archive is one engine that ships in two forms, built as two targets in this repository:

  • ES Archive MCP — a stdio server, and the recommended install. Any client that can launch a stdio MCP server spawns it directly: Claude Desktop, Claude Code, ChatGPT desktop, LM Studio, Codex. No localhost port, no network listener. Concurrent sessions — across all of those clients at once — share one in-process engine over a local UNIX-domain socket: the first to start hosts it, the rest relay, so N sessions cost one engine, not N (see Architecture). Each session declares its persona at launch with --author, so Claude, ChatGPT, and a local model each write as themselves into the same archive.
  • ES Archive Server — the HTTP app. Hosts the same engine behind a hardened localhost web server for clients that speak MCP-over-HTTP or SSE (curl, a cloudflared tunnel, HTTP-only clients), with port-bound personas and per-port authentication. Use this when you need /sse or HTTP clients, or remote access.

Both read and write the same kind of archive; each keeps its own local store.

Requirements

  • macOS 26 (Tahoe) or later
  • ES Archive MCP: any client that launches stdio MCP servers — tested with Claude Desktop, Claude Code, ChatGPT desktop, LM Studio, and Codex
  • ES Archive Server: any MCP-over-HTTP or SSE client
  1. Install ES Archive MCP from the Mac App Store.
  2. Connect the client(s) you use — see below. Each is a one-time step.

That's all. The client launches the server on demand and the archive tools appear automatically — no separate app to keep running, nothing listening on a port. While it's running the host presents the app's UI — a Dock app by default (Archive Scope, persona management, backup/restore), or a menu-bar item if you switch to Minimal mode in Settings.

Every client points at the same executable:

/Applications/ES Archive MCP.app/Contents/MacOS/ES Archive MCP

and passes --author <name> to say who is writing. The name is the persona: it is stamped on every entry the session stores and scopes what the session reads, so each assistant keeps to its own slice of the shared archive. Without the flag the session writes as Claude.

Claude Desktop

In ES Archive MCP, choose Help ▸ Connect ES Archive… and click Connect to Claude. That builds a connector pointing at this copy of the app and hands it to Claude Desktop, which asks you to approve the install. (Equivalently: Claude Desktop → Settings → Extensions → install the .mcpb from a release.)

ChatGPT desktop

ChatGPT's desktop app can launch stdio MCP servers directly. In ChatGPT, open Settings → Plugins → MCPs → Add. The Connect to a custom MCP dialog opens with the Type toggle already on STDIO (the other option, Streamable HTTP, is for the Server app). Fill in:

FieldValue
NameES Archive (any name you like)
TypeSTDIO (the default)
Command to launch/Applications/ES Archive MCP.app/Contents/MacOS/ES Archive MCP
Arguments--author and ChatGPT — one argument per row, using Add argument for the second
Environment variables, passthrough, working directoryleave empty

Save, then start a new conversation; the archive_* tools appear as a plugin. Use whatever persona name you like in place of ChatGPT — that is the name entries will carry. To change the arguments later, open the server from the MCPs tab; switching between STDIO and Streamable HTTP requires an uninstall and re-add. Note that this is a recent ChatGPT feature and much of the older advice online (HTTP-only connectors, developer mode) no longer applies.

LM Studio

In ES Archive MCP, choose Help ▸ Connect ES Archive… and click Copy MCP Configuration, then in LM Studio choose Program ▸ Edit mcp.json and paste. Add an author for the model you run, and load a model that supports tool use:

{
  "mcpServers": {
    "es-archive": {
      "command": "/Applications/ES Archive MCP.app/Contents/MacOS/ES Archive MCP",
      "args": ["--author", "Gemma"]
    }
  }
}

Claude Code

claude mcp add es-archive -- "/Applications/ES Archive MCP.app/Contents/MacOS/ES Archive MCP" --author Claude

Any other stdio client

The LM Studio snippet is plain MCP-over-stdio. Any client that can launch a command with arguments (Codex, editors, agent frameworks) uses the same executable path and --author.

ES Archive MCP is distributed through the Mac App Store, sandboxed like every App Store app. All data stays on your Mac; if you're signed into iCloud it syncs through your own private CloudKit database, and nothing else leaves the machine.

Build from source

The repository uses git submodules for the on-device embedder and the two dependency projects, so clone with them:

git clone --recurse-submodules https://github.com/apocryphx/ES-Archive.git

If you already have a clone without them:

git submodule update --init

The embedder submodule pulls ~220 MB of model weights and tokenizer through Git LFS, so install it once beforehand (brew install git-lfs && git lfs install).

SubmodulePathWhat it is
embeddinggemma-300m-qat-q4_0-coremlES_Archive/Embedders/embeddinggemma-300m-qat-q4_0-coremlEmbeddingGemma Core ML package + tokenizer (Hugging Face, LFS)
ObjCTokenizerExternal/ObjCTokenizerHuggingFace-compatible tokenizer in Objective-C
GCDWebServerExternal/GCDWebServerHardened localhost HTTP server for ES Archive Server

Open ES-Archive.xcworkspace (not the bare .xcodeproj — it cannot resolve the dependency projects on its own) and build the ES Archive MCP or ES Archive Server scheme. A build phase verifies the embedder model landed in the bundle and fails red if a submodule is missing.

To keep the submodules moving with the main repo on every pull, set once per clone:

git config submodule.recurse true

What it does

ES Archive exposes 22 MCP tools. Most retrieval and curation runs through archive_cli, a Unix-pipeline surface — compose operations with | the way you would in a shell (lfind --tag "X" | w2vgrep "concept" | head 5); run archive_cli("man") for the full vocabulary. The rest are direct tools:

  • Storagearchive_store, archive_read, archive_update, archive_erase
  • Retrievalarchive_search (semantic, with optional recency weighting), archive_grep (line-level pattern search — the matching passages with context, not just which entries contain a string), archive_timeline, archive_tagged
  • Pipelinearchive_cli (composable surface), archive_pipeline (its underlying executor)
  • Discoveryarchive_discover (hubs, orphans, forgotten, and other archive structures)
  • Grapharchive_link, archive_unlink, archive_links, archive_tag, archive_untag, archive_tags
  • Annotation & historyarchive_comment, archive_reference, archive_revisions
  • Identity & upkeeparchive_author_list, archive_maintenance

Tags are deliberately curated — every tag's existence is an authorial judgment, not an automatic extraction. On archive_store, the server returns similarity scores against existing entries as a behavioral cue against duplication.

Skills

The tools are the instrument; the skills are how an assistant learns to play it. The repository carries two complete suites in skills/, each documenting the same tool surface in its own voice, and each owned and edited only by the assistant it is written for:

SuiteWritten forSkills
skills/claude/Claude Desktop, Claude Code, claude.aies-archive-overview (orientation, loads the rest), -store, -research, -curate, -discover, -toml
skills/codex/ChatGPT desktop and Codexcodex-es-archive (orientation), -store, -research, -curate, -discover, -records, -visitor (reading another AI's archive)

They cover the same ground — when and what to store, how to research with archive_cli pipelines, how to curate tags and links, how to listen to the archive's shape — but they are not translations of each other. The Claude suite was written with Claude over a year of daily use; the Codex suite was written by Codex for itself, including a visitor skill for reading an archive that belongs to a different persona without curating it.

The skills are versioned next to the code they describe so that a tool change and its skill change land in the same commit. Both apps bundle the Claude suite at build time and install it from the Install Claude Skills… card of the Connect window (Help ▸ Connect ES Archive…): each skill has a Read button to see its text and an Install button that hands it to Claude Desktop for confirmation and shows a checkmark once done. For a developer machine, scripts/sync-skills.sh copies the Claude suite to ~/.claude/skills and packs .skill files for claude.ai, and copies the Codex suite to ~/.codex/skills, where both Codex and ChatGPT desktop (Settings → Plugins → Skills) pick it up. See skills/README.md.

Storage and embeddings

Entries are stored locally in Core Data. Vector embeddings are computed on-device with EmbeddingGemma — Google's embeddinggemma-300m, quantized to int4 (768-dimensional) — via Core ML. It is multilingual across 100+ languages, so a query in one language reaches entries written in another; each entry is embedded with its title alongside its summary for sharper retrieval. CloudKit sync across your devices is optional — without iCloud, ES Archive works fully offline, and with it, data stays within your iCloud account. No third-party services, no telemetry.

Archive Scope

Both apps include a visual layer that renders the Archive as a force-directed graph. Nodes are entries, edges are explicit links and similarity connections, color encodes access frequency. Each entry draws one similarity edge to its single nearest neighbor, and small clusters that would otherwise float free are bridged into the main body, so the graph reads as one connected whole rather than scattered fragments. A second tab shows tags as an Archimedean spiral, sized by frequency. The views update live as the Archive changes and as tools are called — you can watch new entries find their place, and see when sustained engagement with a topic produces a hub.

Personas

An ES Archive persona is an author: a name that is stamped on everything a session writes and that scopes everything it reads. Several assistants can share one archive without seeing or overwriting each other's entries, and the tags, links, and Archive Scope graph stay one shared structure.

The stdio ES Archive MCP scopes a persona per connection: each session declares its author with --author at launch. That is how Claude Desktop, ChatGPT, and LM Studio coexist on one machine — three clients, three personas, one engine, one archive. Its Settings pane lists the Archive's personas to delete or merge them (merge renames an author across all of its records, which is how you fold a misnamed persona into the right one).

The HTTP ES Archive Server binds personas to ports instead: the port a request arrives on is its identity, so authorship is stamped from the channel rather than asserted by the client, and misattribution is structurally impossible. Personas are managed in Settings → Personas — every author already in the Archive is listed with its record count; from there you can assign a port to serve a persona, create a new one, rename or merge an author, or delete a persona along with its records. Each port can independently require a Cloudflare Access JWT, so a persona exposed over a cloudflared tunnel sits behind edge authentication while a local-only persona stays open. A read-only GET /personas directory lets a client discover which port serves which persona before connecting. Port-bound personas, persona creation, and per-port JWT stay exclusive to the Server app.

Architecture

The engine — the Core Data stack, the on-device embedder, vector search, and every MCP tool implementation — is shared by both targets. What differs is the transport:

  • ES Archive MCP speaks MCP as newline-delimited JSON-RPC over stdio, and N concurrent sessions — whichever clients spawned them — share one engine rather than N. The first session to start binds a UNIX-domain socket in the shared App Group container and hosts the engine in-process; every other session connects to that host, declares its --author, and relays its requests over the socket, never loading its own Core Data stack or embedder (≈30 MB per relay vs. ≈550 MB for the one host). The election is the bind() itself — kernel-arbitrated, no daemon, App-Store-safe (see design-decisions/socket-election.md). The host also owns the single GUI; relays stay headless and exit when their host does, so nothing lingers. There is no HTTP listener anywhere in the target. Shutdown is stdin EOF or SIGTERM, draining cleanly before the store is saved.
  • ES Archive Server hosts the same engine behind a localhost HTTP server — GCDWebServer (a submodule), hardened with security fixes documented in CHANGES-2026-05-09.md and CHANGES-2026-04-25.md — binding to 127.0.0.1 only, one listener per persona. It accepts no external connections; remote access, when wanted, is delegated to a cloudflared tunnel with per-port Cloudflare Access authentication.

Packaging of the stdio .mcpb for Claude Desktop lives in packaging/.

Why Objective-C

ES Archive is written in Objective-C throughout — a deliberate choice, not a legacy constraint. Core Data, CloudKit, and GCDWebServer compose cleanly in Objective-C in ways that Swift's strict type system makes awkward; the dynamic dispatch model fits a server that routes heterogeneous MCP tool calls at runtime. The codebase has no Swift dependencies and no bridging headers.

The practical consequence: the contributor surface is small by design. This is not a project looking for pull requests. It is a working instrument, published so that developers who want to understand the architecture can read it.

Status

ES Archive has been in active development for over a year (as ES Memory until August 2026), used by its author daily and built in collaboration with Claude across many sessions. It is released publicly as part of the alpharecursion research program. The current release is 3.3.12 for both ES Archive MCP (stdio) and ES Archive Server (HTTP); ES Archive MCP is on the Mac App Store, approved September 22, 2026. The tool API listed above is stable; new tools may be added but existing ones will not be removed without notice.

Support

Questions, bug reports and feature requests go to the Issues page. Search first — the answer may already be there — then open a new issue with the app (MCP or Server), its version from the About panel, and what you expected to happen. The in-app help book (Help ▸ ES Archive Help) covers setup, connecting clients, personas and troubleshooting. Your archive stays on your Mac and in your iCloud account; see PRIVACY.md.

License

MIT. See LICENSE for full text. The GCDWebServer submodule retains its original BSD 3-Clause license; see its README.

Author

Kolja Wawrowsky — alpharecursion.com · twilighttales.art

Contributors

apocryphx

56 commits

apocryphx/ES-Archive

Persistent memory for Claude, ChatGPT and LM Studio via MCP. Local, iCloud-synced, Objective-C.

Objective-C

1

56 commits

updated Sep 22, 2026

See the code

See what people are saying

README

ES Archive

An AI-first archive server for Claude, ChatGPT, LM Studio, and any other MCP-compatible client.

Persistent archive that the AI owns: store, retrieve, organize, curate, and forget across sessions. The Archive is the collection; an entry is what a session writes into it. Built natively in Objective-C with Core Data, on-device multilingual Core ML embeddings, and optional CloudKit sync. Designed and optimized for Claude; Claude Desktop, ChatGPT desktop, and LM Studio all connect to the same server over stdio, each as its own persona, in one shared archive.

ES Archive was known as ES Memory through version 3.3.3. The rename was a clean cut, no aliases: the MCP tools (memory_*archive_*), bundle identifiers, and app group all changed. The CloudKit container and sync schema did not, so a synced archive re-downloads on first launch, and legacy .esmemory backups still open.

Read more about the technology and philosophy behind ES Archive on alpharecursion.com.

Two ways to run it

ES Archive is one engine that ships in two forms, built as two targets in this repository:

  • ES Archive MCP — a stdio server, and the recommended install. Any client that can launch a stdio MCP server spawns it directly: Claude Desktop, Claude Code, ChatGPT desktop, LM Studio, Codex. No localhost port, no network listener. Concurrent sessions — across all of those clients at once — share one in-process engine over a local UNIX-domain socket: the first to start hosts it, the rest relay, so N sessions cost one engine, not N (see Architecture). Each session declares its persona at launch with --author, so Claude, ChatGPT, and a local model each write as themselves into the same archive.
  • ES Archive Server — the HTTP app. Hosts the same engine behind a hardened localhost web server for clients that speak MCP-over-HTTP or SSE (curl, a cloudflared tunnel, HTTP-only clients), with port-bound personas and per-port authentication. Use this when you need /sse or HTTP clients, or remote access.

Both read and write the same kind of archive; each keeps its own local store.

Requirements

  • macOS 26 (Tahoe) or later
  • ES Archive MCP: any client that launches stdio MCP servers — tested with Claude Desktop, Claude Code, ChatGPT desktop, LM Studio, and Codex
  • ES Archive Server: any MCP-over-HTTP or SSE client
  1. Install ES Archive MCP from the Mac App Store.
  2. Connect the client(s) you use — see below. Each is a one-time step.

That's all. The client launches the server on demand and the archive tools appear automatically — no separate app to keep running, nothing listening on a port. While it's running the host presents the app's UI — a Dock app by default (Archive Scope, persona management, backup/restore), or a menu-bar item if you switch to Minimal mode in Settings.

Every client points at the same executable:

/Applications/ES Archive MCP.app/Contents/MacOS/ES Archive MCP

and passes --author <name> to say who is writing. The name is the persona: it is stamped on every entry the session stores and scopes what the session reads, so each assistant keeps to its own slice of the shared archive. Without the flag the session writes as Claude.

Claude Desktop

In ES Archive MCP, choose Help ▸ Connect ES Archive… and click Connect to Claude. That builds a connector pointing at this copy of the app and hands it to Claude Desktop, which asks you to approve the install. (Equivalently: Claude Desktop → Settings → Extensions → install the .mcpb from a release.)

ChatGPT desktop

ChatGPT's desktop app can launch stdio MCP servers directly. In ChatGPT, open Settings → Plugins → MCPs → Add. The Connect to a custom MCP dialog opens with the Type toggle already on STDIO (the other option, Streamable HTTP, is for the Server app). Fill in:

FieldValue
NameES Archive (any name you like)
TypeSTDIO (the default)
Command to launch/Applications/ES Archive MCP.app/Contents/MacOS/ES Archive MCP
Arguments--author and ChatGPT — one argument per row, using Add argument for the second
Environment variables, passthrough, working directoryleave empty

Save, then start a new conversation; the archive_* tools appear as a plugin. Use whatever persona name you like in place of ChatGPT — that is the name entries will carry. To change the arguments later, open the server from the MCPs tab; switching between STDIO and Streamable HTTP requires an uninstall and re-add. Note that this is a recent ChatGPT feature and much of the older advice online (HTTP-only connectors, developer mode) no longer applies.

LM Studio

In ES Archive MCP, choose Help ▸ Connect ES Archive… and click Copy MCP Configuration, then in LM Studio choose Program ▸ Edit mcp.json and paste. Add an author for the model you run, and load a model that supports tool use:

{
  "mcpServers": {
    "es-archive": {
      "command": "/Applications/ES Archive MCP.app/Contents/MacOS/ES Archive MCP",
      "args": ["--author", "Gemma"]
    }
  }
}

Claude Code

claude mcp add es-archive -- "/Applications/ES Archive MCP.app/Contents/MacOS/ES Archive MCP" --author Claude

Any other stdio client

The LM Studio snippet is plain MCP-over-stdio. Any client that can launch a command with arguments (Codex, editors, agent frameworks) uses the same executable path and --author.

ES Archive MCP is distributed through the Mac App Store, sandboxed like every App Store app. All data stays on your Mac; if you're signed into iCloud it syncs through your own private CloudKit database, and nothing else leaves the machine.

Build from source

The repository uses git submodules for the on-device embedder and the two dependency projects, so clone with them:

git clone --recurse-submodules https://github.com/apocryphx/ES-Archive.git

If you already have a clone without them:

git submodule update --init

The embedder submodule pulls ~220 MB of model weights and tokenizer through Git LFS, so install it once beforehand (brew install git-lfs && git lfs install).

SubmodulePathWhat it is
embeddinggemma-300m-qat-q4_0-coremlES_Archive/Embedders/embeddinggemma-300m-qat-q4_0-coremlEmbeddingGemma Core ML package + tokenizer (Hugging Face, LFS)
ObjCTokenizerExternal/ObjCTokenizerHuggingFace-compatible tokenizer in Objective-C
GCDWebServerExternal/GCDWebServerHardened localhost HTTP server for ES Archive Server

Open ES-Archive.xcworkspace (not the bare .xcodeproj — it cannot resolve the dependency projects on its own) and build the ES Archive MCP or ES Archive Server scheme. A build phase verifies the embedder model landed in the bundle and fails red if a submodule is missing.

To keep the submodules moving with the main repo on every pull, set once per clone:

git config submodule.recurse true

What it does

ES Archive exposes 22 MCP tools. Most retrieval and curation runs through archive_cli, a Unix-pipeline surface — compose operations with | the way you would in a shell (lfind --tag "X" | w2vgrep "concept" | head 5); run archive_cli("man") for the full vocabulary. The rest are direct tools:

  • Storagearchive_store, archive_read, archive_update, archive_erase
  • Retrievalarchive_search (semantic, with optional recency weighting), archive_grep (line-level pattern search — the matching passages with context, not just which entries contain a string), archive_timeline, archive_tagged
  • Pipelinearchive_cli (composable surface), archive_pipeline (its underlying executor)
  • Discoveryarchive_discover (hubs, orphans, forgotten, and other archive structures)
  • Grapharchive_link, archive_unlink, archive_links, archive_tag, archive_untag, archive_tags
  • Annotation & historyarchive_comment, archive_reference, archive_revisions
  • Identity & upkeeparchive_author_list, archive_maintenance

Tags are deliberately curated — every tag's existence is an authorial judgment, not an automatic extraction. On archive_store, the server returns similarity scores against existing entries as a behavioral cue against duplication.

Skills

The tools are the instrument; the skills are how an assistant learns to play it. The repository carries two complete suites in skills/, each documenting the same tool surface in its own voice, and each owned and edited only by the assistant it is written for:

SuiteWritten forSkills
skills/claude/Claude Desktop, Claude Code, claude.aies-archive-overview (orientation, loads the rest), -store, -research, -curate, -discover, -toml
skills/codex/ChatGPT desktop and Codexcodex-es-archive (orientation), -store, -research, -curate, -discover, -records, -visitor (reading another AI's archive)

They cover the same ground — when and what to store, how to research with archive_cli pipelines, how to curate tags and links, how to listen to the archive's shape — but they are not translations of each other. The Claude suite was written with Claude over a year of daily use; the Codex suite was written by Codex for itself, including a visitor skill for reading an archive that belongs to a different persona without curating it.

The skills are versioned next to the code they describe so that a tool change and its skill change land in the same commit. Both apps bundle the Claude suite at build time and install it from the Install Claude Skills… card of the Connect window (Help ▸ Connect ES Archive…): each skill has a Read button to see its text and an Install button that hands it to Claude Desktop for confirmation and shows a checkmark once done. For a developer machine, scripts/sync-skills.sh copies the Claude suite to ~/.claude/skills and packs .skill files for claude.ai, and copies the Codex suite to ~/.codex/skills, where both Codex and ChatGPT desktop (Settings → Plugins → Skills) pick it up. See skills/README.md.

Storage and embeddings

Entries are stored locally in Core Data. Vector embeddings are computed on-device with EmbeddingGemma — Google's embeddinggemma-300m, quantized to int4 (768-dimensional) — via Core ML. It is multilingual across 100+ languages, so a query in one language reaches entries written in another; each entry is embedded with its title alongside its summary for sharper retrieval. CloudKit sync across your devices is optional — without iCloud, ES Archive works fully offline, and with it, data stays within your iCloud account. No third-party services, no telemetry.

Archive Scope

Both apps include a visual layer that renders the Archive as a force-directed graph. Nodes are entries, edges are explicit links and similarity connections, color encodes access frequency. Each entry draws one similarity edge to its single nearest neighbor, and small clusters that would otherwise float free are bridged into the main body, so the graph reads as one connected whole rather than scattered fragments. A second tab shows tags as an Archimedean spiral, sized by frequency. The views update live as the Archive changes and as tools are called — you can watch new entries find their place, and see when sustained engagement with a topic produces a hub.

Personas

An ES Archive persona is an author: a name that is stamped on everything a session writes and that scopes everything it reads. Several assistants can share one archive without seeing or overwriting each other's entries, and the tags, links, and Archive Scope graph stay one shared structure.

The stdio ES Archive MCP scopes a persona per connection: each session declares its author with --author at launch. That is how Claude Desktop, ChatGPT, and LM Studio coexist on one machine — three clients, three personas, one engine, one archive. Its Settings pane lists the Archive's personas to delete or merge them (merge renames an author across all of its records, which is how you fold a misnamed persona into the right one).

The HTTP ES Archive Server binds personas to ports instead: the port a request arrives on is its identity, so authorship is stamped from the channel rather than asserted by the client, and misattribution is structurally impossible. Personas are managed in Settings → Personas — every author already in the Archive is listed with its record count; from there you can assign a port to serve a persona, create a new one, rename or merge an author, or delete a persona along with its records. Each port can independently require a Cloudflare Access JWT, so a persona exposed over a cloudflared tunnel sits behind edge authentication while a local-only persona stays open. A read-only GET /personas directory lets a client discover which port serves which persona before connecting. Port-bound personas, persona creation, and per-port JWT stay exclusive to the Server app.

Architecture

The engine — the Core Data stack, the on-device embedder, vector search, and every MCP tool implementation — is shared by both targets. What differs is the transport:

  • ES Archive MCP speaks MCP as newline-delimited JSON-RPC over stdio, and N concurrent sessions — whichever clients spawned them — share one engine rather than N. The first session to start binds a UNIX-domain socket in the shared App Group container and hosts the engine in-process; every other session connects to that host, declares its --author, and relays its requests over the socket, never loading its own Core Data stack or embedder (≈30 MB per relay vs. ≈550 MB for the one host). The election is the bind() itself — kernel-arbitrated, no daemon, App-Store-safe (see design-decisions/socket-election.md). The host also owns the single GUI; relays stay headless and exit when their host does, so nothing lingers. There is no HTTP listener anywhere in the target. Shutdown is stdin EOF or SIGTERM, draining cleanly before the store is saved.
  • ES Archive Server hosts the same engine behind a localhost HTTP server — GCDWebServer (a submodule), hardened with security fixes documented in CHANGES-2026-05-09.md and CHANGES-2026-04-25.md — binding to 127.0.0.1 only, one listener per persona. It accepts no external connections; remote access, when wanted, is delegated to a cloudflared tunnel with per-port Cloudflare Access authentication.

Packaging of the stdio .mcpb for Claude Desktop lives in packaging/.

Why Objective-C

ES Archive is written in Objective-C throughout — a deliberate choice, not a legacy constraint. Core Data, CloudKit, and GCDWebServer compose cleanly in Objective-C in ways that Swift's strict type system makes awkward; the dynamic dispatch model fits a server that routes heterogeneous MCP tool calls at runtime. The codebase has no Swift dependencies and no bridging headers.

The practical consequence: the contributor surface is small by design. This is not a project looking for pull requests. It is a working instrument, published so that developers who want to understand the architecture can read it.

Status

ES Archive has been in active development for over a year (as ES Memory until August 2026), used by its author daily and built in collaboration with Claude across many sessions. It is released publicly as part of the alpharecursion research program. The current release is 3.3.12 for both ES Archive MCP (stdio) and ES Archive Server (HTTP); ES Archive MCP is on the Mac App Store, approved September 22, 2026. The tool API listed above is stable; new tools may be added but existing ones will not be removed without notice.

Support

Questions, bug reports and feature requests go to the Issues page. Search first — the answer may already be there — then open a new issue with the app (MCP or Server), its version from the About panel, and what you expected to happen. The in-app help book (Help ▸ ES Archive Help) covers setup, connecting clients, personas and troubleshooting. Your archive stays on your Mac and in your iCloud account; see PRIVACY.md.

License

MIT. See LICENSE for full text. The GCDWebServer submodule retains its original BSD 3-Clause license; see its README.

Author

Kolja Wawrowsky — alpharecursion.com · twilighttales.art

Contributors

apocryphx

56 commits

Languages

Objective-C

89.1%

HTML

7.5%

Python

1.8%