Horatio

Horatio

A flight recorder and memory server that sits between MCP clients and Blender, recording interactions, distilling them into persistent per-file memory using NVIDIA Nemotron, and serving that memory to agents via MCP tools like recall and search_sessions.

Category
Visit Server

README

Horatio

A flight recorder for MCP-driven Blender work. Horatio sits transparently between your MCP client (Claude Desktop / Claude Code / Cursor) and blender-mcp, records every message, distills the traffic with NVIDIA Nemotron into persistent per-file memory, and serves that memory back to agents over MCP — so every future session warm-starts instead of cold-starts.

Claude ──stdio──> tap ──stdio──> uvx blender-mcp ──tcp──> Blender
                   │
                   └──append──> raw.jsonl ──tail── distiller (Nemotron)
                                                      ├── digest.jsonl   (activity, live)
                                                      └── note.md + blends/<id>/memory.md
Claude ──stdio──> memory-server ──reads──> file memory + notes
                                           (recall / search_sessions / log_decision)

Core invariant: raw.jsonl is the source of truth. Everything downstream is re-derivable (horatio rebuild). The only other source of truth is decisions.jsonl (agent-authored via log_decision).

Deeper docs: architecture & data flow · desktop app internals · why Nemotron · contributor guide (CLAUDE.md).

Why Nemotron

  • Continuous ambient distillation (summarizing every session, all session long) is only economical on a fast, cheap, open model — trivial on nvidia/nemotron-3-super-120b-a12b, absurd on frontier API pricing.
  • Its 1M context enables one-pass full-transcript synthesis experiments.
  • Open weights mean the same system can run fully local (Nemotron Nano via Ollama) — always-on, private, zero token cost.

Setup

Desktop app (recommended)

The Electron app is the viewer + control plane: browse sessions (notes, digests, raw, artifacts), manage the NVIDIA API key, wrap/unwrap MCP servers, and fix store paths if a client is writing to the wrong home.

Build a downloadable macOS app (unsigned .dmg — right-click → Open the first time):

npm install && npm run desktop:install
npm run desktop:dist          # → desktop/release/*.dmg

Or run from the repo (use a normal terminal, not an environment that sets ELECTRON_RUN_AS_NODE):

npm run desktop:install       # once
npm run desktop               # build + Electron hot reload
# or, after desktop:install:
cd desktop && npm start       # production build of the UI, no Vite

Projects are Blender files, not arbitrary names. Sessions live in a flat sessions/ tree and are linked (never moved) to a blends/<id>/ bucket when a .blend path shows up in MCP traffic or you click Link .blend…. Memory hangs off that file; Reveal / Open jump to it on disk.

CLI

npm install && npm run build
cp .env.example .env   # or create .env with: NVIDIA_API_KEY=nvapi-...
node dist/distill/cli.js install
node dist/distill/cli.js install --wrap blender
node dist/distill/cli.js uninstall

install --wrap sets HORATIO_HOME to the platform app-data folder (~/Library/Application Support/Horatio on macOS). Optional --project-dir <path> overrides to <path>/.horatio. Restart the MCP client after install so wraps pick up the new home.

Legacy FLIGHTREC_* env vars still resolve (with a deprecation warning). Older flightrec stores need a one-time horatio migrate.

install finds Claude Code, Claude Desktop, and Cursor configs automatically, wraps the named server with the tap, and registers the memory server alongside. Claude Code uses the official claude mcp CLI; Desktop and Cursor get surgical JSON edits with a timestamped backup and atomic writes. Wrapped entries are self-describing, so uninstall restores the originals without a state file. Use --client <claude-code|claude-desktop|cursor> to target one client, or --config <path> for any config with the standard mcpServers shape.

<details> <summary>Manual config (what install writes)</summary>

{
  "mcpServers": {
    "blender": {
      "command": "node",
      "args": ["/ABSOLUTE/PATH/Horatio/dist/tap.js", "--", "uvx", "blender-mcp"],
      "env": {
        "HORATIO_HOME": "/Users/you/Library/Application Support/Horatio"
      }
    },
    "horatio-memory": {
      "command": "node",
      "args": ["/ABSOLUTE/PATH/Horatio/dist/memory-server.js"],
      "env": {
        "HORATIO_HOME": "/Users/you/Library/Application Support/Horatio"
      }
    }
  }
}

</details>

The tap auto-spawns the activity follower per session (opt out with HORATIO_NO_ACTIVITY=1 / legacy FLIGHTREC_NO_AUTODISTILL=1 and run node dist/distill/cli.js watch latest in a terminal instead — nicer for demos).

Commands

node dist/distill/cli.js watch [session]              # live activity → digests; auto-update memory at session end
node dist/distill/cli.js update [session]             # session note.md + fold into blends/<id>/memory.md
node dist/distill/cli.js rebuild [session]            # wipe digests, re-derive activity, then update memory
node dist/distill/cli.js export-memory [session] [--out path] [--assemble]
node dist/distill/cli.js migrate [--dry-run]          # one-time flightrec (v1) → Horatio (v2) store
npm run desktop                                       # viewer + control plane

Legacy aliases: distill --follow → watch, --save → update, --replay → rebuild.

update / “Update memory” in the app folds digests into durable file memory. Live capture mainly writes activity (Tier 1); synthesis runs at session end, on idle, or when you update manually. recall() returns existing notes/memory — it does not synthesize on demand.

export-memory writes agent-memory.md into the session folder (and optionally --out to your coding-agent project). It uses Nemotron to produce an agent-oriented brief from the session note + file memory; pass --assemble to skip the LLM and concatenate mechanically.

session = latest (default), a session id, or a path.

Store layout

Canonical app-owned store (default, v2):

~/Library/Application Support/Horatio/   # macOS
~/.config/horatio/                       # Linux
%APPDATA%/Horatio/                       # Windows
  config.json                            # storeVersion: 2
  .env                                   # NVIDIA_API_KEY (optional; also loads repo .env)
  live/<session-id>.json                 # per-tap live pointers
  sessions/<ISO-id>/                     # flat — sessions never move
    raw.jsonl  digest.jsonl  note.md  distill.log  artifacts/
    session.json  link.json  memory.json
    agent-memory.md                      # optional export
  blends/<basename>-<hash8>/             # one folder per Blender file
    meta.json                            # { blendPath, name, … }
    memory.md                            # durable cross-session file memory
    decisions.jsonl
    memory-history/                      # recent memory.md archives

Project-local override (--project-dir or HORATIO_HOME=<workspace>/.horatio):

<workspace>/.horatio/
  (same shape as above)

If an older wrap still points at a repo .flightrec / flightrec app-data path, use Preferences → Fix store paths (or install --repair-store / horatio migrate), then restart the client.

Memory tools (MCP)

  • recall — judgment-first warm start for the active .blend (decisions / constraints / failures / threads first; scene inventory last and marked historical). Warns if the .blend file is newer than last memory update. Agents must re-check the live scene with Blender MCP. Resolves from optional file arg → live session link → most recently linked file.
  • search_sessions(query) — substring search across notes, digest events, and file memory, with session/batch citations. No embeddings; at 1M context, brute force is the architecture.
  • log_decision(text) — record a durable decision from the driving agent; memory is bidirectional.

Guarantees

  • The tap is transparent: byte-for-byte forwarding, verified byte-identical against un-tapped runs; logging failures can never affect forwarding; base64 screenshots never reach the log.
  • No speculation in distilled memory: every digest event cites the raw-record seq numbers supporting it; error strings are verbatim; hallucinated causality is prompt-forbidden and schema-policed — bad memory poisons future sessions, so incomplete beats invented.
  • Batch boundaries are deterministic (record-timestamp gaps, not wall clock): rebuild reproduces the same batches a live run made.

Recommended Servers

playwright-mcp

playwright-mcp

A Model Context Protocol server that enables LLMs to interact with web pages through structured accessibility snapshots without requiring vision models or screenshots.

Official
Featured
TypeScript
Magic Component Platform (MCP)

Magic Component Platform (MCP)

An AI-powered tool that generates modern UI components from natural language descriptions, integrating with popular IDEs to streamline UI development workflow.

Official
Featured
Local
TypeScript
Audiense Insights MCP Server

Audiense Insights MCP Server

Enables interaction with Audiense Insights accounts via the Model Context Protocol, facilitating the extraction and analysis of marketing insights and audience data including demographics, behavior, and influencer engagement.

Official
Featured
Local
TypeScript
VeyraX MCP

VeyraX MCP

Single MCP tool to connect all your favorite tools: Gmail, Calendar and 40 more.

Official
Featured
Local
graphlit-mcp-server

graphlit-mcp-server

The Model Context Protocol (MCP) Server enables integration between MCP clients and the Graphlit service. Ingest anything from Slack to Gmail to podcast feeds, in addition to web crawling, into a Graphlit project - and then retrieve relevant contents from the MCP client.

Official
Featured
TypeScript
Kagi MCP Server

Kagi MCP Server

An MCP server that integrates Kagi search capabilities with Claude AI, enabling Claude to perform real-time web searches when answering questions that require up-to-date information.

Official
Featured
Python
E2B

E2B

Using MCP to run code via e2b.

Official
Featured
Neon Database

Neon Database

MCP server for interacting with Neon Management API and databases

Official
Featured
Exa Search

Exa Search

A Model Context Protocol (MCP) server lets AI assistants like Claude use the Exa AI Search API for web searches. This setup allows AI models to get real-time web information in a safe and controlled way.

Official
Featured
Qdrant Server

Qdrant Server

This repository is an example of how to create a MCP server for Qdrant, a vector search engine.

Official
Featured