Skip to content

Blog

Inside the Mémoire harness.

Abstract architectural composition, light and shadow, monochrome.

TL;DR

  • Mémoire is a harness, not a service. Five layers: CLI, harness (Hermes + Mirofish), workspace, MCP server, Studio.
  • The CLI (memi) is the entry point. Every Studio operation, every MCP tool, and every agent action eventually calls the same internals.
  • Everything is open source. This post is the source-walking tour. Read it, then read the code.

The map

A walk through the engine repo. Every directory has one job.

src/engine/    Core orchestrator, project detection, registry, sync,
               token-differ, code-watcher, pipeline.
src/figma/     Figma WebSocket bridge (auto-discovers the plugin on
               ports 9223-9232), tokens, stickies.
src/research/  Research engine: Excel, web, stickies, all of it
               normalized into typed insights.
src/specs/     Spec types (component, page, dataviz, design, ia) plus
               Zod validation for every shape.
src/codegen/   Code generation: shadcn mapper, dataviz, pages, all of
               it routed into atomic-design folders.
src/notes/     Mémoire Notes: skill-pack loader, resolver, installer.
src/preview/   Localhost preview gallery (HTML + API server +
               pipeline/sync/agent dashboards).
src/agents/    Agent orchestrator, multi-agent registry, task queue,
               agent bridge, agent workers.
src/mcp/       MCP server (stdio transport): 14 tools, 3 resources.
src/tui/       Terminal UI (Ink/React).
src/commands/  CLI (Commander.js).
skills/        Built-in skill definitions (ship inside the npm package).

Why this layout? Because every layer is a unit you can replace. Swap codegen, swap the bridge, swap the harness. The engine boundary is what stays.


Layer 1. The CLI surface.

memi is a Commander.js binary installed via:

npm i -g @sarveshsea/memoire

Every command lands in src/commands/. They share the same getEngine() factory, so calling memi pull from the shell or pull_design_system from MCP both end up in the same code path.

CommandPurpose
memi connectConnect to Figma (auto-discovers plugin on 9223-9232)
memi connect --role <role>Connect as a named agent with a role
memi pullExtract design system from Figma
memi spec component|page|dataviz <name>Create a spec
memi generate [name]Generate code from specs into atomic folders
memi research from-file|from-stickies|synthesize|reportResearch pipeline
memi tokensExport design tokens (DTCG JSON, Tailwind v4)
memi compose "<intent>"Agent orchestrator: classify, plan, execute, report
memi previewStart localhost preview server
memi dashboardLaunch the operator dashboard
memi ia extract|create|show|validate|listInformation architecture tools
memi watchWatch specs for changes, auto-regenerate code
memi watch --codeAlso watch generated code for hand edits
memi syncFull sync pipeline (Figma to design system to specs to code)
memi sync --liveKeep running and sync on every change
memi sync --direction <dir>figma-to-code, code-to-figma, bidirectional
memi sync --conflictsShow and resolve pending sync conflicts
memi daemon start|stop|status|restartStart the auto-pull/spec/generate daemon
memi mcp startStart Mémoire as an MCP server (stdio)
memi mcp configPrint MCP config for Claude Code / Cursor
memi agent spawn <role>Spawn a persistent agent worker
memi agent list|kill <id>|statusManage agents and the task queue
memi notes install <source>Install a Note (local path or github:user/repo)
memi notes list|remove|create|infoManage Notes

The CLI is not a wrapper around a service. There is no service. Every command is the same TypeScript that Studio and the MCP server call.


Layer 2. The harness.

The harness is the orchestration layer between intent and execution. Two pieces: Hermes (routing) and Mirofish (sandboxed execution).

Hermes routing

Hermes picks a model per task. The decision matrix is opinionated, not hard-coded; you can override per command with --model.

Task classDefault modelWhy
Spec generation, design rationaleClaudeLong-form structured output, low hallucination on shape
Fast extraction, command generationCodex / GPTSpeed, deterministic output
Tool-heavy sandboxed runsMirofishTight permission gates, JSONL trace
Local privacy, offlineOllamaStays on the machine
Image / visionClaude with visionBest at design comprehension

Hermes calls are recorded to .memoire/.agent-bus/runs/<run-id>.jsonl. Every prompt, every tool call, every response is on disk. Replayable.

Mirofish sandbox

Mirofish is the execution side. When the harness asks the model to “run the code generator,” the model returns a tool call. Mirofish:

  1. Validates the tool name against an allowlist.
  2. Validates arguments against a Zod schema.
  3. Runs the tool inside a sandboxed shell with permission gates (filesystem scoped to the workspace, no network unless explicitly allowed).
  4. Streams output back to the model.
  5. Appends a JSONL line to the run trace.
{"t":"2026-05-12T18:01:42Z","kind":"tool.call","name":"writeFile","args":{"path":"components/ui/Button.tsx","bytes":1284}}
{"t":"2026-05-12T18:01:42Z","kind":"tool.result","ok":true,"durMs":18}
{"t":"2026-05-12T18:01:43Z","kind":"model.message","role":"assistant","tokens":412}

The agent loop

classify(intent) -> route + plan
for step in plan:
  pick model via Hermes
  call model with workspace context
  if tool calls:
    Mirofish.execute(call)
    append trace
  if step.gates.approval:
    pause, surface in TUI / Studio, wait
  yield step.result
report(plan, trace)

Approval gates are first-class. Anything that mutates Figma, runs git, or writes outside the workspace requires an explicit yes. The default is: the harness can read everything, but only writes after you approve.


Layer 3. The workspace.

Every project that uses Mémoire gets a .memoire/ directory. Cheaply structured, plain text wherever possible.

.memoire/
  manifest.json           Project manifest, version-pinned.
  specs/                  Component, page, dataviz, design specs (JSON, Zod-validated).
  tokens/                 Design tokens. DTCG JSON + Tailwind v4 @theme CSS.
  references/             Public design-reference corpus snapshots.
  research/               Insights, transcripts, scenario outputs.
  generated/              Code output from the codegen pipeline.
  notes/                  Installed skill packs. Each is `<name>/note.json` + skills/*.md.
  sync-conflicts.json     Pending bidirectional-sync conflicts.
  .agent-bus/
    agents.json           Registered agents + heartbeats.
    tasks/                Pending and in-flight tasks.
    runs/                 JSONL trace per run.

The workspace is the source of truth. Studio reads it. The CLI reads it. The MCP server reads it. They never disagree because they’re all reading the same files.


Layer 4. The MCP server.

memi mcp start exposes the engine over the Model Context Protocol via stdio. Claude Code, Cursor, and Windsurf can drop Mémoire into their tool list with a one-line config.

Tools

ToolWhat it does
pull_design_systemPull tokens, components, and pages from connected Figma.
get_specsList all specs in the workspace.
get_specRead one spec by name.
create_specCreate a new spec from typed args.
generate_codeGenerate code for one or more specs.
get_tokensRead the active token export.
update_tokenMutate one token; triggers diff + sync.
capture_screenshotScreenshot the live preview at a route.
get_selectionRead the current Figma selection (node IDs, styles).
composeRun the agent orchestrator with a natural-language intent.
run_auditRun the design-system audit (token discipline, atomic levels).
get_researchRead research insights and transcripts.
figma_executeSend a low-level command to the Figma plugin.
get_page_treeRead the IA tree for the active project.

Resources

memoire://design-system     The full design system, tokens + components.
memoire://specs/{name}      One spec by name.
memoire://project           Project metadata, manifest, versions.

.mcp.json snippet

{
  "mcpServers": {
    "memoire": {
      "command": "memi",
      "args": ["mcp", "start"],
      "env": {}
    }
  }
}

Run memi mcp config --target claude-code and it prints the config you paste into Claude Code’s settings. No copy-pasting from docs.


Layer 5. Studio.

Studio is the macOS app. Tauri shell, native windows, signed and notarized DMG. Internally it’s a thin operator surface over the same engine the CLI uses.

apps/studio/
  src-tauri/             Tauri Rust shell. Window mgmt, IPC, sidecar.
  src/                   React UI. Run cockpit, Figma cockpit, traces.
  capabilities/          Tauri capability allowlist (filesystem scopes).

The Tauri shell starts a sidecar daemon that wraps the Node engine. The frontend talks to the sidecar over an IPC bridge. When you click “Pull tokens” in Studio, the same memi pull code path runs. Same workspace, same trace.

Distribution: signed by Humyn LLC, Team Z4ZUZ884U3. One DMG. macOS 13 Ventura or later. Apple silicon and Intel.


Bidirectional sync

Design-code drift is the oldest problem in design systems. Mémoire fixes it with per-entity SHA-256 hashes on both sides.

  • Figma to code. Variable / component changes are detected via granular plugin events on the WebSocket bridge.
  • Code to Figma. Token changes are pushed via the pushTokens bridge command.
  • Conflict detection. When both sides change within a 1-second window, the entity is added to sync-conflicts.json and the user resolves manually with memi sync --conflicts.
  • Echo guard. Before a push, the orchestrator sets a guard flag. Inbound events tagged with the guard are ignored. No loops.
// pseudocode
async function syncFigmaToCode() {
  const remote = await readFigmaState();
  for (const entity of remote) {
    const hash = sha256(entity);
    if (hash !== localHashes[entity.id]) writeLocal(entity);
  }
}

Multi-agent orchestration

When memi compose "<intent>" runs, the orchestrator picks a role (or several) from the registry.

RoleOwns
token-engineerToken extraction, diffs, exports.
component-architectAtomic levels, composition, props.
layout-designerPage templates, IA, navigation.
dataviz-specialistCharts, dashboards, data binding.
code-generatorshadcn/ui mapping, file emission.
accessibility-checkerContrast, ARIA, keyboard order.
design-auditorToken discipline, atomic violations.
research-analystInsights, transcripts, synthesis.
generalCatch-all, lowest-priority claimer.

Lifecycle:

  1. Spawn. memi agent spawn <role> writes a registration to .agent-bus/agents.json.
  2. Heartbeat. Every 10 seconds the worker updates lastSeen. Stale workers (>30s) are evicted.
  3. Claim. Workers poll the task queue, claim with a lock file. Other workers see the lock and skip.
  4. Execute. The worker runs the task. JSONL trace appended.
  5. Report. Result is posted back to the queue. The orchestrator advances.
  6. Reclaim. Tasks unclaimed for >120s are automatically requeued.

The dispatch layer always checks for external agents first. If a worker with the right role is alive, it claims the task. If not, the orchestrator falls back to internal execution. You can run zero workers and everything still works.


Trust by design

Approvals, traces, artifacts.

  • Approvals. Mutating Figma, running shell commands, writing outside the workspace, all gate on explicit approval. Configurable per project in manifest.json.
  • Traces. Every run produces a JSONL trace at .memoire/.agent-bus/runs/<run-id>.jsonl. Replay with memi compose --replay <run-id>.
  • Artifacts. Codegen outputs go to .memoire/generated/. The workspace is the audit log.

No telemetry leaves your machine. The only outbound traffic is the AI provider calls you configured. See Legal for the short version.


What you can read

All of this is open. Read the source. File issues. Send PRs.

If something in this post is wrong, the source is the source of truth. Tell me where; I’ll fix it.