Firekeep documentation

Provision Firekeep, connect your MCP clients, and run the self-hosted stack day to day.

Architecture

Firekeep is two halves. A server you run once, and a client kit installed on each member's machine that wires your agent runtimes into it.

Server services

ServicePortPurpose
Cortex8100 API, 8080 MCPLong-term memory — semantic and graph recall
Bridge8070Session context that survives compression and crashes
Sentinel8060Environment observer — containers, git, file activity
Relay8050Agent-to-agent coordination, leases, tasks, messages
Dashboard8040Web UI over all of the above

Backed by three datastores in the same stack—Neo4j (knowledge graph), Qdrant (vector embeddings) and Redis (cache, queues, streams)— plus Ollama for local model inference.

Client kit

Installs to ~/.firekeep and renders configuration for whichever agent runtimes you use — Claude Code, Codex, Kiro and OpenCode are configured together (Claude Desktop too, when the app is installed), and any other MCP client can be added with firekeep install --runtime generic. It provides the MCP gateway your agent talks to, plus lifecycle automation where each runtime's hook surface allows it — a generic client exposes no hooks, so it gets the MCP tools and instructions on connect but not the hook lifecycle. The day-to-day section below names the current differences explicitly.

Dexes run client-side. A dex has to be local to what it indexes, so Symdex ships as a stdio MCP server on your machine rather than in the server stack, and Docdex reads your folders from there too. Which ones run is a registry on that machine — Dexes and documents. The Decision Board is client-side as well: it opens an ephemeral loopback browser surface and returns submitted answers to the waiting agent.

Capability map

Firekeep joins durable memory, working context, code intelligence and agent coordination. The boundaries below are part of the product: it records what agents explicitly send and automates only the lifecycle events each client exposes.

CapabilityCustomer outcomeCurrent boundary
Cortex memoryStore decisions, incidents and proven fixes, then retrieve project-scoped evidence through semantic and relationship recall within a context budget.Memory is explicitly written and is not a truth-verification system; retrieved sources remain inspectable.
Bridge sessionsKeep an explicit shadow of plans, decisions, progress and file notes so work can survive compression, interruption or a crash.Direct session tools work everywhere; automatic capture and completion depend on the client's lifecycle hooks.
RelayCoordinate agent identities with tasks, channels, direct messages, presence and fenced file or task leases.Presence is best-effort and leases still require clients to cooperate with the protocol.
Corpus & KnowledgeMake an ingested document searchable immediately, then draft detected procedures into skills for human review.Drafting requires a configured generation model. Without one, the source remains searchable but no procedure drafts are produced.
Decision BoardCollect answers to several agent-supplied questions in one browser board, alongside retrieved evidence and optional visual comparisons.Retrieved evidence is deterministic; drafted suggestions need a generation backend that can answer inside the 30 s budget and are skipped on a CPU-only host, where the board still returns your questions and their evidence. Headless clients receive a text fallback. Answers return to the agent but do not execute actions or automatically become memory.
ReplayInspect Firekeep-mediated lifecycle, tool, memory and policy events, open the exact or nearest saved context and narrow likely contributors to a failure.Replay is an inspectable Firekeep trace, not a screen, keystroke or complete client recorder; contributor ranking is not causal proof.
SentinelFollow commits, selected file activity, custom operational events and optional container state.Watch paths and repositories must be selected; Docker observation is deliberately off until an operator enables access.
SymdexIndex local symbols and relationships so agents can request focused caller, impact and architecture context instead of opening every file.The index stays on the workstation; code context requested by an agent enters that agent's model context. Its tools appear once the dex is registered.
DocdexExtract the document folders a person chooses — .md, .txt, .pdf, .docx, .html, .eml and conversation-shaped .json — into recall, private to that member by default even on a shared Keep.Folder selection is human-only; no agent tool for it exists. No OCR, no file watching and no cloud sources; background sync needs a runtime with a session-start hook.
Vault, policy & dashboardKeep credentials out of memory, mediate supported edits and inspect memories, sessions, skills, events, coordination and operations in one UI.Vault values are encrypted at rest and returned in plaintext to authorized readers. Policy enforcement varies by client, as documented below.
FirekeepScopeRun shared, server-backed clarification screens that can block for an answer or stay open while an agent continues.Headless or MCP-only agents call the scope_* tools; answers are human actions through the dashboard Scope tab or the REST answer endpoint.
Evals & patternsReview trace-derived session health, recall use and prediction calibration, and surface recurring tool sequences, hotspots or failure modes.Metrics are operational proxies, not answer-accuracy scores. Pattern observations are not proof; automated validation and experiments are off by default.

Symdex local code intelligence

Symdex parses your working tree locally with tree-sitter and gives supported agents focused codebase context through MCP. It is the first dex — a domain index that gives your Keep understanding of one domain. Its wheel installs with the client kit; whether its tools appear is a registration, and on a fresh machine that is one command: firekeep dex add symdex. A machine that already had Symdex keeps it across the update. See Dexes and documents.

The built-in parsers cover Python, JavaScript, TypeScript, Go, Rust, Java, PHP, C, C#, Ruby, Kotlin and Swift. Depending on the language's syntax, the index captures functions, classes, methods, types, constants, routes and their relationships. Thirty tools are available by default for symbol lookup, search, callers, architecture, impact and related context; eight heavier analytics tools are optional.

Symdex can serve symbol-level context when that is sufficient and include broader file context when an edit needs it. Firekeep's code-and-memory tools can also cross-reference the current code with decisions, fixes and change history recalled from earlier sessions.

Local indexing does not mean model-local processing

The index stays on the workstation and is not uploaded to the Firekeep server. Tool output requested by an agent becomes part of that agent's working context, so it may be sent to whichever model provider you configured for that client.

Targeted symbol benchmark

The repeatable benchmark compares the stable response from a verified Symdex symbol lookup with reading that symbol's entire containing file. It uses one pinned public repository per supported language and 30 deterministic, file-balanced functions, methods, classes or types from each repository. Test, fixture, example and benchmark paths are excluded. No generation model or subjective judge is involved.

LanguageReference projectSampled filesMean estimated-token reductionExact Git-source checks
PythonClick1782.01% lower30/30
JavaScriptExpress683.13% lower30/30
TypeScriptp-queue560.39% lower30/30
GoCobra1880.47% lower30/30
Rustclap3069.64% lower30/30
JavaGson3046.40% lower30/30
PHPGuzzle3021.74% lower30/30
Cjq2967.35% lower30/30
C#Humanizer300.55% lower30/30
RubyRack3032.95% lower30/30
KotlinMoshi3057.12% lower30/30
SwiftSwift Argument Parser3056.27% lower30/30
Balanced result12 projects28554.83% lower360/360

The primary result is the mean of all 360 per-lookup reductions, with equal samples per language and file-balanced selection within each project. Token counts use the cl100k_base encoding; o200k_base produces a similar 54.54% result. Every indexed file and returned source was also checked byte-for-byte against its pinned Git blob, verifying the requested code was returned exactly. The median reduction was 78.42%; 58 of 360 lookups used more tokens because the serialized tool response can exceed an already small source file. The benchmark measures direct known-symbol retrieval against a whole-file baseline.

Mixed-task Click benchmark

A separate archived benchmark asked 20 comprehension, navigation and modification questions about Click, with three generated answers per question and an LLM judge. Across the 20 unique context comparisons, Symdex consumed 23.31% fewer total context tokens. Its judged-accuracy point estimate was 4.42 versus 4.45 for raw-file context.

WorkloadUnique context comparisonsTotal context-token resultJudged accuracy: Symdex / raw
All questions2023.31% fewer4.42 / 4.45
Comprehension747.67% fewer4.62 / 4.67
Navigation739.75% fewer4.43 / 4.43
Modification625.30% more4.17 / 4.22

Judged accuracy was comparable across both conditions. Modification questions consumed more context because the tested builder combined raw files with structural analysis.

Working-state restore benchmark

When an agent's context window is compacted, it restores its working state from the session server. That restore returns the whole session document — plan, decisions, file knowledge, progress and scratchpad — and still does by default. An agent may instead hand back an opaque cursor and receive only what changed since it last looked. This benchmark measures the difference between those two responses. No generation model or subjective judge is involved; token counts use the cl100k_base encoding.

ScopeFull restoreDelta restoreToken reduction
26 real sessions, aggregate16,72510,07539.8% lower
The 7 sessions above 1,000 tokensnot recorded separatelynot recorded separately50.7% lower
Weakest single session9919830.8% lower
Strongest single session47015367.4% lower

This is a per-restore reduction, not a per-request one. A delta is returned when an agent asks to restore its working state, which happens after a context compaction rather than on every turn.

Per-session reductions ranged from 0.8% to 67.4%, and the variation is structural. Scratchpad entries are stored without per-entry timestamps, so a delta always returns them in full; the same applies to proactively recalled memories, which are replaced wholesale rather than appended. Scratchpad alone accounted for 14.1% of all measured session tokens. Of the reduction, 80% comes from filtering decision, progress and file entries and 20% from omitting an unchanged plan.

The dataset is 26 real sessions from one operator on one machine. A separate check against a live deployment on 2026-08-01 reduced one session's restore from 12,122 to 4,977 characters.

The delta is opt-in. An agent that never sends a cursor receives byte-identical output to before, and six independent conditions — an absent, unparsable, wrong-session, stale, unreadable or unanchored cursor — each return the complete document rather than a partial one. Where the mechanism can be wrong, it returns too much rather than too little. A restore that omits content states what it withheld and how to retrieve it, so an agent reading a delta cannot mistake an omission for an absence.

Requirements

Server

  • Docker and Docker Compose v2 with linux/amd64 container support — use an x86-64 Linux server or VPS, or Docker Desktop with amd64 support on Windows or Mac (on Windows, run setup under WSL2 or Git Bash)
  • 2 x86-64 CPU cores minimum
  • Git
  • 16 GB RAM recommended for the default stack
  • No open ports required — a default install binds to 127.0.0.1
The current server release targets linux/amd64

Run it directly on an x86-64 Linux host, or through Docker Desktop with amd64 container support on Windows or Mac. On Windows the setup runs under WSL2 or Git Bash (Docker Desktop’s own Linux backend). The Linux x86-64 install path has automated smoke coverage on relevant main-branch changes and nightly; Windows and macOS are hand-checked on Docker Desktop. See Installing Firekeep.

Size RAM first

8 GB is the practical floor, and only with a small embedding model (EMBEDDING_MODEL=granite-embedding:30m, EMBEDDING_DIM=384). Below that, containers are OOM-killed while HTTP health checks still pass — a failure mode that looks like anything except running out of memory.

On Docker Desktop (Windows or macOS) the stack runs inside a VM given a fraction of host RAM by default — a 16 GB machine hands the stack roughly half that and drops it onto the floor above. Raise Docker Desktop → Settings → Resources → Memory to at least 16 GB before you set one up.

Client

  • Linux — CI cold-installs the published one-liner on seven distros every run: Ubuntu, Debian, Alpine, Fedora, Rocky, Arch and openSUSE. glibc and musl both work; Alpine is there to prove the musl path rather than to pad the list.
  • Windows — PowerShell. CI runs the client suite and executes install.ps1 on a Windows runner.
  • macOS — supported by the same bootstrap and its toolchain is built for it, but it is not in the CI matrix: our lab runs in Docker, which cannot host macOS. We test it by hand, not on every commit.
  • Nothing preinstalled — the bootstrap fetches its own pinned toolchain
  • Installing from a source checkout instead needs a system python3 >= 3.10

Licensing

Firekeep is one product: one client, one server, one capability set. There are no editions and no feature gates — the tier answers who governs the Keep, not which features you get.

The source is available under the Business Source License 1.1. Self-hosted use is free for self-hosted internal use is free for individuals and teams while Firekeep is in early access — any number of members, with unlimited agents, terminals and devices. Production use outside that grant requires a commercial licence. Each release converts to Apache-2.0 four years after publication.

There are no licence keys and nothing to activate. Every install is the complete product; the licence terms are the only boundary.

The terms also carry a published expiry: each release’s licence converts to Apache-2.0 four years after that release first ships. What you deploy today has a dated path to a permissive licence built into it.

Personal mode is a session state, not a licence

firekeep personal temporarily makes Firekeep dormant for private work. It has nothing to do with licensing.

Installing Firekeep

One bootstrap command per platform. It asks two required questions — who you are, and where your server is — then offers a skippable prompt for another MCP client. Standing up the server is one of the answers, not a separate procedure. There is no registry account and no licence token.

macOS / Linux
$ curl -fsSL https://firekeep.ai/latest/install | sh
Windows (PowerShell)
> irm https://firekeep.ai/latest/install.ps1 | iex

The bootstrap brings its own pinned Python toolchain and checksum-verifies everything it downloads before running it. Nothing has to be installed first — no system Python, no Node.

Or let your agent do it

If you already work with a coding agent, it can run the install for you. In Claude Code:

Claude Code
> /plugin marketplace add kapella-hub/FirekeepHQ

Then ask it to install Firekeep. The skill file itself is the portable Agent Skills format, so it works in any agent that reads them — only the directory differs. For Codex (including the Codex surface inside the ChatGPT desktop app, which shares the same host configuration):

Codex
$ mkdir -p ~/.codex/skills/install-firekeep && curl -fsSL https://firekeep.ai/install-firekeep/SKILL.md -o ~/.codex/skills/install-firekeep/SKILL.md

For Claude Code without the plugin, swap ~/.codex/skills for ~/.claude/skills. For anything else, drop the same file wherever that agent reads skills from.

Agents with no skills mechanism — Cursor, Gemini CLI, and ordinary ChatGPT conversations among them — have nothing to drop the file into. Install with the one-liner above and connect them the normal way: MCP for Cursor and other MCP clients (firekeep install --runtime generic), and for ChatGPT chats the Secure MCP Tunnel recipe.

The skill drives the same commands documented on this page and finishes by running firekeep doctor, so you see the real result rather than a claim of success.

It installs the client only. The install path it uses cannot provision a server — that is a property of the installer, not a promise about the agent. Standing up Neo4j, Qdrant, Redis and Ollama is a separate command the skill is instructed to confirm with you first, and asking is the one part that rests on the agent honoring an instruction rather than on the code refusing.

Three shapes, one command

Firekeep is a server you run once and a client kit on each member's machine. The same one-liner installs either or both; your answer to its server question decides which. Skim this, then read the walkthrough below.

ShapeRun it onWhat you doWhat you get
Both
one machine
x86-64 Linux, or Docker Desktop with amd64 support on Windows/Mac The one-liner → answer 1 (Set one up on this machine) Client and server, with this box already enrolled against it. The default when Docker is present.
Client only Any Mac, Windows or Linux machine The one-liner → answer 2 (join code), 3 (address + key) or 4 (not yet) Just the kit, pointed at a server your team already runs — or at nothing yet, finished later.
Server only x86-64 Linux, or Docker Desktop with amd64 support on Windows/Mac firekeep init --no-self-enroll, or bash install.sh from a checkout or bundle The full stack, with no machine enrolled — a build host, CI runner or golden image. Invite laptops afterwards.

Both and Server only are the same install with one difference — whether the box that built the server also becomes a client of it. Current server images target linux/amd64, so use an x86-64 Linux host or Docker Desktop with amd64 support on Windows or Mac (on Windows, run setup under WSL2 or Git Bash). The detail for each answer follows.

The two required questions

what you actually see
Agent identity (attributes every memory, session, and replay event) [alex]: Where is your Firekeep server? 1 Set one up on this machine (installs the server here with Docker) 2 I have a join code (Dashboard -> Devices, or from a teammate) 3 It is already running (you know its address and have a key) 4 Not yet (finish the client; `firekeep doctor` will tell you how to finish the job later) Choose [1]:

After these required questions, the installer offers one skippable prompt to add another MCP client and optionally manage its rules file. The four shipped adapters do not depend on that prompt.

The identity default is your OS username. It is kept as a question because the username is a good default and a poor answer — on a server it is often root, and every memory, session and replay event this machine writes is attributed to whatever you say here.

AnswerWhat happens
1 — set one upRuns firekeep init for you: provisions the whole stack with Docker on this machine, then enrolls the machine against it. The default when Docker is present.
2 — join codeAsks you to paste the code and redeems it. The default when Docker is not present.
3 — already runningAsks for the server address and an API key.
4 — not yetFinishes the client and stops. firekeep doctor then tells you how to finish the job whenever you are ready.
Which answer is yours

The machine that will host the server answers 1 — use an x86-64 Linux VPS or office box, or Docker Desktop with amd64 support on Windows or Mac (on Windows, run setup under WSL2 or Git Bash).

A laptop that should be a client of a server someone else runs answers 2 or 3 instead. The client kit runs on Linux, Windows and macOS — see Requirements for what continuous testing covers.

Answer 1 — the server provisions itself

It asks nothing further. The host address is detected (ip route get, falling back to 127.0.0.1) and the Neo4j password is generated. Both are overridable for the cases that need it — a NAT'd host or floating IP, a restored backup, a policy-managed secret — with --ip and --neo4j-password, or the FIREKEEP_VPS_IP and FIREKEEP_NEO4J_PASSWORD environment variables for unattended provisioning.

It downloads and checksum-verifies a source-free deployment bundle, pulls the public Firekeep images and starts the stack. When the stack is up, the machine enrolls itself through a join code minted locally over loopback, so firekeep doctor reports a connected server straight away — no dashboard, no SSH tunnel, no copied key. firekeep init --no-self-enroll opts out, which is what CI runs and what a golden image wants.

Server only — the stack, with nobody enrolled

A build host, a CI runner or a golden image should stand the stack up but not become a client itself. That is the same provisioning as answer 1 minus the self-enrollment:

x86-64 Docker host
$ firekeep init --no-self-enroll

From a source checkout or an unpacked release bundle, the direct equivalent is bash install.sh — add --pull to run the published images instead of building from source. Either way the stack comes up unenrolled; there is no client on this box and nothing is attributed to it.

Enroll machines against it afterwards exactly as below: hand each one the printed FIREKEEP_JOIN=… one-liner, or mint a code on the server with deploy/firekeep-admin invite --agent <name>. See Connecting a device.

Adding a second machine

The server prints a ready-to-paste command for the next machine. Run it there:

printed by the server — run it on the laptop
$ curl -fsSL https://firekeep.ai/latest/install | FIREKEEP_JOIN=fk_join_… sh

Same one command, with the code supplied up front, so that machine is not asked where the server is. A stock server answers only on 127.0.0.1, so the code carries an SSH route and firekeep join opens the tunnel itself using the SSH access you already have. The code is single-use and expires.

For every machine after that, mint another on the server with deploy/firekeep-admin invite --agent <name>, or use Dashboard → Devices → Add device.

The dashboard, and the two credentials

The dashboard is at http://127.0.0.1:8040/ on the server itself, and over the same tunnel from a machine that joined through a code. The browser asks for a login: username admin, with the password the installer wrote once to dashboard/.htpasswd.cred on the server at mode 0600 — read it once, then delete the file.

That is a separate credential from the admin API key. The admin key is an nxs_ token you send as an X-API-Key header to the Cortex API; the dashboard login will not accept it, and the dashboard password will not authenticate an API call. Join codes issued from the dashboard are single-use and valid for 24 hours.

While the models download

The install does not block on the ~3.3 GB embedding-model pull. The command returns as soon as the stack is up and the pull continues behind it. Until it finishes, memory writes return status="partial": stored and queued for backfill, but not yet findable by search. firekeep doctor shows an embeddings warning row saying exactly that, and docker compose logs -f ollama-pull shows progress. Use bash install.sh --wait-for-models if you would rather the install block until the pull is done.

Pinning and TLS deployment

Use firekeep init --version vX.Y.Z to install a specific published server release. firekeep init --office enables the bundled TLS reverse-proxy deployment. Both provision the same complete product.

Only the four Firekeep service images are published. Neo4j, Redis, Qdrant, Ollama and the nginx that serves the dashboard are pulled by your own Docker daemon from their upstream registries — Firekeep never redistributes them.

As a developer — build from source

From a checkout of the repository you have been granted access to:

source checkout
$ firekeep init --server-dir .

A source checkout builds the Firekeep services locally. Add --pull only when deliberately testing the published-image path.

What the server installer does

  • Checks for Docker and Compose v2, installing Docker if absent
  • Asks nothing — it detects the host address and generates the Neo4j password, writing a validated .env at mode 600
  • Generates a vault encryption key
  • Mints API keys and prints an admin key exactly once
  • Pulls public images or builds source images, then starts the complete stack
  • Enrolls the machine it is running on, and prints a ready-to-paste command for the next one
Keep the admin key

It is printed once and never stored. You do not need it to get started — this machine enrolls itself and the next one joins with a printed code — but it is the key that administers devices and workspace membership later. On a long-running server it simply does not exist any more, and if you lose it, key minting must be done on the server itself, where a shell already implies total control.

Your first authenticated call

A fresh install is closed by default in two independent ways.

DefaultValueEffect
AUTH_ENABLEDtrueProtected API routes require a key
BIND_ADDR127.0.0.1Ports answer only on the host itself

Both are deliberate. A fresh install answers only on the host itself and requires a key on every protected route — widening either is an explicit operator decision.

on the server
# Pre-auth paths answer keyless — this is how you tell "up" from "gated" $ curl -fsS http://127.0.0.1:8100/health $ curl -fsS http://127.0.0.1:8100/version # A real route without a key → 401 $ curl -s -o /dev/null -w '%{http_code}\n' http://127.0.0.1:8100/memory/stats # ...and with one → 200 $ curl -fsS -H "X-API-Key: $KEY" http://127.0.0.1:8100/memory/stats
401 and "connection refused" are not faults

If you are following an older walkthrough, both are the security defaults doing their job. /health and /version stay keyless precisely so you can distinguish a service that is down from one that is merely gated.

Server configuration

Everything lives in .env beside the compose file. The settings that actually change behaviour:

VariableDefaultWhat it controls
BIND_ADDR127.0.0.1Which interface ports publish on. Widening this exposes the stack.
AUTH_ENABLEDtruePer-key auth and scopes on protected API surfaces.
IMAGE_TAGdevPublished version to pull. dev is never published.
EMBEDDING_MODELmxbai-embed-largeEmbedding model. Changing it requires re-embedding, and EMBEDDING_DIM must match.
EMBEDDING_DIMVector width. Changing it requires a collection rebuild.
VAULT_KEYgeneratedEncrypts stored secrets at rest.
NEO4J_PASSWORDgeneratedGraph credential. Embedded in the data volume. Set it yourself at install time with --neo4j-password or FIREKEEP_NEO4J_PASSWORD when restoring a backup.
VPS_IPdetectedThe address the stack advertises. Detected with ip route get, falling back to 127.0.0.1; override with --ip or FIREKEEP_VPS_IP.
Two settings you cannot change casually

EMBEDDING_MODEL and EMBEDDING_DIM are load-bearing. Changing the model without re-embedding leaves old memories unsearchable; changing the dimension without rebuilding the collection breaks recall outright. They are independent of the generation model — conflating the two forces an avoidable rebuild.

The client kit

The same one command from Installing Firekeep, seen from the client side: what the bootstrap does on a bare machine, and how to re-run parts of it. No system Python or Node required.

macOS / Linux
$ curl -fsSL https://firekeep.ai/latest/install | sh
Windows (PowerShell)
> irm https://firekeep.ai/latest/install.ps1 | iex

What the bootstrap does

  1. Resolves the version and fetches that version's checksum manifest once.
  2. Verifies before use. Both a mirrored toolchain and the client wheel are checksum-verified against that manifest before either is executed. The wheel is fetched to a local file and installed by path — never by URL, which does no hash checking, and never by name.
  3. Installs the kit into ~/.firekeep with its own standalone Python.
  4. Asks two required questions — your agent identity, and where your server is — then offers a skippable prompt for another MCP client. The install walkthrough shows the menu and what each answer does.
  5. Acts on the answer: provisions a server here, redeems a join code, records an existing server, or stops and leaves the rest to firekeep doctor.
  6. Renders every shipped adapter for Claude Code, Codex, Kiro and OpenCode — Claude Desktop too, when the app is installed — and, with firekeep install --runtime generic, prints a paste-in snippet for any other MCP client.
  7. Installs both dex wheels, Symdex and Docdex, checksum-verified like everything else. Turning one on is separate and is yours: firekeep dex add symdex. An existing install keeps whatever it already had — see Dexes and documents.
Skipping the questions

A machine invited by a server gets its command with the code already in it — curl -fsSL https://firekeep.ai/latest/install | FIREKEEP_JOIN=fk_join_… sh — so it is never asked where the server is.

Device credentials

However a machine joins, the client creates its credential locally, redeems the code once and writes a single server connection. Device credentials default to 90 days; firekeep doctor warns during the final 14 days, and a new join code rotates the device onto a fresh credential.

From a source checkout

developer install
$ cd client && ./install # .\install.ps1 on Windows $ firekeep install --runtime claude # re-render one runtime

./install installs the kit and renders adapters. firekeep install run from that environment re-renders adapters only — it skips the package install, because the code it would install is the code already running.

Use firekeep install --runtime <name> only to repair or re-render one adapter. A normal install prepares all four supported clients together. firekeep install --runtime generic --agents-md <path> adds any other MCP client: it prints the gateway’s MCP-server JSON snippet to paste into that client, and — when --agents-md is given — manages a marker-delimited instruction block in that rules file. The install wizard also offers this as one skippable question (“Also use an MCP client we do not ship an adapter for? Paste its rules/AGENTS.md path, or Enter to skip”). The generic tier gets the MCP tools and instructions on connect, not the hook lifecycle.

Firekeep Studio

One desktop workspace for Codex, Claude Code, Kiro CLI and Grok. Choose the primary agent, bring in fresh review, and run evidence-backed Missions without switching apps.

Windows installer

x64 · Setup .exe

Run the per-user setup wizard and choose an install folder if you want a different location.

Download for Windows Latest stable · Windows x64

Universal Mac installer

Apple Silicon + Intel · DMG

Open the DMG, move Firekeep Studio to Applications, then launch it from Applications.

Download for macOS Latest stable · Apple Silicon + Intel
First-launch confirmation and SHA-256 verification

Your operating system may ask you to confirm this preview on first launch. Only continue after downloading from the official links above and checking the published SHA-256 value. On Windows, open More info → Run anyway if SmartScreen appears. On macOS, open System Settings → Privacy & Security → Open Anyway if the app is held.

Windows: run Get-FileHash "$env:USERPROFILE\Downloads\Firekeep-Studio-*-Setup.exe" -Algorithm SHA256.

macOS: run shasum -a 256 ~/Downloads/Firekeep-Studio-*-universal.dmg.

Match the result to the filename in the latest published checksums.

Bring the agents you already use. Install and sign in to Codex, Claude Code or Kiro CLI before selecting it in Studio. Grok connects directly with an xAI API key protected by your operating system.

First run

  1. Choose a workspace. Select the project folder every runtime should use. Studio remembers the choice locally; Missions require an explicit workspace.
  2. Choose the primary agent. Pick Codex, Claude Code, Kiro CLI or Grok. The primary leads the conversation until you switch it.
  3. Connect the provider when needed. Open Runtime Center from the primary picker. It shows account, connection, review and Keep status for every supported runtime.
  4. Check readiness, then work normally. Type /doctor, resolve any setup item it names, and send your first prompt. Type / for live command completion.

Useful Studio commands

CommandUse it for
/helpOpen the complete command inventory.
/doctorCheck installed runtimes and provider sign-in.
/workspace choosePick the one project folder passed to every runtime.
/use codexSwitch the primary agent. Replace codex with another available runtime.
/reviewer add claudeAdd a fresh, read-only reviewer.
/reviewer mode after-turnRun configured reviewers after each primary turn.
/mission new "goal"Create a bounded Mission in the current session.
/mission runRun the Mission, its checks and any bounded repair.
/mission reportInspect the evidence and stored result.
/update statusInspect Studio's separate desktop release channel.

Run a verified Mission

Give the Mission a clear goal, add the project’s real acceptance command, then run it:

Studio composer
/mission new "Ship the feature" /mission check add "npm test" --name tests --timeout 10m /mission run

Studio confirms the workspace, permission mode, repair limit, token guard and commands before execution. Checks drive bounded repair, reviewers stay independent, and you make the final call.

Connect Studio to your Keep

Studio and the Client Kit are separate. Add the Client Kit when you want supported runtimes to receive Firekeep memory, briefings and hooks. Grok runs through its direct provider connection; Runtime Center shows the Keep status of every runtime.

Desktop updates

Use /update status or /update check at any time. Windows verifies and downloads ready updates in the background, then offers Restart to update. On macOS, Studio opens the latest universal DMG for a manual replacement.

Connecting a device

Every path here is the same mechanism: a single-use join code. It identifies the server and the enrollment ticket; the client chooses its own credential and stores one connection. What differs is only where the code comes from.

SituationPath
The server's own machineNothing to do — it enrolled itself over loopback during the install.
A machine with no kit yetRun the install one-liner the server printed, which carries the code — see Adding a second machine.
A machine with the kitfirekeep join fk_join_… with a code from Dashboard → Devices → Add device or deploy/firekeep-admin invite.
You have SSH to the boxfirekeep connect user@host — the operator shortcut below.
existing client kit
$ firekeep join fk_join_…
The credential never crosses the enrollment exchange

The client generates the secret and sends only its SHA-256 hash while redeeming the single-use code. Later authenticated calls necessarily send the plaintext API key, so remote connections still require an SSH tunnel, private network or HTTPS.

SSH shortcut for operators

An operator who already has shell access can use firekeep connect. It issues a single-use code over SSH and then calls the same join path locally:

It attaches to a server; it does not create one

firekeep connect expects Firekeep to be installed already on the far end and stops with no Firekeep install found on the server if it is not. To stand a server up on another box, install Firekeep on that box and answer 1; then connect to it.

operator shortcut
$ firekeep connect root@203.0.113.10 --remote-dir ~/.firekeep/server
Loopback is the default

A stock server answers only on 127.0.0.1. The SSH shortcut establishes a tunnel and reuses it on later runs. Tailscale, WireGuard or your own HTTPS reverse proxy are also valid; Firekeep does not require a network vendor.

Restart your agent session afterwards so it picks up the newly registered MCP servers.

CLI reference

CommandWhat it does
firekeep initProvision or update a local/self-hosted Firekeep server, and enroll this machine against it. Answering 1 at install runs this for you. --no-self-enroll skips the enrollment (CI, golden images); --ip and --neo4j-password override what it would otherwise detect and generate; --version pins a release and --office selects the TLS deployment
firekeep join <code>Enroll this machine through a single-use join code
firekeep installInstall from a source checkout, or re-render adapters in an installed kit
firekeep connect <target>Operator SSH shortcut against a server that is already installed on the far end: mints a join code over SSH, opens a reusable tunnel and enrolls this machine
firekeep login <url>Reserved for hosted OAuth sign-in when a server supports it
firekeep doctor [--report]Preflight: health, versions, key ACLs, CA expiry, permissions. firekeep status is an alias (client ≥ 0.1.40). --report additionally sends an anonymous, redacted summary — see below
firekeep dex [list|add|remove]Which dexes this machine has turned on — see Dexes and documents
firekeep docdex [list|add|sync|remove]The document folders Docdex may read, and their sync state
firekeep personal [on|off|status]Toggle personal mode — dormant, nothing recorded
firekeep updateUpdate the kit. --check reports only; --to pins or rolls back
firekeep night-shiftDistil queued sessions into memory and draft skills via a local model
firekeep versionPrint the client version

Start with doctor

When anything is wrong, this is the first command to run — it checks the whole chain rather than one link.

diagnostics
$ firekeep doctor

firekeep doctor --report additionally sends an anonymous summary to firekeep.ai — the name and pass/warn/fail status of each check, plus your client version. Nothing else: not the messages doctor just printed, not a file path or hostname, not an IP address. This is off unless you type the flag — plain firekeep doctor never leaves your machine. See the privacy notice for exactly what is logged.

A client with no server

If you answered 4 at install, or the server never came up, doctor leads with the routing row rather than four identical connection errors:

firekeep doctor
[FAIL] server: This machine has a Firekeep client but no server to talk to. Pick the one that describes you: • Run the server on THIS machine: firekeep init • Join a server your team already has: firekeep join <code> (get a code from Dashboard -> Devices -> Add device) • Set one up over SSH on another box: firekeep connect <user@host> The four rows below are the same fact, once per service.

On a machine that does have a server configured, the same row names the host that is not answering instead. Note that the third suggestion attaches to a server that is already installed on that box — see Connecting a device.

Embeddings still warming

A warn row on a freshly installed server is expected and needs no action — it is the model pull finishing:

firekeep doctor
[WARN] embeddings: still warming — memories you write now are STORED and queued for backfill, but not searchable until this finishes. Nothing to do; watch it with: docker compose logs -f ollama-pull

Dexes and documents

A dex is a domain index that gives your Keep understanding of one domain. Three ship today — Symdex for code, Docdex for documents, Maildex for email — and a registry decides which of them runs on this machine. Since client 1.2.0 a fresh install registers Symdex and Docdex out of the box; Maildex registers itself when you connect a mailbox.

firekeep dex — what is turned on

CommandWhat it does
firekeep dex listEvery dex this client knows, with its state: registered, available (wheel present, not registered), or not installed. The default when no action is given
firekeep dex add <name>Register symdex, docdex or maildex — though maildex is registered automatically by firekeep maildex add. Refused if the wheel is not present, rather than written and failing silently next session
firekeep dex remove <name>Unregister it. The wheel stays installed; add brings it straight back

Registration gates activity, not installation. All three wheels arrive with every release and are checksum-verified by the installer; add downloads nothing and remove uninstalls nothing. The only thing that changes is a line in ~/.firekeep/dexes.json, which decides whether the gateway mounts the dex's tools and whether its background work runs. Both commands are idempotent, and both take effect on the next agent session — the gateway reads the registry once, at startup.

An update never removes what an install already had

A machine that had Symdex before the registry existed is grandfathered: it keeps working across the update with no action and no extra install question. Since client 1.2.0 a fresh machine seeds the registry with symdex and docdex, so both are on out of the box — and because an update never touches an existing ~/.firekeep/dexes.json, a firekeep dex remove sticks across every later release. The one thing the doctor row reports as a warning is a dex registered whose wheel has gone missing, because that is a backend that will fail to start.

firekeep docdex — the folders it may read

CommandWhat it does
firekeep docdex listSources with their counts, staleness, failures and pending deletes. The default when no action is given
firekeep docdex add <path>Add a folder — private to you by default, even on a shared Keep. --shared makes that one folder visible to your workspace. Refuses a path that is not a folder, or one already added
firekeep docdex syncScan every source now. --source <id> does just one
firekeep docdex remove <id>Delete the source and its replicas in the Keep. The folder on disk is never touched

Docdex extracts .md, .txt, .pdf, .docx, .html/.htm, .eml and conversation-shaped .json (AI-chat exports with role-labeled turns); anything else is counted as skipped. The extracted text is ingested into your Keep's corpus and surfaces through ordinary memory_recall in your own sessions — there is no new recall surface and no MCP server. Deleting a file locally deletes its replica on the next sync, retried until the server confirms it.

These four commands work whether or not the dex is registered: registration gates the background sync and the doctor row, never a person's ability to say which of their own folders the Keep may read. There is deliberately no agent-callable tool for choosing a folder — that tool is absent, not guarded.

When a sync happens

With docdex registered and at least one source, a stale source is picked up in the background at session start on runtimes that expose a hook for it. It is detached from the session, so a cold scan never delays a session opening.

RuntimeBackground sync
Claude Code, Kiro, OpenCodeAutomatic when stale
Codex, any other MCP clientNone — no hook surface. Run firekeep docdex sync

Opt out with FIREKEEP_NO_AUTO_SYNC=1 or [docdex] auto_sync = false in ~/.firekeep/config. Personal mode suspends syncing entirely — the trigger does not fire, and a run already in flight stops between batches.

Caps

All env-overridable; an unparseable value falls back to the documented default.

VariableDefaultOn breach
FIREKEEP_DOCDEX_MAX_FILES5000 per sourceThe source is refused until narrowed. Nothing is written — a folder half-indexed would look synced and be wrong forever
FIREKEEP_DOCDEX_MAX_FILE_MB25File skipped and counted. Skipped is not deleted: it keeps any replica it already has
FIREKEEP_DOCDEX_MAX_EXTRACT_KB400Extracted text truncated at the cap, flagged, and shown by list
FIREKEEP_DOCDEX_SYNC_INTERVAL_HOURS6Staleness threshold for the background trigger
FIREKEEP_DOCDEX_INGEST_TIMEOUT_SECONDS180Per-document upload budget — the server embeds synchronously, so large documents need real time. A timeout aborts the sync honestly (“timed out”, never a false “unreachable”); what landed is kept and the rest retries next sync
What Docdex does not do

There is no OCR — a scanned PDF yields no text, recorded as an honest zero rather than retried as a failure. There is no live file watching: syncs are session-start-triggered or manual. There are no cloud sources (Drive, Notion and the like). Visibility is per folder, never per file. And removing a document removes its replica, not a separate memory an agent may have written after reading it.

Default excludes cover dot-directories, node_modules, __pycache__ and secret patterns such as .env and *.pem — a net for mistakes, not a security boundary. Do not point Docdex at a folder containing secrets.

firekeep maildex — mail, read-only

Maildex connects a mailbox over IMAP and indexes recent mail into the same recall — always private to you, even on a shared Keep; there is no --shared for mail. firekeep maildex add imap.example.com you@example.com prompts for an app password and registers the dex automatically; firekeep maildex sync, list and remove work like their Docdex counterparts.

Read-only is structural, not promised: every mailbox open is IMAP EXAMINE and every fetch a PEEK — the wheel contains no send, move, flag or delete capability anywhere, and a build-time guard fails if one is ever added. The app password is stored in the server's vault under your identity — never on the client's disk — and is deleted when you remove the account. Defaults: INBOX and Sent, the last 90 days of mail, then incremental syncs.

What Maildex does not do yet

Mail you delete at your provider stays in the corpus until you remove and re-add the mailbox — provider-side deletions are not mirrored, and maildex list restates this every run. Attachments are not read (their names are noted). OAuth sign-in is deliberately absent; an app password you can revoke in one click is the current trade.

All three dexes report to firekeep doctor, read from disk with no server call, so the rows are still there when the server is the thing that is broken:

firekeep doctor
dexes ok symdex, docdex (registered) docdex ok 2 sources · last sync 3h ago · 0 pending deletes · 0 failures

last sync reports the stalest source, not the freshest: a row saying "just now" because one folder of five synced would hide the four that did not.

Day to day

The Keep volunteers (client 1.0.3)

On Claude Code, every user prompt is checked against team memory and up to three genuinely relevant, not-yet-seen memories are pushed into the model's context as a [firekeep recall] note — usually none. Kiro runs the same check, but delivery over its userPromptSubmit channel has not been measured — treat it as unverified there. Off-switch: FIREKEEP_NO_RECALL_PUSH=1. Pushed recalls carry trigger: prompt-hook in replay, so the compliance measurement can slice pushed from deliberate recall.

And since server v1.2.0, declaring a session goal answers back: the response to ctx_start_session carries a prior art block — up to three team memories about similar past work, plus what other agents are building right now — so "build X" surfaces "the team already built X" before a line is written. It rides the tool response itself, so it reaches every runtime, hooks or not; checks are marked trigger: prior-art in replay.

The core MCP capabilities work through every shipped adapter — and through any other MCP client, installed with firekeep install --runtime generic. Lifecycle automation varies because each client exposes different hook surfaces; a generic client exposes none, so it gets the MCP tools and instructions on connect but not the hook lifecycle.

Automation by client

ClientAutomatic surfaceCurrent boundary
Claude CodeThe richest hook coverage: start briefing and presence, prompt polling, pre-compaction capture, pre/post edit mediation, final snapshots and true session-end deregistration.Its pre-edit hook can hard-block a denied edit; service failures still degrade according to the documented hook policy.
KiroAgent-spawn and prompt hooks provide briefing, presence, inbox polling and snapshots; pre/post tool hooks record mediated actions.There is no true session-end or PreCompact event. On validated Kiro 2.12.1, the pre-edit hook fires but is advisory rather than a hard block.
OpenCodeA local plugin bridges the lifecycle and edit events OpenCode exposes; supported edits can be hard-blocked and session deletion drives final capture.Briefing and inbox output appear in the console, not model context. Its lifecycle surface is narrower than Claude's and has no pre-compaction event.
CodexMCP servers and repository guidance expose the full direct-call tool surface.Codex has no Firekeep hooks: recall, session updates, inbox polling and policy calls are manual. Presence, heartbeat and snapshots require starting the optional sidecar yourself.
Claude Desktop
the consumer chat app
Auto-detected at install (when the app's config directory exists) and mounted into claude_desktop_config.json by its own adapter — the full MCP tool surface plus the on-connect protocol. The first non-coding host with a bespoke adapter: a decision made chatting in Claude Desktop is recallable in your coding agent the next morning, and vice versa. Restart the app after install.The app exposes no hooks, so nothing hook-driven exists: no auto-briefing, no pre-edit gate, no stop→learn, no background dex sync (run firekeep docdex sync yourself). Presence requires the optional sidecar. Only the firekeep entry in its config is ever written or removed; the rest of the file is never touched.
ChatGPT
via OpenAI's Secure MCP Tunnel
A server-side recipe (deploy/chatgpt-tunnel/ in the repo): a tunnel client on the Keep host makes outbound-only HTTPS to OpenAI and forwards ChatGPT's MCP requests to the Firekeep gateway running a curated 12-tool chat surface — recall, learn, feedback, skills and sessions, with vault, corpus, relay and backup tools excluded at the gateway's routing layer (invisible and uncallable). The Keep stays private: no public port ever opens.Requires your own OpenAI Platform tunnel and ChatGPT developer mode; requests transit OpenAI's control plane — a disclosed third party in the request path. No hooks. Every call is attributed runtime: chatgpt in replay, so chat-authored memories stay auditable as a class. (ChatGPT desktop's local MCP setting belongs to its Codex surface, which reads the shared Codex config and gets Firekeep the ordinary way.)
Any other MCP client
Cursor, Windsurf, Gemini CLI, …
The full MCP tool surface, plus the cognitive-protocol instructions the gateway delivers on connect. Installed via firekeep install --runtime generic, which prints a paste-in MCP-server JSON snippet and can manage a marker-delimited instruction block in an AGENTS.md-style rules file (--agents-md <path>).No hooks at all, because a generic client exposes none Firekeep can wire: no auto-briefing at session start, no blocking pre-edit gate, no stop→learn and no pre-compaction checkpoint. As with Codex, presence and heartbeat require starting the optional sidecar yourself. The MCP tools and shared memory are identical to every other client; what is absent is the lifecycle automation, not the memory.

These differences affect convenience, not access to the underlying MCP capabilities. Every supported client can call the same server tools when its agent chooses to do so.

What your agent calls directly

Firekeep exposes its server capabilities through one local gateway, with Symdex and Decision Board running client-side. The tools that matter in ordinary work include:

AreaToolsUse
Memorymemory_recall / memory_learn / memory_feedbackFind prior evidence, record a fix or decision, and report whether recalled knowledge actually held up when acted on — the feedback feeds ranking.
Skillsskill_recall / skill_createFind or author a reusable playbook; document-derived drafts stay out of recall until reviewed.
Knowledgecorpus_ingest / knowledge_ingest / knowledge_ingest_urlMake pasted content or a bounded public documentation crawl searchable; the Knowledge front door also queues reviewable procedure drafts.
Sessionsctx_start_session / ctx_update / ctx_get_shadow / ctx_resume_sessionPersist explicit working state across compression, interruption and crashes.
Relay leasesrelay_lease / relay_heartbeat / relay_releaseCoordinate ownership of a file or task with a renewable fenced lease.
Relay workrelay_task_post / relay_task_list / relay_task_updateCreate, assign and advance work that another agent identity can pick up.
Relay messagesrelay_post / relay_read / relay_send_dm / relay_get_dmPost to a catch-up channel or exchange pollable direct messages; relay_who_is_online reports best-effort presence.
Decision Boarddecision_board / decision_board_checkOpen a multi-question clarification board and wait for the human's submitted answers.
FirekeepScopescope_start / scope_ask / scope_post / scope_checkRun gating or asynchronous clarification screens through Relay and the dashboard.
Replayreplay_timeline / replay_inspect / replay_context_at / replay_narrowMove from a recorded timeline to event details, nearby context and likely contributors to a failure.
Sentinelsentinel_get_events / sentinel_get_health / sentinel_push_eventRead configured environment activity, check collector health or add a custom operational event.
Vaultvault_list / vault_retrieveDiscover metadata and explicitly retrieve an authorized secret without putting it in memory.
Vault administrationvault_store / vault_deleteCreate or irreversibly remove entries; these operations require an admin-scoped credential.
Evalseval_session / eval_summaryInspect trace-derived operational metrics for one completed session or recent sessions.
The habit that pays

Recall before starting and learn after finishing. Relevant recorded decisions and fixes can save rediscovery, and the value compounds as later agents retrieve evidence from earlier work in the same project.

The knowledge lifecycle, on autopilot

The knowledge base maintains itself without deciding anything on its own. What runs automatically: recorded session outcomes and explicit useful or not-useful feedback can nudge recall ranking, though current outcome discrimination is limited; sessions whose agent crashed or walked away are closed out after three days of silence so failures count instead of vanishing; close restatements supersede what they restate; stale knowledge ages into a recoverable archive.

What is deliberately proposed, never auto-applied: when two unconfirmed memories contradict each other, neither is dropped — both stay recallable, visibly marked as contested, until a human picks a winner or rules that both are true in their own contexts. Draft skills, stale skills, procedure proposals and contested pairs all queue in one review inbox on the dashboard's Autopilot tab, next to a digest of what changed in the last week. A memory's full evidence — provenance, usage, confirmations, feedback, outcome efficacy, disputes and lineage — is one read away, so every ranking has a visible why.

The instruction layer is measured too. The same tab's Living Instructions table scores each instruction Firekeep gives your agents — recall before answering, record as you go, declare consequential actions — against what sessions actually did, computed deterministically from the replay record with the caveat built into the response: compliance measures behavior, not whether the behavior helped. Agent-drafted instruction rewrites under human approval, validated by A/B across sessions, are roadmap — not shipped.

The dashboard

Served on port 8040. Because the stack binds to loopback, reach it through the tunnel connect established — at http://127.0.0.1:8040/, not the server's own address.

Governance, trust & private documents

Three capabilities that landed recently. Each is scoped honestly here — what it enforces, what it only reports, and what is still being built.

Enforced Runbooks

A skill is advice text until something watches whether its steps happen. Give a skill's steps command matchers and it becomes a runbook — and a human, never an agent, can arm it with an enforcement mode. Agents may propose a runbook; only a human with an admin key arms it, on a route the ordinary skill-edit path cannot reach.

advise require_ack block armed by a human · admin-only

Illustrative — the three human-armed enforcement modes.

  • advise — a matched command is annotated, and proceeds.
  • require_ack — it is challenged, and proceeds only after an audited acknowledgement with a recorded reason.
  • block — it is stopped.

A command counts only when it actually ran and succeeded. Evidence commits in two phases: permission time writes a pending record, and only a matching exit status of zero commits it. A deploy that crashed never scores as a completed one.

Block fails closed. The client honours an allow only when the server's answer carries the marker it appends on a genuinely evaluated path — so a reachable but broken server reads as a block, not as an authenticated allow. Every lookup and permit is scoped to the verified workspace; the self-reported agent_id is a label, never the boundary.

Every enforcement event an operator would triage — a block fired, a challenge acknowledged with its reason, a matched command that ran and failed — lands in a per-workspace deviation ledger, surfaced on the dashboard's runbook cards and the Autopilot inbox. It stores the command's hash, never its text.

Honest scope

Opt-in (PROCEDURE_ENABLED), and it needs client 0.1.44+. Full enforcement lands only on runtimes with a blocking hook — Claude Code today; Kiro observes but does not stop the command. Command matching catches a well-meaning agent's mistake; it is not adversary-proof, and a machine's owner can always remove the hooks. This gates agents, not humans.

We are proving it on our own deployments first — observed under advise, then require_ack, then block — and will not call it finished until block mode has stopped a real mistake.

The Trust Ledger

Agents already declare consequential actions through the gateway: what they are about to do, how sure they are, and afterwards what actually happened. The Trust Ledger turns that stream into a per-agent employment record — how much each identity declared, how often it reconciled the outcome, how well its stated predictions matched reality, and how many of its own actions it later marked failed.

Illustrative — not a live capture. Components only; there is deliberately no single trust score.

It reports; it never gates. There is no headline trust number, on purpose — a composite gets treated as a gate, and a self-reported identity is the wrong thing to gate autonomy on. Turning this into earned autonomy is a separate, later piece of work; round one is the honest measurement, on the dashboard's Autopilot tab beside the compliance table.

Read the components for what they are

Behaviour, not competence. Calibration scores whether an agent's stated prediction criteria matched what was observed — not whether its decisions were good. An action with no stated criteria scores a perfect match even when it failed. A lower score is better, so an improving agent trends down.

Declared actions only. The ledger sees what an agent declared through the gateway, and only what the replay log captured of it — a floor on a floor. An agent that declares nothing is unmeasured, not trusted, and a metric a truncated read would bias is returned as unknown rather than as a guessed number.

Member-private documents

Memory on a shared server is a team asset — but not everything you want an agent to recall should be. Firekeep's document memory carries a per-folder visibility setting, and the default is private to you, even on a shared Keep. Private content surfaces through ordinary memory_recall in your own sessions and nowhere else.

The enforcing half — server-side tenancy — is shipped. One shared filter runs at every member-facing exit: a private chunk never appears in another member's recall, and a private source's name never appears in another member's listings or dashboard. Each document's chunks carry their own identity, so deleting your copy of some text can never remove a teammate's identical copy, and a half-finished re-ingest never exposes a partial document — recall only ever sees a committed generation.

Both halves are shipped

The server-side visibility filter, per-source identity, committed-generation recall and scoped credentials are built and tested. So is the client: firekeep docdex points at folders and ingests .md, .txt, .pdf, .docx, .html/.htm, .eml and conversation-shaped .json. The commands, caps and sync behaviour are in Dexes and documents.

Private from other members — not encrypted from the operator

The filter is a tenancy boundary between people who share a server, not cryptography. Content is visible to agents acting as you, and anyone who can read the server's vector store directly can read everything. Indexed document text is always treated as evidence, never as instructions to the agent.

Personal mode

An escape hatch that makes Firekeep dormant for work you do not want it to record.

any runtime
$ firekeep personal toggle # or: on | off | status

Hooks, the presence sidecar and Decision Board re-read the state and stop communicating immediately. An MCP shim that is already running evaluates hard bypass only when it starts, so restart the active agent after changing Personal mode. A restarted shim exposes zero Firekeep tools while the mode is on; restart again after turning it off to restore them.

How it clears

Claude Code and OpenCode wire a true session-end or session-deletion event to clear the marker. Kiro has no true session-end event, and Codex has no hooks, so turn it off with firekeep personal off or rely on the 12-hour TTL backstop. firekeep doctor reports a warning whenever it is active.

For a whole session that is personal from the start, set FIREKEEP_BYPASS=1 before launching your agent.

Operations

Updating

server / client
$ firekeep init # server: current release $ firekeep init --version vX.Y.Z # server: pin or roll back $ firekeep update # client: latest release $ firekeep update --check # report only $ firekeep update --to X.Y.Z # client: pin or roll back
Updates never ask you to close your sessions

Since client 0.1.35, each release installs side-by-side and a link flip selects it — the environment your open sessions run from is never touched. Running sessions keep working on the old version; anything started after the update gets the new one, and firekeep update --to back to the previous release is an instant flip. Old versions are cleaned up automatically once nothing is using them.

What version am I running?

Every service answers /version without a key and without touching its dependencies, so it responds even when the things behind it are down.

on the server
$ curl -fsS http://127.0.0.1:8100/version

Health

default server directory
$ cd ~/.firekeep/server $ docker compose ps $ docker compose logs -f cortex-api $ docker stats --no-stream
Healthy is not the same as working

Compose health checks are TCP-only. A container can report healthy while the service inside it cannot reach Redis or Qdrant — which is exactly what an out-of-memory kill looks like from the outside. Check /health bodies, not just container state.

Removing Firekeep

client / server
$ firekeep uninstall # remove the client kit from this machine $ firekeep uninstall --server # also tear down the server + ALL its data

firekeep uninstall removes only what the kit installed: the Firekeep blocks in each runtime's config (your own settings are left intact), the firekeep launcher and its PATH entry, and ~/.firekeep. It asks first; --yes skips the prompt. It never touches a server you set up — memory, sessions and the vault survive.

--server deletes everything the server stored

--server additionally runs docker compose down -v on the stack this machine provisioned, which removes the Neo4j, Qdrant and Redis volumes — every memory, session, replay trace and vault secret, permanently. It is gated behind a separate data-loss confirmation of its own, so a plain uninstall (or --yes) can never trigger it by accident. Back up first with deploy/backup.sh if you might want the data again. On a server-only box, the bundle's uninstall.sh does the same teardown.

Backup & restore

The rule this feature exists to satisfy: you should never discover your backup story during the disaster. The Keep backs itself up automatically; your job is one command to keep an off-box copy, and one runbook if the worst happens.

Automatic nightly backups

Since server v1.0.3 the Keep backs itself up: a cold snapshot nightly at 04:30 server time (neo4j, qdrant and redis stop for the one-to-three minutes of archiving — a copy of a live store restores without error and is wrong), with per-file checksums in a manifest, retention of 7 nightly + 4 weekly, and the server's .env included so a bare-metal restore recovers vault secrets too. Model weights are excluded — docker compose up -d re-pulls them. A backup on the server's own disk still dies with the server, so the off-box copy is a pull to a machine you control (client 1.0.2):

any enrolled machine
$ firekeep backup link # once: paste a deployment ADMIN key (dashboard or firekeep-admin) $ firekeep backup pull # download newest backup, verify every sha256 $ firekeep backup status # ages, counts, policy — and this machine's last pull $ firekeep backup list # one line per backup, indexed and unindexed $ firekeep backup restore # prints the guided host-side restore steps
The archive is a secret, and downloads are admin-only — permanently

A backup holds every member's private documents and the server's .env with VAULT_KEY. That is what makes it bare-metal restorable, and what makes it sensitive: pull requires a deployment admin key (link verifies it against the live server before storing anything), member keys get 403 by design, and no member-grantable backup scope will ever exist. Off-box freshness equals your last pull — firekeep doctor shows both the newest server backup (warns past 36 hours) and when this machine last pulled.

Disaster runbook, retention details and the manual tools: docs/guides/backup-and-restore.md. The short version: fresh host → install.sh → copy the pulled backup over → deploy/restore.shdocker compose up -d.

Restoring

Restore runs on the server host with the stack stopped — firekeep backup restore prints these steps with your machine's real paths filled in. On a brand-new host, run the installer first, then restore into it:

disaster runbook
# fresh host only: install the server first $ bash install.sh # copy the pulled backup up from your machine $ scp -r ~/FirekeepBackups/firekeep-backup-STAMP root@server:/opt/firekeep/backups/ # restore with the stack down, then start it $ docker compose down $ bash deploy/restore.sh backups/firekeep-backup-STAMP $ docker compose up -d # ollama-pull re-fetches model weights once

restore.sh restores the archived .env when present — with an explicit confirmation, never a silent overwrite — and firekeep doctor from any enrolled machine confirms the Keep is healthy afterwards.

Manual backups and recovery caveats

The nightly job wraps the shipped deploy/backup.sh, which you can also run by hand; it quiesces Neo4j, Qdrant and Redis before their files are copied, because a partial or hot filesystem copy can look valid while containing inconsistent graph, vector or auth state. A manual run archives the four base volumes (including Ollama's model weights) and — unlike the nightly job — does not copy .env.

from the server bundle directory
$ bash deploy/backup.sh ~/firekeep-backups # restore only with the stack stopped; the script asks for confirmation $ docker compose down $ bash deploy/restore.sh ~/firekeep-backups/firekeep-backup-…
A manual volume archive is not a complete recovery set

For manual backup.sh runs, separately protect the original .env as a secret: it contains the VAULT_KEY required to decrypt stored secrets, the Neo4j password, internal credentials and stable workspace/member IDs. (Nightly archives include it — that is why they are treated as secrets themselves.) An office-mode deployment must additionally back up its caddy_data volume, which holds the internal CA private key and is in neither the nightly nor the manual volume set. Restore those identities with the data; generating replacements can make the restored vault unreadable, invalidate clients or change workspace ownership.

The admin JSONL export covers memories and the knowledge graph; session state, vault entries and replay traces live only in the volume archive. Use the volume backups — not the export — as the recovery mechanism.

Troubleshooting

Everything returns 401

Expected on a fresh install — AUTH_ENABLED=true is the default. Confirm the service is actually up with the keyless /health, then check that your client connection has an API key. firekeep doctor reports a missing or rejected key directly.

Memories save, but recall finds nothing

On a server installed in the last few minutes, this is the model pull, not a fault. The install stops blocking once the stack is up, and until the ~3.3 GB embedding model has finished downloading, writes return status="partial": the memory is stored and queued for backfill, but it is not searchable yet. Nothing is lost and nothing needs re-writing — the backfill makes it findable.

Confirm with firekeep doctor, which shows an embeddings warning row until the model is loaded, and watch it with docker compose logs -f ollama-pull. To avoid the window entirely on the next install, use bash install.sh --wait-for-models.

Connection refused from another machine

Also expected. BIND_ADDR=127.0.0.1 means the ports answer only on the host. Attach the machine with a join code rather than pointing it at an address: firekeep join fk_join_… if it already has the kit, or the FIREKEEP_JOIN=… one-liner the server printed if it does not — a code issued by a loopback-bound server carries its own SSH route. An SSH tunnel, private network or HTTPS reverse proxy of your own works too, as does the operator shortcut firekeep connect user@host --remote-dir ~/.firekeep/server. Pointing a client at an unbound public address simply times out.

If firekeep doctor instead reports this machine has a Firekeep client but no server to talk to, there is no server configured at all — see Start with doctor.

The dashboard says a service is unreachable

Check the service directly on the host with curl against /health. If that answers and the dashboard disagrees, the proxy in front of the dashboard is misrouting rather than the service being down.

Containers restart or get killed

Almost always memory. Check docker stats against the requirements above. The symptom is misleading: health checks keep passing while the process inside is killed and restarted.

The agent does not see the tools

MCP servers are registered at install, and a running agent session does not pick up new ones. Restart the session. If they are still missing, firekeep install --runtime <name> re-renders that runtime's configuration.

On Linux or macOS, if the gateway connects but exposes only firekeep_gateway_status, you are on client 0.1.37 — a resolution bug fixed in 0.1.38. firekeep update resolves it.

The Symdex tools are gone

Check firekeep dex list. An existing install is grandfathered across the update, but if that listing says available rather than registered, run firekeep dex add symdex — and note that it takes effect on the next agent session, not the current one. If it says registered (wheel missing!), the wheel did not land: re-run the installer, or firekeep dex remove symdex.

Documents never appear in recall

In order: is the dex registered (firekeep dex list); is the folder added (firekeep docdex list); has a sync actually run (last sync in that listing, or the docdex row in firekeep doctor); does the runtime have a hook surface at all — on Codex, Claude Desktop and generic MCP clients nothing syncs until you run firekeep docdex sync; and is personal mode on (firekeep personal status), which suspends syncing. A source shown as refused holds more indexable files than FIREKEEP_DOCDEX_MAX_FILES — narrow the folder or raise the cap.

Still stuck

Run firekeep doctor and include its output when you get in touch. It reports the whole chain — connection, auth, versions, permissions — rather than one link of it.