Skip to content
Download

Architecture decision records

Each record captures one significant decision: the problem, what was chosen, what was rejected and why, the consequences, what would reopen it, and how it was validated. An accepted record is not rewritten; a later change is a new record that links back to it.

  • To learn how Imprint works now, read Current decisions: only the records in force, grouped by area, each with its decision in one line.
  • Amended records are in force, but later records changed part of them. Read a record together with the ones named after it; where they differ, the later record wins. Superseded records are history: follow Superseded by to the record in force.
  • Open proposals are under consideration and do not describe current behavior. The decision log lists every record in number order with its status.
  • To challenge a decision in an issue or pull request, cite its number, for example ADR 0063. Check its Rejected alternatives first, then say which of its Invalidation conditions holds, or which one is missing.
  • To add or change a record, follow How to write and maintain ADRs.

Records 0001 to 0062 were brought to this structure on 2026-10-25 (Restructured in their headers); their Invalidation conditions were derived then from each record’s own text. A record marked Retrospective was written after its decision, from the code and history it cites.

The records in force, by area. An amended record is listed with the records that changed it; read them together.

  • ADR 0083 Apple silicon laptop runner. Trusted ARM64 jobs use the laptop; PR checks remain hosted. Amended by ADR 0106 (Intel jobs on the Intel laptop, since superseded) and ADR 0111 (no Intel macOS jobs) and ADR 0112 (no hosted PR jobs) and ADR 0115 (disposable VMs).
  • ADR 0112 CI runs on the owner’s machines. Trusted jobs use bedrock’s Swarm runners, Windows VMs and the Apple silicon laptop; Linux PR jobs run in throwaway just-in-time containers with no token or Docker socket; arm64 runs emulated; Windows and macOS jobs skip pull requests. Amended by ADR 0115 (macOS jobs in disposable VMs) and ADR 0119 (runner image with CI’s dependencies).
  • ADR 0115 Apple silicon jobs run in disposable Tart VMs. A laptop supervisor clones a golden macOS VM per queued job with a single-use JIT runner and deletes it afterwards; the macOS package job installs and smokes the package.
  • ADR 0119 Throwaway runners carry CI’s dependencies, and the dashboard is built once. The throwaway Linux runners start from an image with the locked Python dependencies and Go installed; CI builds the dashboard export in one job for every platform.
  • ADR 0001 Record significant decisions. Repository documentation and ADRs are the durable engineering record.
  • ADR 0019 Reproducible benchmark evidence. Frozen public corpora, paired trials, visible failures and auditable JSON statistics for benchmark claims.
  • ADR 0031 Website analytics events and public relay status. GA4 events for website actions, a live public-relay status from a CORS-readable /health, and opt-in analytics on the relay page.
  • ADR 0005 Source lifecycle and hybrid retrieval. Content provenance, safe source replacement and bounded hybrid ranking. Amended by ADR 0110 (the scan follows no links) and ADR 0172 (lexical candidates and verbatim matches).

  • ADR 0021 Budgeted MCP evidence and selective expansion. Compact bounded MCP evidence, selective expansion and separately pinned runtime/corpus benchmark provenance.

  • ADR 0022 Retain HTTP clients during model work. Keep HTTP Qdrant clients alive through cold model work; retire the embedded-lock idle timer.

  • ADR 0036 Move memories between projects. Projects place memories their writers named; workspace rules applied at every write keep moves through refresh, learning and sync, without changing source keys. Amended by ADR 0134 (rules travel to paired devices).

  • ADR 0058 Recall: batched reads with optional local planning. One additive read-only recall tool runs several read steps concurrently under one budget; without a plan it is search; an opt-in local model may add steps and answer with checked citations.

  • ADR 0063 Run Qdrant as an auto-spawned local server. Every Imprint process reaches one Qdrant server on loopback that the first process to need it starts; embedded mode admits one process at a time.

  • ADR 0065 Qdrant over LanceDB as the vector store. Memories live in Qdrant, reached through its server API so the auto-spawned local server and a separately run one serve the same code; it replaced LanceDB, which as the owner recalls could not run as a remote server.

  • ADR 0081 Verifiable redacted source snapshots. Complete redacted readable sources, character-span manifests and bounded verified source reads.

  • ADR 0095 Audio files enter the source ingestion pipeline. Local audio becomes timestamped neutral-speaker conversations; existing redacted source snapshots provide the workspace-scoped transcript cache.

  • ADR 0172 Exact matches survive a large corpus. The lexical channel reads the points holding every query term, then each term’s points from the rarest up; a query of several terms found verbatim ranks as a third list in the fusion.

  • ADR 0015 Workspace roots and source purge. Approved workspace roots, confirmed sharing, stable writes and previewable file/directory purge. Amended by ADR 0034 (learning rules) and ADR 0072 (directory workspaces).

  • ADR 0029 Paired local browser capture prototype. Explicit browser capture through workspace-bound extension pairing and serialized local ingestion. Amended by ADR 0030 (Gmail availability and distribution).

  • ADR 0034 Learn from client stores by conversation ownership. Learning reads the clients’ own stores without an approved root; recorded working directories decide which workspace a conversation belongs to. Amended by ADR 0037 (stores and Codex working directories), ADR 0052 (Cursor folder names) and ADR 0072 (project files). Amended by ADR 0100 (explicit directory-free inbox).

  • ADR 0037 Learn from every integrated client store. Learning reads this computer’s Claude Code and Codex profiles and every registered WSL profile, each in the path context its hooks use. Amended by ADR 0052 (Cursor stores), ADR 0056 (Cline stores), ADR 0057 (Copilot stores) and ADR 0124 (OpenCode stores).

  • ADR 0107 Git lists a repository’s files; WSL repositories through their distribution. Inside a git repository the scan indexes only what git lists and never enters ignored directories; a WSL repository is listed by its distribution’s git, and a repository git cannot list fails the scan.

  • ADR 0110 The scan follows no links. The directory scan lists no symbolic link or Windows junction, so it keeps files inside their root without resolving each one.

  • ADR 0147 The scan reads paths beyond MAX_PATH through extended-length spellings. On Windows, ingest and refresh list and read a path of 240 characters or more through its \\?\ spelling, and keep the usual spelling for everything they compare, show or store.

  • ADR 0040 Documents with nothing to index. A document without extractable text is skipped with a reason, not failed, and retried only when its bytes or the extraction profile change. Amended by ADR 0076 (default bundled OCR and retryable tool failures) and ADR 0156 (bytes that are not the format).

  • ADR 0155 An HTML fragment is indexed as markup. A local HTML file without a doctype or an <html>, <head> or <body> element (a component template or fixture) is indexed verbatim as code; a page keeps readability extraction, and a page without text has nothing to index.

  • ADR 0156 A file whose bytes are not its format is an outcome, not a failure. A PDF or image its parser rejects as not that format is skipped with the reason and remembered like a document without text; JSON that does not parse is indexed verbatim; other extraction errors and the size limits stay failures.

  • ADR 0052 Learn Cursor conversations from their folder names. A Cursor folder name counts as a conversation’s working directory when exactly one existing directory has it; Cursor’s profile is a learn store and a WSL registration target. Amended by ADR 0100 (explicit directory-free inbox).

  • ADR 0056 Learn Cline sessions from their manifests. A Cline session’s manifest is its working-directory evidence; Cline’s sessions directory is a learn store, setup registers where Cline 4 reads, and cline is a WSL registration target.

  • ADR 0064 Serialize heavy commands with a single-slot queue and a shared lock file. One heavy job at a time per data directory, enforced by an advisory lock on data/queue.lock that the Go CLI and the Python dashboard share; the dashboard queues its jobs in SQLite. Amended by ADR 0067 (background tagging and preemptible holders), ADR 0068 (merged submissions) ADR 0077 (the Stop hook’s learner takes the lock) and ADR 0089 (one progress record every surface reads).

  • ADR 0067 Background LLM tagging that yields to every other job. Storing paths mark memories instead of running the LLM tagger; a background job tags them newest first when nothing else waits, steps aside between memories and holds the lock as a holder any other taker may stop. Amended by ADR 0132 (the job also organizes), ADR 0138 (the backlog travels to a paired device that tags) and ADR 0167 (random order while another device tags).

  • ADR 0132 Organize runs in the idle slot after background tagging. With organize.background on, the background job organizes what changed since its last pass after tagging, as the same preemptible holder, and steps aside for every other job.

  • ADR 0138 Memories that wait for LLM tagging travel to a paired device that tags. The waiting marker syncs, as the backlog dataset for memories both devices hold; the device that tags them sends the tags back; with LLM tagging off and tagger.peer on, a device paired with one that tags marks its new memories for it.

  • ADR 0167 Devices that tag together take waiting memories in random order. While a paired device in the workspace also runs LLM tagging, each page of the backlog is a random sample instead of the newest memories, so the devices rarely classify the same memory before sync brings the other’s tags; a device that tags alone keeps newest first.

  • ADR 0068 Merge identical waiting jobs. A submission identical to a waiting job (same command, workspace and normalized arguments) returns that job; one follow-up may wait behind an identical running job.

  • ADR 0072 Projects name their workspace and each device approves it. A project’s .imprint/workspace.json, honoured when this device’s roots approve it, picks the workspace of sessions, hooks, ingest, refresh and learning there; sessions ask once and use_workspace assigns a project without a restart. Amended by ADR 0100 (explicit directory-free inbox).

  • ADR 0077 The Stop hook hands its turn to one waiting learner under the queue lock. The Stop hook starts a detached learner and returns; at most one learner per conversation waits, lets a burst of turns settle, then learns in one process while holding the queue lock.

  • ADR 0089 One progress record for the running job. Every queue-lock holder, setup and the Stop hook’s learner included, reports in data/progress.json; the dashboard shows it on every page, the desktop app while the server is down, and waiting commands print it.

  • ADR 0079 Learn only what the Claude Code user typed. Client context is not a human question. Amended by ADR 0082 (retain readable context as attributed evidence).

  • ADR 0080 Conversations are learned again when their reading changes. Learning replaces the current reading and reuses unchanged chunks. Amended by ADR 0081 (source profile and manifest checks).

  • ADR 0082 Retain readable conversation evidence. Preserve available messages, analysis and tool evidence with explicit attribution and omission counts. Amended by ADR 0088 (unwritten bytes are counted omissions) and ADR 0162 (long tool events are one chunk, embedded from a reduced view).

  • ADR 0088 Bytes a crash never wrote are counted omissions. A reading drops the NUL bytes an interrupted write leaves and counts each run, instead of failing the transcript.

  • ADR 0162 Long tool events are one chunk, embedded from a reduced view. A learned tool output or call longer than chunker.hard_max is one chunk holding its exact text; its vector comes from the header, opening lines, error lines and closing lines, with repeated lines collapsed. Conversations are rechunked when next learned.

  • ADR 0130 Reorganization is proposed by a background job and reviewed. A queued job writes project profiles, proposes projects for the sources in catch-alls backed by an identifier, a path or a quoted model answer, and proposes core memories; accepted moves apply as placement rules. Amended by ADR 0132 (runs in the background), ADR 0133 (strong placements apply by themselves), ADR 0134 (proposals travel) and ADR 0136 (decisions reopen).

  • ADR 0133 Strong placements apply by themselves. A catch-all source that names exactly one project’s registered folder, or one distinctive project name at least twice and no other, early in what it says, moves without review and can be undone; every other placement waits. Amended by ADR 0136 (Move back, and its undo).

  • ADR 0010 Qwen defaults and explicit reindex. Qwen defaults, collection encoding identity, explicit reindex and shared bounded helper. Amended by ADR 0049 (classification grammar) and ADR 0086 (default export and device).
  • ADR 0032 One ONNX Runtime per environment. Each profile installs base requirements plus exactly one ONNX Runtime build, verified from package records and repaired by setup. Amended by ADR 0062 (runtime selection) and ADR 0086 (the CPU build only, for OCR and the privacy filter).
  • ADR 0035 Prebuilt llama.cpp wheels and first-chat provisioning. llama-cpp-python installs from upstream’s hash-pinned prebuilt wheels where they exist; the first local chat installs the binding and downloads the model, with progress in the chat. Amended by ADR 0049 (GPU build) ADR 0086 (the binding in every installation) and ADR 0090 (macOS wheels built here).
  • ADR 0045 Settings declare their choices; the GPU device defaults to auto. Settings declare their choices; the GPU device defaults to auto. Amended by ADR 0062 (setup’s device-0 check) and ADR 0087 (the GPU llama.cpp runs on).
  • ADR 0049 llama.cpp GPU offload through upstream’s Vulkan wheels. The gpu and auto profiles install llama.cpp’s hash-locked Vulkan build and keep it only when it finds a GPU; the nvcc rebuild is removed. Amended by ADR 0087 (one GPU per model) and ADR 0113 (unchosen profiles resolve to auto).
  • ADR 0113 Unchosen install profiles try the GPU. Only a profile the user picked is kept; installer defaults and older profile.json files resolve to auto, so setup and update try llama.cpp’s GPU build.
  • ADR 0059 Chat speaks each model’s native tool protocol. Chat keeps one registry of tool JSON schemas; local models get them through their chat template and remote providers through API function calling, with no text protocol of Imprint’s own. Amended by ADR 0061 (local parsing). Amended by ADR 0101 (reserved final synthesis).
  • ADR 0061 Local tool-call formats by model family. Local chat parses tool calls in the model family’s format (Qwen XML, Hermes JSON, Llama 3, Mistral), detected by rendering a probe call through the template or chosen with chat.tool_format; other models chat without tools and say so.
  • ADR 0086 Embeddings run on llama.cpp, without CUDA. Qwen’s Q8_0 GGUF of Qwen3-Embedding-0.6B runs on llama.cpp: the Vulkan or Metal build on any GPU it finds, the CPU build elsewhere. The CUDA runtime and the int8 ONNX export are gone, and the binding is part of every installation. Amended by ADR 0090 (macOS installs prebuilt wheels) and ADR 0122 (a GPU build of ONNX Runtime for the Privacy Filter).
  • ADR 0087 llama.cpp runs each model on one GPU. Embeddings and the local LLM load whole onto model.gpu_device, by default the discrete GPU with the most memory, instead of llama.cpp’s split across every GPU. Amended by ADR 0125 (integrated GPUs can be named; models load through llama.cpp’s device list).
  • ADR 0125 Integrated GPUs can be chosen beside a discrete one. Settings lists integrated GPUs after the discrete ones, and each model loads through llama.cpp’s device list, so model.gpu_device can name an integrated GPU; auto still prefers the discrete GPU.
  • ADR 0090 macOS installs llama.cpp wheels built by this repository. A manually run workflow builds the binding’s macOS wheels, Metal on both architectures, from the hash-locked source and publishes them as the prerelease llama-cpp-python-v<version>; the locks pin them, so no Mac needs a compiler. Amended by ADR 0106 (Intel wheel built on the laptop runner), ADR 0111 (Apple silicon wheel only).
  • ADR 0078 Keep Qwen3.5-4B as the local tagger. Qwen3.5-2B tags 2.2–2.5× faster and no worse at memory types, but worse at the language and topic tags search filters on; putting the prompt’s fixed text first gains nothing on Qwen3.5’s architecture. Amended by ADR 0164 (reordering, measured once checkpoints made it faster, changes the classifications: the layout stays).
  • ADR 0163 Tagging asks for its classification as one line of JSON. The classification prompt asks for the JSON on one line; the local model’s replies fall from about 77 tokens to about 37, and a memory from about 3.0 s to about 2.1 s on the measured GPU, with types and languages as before and about a third fewer domains and topics.
  • ADR 0164 The tagging prompt keeps its layout despite prompt checkpoints. Putting the fixed instructions first would let the local model keep them evaluated (ADR 0161) and roughly halve a memory’s time, but in every measured arrangement the model then classified by the file path more than by the text; the project and file stay first, then the instructions, then the memory.
  • ADR 0165 The local model tags several memories as one batch. tagger.llm_concurrency now applies to the local model: a second llama.cpp context on the loaded model decodes that many memories at once, each in its own 4,096-token sequence, sharing the decoding (about a fifth less time per memory with 4 on the measured GPU, the same tags); a prompt that does not fit, or a batch the GPU cannot hold, is completed one at a time. The default stays 1.
  • ADR 0166 Tagging never asks a model to think. OpenAI-compatible servers are asked not to think (chat_template_kwargs for vLLM and an openai provider at another address, reasoning_effort: "none" for Ollama), a server that refuses the field is asked without it, and the local template keeps thinking off.
  • ADR 0153 Chat offers a larger Qwen MoE and custom models. chat.local_model keeps Qwen3.5-4B as the default, offers the pinned Qwen3.5-35B-A3B mixture-of-experts model on machines with about 32 GB of memory, or any custom GGUF; chat reloads when it changes, the tagger keeps its model.
  • ADR 0093 Sequential chat section analysis. Two configurable logical workers analyze oversized questions and evidence sequentially, with bounded notes and reply-local exact rereads. Amended by ADR 0140 (history goes a piece at a time).
  • ADR 0140 Chat keeps the conversation and drops old research first. When a prompt does not fit, earlier turns’ tool exchanges go first, oldest first, then whole earlier exchanges, oldest first, instead of the whole history at once. Amended by ADR 0141 (what no longer fits is summarized; dropping is the fallback).
  • ADR 0141 Chat summarizes what no longer fits and can look back through the conversation. When the conversation’s text no longer fits, its oldest exchanges become a running summary kept with the session and carried in the prompt; a read-only conversation_history tool searches and rereads every earlier message of the conversation; voice keeps both in memory only. Amended by ADR 0145 (voice keeps every completed reply) and ADR 0146 (voice’s history and summary are saved with its chat).
  • ADR 0016 Sync direction and workspace sharing. Per-machine sync direction policies, per-session workspace selection and copy migration for sharing curated workspaces. Amended by ADR 0018 (implementation details).
  • ADR 0017 Device provenance and local project paths. Portable memory origin, current-device context and approved local project-path mappings.
  • ADR 0018 Single sync implementation and end-to-end encryption. One Python sync implementation for CLI and dashboard; SPAKE2 + AES-256-GCM end-to-end encryption with no plaintext fallback.
  • ADR 0020 Explicit pairing and automatic workspace sync. Mutually approved workspace pairing, automatic encrypted merge, pause and acknowledged peer revocation. Amended by ADR 0073 (one-sided removal), ADR 0116 (only differences, in stored chunks) and ADR 0176 (sync carries deletions).
  • ADR 0051 Synced tags follow the latest retag. Each memory carries a tagged_at stamp; sync gives a memory both devices hold the classification that was set last.
  • ADR 0073 Remove a pairing from one device without the other’s acknowledgement. A confirmed removal deletes this device’s pairing with a peer, its credentials and trust at once, without contacting the relay or the peer; forgetting on both devices stays the normal path.
  • ADR 0116 Paired devices send only what the other lacks, in stored chunks. Vector-free manifests are swapped and only missing or newer records sent, as small streams each stored and acknowledged before the next; an attempt is bounded by progress, not total time. Amended by ADR 0120 (a device storing a chunk says so) and ADR 0176 (a deletion swap after the manifests).
  • ADR 0176 Deletions reach paired devices that hold the memory. A device records what it deleted on purpose and, after the manifests, names to the other only those deletions the other holds; copies older than the deletion go and the deletion travels on; no device imports a memory older than a deletion it holds. Amended by ADR 0177 (recordings too).
  • ADR 0177 Recordings travel between devices that both turned it on. sync.recordings, off by default: finished recordings, audio included, reach paired devices by themselves in resumable checked 1 MiB pieces; deleting a recording or its audio does the same on the other. Amended by ADR 0180 (speakers’ names and the transcript’s parts travel too) and ADR 0184 (audio without a length is indexed on arrival and goes back).
  • ADR 0120 A device storing a synced chunk says so. While a paired device stores a chunk it sends a storing frame every 30 seconds, so a store slower than the 10-minute wait no longer fails the sync; both devices show “storing”.
  • ADR 0134 Placement rules and Organize’s proposals sync between paired devices. Rules carry their change time and keep removals; a peer that offers them takes the newer rule and moves its own copies by it. Organize’s proposals and decisions travel the same way.
  • ADR 0011 Nightly Trivy security scanning. Nightly Trivy repository scans, retained reports and a high/critical failure gate.
  • ADR 0013 Remediate security scan dependencies. Patched website/build dependencies, non-root relay and explicitly disabled LLM disk caching.
  • ADR 0024 Enforce local service boundaries. Loopback-only managed Qdrant, dashboard peer validation, legacy graph browser checks and explicit container isolation.
  • ADR 0033 Stored secret settings. Hugging Face token as a masked secret setting in config.json, resolved per download with HF_TOKEN taking precedence.
  • ADR 0060 Redact secrets before memories are stored. Every memory and fact write, and every tagger or summarizer prompt, replaces credentials with [REDACTED:<kind>:<length>] first; the most redacted version of a memory wins on every synced device; OpenAI Privacy Filter is opt-in. Amended by ADR 0122 (GPU, q4 export, the receiver trusts a sender’s filter mark).
  • ADR 0122 The Privacy Filter runs on a GPU that passes a probe, and that device filters what it syncs. Setup installs ONNX Runtime’s CUDA, ROCm (MIGraphX) or DirectML build for a GPU it finds; the filter keeps a GPU only when it labels exactly like the CPU and at least 1.5x faster; a device whose filter runs on a GPU marks the memories it sends as filtered, and a receiver with the same filter skips the model for them but still applies the rules. Amended by ADR 0123 (the next chunk is filtered while the last is stored) and ADR 0126 (CUDA only for an NVIDIA GPU CUDA 13 supports).
  • ADR 0126 CUDA only for an NVIDIA GPU CUDA 13 supports. Setup tries ONNX Runtime’s CUDA build only when nvidia-smi lists an NVIDIA GPU of compute capability 7.5 or newer.
  • ADR 0123 A paired sender prepares the next chunk while the other device stores the last. One chunk ahead at most, frames unchanged; a send that ends early drops it and waits for its thread.
  • ADR 0003 Local MCP and portable hooks. Local stdio MCP, shared runtime preparation and portable hook commands.
  • ADR 0006 Durable MCP and preserved client configuration. Durable writes, workspace binding, diagnostics and preserved profiles. Amended by ADR 0015 (workspace binding) and ADR 0072 (per-project sessions).
  • ADR 0026 Windows installer registration for WSL clients. Opt-in WSL Claude Code/Codex registration through a shared Windows stdio runtime, path-aware hooks and preserved profiles. Amended by ADR 0027 (WSL cleanup on disable and uninstall) and ADR 0091 (the imprint command in WSL homes).
  • ADR 0053 Connect and disconnect clients without touching the runtime. One client table drives every client command; imprint connect and disconnect only register and unregister clients, so the dashboard can run them, and Settings enrolls WSL profiles.
  • ADR 0057 The Copilot home is GitHub Copilot’s store, configuration and hook root. GitHub Copilot’s surfaces share COPILOT_HOME: Imprint registers MCP, instructions and SessionStart/Stop hooks there, learns its session events by their recorded context, and copilot is a WSL registration target.
  • ADR 0124 OpenCode is a client; its sessions are exported from its database and learned when idle. Setup registers a local MCP server and a listed instructions file in OpenCode’s global opencode.json (not AGENTS.md) and a plugin that starts the learner when a session goes idle; learning exports each session from OpenCode’s SQLite database to a transcript in Imprint’s data directory.
  • ADR 0091 WSL homes with a connected client get the imprint command. imprint wsl setup puts the Windows bridge’s CLI in the home’s ~/.local/bin/imprint, keeps any other imprint there (a Linux installation’s link, for one), and removes it with the home’s last registration.
  • ADR 0129 Core memories are user-approved and start every session. Short statements of the user’s preferences and standing instructions, approved by the user, kept apart from ordinary memories, synced to paired devices and appended to the MCP server’s handshake instructions. Amended by ADR 0136 (a proposal can return to proposed) and ADR 0143 (sessions receive guidelines; core memories are records).
  • ADR 0143 Agents receive generalised guidelines; core memories are kept as records. Agents and Organize record specific core memories without approval and no session receives them; Organize drafts guidelines from groups of alike records, the user approves them, and every agent session, chat and Echo included, receives the active ones within 3,000 estimated tokens. Amended by ADR 0144 (contradictions wait for the user).
  • ADR 0144 Newer core memories that contradict older ones wait for the user. Organize notes a newer record that contradicts an older one, and a rewrite that contradicts an approved guideline; the user keeps the newer, the older or both, or overwrites the guideline or leaves it as is.
  • ADR 0168 Skills and personas are kept once and synced to paired devices. A registry outside every workspace stores each item’s text files verbatim, refuses credentials instead of redacting them, and syncs items as their own dataset: the newest change wins and the replaced version stays in the receiving device’s history.
  • ADR 0169 Skills and personas are written into the folders the clients read. Skills go into the fewest of the connected clients’ skill folders that reach them all, personas into Claude Code’s subagents folder; a manifest there records what Imprint wrote, edits made there come back, and what Imprint did not write is never touched. Amended by ADR 0170 (the MCP route) and ADR 0171 (personas for Codex and Cursor).
  • ADR 0170 Skills and personas reach every MCP client through Imprint’s server. The handshake lists the active items a client does not already load from its own folders on this computer; the read-only skills tool lists and reads them and skill_edit creates and changes them, written into the clients’ folders at once.
  • ADR 0171 Personas are written for Codex and Cursor. Personas go into the fewest of the connected clients’ subagent folders that reach them all: Markdown for Claude Code and Cursor, a TOML custom agent for Codex, whose edits come back into the persona.
  • ADR 0142 Agents are reminded to search Imprint, never refused. The read hook reminds a session that has not searched Imprint, once, to prefer searching first, and always lets Read, Grep and Glob run; Cursor gets the reminder after the read.
  • ADR 0008 Dashboard retrieval and accessibility. Same-origin dashboard, usable search states and accessible modal behavior. Amended by ADR 0039 (dialog primitive) and ADR 0154 (light, dark or system theme).
  • ADR 0025 Desktop-owned background service. Open the splash before Python startup, hide the dashboard independently and stop its owned API on explicit Quit. Amended by ADR 0050 (service registration).
  • ADR 0039 shadcn overlays and desktop drag handles. Dashboard overlays and controls use the vendored shadcn (Base UI) components; the frameless window’s drag handles stand down while an overlay is open.
  • ADR 0050 Registered dashboard server and supervised restart. The serving dashboard registers itself; its launcher starts it again when it exits for a restart, so every update method replaces it and the dashboard reloads. Amended by ADR 0084 (launchers wait while setup changes the runtime; setup restarts the server).
  • ADR 0094 The dashboard reads whole sources from their snapshots. Topics group their memories by conversation or file, named by a conversation’s first question; any source opens whole from its stored redacted snapshot, events read back from the snapshot’s headers, with a topic’s passages marked. A source without a snapshot is not rebuilt from chunks. Amended by ADR 0095 (audio events and filenames).
  • ADR 0114 Linux desktop app runs unpacked with an AppArmor profile. Setup unpacks the AppImage (no FUSE) and, where AppArmor restricts user namespaces, installs a profile with sudo after asking; ui open falls back to the browser with the reason when the app dies at startup.
  • ADR 0117 The dashboard shows each agent session and its calls. Each MCP server process records its client, folder, workspace and tool calls (arguments shortened and redacted, kept 30 days) in data/agent_activity.sqlite3; the Agents page lists them. Amended by ADR 0151 (sessions page by last activity with a cursor).
  • ADR 0151 Agent sessions page by last activity with a cursor. GET /api/agents lists connected sessions apart and the others 50 at a time, newest activity first, resumed from a (last_seen, id) cursor; client totals cover every session; the Agents page groups the history by calendar period in the viewer’s time zone.
  • ADR 0152 Dashboard summaries are served stale while they refresh. GET /api/dashboard answers from a per-workspace snapshot rebuilt in the background after writes, jobs or 60 s, marked stale meanwhile; the dashboard’s useCached shows the last answer per workspace (memory and sessionStorage) while it fetches again.
  • ADR 0154 The dashboard and desktop app follow a light, dark or system theme. Colour tokens with light and dark values (status success/warning and passage mark tokens at WCAG AA), applied before first paint and in every open window; the desktop app takes the choice through a validated theme-set IPC message that sets nativeTheme.themeSource, the window backgrounds and the next start’s theme.
  • ADR 0182 The dashboard has a simple and an advanced form. One dashboard shown two ways, chosen per device by ui.mode and settled once per installation; Simple lists eleven pages under plain names, trims the shared pages and offers settings as plain choices over the same keys; nothing is disabled and every address works in both.
  • ADR 0183 Each page has a short tutorial that can be skipped. A welcome on a new installation and a few steps per page, each a card beside the control it describes, start once per browser, are skipped singly or all at once (ui.tutorials) and replayed from the help menu.
  • ADR 0135 The floating launcher is a handle with its actions around it. While the dashboard is hidden, the Imprint button is an orb that drags everything docked to it; a click fans out Dashboard, Echo and Record in their own window toward free space; Echo folds into it; a recording starts from it in the hidden dashboard after the same consent. Amended by ADR 0137 (the orb’s ear), ADR 0145 (folded Echo lets go of a conversation that goes on) and ADR 0174 (the orb is off unless turned on).
  • ADR 0174 The floating orb is off unless the user turns it on. desktop.floating_orb, off by default, decides whether the orb comes up while the dashboard is hidden; without it a minimized dashboard stays in the taskbar and a closed one goes to the tray. A running recording brings it up either way.
  • ADR 0136 Review pages use paged tabs, and decisions reopen. Organize and Core memories review in hash-linked tabs of paged lists, with keyboard shortcuts and optimistic decisions that can be undone; the user’s moves, keeps, approvals and rejections can be reopened.
  • ADR 0139 Projects and Sources browse every source in paged tabs. Both pages use the review pages’ tabs, paged lists, filters and keys; the browser lists every source of the workspace or project and pages, filters and sorts it, after the source listing reads only the snapshot columns it needs.
  • ADR 0148 The graph draws itself on a canvas, and as a star system. The Graph page renders from one d3-force model stepped a few milliseconds per frame, on a Canvas 2D of its own instead of G6, or as an animated three.js star system with electric impulses (a remembered toggle); the overview’s topic links take one facet per project and scopes are cached against the data fingerprint.
  • ADR 0149 Graph search is a scope of its own. The graph’s box still finds names on screen and otherwise runs the hybrid search; its hits, sources, projects and topics form a search:<query> scope built in the browser, beside a ranked list linked both ways to the nodes; the Search page opens its query in the graph.
  • ADR 0150 Topics page on the server, and copies between workspaces are previewed. GET /api/topics searches, sorts and pages every topic and GET /api/topic/{name} can page its sources; POST /api/migrate/preview counts what copying or moving projects, topics or sources to another workspace takes, and how much the target already holds, before one migrate job per selection runs.
  • ADR 0158 Reminders, timers and scheduled jobs fire from the API process. Entries live in device-local data/schedule.sqlite3; a scheduler thread in the dashboard API fires each occurrence once across restarts (missed ones once, late), submits allow-listed queue jobs or runs a question as a chat reply; the dashboard shows each firing as a toast and desktop notification until done or snoozed; chat and voice set them through personal tools. Amended by ADR 0161 (the time follows the question).
  • ADR 0159 A reply can ask the user and wait for the answer. Chat and Echo offer an ask_user tool; the reply pauses on a question that is one of its events in the API, waits outside its research time for an answer from any window (POST /api/chat/sessions/{sid}/answer), a tapped choice or the next thing said, stores the exchange as an ask_user tool call, and goes on with the model’s stated assumption after 30 minutes.
  • ADR 0118 The PersonaPlex prototype is removed; the voice memory snapshot stays. The unused PersonaPlex runtime adapter, launcher and test-only dependencies are gone; the live voice’s read-only memory snapshot lives in imprint/voice_memory.py.

  • ADR 0042 Small LFM audio experiment on CPU. Small, verified native LFM2.5-Audio Q4 inference on Linux x64 CPU with read-only MCP snapshots (experimental offline turns).

  • ADR 0043 Local live voice and the Echo companion. Private local speech worker, same-chat reasoning, opt-in VAD and a floating Echo companion (experimental live pilot). Amended by ADR 0044 (native platforms), ADR 0048 (avatar asset), ADR 0069 (microphone on Start), ADR 0092 (playback pacing), ADR 0137 (the wake listener), ADR 0141 (the conversation’s history and summary) , ADR 0145 (speech queues instead of interrupting; the conversation outlives its window) and ADR 0146 (transcripts saved in Chat history unless turned off).

  • ADR 0044 Native Windows and macOS voice. Portable weights and native Windows/macOS/Linux speech workers, transparent companion and dashboard lifecycle control. Amended by ADR 0046 (UI-driven setup), ADR 0047 (bundled engine), ADR 0055 (entitlements) and ADR 0069 (consent check), ADR 0111 (no macOS Intel worker).

  • ADR 0046 Visible first-time Echo setup. Explicit first-time Echo download with real progress, persistent dashboard status, prerequisite checks and owned setup cancellation. Amended by ADR 0047 (release toolchain policy).

  • ADR 0047 Bundle the private voice engine. Native release engines remove the end-user compiler requirement while preserving explicit verified model downloads.

  • ADR 0048 Anime Echo and recoverable desktop controls. Whole-head drag, a recovery shortcut and a floating launcher after Close/minimize for the Echo companion and dashboard. Amended by ADR 0054 (Echo’s look) and ADR 0070 (drag handles and the launcher group).

  • ADR 0054 Echo’s looks declare their motion and follow the pointer. Looks declare gaze, spin and pulse as glTF node extras; the heads’ eyes turn at their eye bones; Echo is a generated core that follows the pointer across the screen. Amended by ADR 0097 (the flow extra and Echo’s synaptic core).

  • ADR 0069 Echo opens the microphone only on the user’s intent, after an OS consent check. Enable microphone, or Start conversation once the user has chosen the microphone, asks the operating system for consent through scoped IPC before opening the device; the device remembers the choice, never the grant. Amended by ADR 0137 (the “Hey Echo” listener).

  • ADR 0070 The floating companion moves with the launcher and keeps its options in settings. While the dashboard is hidden the companion docks beside the launcher and either window drags both; only the head and header drag it; everything except talking sits in a settings panel. Amended by ADR 0135 (the orb and its actions).

  • ADR 0071 Each look speaks in its own voice. The voice.avatar look also chooses Echo’s voice, the native model’s speaker on both reasoning routes plus a robotic effect for Echo; a session keeps the voice it started with. Amended by ADR 0145 (a new look or model takes over after the reply in progress) and ADR 0146 (a new look or model keeps the conversation).

  • ADR 0092 Voice generation follows playback. Completed audio releases bounded playback credit; active replies use an inactivity timeout instead of a fixed whole-turn limit. Amended by ADR 0145 (completion, not playback, keeps a reply; credit released when its window goes).

  • ADR 0097 Echo’s looks fire like synapses. A flow node extra runs light through a node at moments stored on its vertices; Echo is a generated 3D neural network whose signals cascade from hubs, and each head gets a synaptic halo. Amended by ADR 0103 (generated eye and shared morphs).

  • ADR 0098 Head surfaces take light; generated parts glow. Lighting follows each glTF material: the heads’ lit materials take a sky and a key light, unlit generated parts render as light that fades toward their silhouettes. Amended by ADR 0103 (generated eye and shared morphs).

  • ADR 0137 Echo wakes on “Hey Echo” from a hidden desktop listener. On the user’s choice the desktop app keeps a hidden, always-indicated listener window; the first 2 s of each burst of speech goes to a local worker running Silero VAD and Whisper tiny.en with the phrase as hotwords, and a wake shows Echo without focus with the rest of the sentence as its first question.

  • ADR 0145 A request runs until it is answered or explicitly stopped. Echo’s voice conversation and each Chat reply belong to the API, not to the connection that asked: switching modes, speaking, typing, hiding, folding or leaving never cancels them; a question asked meanwhile waits its turn, a window that comes back picks the reply up, and only the user’s stop cancels. Amended by ADR 0146 (voice exchanges are also saved in Chat history; a stopped reply joins the history as far as it got) and ADR 0159 (while a reply waits for an answer, what is said next is that answer).

  • ADR 0146 Echo saves its conversations in Chat history and carries chats on. Echo’s exchanges are saved as text in Chat history on this device unless the user turns that off; audio never is. A look or model change keeps the conversation, and Echo can carry on any chat from Chat history.

  • ADR 0096 CPU Whisper runtime for audio imports. Locked native wheels provide CPU transcription with pinned multilingual models downloaded on first audio use. Amended by ADR 0137 (the wake word’s English model) and ADR 0178 (large-v3 is the default).

  • ADR 0178 Whisper large-v3 is the default transcription model. The full large-v3 conversion, pinned like the others, for fewer mistakes in Romanian at about twice Turbo’s time on a CPU; Large v3 Turbo and Small stay as choices.

  • ADR 0131 Meetings are recorded by channel and transcribed locally. With the user’s confirmed consent, the dashboard records the microphone and what the computer plays as two channels kept on the device; each is transcribed locally, so the transcript says who spoke, and stored as a replaceable source. Amended by ADR 0135 (recording from the floating button), ADR 0173 (the microphone’s echo left out) ADR 0177 (recordings sync when both devices turn it on), ADR 0180 (voices told apart within each channel), ADR 0181 (what Whisper likely invented left out) and ADR 0184 (the audio states its length and can be sought).

  • ADR 0173 A transcript leaves out the microphone’s echo of the call. Microphone passages that repeat what the computer played at the same moment are left out and counted; each turn is a paragraph.

  • ADR 0180 A recording’s transcript tells voices apart within each channel. A port of pyannote’s speaker-diarization-3.1 that matches pyannote’s own turns splits each channel into voices, a sentence to one voice, and leaves out the microphone’s echo of the call by its timing; speakers have default names the user can change, and the names and parts sync with the recording.

  • ADR 0181 A recording’s transcript leaves out what Whisper likely invented. Sentences whose words Whisper’s anomaly score marks, or in a language the recording does not use and decoded with little confidence, are left out and counted; mixed-language recordings keep each language.

  • ADR 0184 A recording’s audio states its length and can be sought. Once stopped, the recorder’s WebM is copied packet for packet into a file with Duration and Cues; earlier recordings and audio from older releases are copied the same way, and the copy is a newer version paired devices take.

  • ADR 0002 Validate releases before publication. Build all release artifacts and run native checks before publication. Amended by ADR 0014 (which branches build and publish releases).

  • ADR 0004 Runtime dependencies and local boundaries. Resolve base dependencies and enforce explicit local browser/process boundaries. Amended by ADR 0007 (deferred hash locks, Electron upgrade and Host defense).

  • ADR 0007 Verified runtime and desktop baseline. Hashed dependencies/downloads, Electron 45, macOS 13 and container parity.

  • ADR 0012 Native package runtime and silent installs. Platform-specific Intel ONNX runtime and bounded, noninteractive Windows installer smoke. Amended by ADR 0086 (no LLM choice), ADR 0111 (no Intel ONNX pin).

  • ADR 0014 Main-only release packaging. Compile/test branches; package and publish release artifacts only from main. Amended by ADR 0066 (dev prereleases).

  • ADR 0023 Update by installation type. The dashboard updates through the CLI, which installs a release the way the installation was set up. Amended by ADR 0050 (dashboard server stop and restart), ADR 0128 (the dashboard follows the Windows installer to the end) and ADR 0175 (releases install by themselves when idle).

  • ADR 0175 Releases install by themselves when nothing would be interrupted. update.auto, on by default: the dashboard server installs a release through a method that needs nobody, only when no job, recording, chat reply, Echo conversation, recent agent call or recent keyboard and mouse input would be interrupted.

  • ADR 0128 The dashboard follows the Windows installer to the end. The server reports the installer’s progress from its log; a failed installer stops the wait, a finished one whose server restart did not happen gets the server restarted, and a dashboard still on the old version says to reopen Imprint.

  • ADR 0027 Symmetric uninstall and branch synchronization. Disconnect managed clients before uninstall, retry failures and fast-forward dev after main changes. Amended by ADR 0028 (data retention), ADR 0066 (dev publishes prereleases) and ADR 0085 (no dev sync).

  • ADR 0028 Complete uninstall. Uninstall stops every process of the installation and removes its runtime and data unless the user keeps the data. Amended by ADR 0074 (desktop profile).

  • ADR 0030 Chrome preview ZIP and release downloads. Allowlisted Chrome preview ZIP in validated releases, website download/install guide and coming-soon integrations.

  • ADR 0055 Ad-hoc signed macOS desktop bundle. The macOS desktop app is signed ad hoc as a bundle so privacy consent can read its microphone usage text; packaging rejects an unsigned bundle. Amended by ADR 0075 (enclosing installer app), ADR 0111 (arm64-only app).

  • ADR 0066 Dev prereleases from the dev branch. Releasable dev pushes publish vX.Y.Z-dev.N prereleases of the next stable version through the release pipeline, skipping commits main holds; --dev installs the highest release version. Amended by ADR 0108 (installations opt in to dev builds).

  • ADR 0108 Installations opt in to dev builds in Settings. update.channel (stable or dev) chooses the releases offered; imprint update resolves it unless --stable or --dev is passed, so the dashboard and the terminal follow the same channel.

  • ADR 0074 Uninstall removes the shared desktop profile. An uninstall that deletes data also deletes the desktop shell’s Electron profile, which every installation on the account shares.

  • ADR 0075 Microphone purpose in the macOS installer wrapper. The enclosing .pkg app declares microphone usage as well as the nested Electron shell.

  • ADR 0179 The macOS desktop app is com.alexandruleca.imprint.desktop. The Electron app’s bundle identifier moves to the project’s namespace, distinct from the installer’s enclosing Imprint.app.

  • ADR 0076 Default OCR. Install local models and the PDF renderer with the base runtime; keep OCR enabled unless explicitly disabled. Amended by ADR 0109 (automatic missing-runtime repair), ADR 0111 (no Intel OpenCV pin).

  • ADR 0109 Automatic OCR runtime repair. Release the job lock, attempt noninteractive bootstrap once per managed command and retry in a fresh extraction worker when bundled OCR dependencies are missing.

  • ADR 0121 Optional ingestion tools install when turned on. Turning on ingest.use_kreuzberg or ingest.use_obscura installs the hash-locked kreuzberg wheel or the pinned obscura release; setup, the dashboard and the first extraction that needs one repair a missing tool, and failures fall back to the native extractors with the manual fix.

  • ADR 0085 Main only fast-forwards to dev. Every change reaches main by fast-forwarding main to a dev commit; pull requests target dev, and no workflow fast-forwards dev after pushes to main.

  • ADR 0084 Setup frees the runtime before replacing its files. Setup holds the queue and runtime locks while it changes the venv; before it replaces or removes packages it restarts the dashboard server and, on Windows, stops every other process running from the runtime. Amended by ADR 0086 (Settings starts no bootstrap).

  • ADR 0105 Project analysis continues after model timeouts. Preserve identifier suggestions, warn and retry incomplete model analysis.

  • ADR 0099 Sources can belong to several projects. Reviewable local links add retrieval membership while preserving the canonical source. Amended by ADR 0105 (per-source timeout recovery).

  • ADR 0100 Explicit unassigned inbox. One opted-in workspace may learn conversations without directory evidence; conflicting evidence still rejects them.

  • ADR 0101 Chat research always reserves an answer. Tool rounds are bounded; exhaustion, repeating reads or a full research context transition to tools-free synthesis and preserved evidence. Amended by ADR 0102 (evidence novelty and resource budgets) and ADR 0127 (the answer is written from research notes).

  • ADR 0102 Chat research follows progress and resource budgets. No fixed round cutoff; bounded evidence-novelty tracking and reply-wide time/token reservations lead to synthesis. Amended by ADR 0157 (a request is charged for its new prompt and generated output) and ADR 0159 (waiting for the user’s answer is not research time).

  • ADR 0157 Chat research is charged for the work each request does. The research token budget charges the prompt past the prefix the previous request already processed plus the output generated, refunding unused allowance; every coordinator and section-worker request is still reserved before it starts.

  • ADR 0160 Chat’s search filters are hints, and repeated reads are not run again. A chat search filtered by guessed tags also lists up to three matches the filters left out; a read call repeated with the same arguments in one reply returns a note pointing to the earlier result.

  • ADR 0161 Chat keeps its instructions a reusable prompt prefix. The current time follows the user’s question in the request; the local model keeps the evaluated instructions and tools in memory (up to two checkpoints) and restores them for the next turn, which a hybrid model like Qwen3.5 cannot otherwise reuse.

  • ADR 0127 The final answer is written from research notes. After a budget stop, the reserved answer reads a deduplicated digest of what research found, without the raw research turns, and lists the sources it cites; an answer that cannot finish ends with a short list of findings.

  • ADR 0103 Echo has a generated eye with shared morph controls. An opaque generated iris follows gaze and the nucleus blinks with it through named morph targets.

  • ADR 0104 Bundle uv with conditional hash-lock support. Pin verified uv 0.13.6 so fresh native bootstrap resolves the platform-specific audio/ONNX requirements without weakening hashes.

  • ADR 0111 Intel Macs are not supported. No Intel macOS release builds, packages, wheels, pins or CI runner; install.sh and imprint update refuse an Intel Mac with a clear message.

Under consideration; not current behavior.

  • ADR 0009 Model profiles and embedding identity. Evaluate local model profiles with explicit embedding identity and safe re-embedding.

Every record in number order. Date is when the decision was made.

ADR Date Status Title
0001 2026-10-23 Accepted Record significant decisions
0002 2026-10-23 Amended by ADR 0014 Validate releases before publication
0003 2026-10-23 Accepted Local MCP and portable hooks
0004 2026-10-23 Amended by ADR 0007 Runtime dependencies and local boundaries
0005 2026-10-23 Amended by ADR 0110, ADR 0172 Source lifecycle and hybrid retrieval
0006 2026-10-23 Amended by ADR 0015, ADR 0072 Durable MCP and preserved client configuration
0007 2026-10-23 Accepted Verified runtime and desktop baseline
0008 2026-10-23 Amended by ADR 0039, ADR 0154 Dashboard retrieval and accessibility
0009 2026-10-23 Proposed Model profiles and embedding identity
0010 2026-10-23 Amended by ADR 0049, ADR 0086 Qwen defaults and explicit reindex
0011 2026-10-23 Accepted Nightly Trivy security scanning
0012 2026-10-23 Amended by ADR 0086, ADR 0111 Native package runtime and silent installs
0013 2026-10-23 Accepted Remediate security scan dependencies
0014 2026-10-23 Amended by ADR 0066 Main-only release packaging
0015 2026-10-23 Amended by ADR 0034, ADR 0072 Workspace roots and source purge
0016 2026-10-23 Amended by ADR 0018 Sync direction and workspace sharing
0017 2026-10-23 Accepted Device provenance and local project paths
0018 2026-10-23 Accepted Single sync implementation and end-to-end encryption
0019 2026-10-23 Accepted Reproducible benchmark evidence
0020 2026-10-23 Amended by ADR 0073, ADR 0116, ADR 0176 Explicit pairing and automatic workspace sync
0021 2026-10-23 Accepted Budgeted MCP evidence and selective expansion
0022 2026-10-23 Accepted Retain HTTP clients during model work
0023 2026-10-23 Amended by ADR 0050, ADR 0128, ADR 0175 Update by installation type
0024 2026-10-23 Accepted Enforce local service boundaries
0025 2026-10-23 Amended by ADR 0050 Desktop-owned background service
0026 2026-10-23 Amended by ADR 0027, ADR 0091 Windows installer registration for WSL clients
0027 2026-10-23 Amended by ADR 0028, ADR 0066, ADR 0085 Symmetric uninstall and branch synchronization
0028 2026-10-23 Amended by ADR 0074 Complete uninstall
0029 2026-10-23 Amended by ADR 0030 Paired local browser capture prototype
0030 2026-10-23 Accepted Chrome preview ZIP and release downloads
0031 2026-10-24 Accepted Website analytics events and public relay status
0032 2026-10-24 Amended by ADR 0062, ADR 0086 One ONNX Runtime per environment
0033 2026-10-24 Accepted Stored secret settings
0034 2026-10-24 Amended by ADR 0037, ADR 0052, ADR 0072, ADR 0100 Learn from client stores by conversation ownership
0035 2026-10-24 Amended by ADR 0049, ADR 0086, ADR 0090 Prebuilt llama.cpp wheels and first-chat provisioning
0036 2026-10-24 Amended by ADR 0134 Move memories between projects
0037 2026-10-24 Amended by ADR 0052, ADR 0056, ADR 0057, ADR 0124 Learn from every integrated client store
0038 2026-10-24 Superseded by ADR 0086; amended by ADR 0062 GPU runtime ships its CUDA libraries
0039 2026-10-24 Accepted shadcn overlays and desktop drag handles
0040 2026-10-24 Amended by ADR 0076, ADR 0156 Documents with nothing to index
0041 2026-10-24 Superseded by ADR 0118 PersonaPlex startup memory prototype
0042 2026-10-24 Accepted Small LFM audio experiment on CPU
0043 2026-10-24 Amended by ADR 0044, ADR 0048, ADR 0069, ADR 0092, ADR 0137, ADR 0141, ADR 0145, ADR 0146 Local live voice and the Echo companion
0044 2026-10-24 Amended by ADR 0046, ADR 0047, ADR 0055, ADR 0069, ADR 0111 Native Windows and macOS voice
0045 2026-10-24 Amended by ADR 0062, ADR 0087 Settings declare their choices; the GPU device defaults to auto
0046 2026-10-24 Amended by ADR 0047 Visible first-time Echo setup
0047 2026-10-24 Accepted Bundle the private voice engine
0048 2026-10-24 Amended by ADR 0054, ADR 0070 Anime Echo and recoverable desktop controls
0049 2026-10-24 Amended by ADR 0087, ADR 0113 llama.cpp GPU offload through upstream’s Vulkan wheels
0050 2026-10-24 Amended by ADR 0084 Registered dashboard server and supervised restart
0051 2026-10-24 Accepted Synced tags follow the latest retag
0052 2026-10-25 Amended by ADR 0100 Learn Cursor conversations from their folder names
0053 2026-10-25 Accepted Connect and disconnect clients without touching the runtime
0054 2026-10-25 Amended by ADR 0097 Echo’s looks declare their motion and follow the pointer
0055 2026-10-25 Amended by ADR 0075, ADR 0111 Ad-hoc signed macOS desktop bundle
0056 2026-10-25 Accepted Learn Cline sessions from their manifests
0057 2026-10-25 Accepted The Copilot home is GitHub Copilot’s store, configuration and hook root
0058 2026-10-25 Accepted Recall: batched reads with optional local planning
0059 2026-10-25 Amended by ADR 0061, ADR 0101 Chat speaks each model’s native tool protocol
0060 2026-10-25 Amended by ADR 0122 Redact secrets before memories are stored
0061 2026-10-25 Accepted Local tool-call formats by model family
0062 2026-10-25 Superseded by ADR 0086; amended by ADR 0084 CUDA only for GPU embedding on a supported NVIDIA GPU
0063 2026-04-13 Accepted Run Qdrant as an auto-spawned local server
0064 2026-04-19 Amended by ADR 0067, ADR 0068, ADR 0077, ADR 0089 Serialize heavy commands with a single-slot queue and a shared lock file
0065 2026-04-13 Accepted Qdrant over LanceDB as the vector store
0066 2026-10-25 Amended by ADR 0108 Dev prereleases from the dev branch
0067 2026-10-25 Amended by ADR 0132, ADR 0138, ADR 0167 Background LLM tagging that yields to every other job
0068 2026-10-25 Accepted Merge identical waiting jobs
0069 2026-10-25 Amended by ADR 0137 Echo opens the microphone only on the user’s intent, after an OS consent check
0070 2026-10-25 Amended by ADR 0135 The floating companion moves with the launcher and keeps its options in settings
0071 2026-10-25 Amended by ADR 0145, ADR 0146 Each look speaks in its own voice
0072 2026-10-26 Amended by ADR 0100 Projects name their workspace and each device approves it
0073 2026-10-26 Accepted Remove a pairing from one device without the other’s acknowledgement
0074 2026-10-26 Accepted Uninstall removes the shared desktop profile
0075 2026-10-26 Accepted Microphone purpose in the macOS installer wrapper
0076 2026-10-26 Amended by ADR 0109, ADR 0111 Default OCR with wheel-installed models and renderer
0077 2026-10-26 Accepted The Stop hook hands its turn to one waiting learner under the queue lock
0078 2026-10-26 Amended by ADR 0164 Keep Qwen3.5-4B as the local tagger
0079 2026-10-26 Amended by ADR 0082 Learn only what the Claude Code user typed
0080 2026-10-26 Amended by ADR 0081 Conversations are learned again when their reading changes
0081 2026-10-26 Accepted Verifiable redacted source snapshots
0082 2026-10-26 Amended by ADR 0088, ADR 0162 Retain readable conversation evidence

| 0083 | 2026-10-26 | Amended by ADR 0106, ADR 0111, ADR 0112, ADR 0115 | Apple silicon laptop runner | | 0084 | 2026-10-26 | Amended by ADR 0086 | Setup frees the runtime before replacing its files | | 0085 | 2026-10-27 | Accepted | Main only fast-forwards to dev | | 0086 | 2026-10-27 | Amended by ADR 0090, ADR 0122 | Embeddings run on llama.cpp, without CUDA | | 0087 | 2026-10-27 | Amended by ADR 0125 | llama.cpp runs each model on one GPU | | 0088 | 2026-10-27 | Accepted | Bytes a crash never wrote are counted omissions | | 0089 | 2026-10-27 | Accepted | One progress record for the running job, read by every surface | | 0090 | 2026-10-27 | Amended by ADR 0106, ADR 0111 | macOS installs llama.cpp wheels built by this repository | | 0091 | 2026-10-27 | Accepted | WSL homes with a connected client get the imprint command | | 0092 | 2026-10-28 | Amended by ADR 0145 | Voice generation follows playback | | 0093 | 2026-10-28 | Amended by ADR 0140 | Sequential chat section analysis | | 0094 | 2026-10-28 | Amended by ADR 0095 | The dashboard reads whole sources from their snapshots | | 0095 | 2026-10-28 | Accepted | Audio files enter the source ingestion pipeline | | 0096 | 2026-10-28 | Amended by ADR 0137, ADR 0178 | CPU Whisper runtime for audio imports | | 0097 | 2026-10-28 | Amended by ADR 0103 | Echo’s looks fire like synapses | | 0098 | 2026-10-28 | Amended by ADR 0103 | Head surfaces take light; generated parts glow | | 0099 | 2026-10-28 | Amended by ADR 0105 | Sources can belong to several projects | | 0100 | 2026-10-28 | Accepted | Explicit workspace inbox for unassigned conversations | | 0101 | 2026-10-28 | Amended by ADR 0102, ADR 0127 | Chat research always reserves an answer | | 0102 | 2026-10-28 | Amended by ADR 0157, ADR 0159 | Chat research follows progress and resource budgets | | 0103 | 2026-10-28 | Accepted | Echo has a generated eye with shared morph controls | | 0104 | 2026-10-28 | Accepted | Bundle uv with conditional hash-lock support | | 0105 | 2026-10-28 | Accepted | Project analysis continues after model timeouts | | 0106 | 2026-10-28 | Superseded by ADR 0111 | Intel Mac laptop runner | | 0107 | 2026-10-28 | Accepted | Git lists a repository’s files; WSL repositories through their distribution | | 0108 | 2026-10-28 | Accepted | Installations opt in to dev builds in Settings | | 0109 | 2026-10-28 | Accepted | Automatic OCR runtime repair | | 0110 | 2026-10-28 | Accepted | The scan follows no links | | 0111 | 2026-10-29 | Accepted | Intel Macs are not supported | | 0112 | 2026-10-29 | Amended by ADR 0115, ADR 0119 | CI runs on the owner’s machines | | 0113 | 2026-10-29 | Accepted | Unchosen install profiles try the GPU | | 0114 | 2026-10-29 | Accepted | Linux desktop app runs unpacked with an AppArmor profile | | 0115 | 2026-10-29 | Accepted | Apple silicon jobs run in disposable Tart VMs | | 0116 | 2026-10-30 | Amended by ADR 0120, ADR 0176 | Paired devices send only what the other lacks, in stored chunks | | 0117 | 2026-10-29 | Amended by ADR 0151 | The dashboard shows each agent session and its calls | | 0118 | 2026-10-30 | Accepted | The PersonaPlex prototype is removed; the voice memory snapshot stays | | 0119 | 2026-10-30 | Accepted | Throwaway runners carry CI’s dependencies, and the dashboard is built once | | 0120 | 2026-10-31 | Accepted | A device storing a synced chunk says so | | 0121 | 2026-10-31 | Accepted | Optional ingestion tools install when turned on | | 0122 | 2026-10-31 | Amended by ADR 0123, ADR 0126 | The Privacy Filter runs on a GPU that passes a probe, and that device filters what it syncs | | 0123 | 2026-10-31 | Accepted | A paired sender prepares the next chunk while the other device stores the last | | 0124 | 2026-11-02 | Accepted | OpenCode is a client; its sessions are exported from its database and learned when idle | | 0125 | 2026-11-04 | Accepted | Integrated GPUs can be chosen beside a discrete one | | 0126 | 2026-11-04 | Accepted | CUDA only for an NVIDIA GPU CUDA 13 supports | | 0127 | 2026-11-04 | Accepted | The final answer is written from research notes | | 0128 | 2026-11-04 | Accepted | The dashboard follows the Windows installer to the end | | 0129 | 2026-11-04 | Amended by ADR 0136, ADR 0143 | Core memories are user-approved and start every session | | 0130 | 2026-11-04 | Amended by ADR 0132, ADR 0133, ADR 0134, ADR 0136 | Reorganization is proposed by a background job and reviewed | | 0131 | 2026-11-04 | Amended by ADR 0135, ADR 0173, ADR 0177, ADR 0180, ADR 0181, ADR 0184 | Meetings are recorded by channel and transcribed locally | | 0132 | 2026-11-05 | Accepted | Organize runs in the idle slot after background tagging | | 0133 | 2026-11-05 | Amended by ADR 0136 | Strong placements apply by themselves | | 0134 | 2026-11-05 | Accepted | Placement rules and Organize’s proposals sync between paired devices | | 0135 | 2026-11-05 | Amended by ADR 0137, ADR 0145, ADR 0174 | The floating launcher is a handle with its actions around it | | 0136 | 2026-11-05 | Accepted | Review pages use paged tabs, and decisions reopen | | 0137 | 2026-11-05 | Accepted | Echo wakes on “Hey Echo” from a hidden desktop listener | | 0138 | 2026-11-05 | Accepted | Memories that wait for LLM tagging travel to a paired device that tags | | 0139 | 2026-11-05 | Accepted | Projects and Sources browse every source in paged tabs | | 0140 | 2026-11-05 | Amended by ADR 0141 | Chat keeps the conversation and drops old research first | | 0141 | 2026-11-05 | Amended by ADR 0145, ADR 0146 | Chat summarizes what no longer fits and can look back through the conversation | | 0142 | 2026-11-06 | Accepted | Agents are reminded to search Imprint, never refused | | 0143 | 2026-11-06 | Amended by ADR 0144 | Agents receive generalised guidelines; core memories are kept as records | | 0144 | 2026-11-06 | Accepted | Newer core memories that contradict older ones wait for the user | | 0145 | 2026-11-06 | Amended by ADR 0146, ADR 0159 | A request runs until it is answered or explicitly stopped | | 0146 | 2026-11-06 | Accepted | Echo saves its conversations in Chat history and carries chats on | | 0147 | 2026-11-07 | Accepted | The scan reads paths beyond MAX_PATH through extended-length spellings | | 0148 | 2026-11-08 | Accepted | The graph draws itself on a canvas, and as a star system | | 0149 | 2026-11-08 | Accepted | Graph search is a scope of its own | | 0150 | 2026-11-08 | Accepted | Topics page on the server, and copies between workspaces are previewed | | 0151 | 2026-11-08 | Accepted | Agent sessions page by last activity with a cursor | | 0152 | 2026-11-08 | Accepted | Dashboard summaries are served stale while they refresh | | 0153 | 2026-11-08 | Accepted | Chat offers a larger Qwen MoE and custom models | | 0154 | 2026-11-08 | Accepted | The dashboard and desktop app follow a light, dark or system theme | | 0155 | 2026-11-08 | Accepted | An HTML fragment is indexed as markup | | 0156 | 2026-11-08 | Accepted | A file whose bytes are not its format is an outcome, not a failure | | 0157 | 2026-11-08 | Accepted | Chat research is charged for the work each request does | | 0158 | 2026-11-08 | Amended by ADR 0161 | Reminders, timers and scheduled jobs fire from the API process | | 0159 | 2026-11-08 | Accepted | A reply can ask the user and wait for the answer | | 0160 | 2026-11-08 | Accepted | Chat’s search filters are hints, and repeated reads are not run again | | 0161 | 2026-11-08 | Accepted | Chat keeps its instructions a reusable prompt prefix | | 0162 | 2026-11-08 | Accepted | Long tool events are one chunk, embedded from a reduced view | | 0163 | 2026-11-09 | Accepted | Tagging asks for its classification as one line of JSON | | 0164 | 2026-11-09 | Accepted | The tagging prompt keeps its layout despite prompt checkpoints | | 0165 | 2026-11-09 | Accepted | The local model tags several memories as one batch | | 0166 | 2026-11-09 | Accepted | Tagging never asks a model to think | | 0167 | 2026-11-09 | Accepted | Devices that tag together take waiting memories in random order | | 0168 | 2026-11-09 | Accepted | Skills and personas are kept once and synced to paired devices | | 0169 | 2026-11-09 | Amended by ADR 0170, ADR 0171 | Skills and personas are written into the folders the clients read | | 0170 | 2026-11-10 | Accepted | Skills and personas reach every MCP client through Imprint’s server | | 0171 | 2026-11-10 | Accepted | Personas are written for Codex and Cursor | | 0172 | 2026-11-11 | Accepted | Exact matches survive a large corpus | | 0173 | 2026-11-11 | Accepted | A transcript leaves out the microphone’s echo of the call | | 0174 | 2026-11-11 | Accepted | The floating orb is off unless the user turns it on | | 0175 | 2026-11-11 | Accepted | Releases install by themselves when nothing would be interrupted | | 0176 | 2026-11-11 | Amended by ADR 0177 | Deletions reach paired devices that hold the memory | | 0177 | 2026-11-11 | Amended by ADR 0180, ADR 0184 | Recordings travel between devices that both turned it on | | 0178 | 2026-11-11 | Accepted | Whisper large-v3 is the default transcription model | | 0179 | 2026-11-11 | Accepted | The macOS desktop app is com.alexandruleca.imprint.desktop | | 0180 | 2026-11-11 | Accepted | A recording’s transcript tells voices apart within each channel | | 0181 | 2026-11-11 | Accepted | A recording’s transcript leaves out what Whisper likely invented | | 0182 | 2026-11-11 | Accepted | The dashboard has a simple and an advanced form | | 0183 | 2026-11-11 | Accepted | Each page has a short tutorial that can be skipped | | 0184 | 2026-11-12 | Accepted | A recording’s audio states its length and can be sought |

Records are useful only while they stay consistent: a reader must be able to trust that every record has the same shape, that its status is current, and that a decision which changed points to what replaced it. These rules apply to every record from 0001 on; tests/test_adr_records.py enforces the mechanical parts.

Starting 2026-10-23, significant decisions are recorded here in the same change that implements them; root AGENTS.md makes this the working agreement for contributors and coding agents. Write a record when a change alters storage or schema, runtime or dependency policy, client configuration or hooks, security boundaries, supported platforms, installer or update behavior, or release architecture. A routine fix cites the existing record instead of adding one. A proposal is not authorization to claim the behavior exists. Human review follows the repository’s normal pull-request process.

One decision per record. A record answers one question, so it can be cited, challenged and superseded on its own. When a change makes several independent decisions, write several records. Some early records bundle related choices; they stay as they are.

  • Copy the template to docs/adr/NNNN-short-title.md, using the next unused four-digit number.
  • The front matter needs title: ADR NNNN — Title and a one-sentence description. The website parses it as YAML: quote a title that contains a colon. The body has no # heading; the site renders the title.
  • Never renumber or delete a published record. Superseded and rejected records stay, so links and citations keep working.
  • Two branches can take the same number. Whichever merges second renumbers its record before it merges: the filename, the title and every link to it.

The header is the bullet list right after the front matter, with these fields in this order:

Field When Meaning
Status always One word from the vocabulary below.
Date always When the decision was made, YYYY-MM-DD. Never changed afterwards.
Recorded retrospective records When the record was written.
Retrospective retrospective records reconstructed from …, naming the code, docs and commits used.
Scope when the acceptance is limited For example an experimental adapter, a branch-only implementation, or validation recorded separately.
Supersedes / Superseded by full replacement Links to the other record.
Amends / Amended by partial change Links to the other record, each followed by — and the part it changes.
Related optional Other records and docs in the same area that this record does not change.
Restructured records normalized after acceptance The date of the normalization. Sections added then (for the 2026-10-25 restructuring: Invalidation conditions) were derived from the record’s own text, not written by its original authors.

Link records as [ADR NNNN](NNNN-short-title.md). When a Supersedes, Superseded by, Amends or Amended by field names several records, each goes on its own indented bullet under the field.

Status Meaning
Proposed Under consideration. Nothing is implemented on its authority, and documentation must not describe it as current behavior.
Accepted In force as written.
Amended In force, but one or more later records change part of it. Its Amended by field names them and what each changes. Read them together; where they differ, the later record wins.
Superseded No longer in force. The record in Superseded by replaces it entirely.
Rejected Considered and not adopted. It stays so the same proposal is not reopened without new evidence.

Qualifiers do not go on the Status line: limits of an acceptance go in Scope, and changes by later records in Amended by or Superseded by.

Every record has these sections, in this order. Others, such as Security review, may sit between them where they fit.

  1. Context. The concrete problem or constraint, with its evidence: code, logs, measurements, the request.
  2. Decision. What is chosen and how far it reaches.
  3. Rejected alternatives. Each option that was actually considered, tried or measured, and why it was discarded, with the evidence where it exists. This section is what stops a settled debate from resurfacing, so it lists only options that really were weighed; it is never padded with options nobody evaluated. When none were recorded, it says so: No alternative evaluation was recorded.
  4. Consequences. Benefits, costs, compatibility effects, migrations and known gaps.
  5. Invalidation conditions. Concrete, observable conditions that would repeal the decision or reopen it: an upstream capability appearing or disappearing, a measurement crossing a stated line, a constraint from the context going away, a requirement the decision excluded becoming necessary. Write each one as the condition and its effect, for example If Qdrant’s embedded client supports several processes reading and writing one storage path, retire the auto-spawned daemon in favor of direct disk access. “If requirements change” is not a condition. Required for every record in force (Accepted or Amended); a proposal states them before it is accepted.
  6. Validation. What was executed, on which platforms, and what remains unverified. Never present an unexecuted check as passing.

An accepted record’s reasoning is never rewritten. When a decision changes materially, write a new record:

  • It replaces the old decision entirely: the new record says Supersedes, and the old record’s status becomes Superseded with Superseded by.
  • It changes part of the old decision: the new record says Amends and which part; the old record’s status becomes Amended with Amended by and the same part.

Both links, the old record’s status and this index change in the same pull request. On the old record, only header metadata changes; do not append follow-up paragraphs to its body (notes earlier records already carry are kept as history). When an invalidation condition is met, the response is a new record that supersedes or amends the old one, not an edit to the old one’s conclusions. Typos and broken links may be fixed in place.

A decision made before anyone recorded it can be recorded later, for example when its rationale lived only inside another document:

  • Date is when the decision was made, as far as the history shows; Recorded is today; Retrospective names the evidence.
  • Use only what the code, documentation, commits and tests show, and cite it. Never invent tests, measurements, rejected alternatives or motives. Where the history is silent, say so (No alternative evaluation was recorded.), and list the open question in the pull request instead of answering it.
  • Invalidation conditions look forward, so they may be written at recording time, derived from the recorded context.

Keeping the rest of the documentation consistent

Section titled “Keeping the rest of the documentation consistent”
  • Architecture and operational docs (docs/architecture.md, subsystem pages, CLAUDE.md, AGENTS.md) summarize a decision in a sentence or two and link to its record. The rationale — why, the rejected alternatives, the trade-offs — lives only in the record.
  • This index changes with every new record and every status change: the record goes in the decision log, and, while it is in force, under its area in the current decisions.
  • tests/test_adr_records.py checks that every record is indexed with its current status and title, that numbers are contiguous and match filenames and titles, that front matter, header fields and statuses follow these rules, that supersede and amend links resolve and are reciprocated, that the required sections are present in order, and that links between records resolve.