# GNO > A local knowledge engine for notes, code, PDFs, and Office documents. GNO indexes your files on your own machine and gives you hybrid keyword-plus-semantic search, a browsable workspace with knowledge graph and editor, a CLI, an SDK, a REST API, and MCP or agent-skill integration for ten AI clients. What sets it apart is that its retrieval can show its work: deterministic evidence with exact line spans and content hashes, answers that abstain when support is incomplete, and receipts you can re-verify later. Open source, MIT licensed, zero telemetry. ## What you get - **One local index** across Markdown, PDF, Office documents, plain text, source code, portable mail and calendar exports, transcripts, JSONL, and browser exports. - **Three search modes**: keyword (BM25), semantic (vector), and hybrid — fused, reranked, and explainable, with structured intent controls and metadata filters. - **A real workspace**: cross-collection folder tree, per-tab browse context, a markdown editor, provenance-carrying quick capture, and a navigable knowledge graph. - **Cited AI answers** over your own documents, with citations that resolve to the source passage. - **Six interfaces on one index**: CLI, web UI, REST API, TypeScript SDK, MCP server, and a desktop shell. - **Ten AI clients, one command each**: Claude Code, Claude Desktop, Cursor, Codex, Zed, Windsurf, OpenCode, Amp, LM Studio, LibreChat. - **Optional hosted publishing** at gno.sh when a slice of your workspace needs a URL. No GPU required, no account required, no telemetry. Free and MIT licensed. ## Why not another local RAG tool - **Context Capsules**: one bounded, deterministic evidence bundle per goal, with exact line ranges, three levels of content hash, declared coverage gaps, and explained omissions, all under a single global token budget. Measured on 48 paired agentic benchmark tasks: 100% task completion accuracy retained, 48.94% fewer retrieval calls, 44.12% less model-visible context. - **Verified answers**: `gno ask --verify` generates against one closed Capsule, classifies every substantive claim as supported, contradicted, insufficient, or uncertain, and withholds the draft below 100% support. Abstention is a valid outcome, not a failure. - **Verified setup**: `gno setup` returns only after lexical search proves a real corpus-derived hit. Semantic readiness is tracked separately and honestly. - **Knowledge Delta**: bounded metadata-only change journal, structural diffs, dependency impact paths, and freshness reverification for saved Capsules. - **Private retrieval learning**: opt-in local traces, explicit judgments only, content-free qrels export, read-only baseline-versus-candidate replay. Nothing is recorded or personalized by default. - **Collection egress policies**: fail-closed `local_only`, `lan`, or `remote` boundaries per collection. Derived Capsules, traces, and exports inherit the most restrictive source policy, and authentication never overrides it. ## Boundaries and honest limits - Corpus, index, and built-in models stay local. The three explicit network boundaries are: downloading a model, configuring an HTTP inference endpoint, and uploading an artifact you exported for gno.sh publishing. - Verified Ask checks claims only against the evidence retained in its local Capsule. It is not a general fact-check and cannot make an incorrect source correct. - Local models load on demand, remain reusable during idle grace, then retire. Keyword search needs no model load; later semantic requests may be cold. Resident MCP clients share that lifecycle; stdio remains supported. After native-child failure, retry explicitly after cleanup: failed requests are not replayed. - Supported search filters apply before candidate limits. Empty or fewer-than-requested results are valid, distinct from reported vector failure or lexical fallback. Vector and hybrid language filters match chunk language; lexical language filtering is reserved. - Leaving the indexing view stops polling, not accepted server jobs. Caller cancellation does not release native ownership before work settles. Pending embeddings resume from durable checkpoints on a later run. - File and export adapters read local export files only. They never authenticate to accounts, read live browser databases, fetch URLs, or open attachments. ## Install ```bash bun install -g @gmickel/gno # requires Bun >= 1.3 gno setup ~/notes --name notes gno mcp install --target cursor # or claude-code, zed, windsurf, ... ``` ## Documentation Every docs page is also served as Markdown at the same path with a `.md` suffix, or by requesting the HTML path with `Accept: text/markdown`. The whole docs set in one file: https://gno.sh/llms-full.txt. ### Getting Started - [Quickstart](https://gno.sh/docs/quickstart): Index a local folder and prove BM25 in under five minutes; semantic search and Ask follow once models download. - [Installation](https://gno.sh/docs/installation): Install GNO via Bun, prove local retrieval with gno doctor, and configure vector search on macOS. - [Configuration](https://gno.sh/docs/configuration): Configure GNO via user config or a portable project profile, manage collections, and pick the right model preset. ### Reference - [CLI commands](https://gno.sh/docs/cli): Reference for every gno command, global option, retrieval mode, background service, and integration surface. - [Packaging proof](https://gno.sh/docs/packaging): How GNO proves the npm tarball users install contains the runtime files and doctor contract needed for release. - [Web UI](https://gno.sh/docs/web-ui): The local browser workspace started by gno serve: search, browse, graph, edit, capture, API, and live indexing. - [REST API](https://gno.sh/docs/api): HTTP endpoints exposed by gno serve for search, documents, graph data, models, jobs, and workspace automation. - [SDK](https://gno.sh/docs/sdk): Import GNO directly into a Bun or TypeScript app with createGnoClient and the same local retrieval engine. - [MCP integration](https://gno.sh/docs/mcp): Install GNO automatically as a local MCP server for exactly 10 named clients; configure Raycast and other compatible clients manually. - [Agent skills](https://gno.sh/docs/skills): Install GNO as a progressive agent skill for Claude Code, Codex, OpenCode, OpenClaw, Hermes Agent, and compatible clients. - [Agent instructions](https://gno.sh/docs/agents-install): gno agents install keeps one versioned, marker-managed GNO protocol block in the global instruction file of every harness on the machine: the harness matrix with its evidence, what the markers and the version stamp guarantee, and what the block teaches. - [Structured query syntax](https://gno.sh/docs/syntax): Multi-line query documents with term, intent, and hyde for explicit retrieval behavior. - [Fine-tuned models](https://gno.sh/docs/fine-tuned-models): GNO ships gno-expansion-slim-retrieval-v1 as the expand role in slim-tuned (nDCG@10 0.925, Ask Recall@5 0.875). It does not train on your corpus. ### Integrations - [Browser clipper](https://gno.sh/docs/browser-clipper): Capture a visible selection or Reader-style page into local GNO with previewed Markdown and exact provenance. - [Claude Code](https://gno.sh/docs/claude-code): Use GNO with Claude Code via the SKILL.md install or the MCP server. - [Cursor](https://gno.sh/docs/cursor): Install GNO as an MCP server in Cursor for hybrid retrieval while you code. - [Claude Desktop](https://gno.sh/docs/claude-desktop): Install GNO as an MCP server in Claude Desktop for hybrid retrieval over your local documents. ### Guides - [Context Capsules](https://gno.sh/docs/context-capsules): What a Capsule is, how GNO compiles one, every field it contains, how to verify it later, and when to use one instead of a plain query. - [Retrieval learning & replay](https://gno.sh/docs/retrieval-learning): Turn a real retrieval miss into a content-free regression fixture, then replay a candidate pipeline against it before you change anything. - [Knowledge Delta](https://gno.sh/docs/knowledge-delta): Answer change-shaped questions directly: what moved since Tuesday, what structurally changed in this note, and which conclusions depended on it. - [Memory](https://gno.sh/docs/memory): How gno remember and gno recall store and retrieve agent facts: the write-path taxonomy, explicit scopes, supersession, budgeted cited recall, context fencing and its limits, and what the memory slice deliberately does not do. - [Knowledge protocol](https://gno.sh/docs/protocol): The retrieval ladder and the writing contract an agent follows over your collections: which GNO command answers which kind of question, what each rung returns and where it stops, and when a write is an edit, a capture, or a remember. - [Project setup & profiles](https://gno.sh/docs/project-profiles): gno setup returns only after a corpus-derived BM25 proof. Commit .gno/index.yml for portable collection/context/content rules; the SQLite DB, model cache, and locks stay out of the repo. - [File & export adapters](https://gno.sh/docs/file-export-adapters): Index mail, calendar, transcript, browser, and JSONL exports as individually searchable records, with no account access and no live connectors. - [Integrity audits](https://gno.sh/docs/integrity-audits): Find broken local links, incomplete declared provenance, and source/index drift. Stable finding IDs; no automatic repair. - [Collection egress](https://gno.sh/docs/collection-egress): Give each collection a fail-closed transport boundary that follows its content through inference, publishing, exports, Capsules, and traces. - [How-To](https://gno.sh/docs/how-to): Practical GNO recipes for keeping collections fresh, building personal knowledge bases, connecting AI tools, and recovering stale indexes. - [How search works](https://gno.sh/docs/how-search-works): BM25, vector, default bounded graph expansion, fusion, and reranking, end to end. - [Architecture](https://gno.sh/docs/architecture): Bun, SQLite, local GGUF models via node-llama-cpp, and one retrieval core shared by CLI, Web UI, SDK, REST, and MCP. - [Use cases](https://gno.sh/docs/use-cases): Obsidian vaults, Claude Code memory, client corpora under local_only, Capsule-backed agent answers, and export-adapter records. - [Troubleshooting](https://gno.sh/docs/troubleshooting): Doctor output, Homebrew SQLite on macOS, model pulls, stale embeddings, and Windows llama.cpp startup. ### gno.sh Publishing - [Publish a note](https://gno.sh/docs/publish-quickstart): Sign up for gno.sh, import an exported artifact, and publish a versioned reading-first snapshot. - [Visibility modes](https://gno.sh/docs/publish-visibility): Choose public URL, secret-link token, org invite, or client-side passphrase encryption. ## Features - [Context Capsules](https://gno.sh/features/context-capsules): One bounded, checkable evidence handoff for an agent - [Verified Answers](https://gno.sh/features/local-llm): A cited answer from a local LLM, or an honest abstention - [Knowledge Delta](https://gno.sh/features/knowledge-delta): Know what changed, and which conclusions depended on it - [Agent Memory](https://gno.sh/features/agent-memory): One auditable memory store for every agent you authorize - [Integrity Audits](https://gno.sh/features/integrity-audits): Know what needs attention from one read-only local report - [Private Retrieval Learning](https://gno.sh/features/retrieval-learning): Turn a real miss into a regression test you own - [Verified Setup & Project Profiles](https://gno.sh/features/project-setup-profiles): Activate a folder with proof, then keep its retrieval intent portable - [Collection Egress Governance](https://gno.sh/features/collection-governance): Decide where each collection is allowed to travel - [Hybrid Search](https://gno.sh/features/hybrid-search): Rank the matching paragraph first - [Advanced Retrieval](https://gno.sh/features/advanced-retrieval): Filter by date, tag, author, and language; expand, steer, exclude, and `--explain` - [AI Agent Integration](https://gno.sh/features/agent-integration): Your agents retrieve from your knowledge base on demand - [AI Tool Integration](https://gno.sh/features/mcp-integration): Install GNO as MCP in ten named clients - [Daemon Mode](https://gno.sh/features/daemon-mode): Keep GNO fresh without the web UI - [Benchmarks](https://gno.sh/features/benchmarks): Measure before you switch, and publish it either way - [Fine-Tuned Models](https://gno.sh/features/fine-tuned-models): Measured query expansion with a tuned local model - [Web UI](https://gno.sh/features/web-ui): Browse and edit notes. Read PDFs in their native layout. - [Desktop App](https://gno.sh/features/desktop-app): The workspace in a native window, with gno serve supervised for you - [GNO Recall for Omarchy](https://gno.sh/features/omarchy-recall): The index in your bar: health, recent documents, and a Super+R overlay - [Knowledge Graph](https://gno.sh/features/graph-view): Force-directed graph of wiki links, markdown links, similarity edges, and typed `doc_edges` - [Note Linking](https://gno.sh/features/note-linking): Follow wiki links, backlinks, and typed relations; rewrite them on rename - [Collections](https://gno.sh/features/collections): Group sources by directory, glob, context, and per-collection egress policy - [Tag System](https://gno.sh/features/tags): Filter the local index by frontmatter and hierarchical tags - [Multi-Format Indexing](https://gno.sh/features/multi-format): Index Markdown, Office, PDF, mail, calendar, transcripts, and browser exports - [Browser Clipper](https://gno.sh/features/browser-clipper): Capture a visible selection or Reader extract over loopback pairing - [Privacy First](https://gno.sh/features/privacy-first): Corpus, index, and default models stay on disk with zero telemetry - [Fast CLI](https://gno.sh/features/fast-cli): Keyword search without a model startup - [REST API](https://gno.sh/features/api): 35+ localhost HTTP endpoints for search, ask, graph, and models - [SDK](https://gno.sh/features/sdk): Embed GNO directly - [Publish & Sharing](https://gno.sh/features/publish-sharing): Share your GNO workspace as a reading surface ## Integrations - [Claude Code](https://gno.sh/integrations/claude-code): Give Claude Code a memory that outlives the session - [Claude Desktop](https://gno.sh/integrations/claude-desktop): Ask Claude Desktop about your own files - [Cursor](https://gno.sh/integrations/cursor): Cursor's assistant retrieves ADRs, vendor PDFs, and notes outside the open repo - [Codex](https://gno.sh/integrations/codex): Codex, with your documentation in reach - [Zed](https://gno.sh/integrations/zed): Local retrieval inside Zed's assistant - [Windsurf](https://gno.sh/integrations/windsurf): Windsurf plus your own reference material - [OpenCode](https://gno.sh/integrations/opencode): OpenCode retrieves from your local index on demand - [Amp](https://gno.sh/integrations/amp): Amp, connected to your local corpus - [LM Studio](https://gno.sh/integrations/lm-studio): A fully local stack: LM Studio for generation, GNO for evidence - [LibreChat](https://gno.sh/integrations/librechat): LibreChat retrieves from a local GNO index, not a hosted vector database - [OpenClaw](https://gno.sh/integrations/openclaw): OpenClaw calls GNO skill retrieval against your local notes, docs, and code - [Obsidian](https://gno.sh/integrations/obsidian): Keep the vault. Add retrieval your agent can use ## Comparisons - [GNO vs Obsidian](https://gno.sh/comparisons/obsidian): Obsidian wins on plugins, Canvas, and visual note-taking. GNO wins on retrieval, agent access, and multi-format indexing. They compose well. - [GNO vs Khoj](https://gno.sh/comparisons/khoj): Khoj is a broader personal AI assistant platform. GNO is a tighter local retrieval and workspace engine for developer workflows. - [GNO vs PrivateGPT](https://gno.sh/comparisons/privategpt): Both are privacy-first local RAG. PrivateGPT is a Python-first server stack. GNO is a local knowledge workspace with stronger retrieval UX and agent integration. - [GNO vs Quivr](https://gno.sh/comparisons/quivr): Quivr is a team-oriented second brain with cloud sync. GNO is a local-first retrieval workspace with CLI, REST API, and agent integration. - [GNO vs AnythingLLM](https://gno.sh/comparisons/anythingllm): AnythingLLM is a full chat app with document upload. GNO is a retrieval engine and workspace that plugs into your existing AI tools. - [GNO vs Reor](https://gno.sh/comparisons/reor): Reor is a standalone note app with built-in chat. GNO indexes any folder and also ships a workspace editor, graph, and PDF viewer; you can keep Obsidian/VS Code or work in GNO’s UI. - [GNO vs GPT4All](https://gno.sh/comparisons/gpt4all): GPT4All is a local LLM chat app with attached document support. GNO is a retrieval workspace for using multiple AI clients with the same local index. - [GNO vs Kotaemon](https://gno.sh/comparisons/kotaemon): Kotaemon is a RAG web UI focused on document Q&A with citations. GNO is a retrieval engine with CLI, REST API, MCP, and agent integrations in addition to a web UI. - [GNO vs Qmd](https://gno.sh/comparisons/qmd): Both run local hybrid search with an MCP server over the notes you keep. Qmd is a single-purpose CLI with four MCP read tools. GNO adds PDF and Office indexing, a 7-tool or 34-tool MCP profile, Context Capsules, verified answers, remember/recall memory, a workspace UI, and optional publishing. - [GNO vs GBrain](https://gno.sh/comparisons/gbrain): GBrain is a self-maintaining agent memory: it writes the brain after conversations and enriches it overnight, on its own agenda. GNO is the knowledge engine your agents capture into and retrieve from, over folders and formats you already keep, on a cadence you wire. - [GNO vs grep](https://gno.sh/comparisons/grep): grep finds exact patterns at sub-millisecond speed. GNO finds concepts, handles multi-format content, and feeds AI agents. - [GNO vs Elasticsearch](https://gno.sh/comparisons/elasticsearch): Elasticsearch is a distributed search engine for production workloads. GNO is a single-user local knowledge workspace with embedded SQLite. ## Optional - [Publishing platform](https://gno.sh/publish): export a note or collection locally and publish it as a reading-first page (public, secret link, invite-only, or encrypted before upload). - [Pricing](https://gno.sh/pricing): the local engine is free and MIT licensed; pricing covers hosted publishing only. - [Ecosystem](https://gno.sh/ecosystem): companion tools. - [Full documentation as one file](https://gno.sh/llms-full.txt) - [Source](https://github.com/gmickel/gno) --- # Full documentation Every docs page follows, in navigation order. Each page starts with its title, its one-line description, and its canonical URL. --- # Quickstart > Index a local folder and prove BM25 in under five minutes; semantic search and Ask follow once models download. Section: Getting Started Canonical: https://gno.sh/docs/quickstart Markdown: https://gno.sh/docs/quickstart.md Index a local folder and prove BM25 in under five minutes; semantic search and Ask follow once models download. Skip downloads with `--no-semantic` or `GNO_NO_AUTO_DOWNLOAD=1`. Most users reach GNO from Claude Code, Claude Desktop, Cursor, Codex, OpenClaw, or Hermes Agent. This guide installs that connector after lexical proof. If GNO is not installed yet, start with [installation](https://gno.sh/docs/installation). Use the intact Bun package, including its native worker source. No separate daemon installation is required. First inference and the first request after the default five-minute idle grace load models and contexts; metadata polling does not keep them warm. See [runtime timeouts](https://gno.sh/docs/configuration#model-timeouts) and [runtime requirements](https://gno.sh/docs/installation). ## 1. Set up and prove your documents A folder can be Markdown, PDF, Office, plain text, code, portable mail or calendar exports, transcripts, JSONL, browser exports, or a mix. ``` gno setup ~/notes --name notes gno setup ~/Documents --name docs --exclude .env --exclude private gno setup ~/Documents --name docs --no-semantic ``` Prefer a guided UI? Start `gno serve`, open `http://localhost:3000`, and use the first-run checklist to add a folder, pick a preset, and start indexing with zero CLI commands. Setup returns only after an exact corpus-derived BM25 result. Reruns reuse the canonical folder and receipt. Semantic work is one-shot and independent; `--no-semantic` starts none. Add repeatable `--connector` flags for explicit agent handoffs. `--exclude` is repeatable and literal. Likely credentials, private keys, and environment files fail closed unless an interactive default-No prompt is accepted or `--authorize-secret-risk` is passed explicitly. `--yes`, JSON, non-terminal input, decline, and EOF never authorize secret risk. ## 2. Finish semantic indexing ``` gno index ``` Lexical indexing is already proven. This finishes vector indexing. GNO handles Markdown, PDF, DOCX, XLSX, PPTX, plain text, JSONL, EML/MBOX, ICS, WebVTT/SRT, and explicit browser-export files. On first run, GNO may download local embedding, reranking, expansion, or generation models. Cache use varies by the selected artifacts and quantization. To skip startup downloads, set `GNO_NO_AUTO_DOWNLOAD=1` and run `gno models pull` explicitly. Cached GGUF files are validated before load, so intercepted HTML or other non-model responses are removed with a clear recovery error. ``` gno ls ``` ## 3. Prove retrieval works ``` gno doctor gno status --json ``` Readiness is not inferred from an existing database or downloaded model. GNO derives a bounded probe from each indexed collection and proves that local lexical search can return the expected document. The same activation result appears in doctor, status, the REST API, and the Web UI. Semantic readiness is independent: it can remain pending while embeddings or local models catch up without hiding a successful lexical proof. ## 4. Connect your AI tools Installed skills and MCP tools search the local index and return cited snippets into the client. Pick one or both integration paths: ### Skills — for agents Installs GNO as a `/gno` slash command. The agent loads GNO tools only when `/gno` is invoked. Works with Claude Code, Codex, OpenCode, OpenClaw, and Hermes Agent. ``` gno skill install --target claude --scope user gno skill install --target codex --scope user gno skill install --target opencode --scope user gno skill install --target openclaw --scope user gno skill install --target hermes --scope user gno skill install --target all --scope user # install everywhere ``` ### MCP — for AI assistants and editors Installs GNO as a Model Context Protocol server for ten named targets: Claude Desktop, Claude Code, Cursor, Codex, Zed, Windsurf, OpenCode, Amp, LM Studio, and LibreChat. Raycast and other compatible clients use manual MCP configuration. ``` gno mcp install --target claude-desktop gno mcp install --target cursor gno mcp install --target zed gno mcp install --target windsurf gno mcp install --target claude-code # MCP for Claude Code gno mcp install --target claude-code --tool-profile core # 7-tool core profile gno mcp status # see what's configured, and each registration's profile ``` `--tool-profile core` writes the slim 7-tool profile into the registration (add `--enable-write` for capture and remember); omitting it keeps the default `full` profile and the same registration as before. Rerun with `--force` to switch an existing client. Restart the client after install. The client can then call GNO. Example prompts:_ “Search my notes for deployment procedures”_ or_ “Find architecture docs related to this change”_. In the Web UI, open **Connectors** and use the explicit read-only verification action for an installed MCP target. It starts that configured MCP command, checks its tools and status, and runs a collection-scoped search without changing client configuration. Installed skill files can be detected, but the client’s skill runtime cannot be invoked safely from GNO; those targets report unverifiable rather than passed. The installer pins the current Bun + GNO package runtime, active index, and absolute config, data, and cache roots. The client therefore opens the same workspace as the CLI even when launched outside your shell. ## 5. Search from the CLI (optional) If you prefer the terminal, GNO exposes three search modes for different trade-offs between speed and depth. ``` # Fast keyword search (~5–20ms) gno search "project deadlines" # Meaning-based search (~0.5s) gno vsearch "how to handle errors" # Hybrid: BM25 + vector + rerank gno query "authentication best practices" # AI answer with citations gno ask "what is the main goal of project X" --answer ``` Use `gno capture` when you want to add a quick note to an editable collection with provenance metadata and an optional typed preset scaffold. ``` gno capture "thought to remember" gno capture --file ./clip.md --source-url https://example.com --source-kind web --json gno capture --preset person --title "Jane Doe" --folder people/ gno capture --preset meeting --title "Weekly sync" --folder meetings/ ``` ## Output formats Search and read commands accept `--json`, `--files`, `--csv`, and `--md`: ``` gno search "important" --json gno search "important" --files gno search "important" --csv gno search "important" --md ``` ## Next steps - Configure presets + collections: [configuration reference](https://gno.sh/docs/configuration) - Full [Claude Code](https://gno.sh/docs/claude-code), [Claude Desktop](https://gno.sh/docs/claude-desktop), and [Cursor](https://gno.sh/docs/cursor) integration guides - All MCP tools + clients: [MCP reference](https://gno.sh/docs/mcp) - Share a note publicly: [gno.sh publishing](https://gno.sh/publish) --- # Installation > Install GNO via Bun, prove local retrieval with gno doctor, and configure vector search on macOS. Section: Getting Started Canonical: https://gno.sh/docs/installation Markdown: https://gno.sh/docs/installation.md GNO ships as a TypeScript CLI package installed and run by Bun. The same package exposes a web server, TypeScript SDK, and MCP server. The supported runtime is Bun 1.3.0 or newer. GNO 2.0 repository development uses Bun 1.4.2 for its current lockfile; that is distinct from the declared consumer runtime range above. Keep the installed package source intact: native inference launches its packaged worker with a real Bun executable. A standalone `bun build --compile` binary without that source runtime is not a supported substitute. No separate daemon installation is required. ## macOS and Linux ``` bun install -g @gmickel/gno ``` On macOS, vector search requires the Homebrew build of SQLite so GNO can load the SQLite extension for vector similarity: ``` brew install sqlite3 ``` After indexing at least one folder, verify with `gno doctor`. Alongside environment checks, doctor derives a bounded term from each local collection and proves that lexical retrieval returns the expected document. ``` gno doctor ``` ## Windows Current support target is **windows-x64**. The CLI path works via Bun/global install, and the desktop beta ships as a packaged Windows zip on GitHub Releases. Windows arm64 is not supported yet. ``` bun install -g @gmickel/gno ``` ## Desktop beta The packaged desktop shell wraps `gno serve` in a native window with the workspace UI pre-wired. Grab a build from [GitHub Releases](https://github.com/gmickel/gno/releases) and run it like any other desktop app. Desktop builds are beta and may trail the current CLI package; verify the version attached to the release before choosing it over the CLI. ## Verify your install ``` gno --version gno doctor gno status ``` `gno doctor` surfaces path resolution, SQLite version, model cache location, disk space, embedding freshness, and retrieval activation. `gno status` exposes the same activation contract without loading or downloading models or starting a connector runtime. A passed lexical proof means the collection is usable even when semantic search remains pending. Status reports degraded state but still exits 0; doctor exits non-zero when lexical activation fails. ## Release package proof GNO releases run `bun run test:package` before publish. That script packs the npm tarball with `npm pack`, installs from that tarball into isolated temporary paths, verifies required packed files including `src/embed/retry.ts`, then runs the packaged `gno --version`, `gno --help`, and `gno doctor --json`. The packaged doctor proof is specific: JSON must include the `embedding-fingerprint` check and its `embeddingFingerprint` payload with `currentFingerprint`, `pendingChunks`, `legacyChunks`, `mixedGroups`, and `groups`. ## Connect your AI tools Most users install a skill or MCP target so the client can search the local index and return cited snippets. One command per client: ``` # Coding agents (zero-overhead skill install) gno skill install --target claude --scope user # Claude Code gno skill install --target codex --scope user gno skill install --target opencode --scope user gno skill install --target openclaw --scope user gno skill install --target hermes --scope user gno skill install --target all --scope user # all agents # AI assistants and editors (MCP) gno mcp install --target claude-desktop gno mcp install --target cursor gno mcp install --target zed gno mcp install --target windsurf gno mcp install --target claude-code gno mcp status ``` Full client list + write-access options: [MCP reference](https://gno.sh/docs/mcp). Per-client setup guides: [Claude Code](https://gno.sh/docs/claude-code), [Claude Desktop](https://gno.sh/docs/claude-desktop), [Cursor](https://gno.sh/docs/cursor). Installation and verification are separate. The Web UI’s** Connectors** page offers an explicit read-only retrieval check for installed MCP targets. Installed skill targets remain `target_runtime_unverifiable` because GNO can inspect their files but cannot prove that a client loaded or executed them. ## Next steps - Run [the quickstart](https://gno.sh/docs/quickstart) to index and search your first collection - Tune presets and collections: [configuration](https://gno.sh/docs/configuration) - Publish a note publicly: [gno.sh publishing](https://gno.sh/publish) --- # Configuration > Configure GNO via user config or a portable project profile, manage collections, and pick the right model preset. Section: Getting Started Canonical: https://gno.sh/docs/configuration Markdown: https://gno.sh/docs/configuration.md Change collections and presets from the CLI or Web UI. The YAML file is for defaults the UI does not cover. User config is `~/.config/gno/config/index.yml` (Windows: `%APPDATA%\gno\config\index.yml`). `gno doctor` prints the resolved paths. ## Config file location - **macOS / Linux**: `~/.config/gno/config/index.yml` - **Windows**: `%APPDATA%\gno\config\index.yml` Run `gno doctor` to see the resolved paths for your machine. ## Index database busy timeout `busyTimeoutMs` sets SQLite `busy_timeout` for the index database. Integer milliseconds from `1000` to `600000`; default `60000`. `gno doctor` reports the live PRAGMA `busy_timeout` value. Raise it for long embedding passes on slow disks. ``` busyTimeoutMs: 60000 ``` ## Project-local retrieval profiles A repository can commit a portable `.gno/index.yml` profile that describes one collection, its contexts and content types, and request-local project-affinity defaults. A profile is optional: repos without one keep the normal user config and current-directory behavior. ``` schemaVersion: "1.0" collection: name: project-docs root: docs include: ["**/*.md"] exclude: [node_modules, .git] contexts: - file: AGENTS.md contentTypes: people: prefixes: [people] preset: person affinityDefaults: enabled: true contribution: 0.03 ``` Paths are repository-relative and cannot escape the selected project root. The schema is closed: unknown keys, absolute paths, traversal, environment expansion, Windows-reserved names, unsafe glob syntax, duplicate IDs, and references to GNO runtime files fail validation. Likely secret context paths such as `.env`, private keys, and credentials are rejected. Context files must be regular UTF-8 files no larger than 64 KiB; the profile itself is capped at 1 MiB. GNO also excludes `.gno` from the declared collection. Profile excludes containing glob metacharacters are real Bun globs; plain values retain directory-component matching. Multiple include globs preserve literal commas and bracket classes. Brace alternatives are rejected; express their branches as separate include or exclude entries. ``` gno profile check gno profile show gno profile diff gno profile apply ``` The first three commands are read-only. `apply` takes a canonical, cross-process config lock and additively creates or updates only profile-declared config and store projections; it does not index documents or delete unrelated DB-only collections, documents, contexts, omitted content types, or index state. Multiple contexts for one collection are preserved. A timestamp-free local binding records the canonical profile path, collection, and fingerprint so removal-only edits remain observable without exposing machine paths in public receipts. The tracked profile is never rewritten. Config, data, database, model cache, selected file-backed models, apply receipt, and lock state must stay in the user’s external GNO runtime directories, never inside the repository. Overlap fails before mutation. Commit the portable profile and referenced guidance, not databases, model files, caches, locks, receipts, or secrets. ## Collections Each collection is a named source of documents. Collections have their own include/exclude rules and can optionally override model presets. ``` # Add a collection gno collection add ~/notes --name notes # Add with a glob pattern gno collection add ~/code --name code --pattern "**/*.{ts,md}" # List collections gno collection list # Remove a collection gno collection remove notes ``` ## Collection egress policy Every collection has one effective boundary: `local_only`, `lan`, or `remote`. An omitted value fails closed to `local_only`. Collections created before this policy was introduced keep their indexed documents and lexical/vector data, but report `legacy_default` provenance; newly synchronized collections without an explicit value report `config_default`. Neither default permits LAN or remote transfer. Egress policy is distinct from source availability (below). - `local_only` permits local files, processes, loopback clients, and loopback model servers only. - `lan` additionally permits authenticated, proven private-network peers. - `remote` additionally permits authenticated public transport and pinned HTTPS model providers. ``` gno collection policy get notes gno collection policy check --action remote_inference \ --destination remote --content-class source -c notes \ --authenticated --authorized --explain-egress gno collection policy set notes remote --confirm-relaxation 0 gno collection policy set notes local_only ``` Authentication, write permission, and collection policy are independent gates. Mixed or derived evidence uses the most restrictive participating collection. Relaxation requires the current single-use policy revision; tightening invalidates resident sessions, active streams, queued jobs, and saved authorization state. Tightening blocks future GNO-controlled transfers but cannot recall data already uploaded. Revoke or expire supported private links separately; public-space deletion is not yet self-service, so request remote takedown. Encrypted gno.sh artifacts remain client-encrypted; gno.sh never receives the passphrase and cannot decrypt or recover them. ## Source availability `collections[].sourceAvailability` is optional and independent of `egressPolicy`. Exact values: `any` (default) or `local`. Availability controls whether source content may be materialized during indexing; egress controls where derived data may travel. There is no separate public knob beyond these two modes. - `any` preserves legacy source reads with no no-materialization guard. - `local` is opt-in for the macOS File Provider layouts covered by physical evidence. It indexes already-local content, refuses cloud-placeholder materialization, classifies directories hierarchically before descent, rechecks at the content boundary, and fails closed on unsupported platforms or policy setup failure. Sync receipts distinguish eligible files, `CLOUD_PLACEHOLDER` / `CLOUD_PARTIAL` skips (not conversion errors), `DATALESS_DIRECTORY`, and fail-closed `SOURCE_AVAILABILITY_*` codes. Previously indexed descendants under unproven prefixes stay searchable rather than being treated as proven deletions. Evidence scope: Google Drive, iCloud Drive, and OneDrive only for the tested macOS/provider configuration; OneDrive only for both validated immediate SharePoint library roots. No Windows or Linux cloud- filesystem guarantee. Metadata or provider bookkeeping may still occur. GNO local mode does not pin, evict, or download as product behavior. On the controlled 5,000-file all-local Markdown corpus (2 warmups, 9 interleaved samples per lane), current production `any`measured -1.1280% versus the pre-implementation production walker and hierarchical `local` added 1.1841% median traversal overhead versus current `any`. These are fixture-scoped scan results, not provider-latency or zero-network-activity guarantees. ``` collections: - name: drive-notes path: /Users/you/Library/CloudStorage/GoogleDrive-…/My Drive/notes pattern: "**/*" sourceAvailability: local egressPolicy: local_only ``` ## File and export adapters GNO streams user-controlled exports into separate searchable records: one JSONL object, mail message, calendar event, transcript cue, or browser item at a time. Each record retains its real export path, exact locator, dates, people, available thread/event/session identity, attachment inventory, and anchors across search, get, Ask, and Context Capsules. - Automatic: `.jsonl`, `.ndjson`, `.eml`, `.mbox`, `.ics`, `.vtt`, `.srt`, and explicit `.browser-export` files. - Generic JSON/text transcripts require a per-collection `recordAdapters.transcript.format`; GNO never guesses. - JSONL field mappings are declarative JSON Pointers and cannot run code, read other files, or make network requests. ``` collections: - name: exports path: /Users/me/exports pattern: "**/*" include: [.jsonl, .eml, .mbox, .ics, .vtt, .srt, .browser-export] recordAdapters: jsonl: fieldMapping: id: /external_id body: /payload/text participants: /participants dateFields: created: /created_at ``` Reimport with the same stable identity updates in place. Only a fully valid complete snapshot can deactivate disappeared records; malformed, truncated, or cap-limited snapshots preserve unseen records. Defaults cap a container at 100 MiB, one record at 2 million canonical characters, a snapshot at 50 million characters or 100,000 records, retained failures at 1,000, and adapter iteration at 60 seconds. Calendar recurrence emits at most 64 bounded local anchors. Partial imports always produce a visible warning; verbose output adds stable codes, locators, retryability, and redacted messages. JSONL updates preserve identity only when a configured mapping or a conventional `id` field supplies one. Without either, GNO derives identity from canonical row content, so editing a row appears as one removed record plus one added record rather than an in-place update. Export adapters never authenticate to mail/calendar/browser accounts, inspect live browser profiles, cookies, passwords, or sessions, fetch URLs or attachments, execute embedded content, or unpack archives. HTML becomes inert text. In structured results, `source.relPath` is the real export container; use the unique `uri` or `docid` to retrieve one record. The bounded `record.adapter` object identifies the exact adapter version and configuration fingerprint. `.gno/records/` is reserved for virtual record identities and never walked as physical collection content. ## Exclusions Add an `exclude` array to a collection to skip files and directories: ``` collections: notes: path: ~/notes exclude: - node_modules - .git - "**/*.tmp" ``` ## Project-aware retrieval `projectAffinity.enabled` defaults to `true` and controls only the user-configured cwd fallback. `projectAffinity.contribution` defaults to and is capped at `0.03`. For a local CLI request, repeatable explicit `--project-root` values win; otherwise the nearest valid`.gno/index.yml` supplies its canonical project root and request-local affinity settings. Missing or invalid profiles fall back to the cwd-derived root and user default. An explicit root or valid profile therefore still applies when the user-config fallback is disabled. `--no-project-affinity` disables all three sources for that request. Explicit roots replace inferred roots, duplicate or overlapping roots never stack, and all auxiliary scoring shares one `±0.08` cap. Remote hints are a separate untrusted input: they never trigger local profile or filesystem discovery and currently contribute zero affinity. Collection, tag, date, exclude, and egress filters remain hard. ## Model presets GNO ships four built-in presets. Switch with one command; the first pull downloads the model files and caches them locally. - **slim-tuned** — current default; fine-tuned query expansion with the slim embedding, rerank, and answer stack. - **slim** — untuned Qwen3 1.7B expansion and answers. - **balanced** — Qwen2.5 3B expansion and answers. - **quality** — Qwen3 4B expansion and standalone answers. All four built-in presets use `Qwen3-Embedding-0.6B-GGUF` for embeddings. Model cache size varies with selected artifacts, quantization, and files already present; the preset names are not measured clean-install size claims. ``` gno models use balanced gno models pull gno models list ``` ## Content types `contentTypes` is an optional schema-lite layer for second-brain pages. Empty or absent rules keep legacy behavior. When a rule matches, GNO indexes canonical `contentType` metadata alongside normal category filters. ``` contentTypes: - id: person prefixes: [people/, contacts/] preset: person - id: meeting prefixes: [meetings/] preset: meeting searchBoost: 1.15 temporal: true ``` Frontmatter `type` becomes canonical only when it matches a configured content type ID. Otherwise it remains category metadata. A canonical configured frontmatter type wins over longest-prefix matching; only one rule applies, so overlapping prefixes cannot stack.`graphHints` types projected graph relationships. `searchBoost` accepts `0.5` to `2`; omitted or `1` is exactly neutral. One matched rule contributes at most `±0.05` and composes once with trusted local project affinity under a shared `±0.08` auxiliary cap. BM25 and vector boosts only adjust already-selected candidates: they never widen candidate retrieval or defer `minScore`. Hybrid applies the composed auxiliary score to normalized fusion before rerank blending, leaving rerank order and lexical top-hit protection authoritative. Final scores stay in `0..1`. No boost bypasses collection, tag, date, category, author, or exclude filters. Query and Ask `--explain` receipts show the base score, factor, bounded contribution, combined cap, final score, rule source, and full ranking-rules fingerprint when a non-neutral rule is active. Status exposes only rule IDs, normalized factors, and that fingerprint; configured prefixes stay private. Boost-only config edits change the ranking fingerprint without requiring document conversion or vector rebuilding. ## Per-collection model overrides Override embed, rerank, expand, or generation models per collection. Example: a code collection on a code embedding model, a notes collection on the preset embed model. ``` collections: code: path: ~/code models: embed: nomic-ai/nomic-embed-code-v1.5 ``` ## Remote model servers Point GNO at an OpenAI-compatible server (Ollama, LM Studio, vLLM) running on another machine. Remote roles receive the query, chunk, or retrieved answer context sent to that role; they do not receive the corpus as a remotely mounted index. ``` models: activePreset: remote presets: - id: remote name: Remote GPU Server embed: http://192.168.1.100:8081/v1/embeddings#qwen3-embedding-0.6b rerank: http://192.168.1.100:8082/v1/completions#qwen3-reranker expand: http://192.168.1.100:8083/v1/chat/completions#gno-expand gen: http://192.168.1.100:8083/v1/chat/completions#qwen3-4b ``` ## Model timeouts and idle grace ``` models: loadTimeout: 60000 inferenceTimeout: 30000 expandContextSize: 2048 warmModelTtl: 300000 ``` Timeout values are integer milliseconds from 1 through 2,147,483,647; zero does not disable either timeout. For local inference, `loadTimeout` bounds dispatched model/context loading and `inferenceTimeout` starts at actual native evaluation, after loading. These independent timers are not added. For HTTP inference, the inference budget covers policy and DNS preparation, fetch, and response-body consumption; local load timeout does not configure the remote server. SDK `deadlineAt` is an absolute Unix epoch time in milliseconds covering queueing, loading, evaluation, and response publication. Caller cancellation or deadline expiry suppresses late success, including lexical fallback. The separate expansion-stage budget can still return a result without expansion; raising a model timeout does not extend that stage budget. `models.warmModelTtl` is the inactivity grace for each native model and its owned child, five minutes by default. Active model work and pending delivery prevent retirement; status and metadata reads do not extend the grace. Background embedding does not keep idle generation or reranking models loaded. The next call after expiry reloads the required models and contexts. A longer grace trades retained native allocations for fewer cold loads; it does not change candidates, precision, or model input text. ## Local model runtime GNO uses `node-llama-cpp` for local GGUF models. The default path uses prebuilt backends only; source builds are opt-in so normal indexing does not unexpectedly require local compiler toolchains. Embedding, generation, and reranking share one owned Bun child per LLM adapter. Command or SDK disposal terminates it; HTTP inference keeps its separate direct adapter path. The npm package and desktop source runtime include the package-relative worker entrypoint. A standalone compiled executable without that source runtime cannot launch native inference and fails explicitly. - `GNO_LLAMA_GPU` — choose `auto`, `true`, `false`, `cuda`, `vulkan`, or `metal`. `NODE_LLAMA_CPP_GPU` remains a compatibility alias when this is unset. - `GNO_LLAMA_BUILD` — backend build mode. Default: `never`. Set `autoAttempt` only when you intentionally want `node-llama-cpp` to try a local source build. - `GNO_LLAMA_INIT_TIMEOUT_MS` — local backend initialization timeout. Default: `30000`. - `GNO_EMBED_CONTEXTS` — override CPU embedding context count, clamped from `1` to `4`. CPU-only runs choose a small adaptive pool automatically: one context on low-memory Windows machines, otherwise at most two contexts unless you explicitly override it. - `GNO_EMBED_THREADS` — override CPU threads per embedding context. - `GNO_EMBED_CONTEXT_SIZE` — override native embedding context size. Minimum: `128`. - `GNO_NO_AUTO_DOWNLOAD` — disable automatic model downloads; explicit `gno models pull` still works. --- # CLI commands > Reference for every gno command, global option, retrieval mode, background service, and integration surface. Section: Reference Canonical: https://gno.sh/docs/cli Markdown: https://gno.sh/docs/cli.md The `gno` CLI indexes local folders into SQLite and runs BM25, vector, hybrid, and cited Ask against that index. Use it to connect folders, build the index, search and ask questions, keep the collection fresh in the background, and wire GNO into AI tools. It is useful from a terminal, but the same commands also power the Web UI, REST API, MCP server, and agent skills. ## Quick chooser Start here when you know what you want to do but not which command to reach for. - `gno setup` — connect the first folder, prove BM25, and optionally install explicit agent handoffs. - `gno search`, `gno vsearch`, `gno query`, `gno ask` — BM25, vector, hybrid, or cited Ask over the local index. - `gno get`, `gno multi-get`, `gno ls` — inspect indexed documents. - `gno capture` — add quick notes with structured provenance and a write/sync/embed receipt. - `gno links`, `gno backlinks`, `gno similar`, `gno graph` — follow relationships. - `gno audit` — inspect links, declared provenance, and source/index freshness without changing the workspace. - `gno trace` with `list`, `show`, `label`, `export`, `replay`, `delete`, or `purge` — manage opt-in private retrieval receipts, explicit relevance feedback, and read-only candidate replay. - `gno serve`, `gno daemon` — run long-lived local services. - `gno peek` — cheap counts, backlog, recent files, and serve status for status bars and desktop widgets. - `gno mcp`, `gno skill`, `gno publish` — connect agents and share snapshots. ## How the CLI thinks 1. **Collections** point at folders on disk: notes, research, PDFs, project docs, client files, or a Karpathy-style personal knowledge base. 2. **Indexing** reads files, extracts text, chunks documents, records links and tags, then embeds chunks for semantic search. 3. **Retrieval** searches with keyword, vector, hybrid, default bounded graph expansion, and optional reranking. 4. **Surfaces** expose the same index through the CLI, browser workspace, REST API, MCP, SDK, and installed skills. ## Setup: verified first retrieval ### gno setup Creates or reuses a collection, indexes it, and succeeds only after an exact `gno://` result. Semantic indexing runs in an independent one-shot process; `--no-semantic` records a truthful skip. Direct setup never attaches to a resident process. ``` gno setup ~/notes --name notes gno setup ~/notes --name notes --exclude .env --exclude private gno setup ~/notes --authorize-secret-risk gno setup ~/notes --no-semantic gno setup . --apply-profile --no-semantic gno setup ~/notes --connector cursor-mcp --connector codex-skill ``` `--exclude` is one repeatable literal pattern, not a CSV. Secret-risk detection fails closed; only interactive confirmation or `--authorize-secret-risk` authorizes likely credentials. Safe-default `--yes`, JSON, non-TTY, decline, and EOF do not. Exit `0` means lexical proof completed, even when semantic or connector follow-up remains. Exit `1` is invalid or safely rejected input. Exit `2` is config, receipt, I/O, store, indexing, proof, or invariant failure. Canonical private state lives under the configured data directory at `setup-receipts//.json` and `setup-semantic//.json`. The lexical receipt is closed before semantic work starts. Semantic identity ignores timestamps, stage tokens, and created/reused disposition, but changes with material folder, index, or activation evidence. One live semantic worker owns that canonical job and PID until exit; reruns cannot replace it, even when options change. `--no-semantic` starts no worker, preserves any live owner, and records skipped intent rather than completed work. Pending or failed receipts keep lexical exit 0 and print an exact foreground `gno ... embed ` resume command. Setup checks for the nearest valid `.gno/index.yml`. By default it only prints an advisory and points to `gno profile diff`; it does not mutate profile-owned config. Pass `--apply-profile` to apply a valid profile before lexical setup. For a valid profile, that option cannot be combined with explicit `--name` or `--exclude`; conflicting input fails before config or index mutation. A missing or invalid profile never makes setup mandatory: normal setup continues, while an explicitly requested apply is reported as a truthful follow-up action. Inspection transport failures abort before apply; failed, incomplete, or unresolvable apply results abort before ordinary setup and connector work. A late apply failure may leave resumable create/update-only state. Without connectors or profile application, JSON is `setup-command-result@1.0`. Connector mode uses `setup-activation-result@1.0` around the unchanged setup result. With `--apply-profile`, the closed `setup-profile-result@1.0` records the profile check, optional apply, setup result, and any connector results. Supported connector IDs: `claude-code-skill`, `claude-desktop-mcp`, `cursor-mcp`, `codex-skill`, `opencode-skill`, `openclaw-skill`, and `hermes-skill`. Skill execution remains `target_runtime_unverifiable`; connector follow-up may be `completed_with_actions` with lexical success intact. Web and Desktop onboarding deliberately use resident collection, sync, model, and connector APIs. They share the lexical-proof semantics but do not proxy this CLI transaction and do not produce or claim its private setup receipts. ## Project profiles: check, show, diff, apply These commands discover the nearest repository-owned `.gno/index.yml`. Discovery stops at the first Git root, filesystem boundary, or filesystem root; a nearer nested profile shadows, rather than merges with, an ancestor profile. Passing a directory or its exact `.gno/index.yml` disables ancestor fallback. ``` gno profile check [path] gno profile show [path] gno profile diff [path] gno profile apply [path] ``` - `check` validates discovery, the closed schema, referenced paths, local model-preset aliases, and offline cache availability when global `--offline` is active. The offline probe never repairs, deletes, or rewrites model-cache files or metadata. - `show` adds normalized, machine-portable desired state. - `diff` compares desired state with user config and reports stale mappings and repair choices without applying them. - `apply` creates or updates declared resources through a resumable locked operation. Omitted and stale same-path resources remain intact, as do unrelated DB-only collections, documents, contexts, and index state. Multiple declared contexts for the same collection are preserved. Changed collections are returned in `pendingIndexing`. Add `--json` for deterministic, path-redacted closed contracts: `project-profile-command@1.0` for check, show, and diff; `project-profile-apply@1.0` for apply. Unknown output fields are not part of either contract. Apply is idempotent and interruption-safe; every config writer reloads and writes through one canonical target-derived cross-process lock, including symlink aliases (including dangling aliases). Local profile provenance keeps repeated apply byte-stable while detecting removal-only edits. Public receipts identify the collection but redact the local profile path, and the apply receipt stays outside the project. Config, data, databases, cache, selected file-backed models, receipts, and locks may not overlap the project root. Apply fails before mutation when that runtime boundary is unsafe. It never writes the tracked profile or indexes documents. ## Advanced setup: init, collection, index ### gno init Creates the first GNO config and points it at a folder. Use it for the first folder in a new index. ``` gno init ~/Documents/Knowledge --name knowledge gno init ~/Notes --name notes --pattern "**/*.md" gno init ~/Research --name research --exclude "**/archive/**" ``` - `--name` sets the collection name used by filters. - `--pattern`, `--include`, and `--exclude` decide which files enter the index. - `--update` records a collection-specific update command, useful for git-backed or generated folders. - `--tokenizer` and `--language` tune text processing for specialized collections. ### gno collection Adds, lists, renames, removes, or resets collection embeddings after the initial setup. ``` gno collection add ~/Downloads/Papers --name papers gno collection list gno collection rename papers reading gno collection clear-embeddings notes gno collection remove old-notes ``` ### gno index, update, embed `update` scans files into SQLite. `embed` creates vectors for semantic search. `index` does both. ``` gno update gno update --git-pull gno embed notes gno index gno index --models-pull gno index --no-embed gno index --lock-wait 5m ``` - `--git-pull` pulls git-backed collections before scanning. - `--models-pull` downloads needed model files before the run. - `--no-embed` builds a fast keyword-only index. - Concurrent writers queue on the shared write lease (default wait 120s; `--lock-wait` to change, `--no-wait` to fail fast). Contention past the wait exits 4 — contention, not corruption. Reads are unaffected. - `gno embed` and `gno embed --force` retry transient embedding chunk failures inside the same command run. Use `--verbose` when a run still fails so the sample errors and retry hint are visible. - Run `gno embed` after changing embedding models or after doctor reports stale vectors. If stale or mixed vectors remain, run `gno embed --force` for a full vector refresh. Restoring identical bytes at the same path reactivates an inactive document on the next successful `update` or `index`. Activation and one `reactivate` journal event commit together; repeated unchanged syncs add no restoration events. Unchanged canonical chunks and proven formatted embedding inputs keep their vectors. Changed titles, text, or actual model/runtime identity require matching embedding coverage. `gno embed` validates current input identity, resumes completed checkpoints, and repairs missing vector-index materialization from stored variants where possible. Owner backlog counts are not counts of native calls: identical inputs may share work. After an exact-input partition activates, missing identity or a corrupt variant index fails semantically instead of restoring legacy authority. Run normal `gno embed` first; use `--force` for an intentional full refresh. ## Retrieve: search, vsearch, query, ask ### gno search and gno vsearch `search` is exact and fast. Use it for titles, names, quotes, filenames, error messages, and identifiers. `vsearch` is semantic. Use it when the right documents may use different words than your query. ``` gno search "spaced repetition" --collection notes gno search "ERR_INVALID_STATE" --line-numbers gno search --query-file /run/user/1000/gno-recall/q.XXXX --json printf '%s' "auth" | gno search --query-file - --json gno vsearch "notes about memory and learning loops" --limit 10 ``` - `--query-file ` reads the query from a file (`-` is stdin) so desktop callers can keep it off argv. Do not also pass a positional query. - Scope with `--collection`, `--limit`, `--min-score`, `--since`, `--until`, `--tags-any`, `--tags-all`. - Change output with `--full`, `--line-numbers`, `--json`, `--md`, `--csv`, `--files`, `--xml`. Structured `--json` results include `results[].source.absPath` when the hit is a resolvable file-backed document. There is no `--source` flag. If `absPath` is absent, show the URI tail and do not offer file-open for that row. Default snippets skip a leading YAML frontmatter fence and prefer document prose. When the FTS window is frontmatter-dominated, GNO falls back to stripped chunk prose. `line` and `snippetRange.startLine` follow that trimmed display range. `--full` and `--line-numbers` still emit the raw source. This display cleaning applies to `gno search`, `gno vsearch`, and `gno query`. Local CLI retrieval uses the canonical repository or worktree for the current directory as a bounded soft signal. When the nearest local `.gno/index.yml` is valid, its canonical root and affinity defaults replace that cwd-derived fallback for the request; the profile does not mutate the user’s global affinity config. A matching collection can receive at most `+0.03`. Pass repeatable `--project-root ` values to replace the profile or cwd-derived root. The user config’s `projectAffinity.enabled` setting controls only cwd fallback; explicit roots and valid profiles retain their higher precedence. Use `--no-project-affinity` to disable every source for one request. Invalid and missing profiles fall back normally. Roots never stack; collection, tag, date, exclude, and egress filters stay hard. Explain output exposes only redacted collection and root aliases. Trusted local diagnose uses a closed `schemaVersion: "1.1"` response with required redacted affinity metadata, including `project_profile` as the source when the profile supplied the request-local root, and unmatched state. Absent, disabled, and remote/untrusted diagnose requests keep exact legacy v1.0 bytes and omit `affinity`. Supported collection/path scope, tags, modified-date bounds, category, author, exclusions, visibility, and managed-memory filters select eligible owners before the corresponding candidate limit. Vector and hybrid retrieval also filter chunk language before their budgets; standalone lexical `--lang` remains reserved. Whole-document exclusions inspect all chunks, including other languages. Score thresholds, deduplication, and available evidence can still yield fewer than `--limit` results, including zero. ### gno query Hybrid retrieval for normal use. It combines keyword, vector, fusion, default bounded graph expansion, and optional reranking. Disable the graph stage only when you explicitly want a graph-free path. ``` gno query "what did I decide about backups?" gno query --query-file /run/user/1000/gno-recall/q.XXXX --json gno query "papers about retrieval evaluation" --tags-any research gno query "pricing notes" --fast gno query "architecture tradeoffs" --thorough --explain gno query "linked context" --explain gno query "pure vector/lexical" --no-graph gno query $'auth flow\nterm: "refresh token"\nintent: token rotation' ``` - `--fast` lowers latency. `--thorough` spends more time for better recall. - Graph expansion resolves outgoing wiki/markdown links and backlinks touching the top seeds, then adds those one-hop neighbors as candidates. Semantic similarity stays in vector retrieval, so the query does not rebuild the collection graph. It is on by default;` --no-graph` and `--fast` skip it. `--no-expand` and `--no-rerank` disable pipeline stages for debugging or speed. - `--query-file` is the same as on `gno search`. It is invalid with a positional query and invalid on `query diagnose`. - `--intent`, `--query-mode`, `--candidate-limit`, and `--explain` steer or inspect retrieval. One configured `contentTypes[].searchBoost` may contribute at most `±0.05` and composes with trusted local project affinity under a shared `±0.08` cap. BM25 and vector only adjust candidates that already survived retrieval and `minScore`. Hybrid adds the composed auxiliary score to normalized fusion before rerank blending, so rerank order and lexical top-hit protection remain authoritative. The signal cannot create a candidate or bypass hard filters. `--explain` reports the base score, factor, bounded contribution, final score, rule source, and ranking fingerprint when active. ### gno ask Retrieves evidence and optionally asks a local model to synthesize a cited answer. Use it for questions over your notes, not for general chatbot use. ``` gno ask "what are my open migration risks?" --answer gno ask "who owns the launch decision?" --verify gno ask "summarize my latest meeting notes" --since "last week" gno ask "what did I save about local-first apps?" --show-sources ``` - `--answer` forces synthesis. `--no-answer` returns retrieval results only. - `--verify` implies answer generation, compiles a closed Context Capsule, and classifies every substantive claim as `supported`, `contradicted`, `insufficient`, or `uncertain`. It withholds the draft unless support reaches 100%. - Verified output retains exact evidence IDs, line ranges, and source, mirror, and passage hashes. Missing or stale evidence, unavailable semantic verification, and degraded retrieval capabilities stay explicit. - `--max-answer-tokens` controls answer length. - `--show-sources` keeps citations visible. ## Context Capsules and saved freshness Compile one deterministic, token-budgeted evidence bundle, verify a saved bundle without rebuilding it, or explicitly register a caller-owned Capsule file for resident freshness checks: ``` gno context build "compare launch proposals" --budget 12000 --json --output capsule.json gno context verify capsule.json --json gno context watch capsule.json --question "Who owns launch?" --notify --json gno context watches --json gno context reverify --json gno context unwatch ``` Watch lifecycle commands are CLI-only and scoped to the Capsule's canonical index. GNO stores bounded metadata and evidence hashes—not Capsule or passage bytes—and never rewrites the saved file. Completed work stores the same canonical, non-generative verification receipt; a failed operation has no receipt. Manual reverification still renders that structured failure, including its code and message, then exits nonzero so scripts cannot mistake it for a successful receipt. Local notifications contain only registration/Capsule identity, operation status, affected-question state, and timestamp. ## Knowledge Delta Read bounded metadata-only change history, one retained structural diff, or explainable inbound dependency paths: ``` gno changes --since 2026-07-20T00:00:00Z --json gno diff gno://notes/plan.md --json gno impact gno://notes/plan.md --max-depth 3 --max-edges 250 --json ``` Change IDs and cursors are opaque. Journal retention can expire old cursors; GNO reports partial, expired, or unavailable history instead of reconstructing source bodies. Impact traversal always enforces depth, node, edge, frontier, and visited-row bounds. ## Private retrieval receipts With `retrievalTraces.enabled: true`, successful search, query, ask, get, and Context Capsule calls print `Trace: ` to stderr. Stdout and structured payloads remain unchanged. Continue a retrieval-only receipt by passing the ID to an exact read: ``` gno query "deployment decision" gno get gno://work/decisions/deploy.md --from 40 --limit 20 --trace-id ``` Terminal replay-mode receipts with explicit labels can become content-free qrels and a verified local replay baseline: ``` gno trace export --format qrels --output qrels.json gno trace replay --candidate hybrid --md ``` Replay checks the aggregate manifest and immutable evidence hashes, then compares rank, coverage, capability fallbacks, and source freshness. It can recommend promotion but always returns `applied: false`; it never edits ranking configuration, models, prompts, traces, or source files. ## Read: get, multi-get, ls, tags ### gno get and gno multi-get Search results return `gno://` URIs, paths, doc IDs, and line anchors. Use the read commands to pull the exact source into a terminal, script, or AI prompt after retrieval. Structured search, vector, query, and ask results may also include `context`: user-configured guidance resolved for that exact `uri` and `docid`. Matching guidance composes global first, collection second, then path prefixes from broadest to most specific. It guides interpretation without changing ranking. ``` gno get gno://notes/learning.md gno get gno://notes/learning.md --from 40 --limit 30 gno multi-get gno://notes/a.md gno://notes/b.md --max-bytes 12000 ``` - `--from` and `--limit` fetch bounded line ranges. - `--line-numbers` preserves citation-friendly anchors. - `--source`, `--json`, `--md`, `--files` control output shape. ### gno ls, tags, status, doctor Use these when results look wrong. First check whether the document is indexed, then inspect tags and health. ``` gno ls --collection notes gno tags gno status --json gno doctor ``` `gno doctor` includes an `embedding-fingerprint` check. In JSON output, that check carries an `embeddingFingerprint` object with `currentFingerprint`, `pendingChunks`, `legacyChunks`, `mixedGroups`, and `groups`. Warnings mean BM25 still works, but semantic results may need `gno embed` or `gno embed --force`. Doctor and status also expose collection-scoped retrieval activation. Lexical readiness comes from a corpus-derived local search that must return the expected indexed document; it does not wait for semantic models. Semantic state is reported independently and may remain pending or skipped. Connector rows come only from fingerprint-current receipts created by the explicit Web connector verification action. If the bounded connector projection is truncated, omitted target/collection pairs have no result and overall connector health remains non-green. ### gno peek Cheap read-only snapshot of index counts, backlog, recent files, and whether detached serve is up. One invocation; no model or embedding initialization. Use it instead of composing `gno status` + `gno ls` + `gno changes`. Keep `gno status` for activation, onboarding, and the full health payload. Status bars and desktop widgets can poll it on a coarse interval. GNO Recall (`omarchy plugin add https://github.com/gmickel/omarchy-gno-recall`) uses this snapshot from the Omarchy bar. ``` gno peek gno peek --json ``` Uninitialized is success: `--json` returns `initialized: false` with pinned nulls and `recent: []`, exit 0. JSON is `peek@1.0`. `recent` is at most 10 files, newest first. `recent[].absPath` is the path to open a recent file without `gno get`. `serve.running` is pid-file based and is true only for `gno serve --detach`. A foreground `gno serve` is not detected. A stale pid reports not running. There is no HTTP probe. Any subquery failure is an atomic `RUNTIME` envelope (exit 2). Peek never emits a half-filled snapshot. ``` { "schemaVersion": "peek@1.0", "initialized": true, "counts": { "documents": 1234, "collections": 5 }, "backlog": { "pending": 0, "failed": 0 }, "lastIndexedAt": "2026-08-29T09:00:00Z", "recent": [ { "docid": "#abc123", "uri": "gno://notes/inbox.md", "title": "Inbox", "collection": "notes", "absPath": "/home/user/notes/inbox.md", "modifiedAt": "2026-08-29T08:55:00Z" } ], "serve": { "running": true, "url": "http://localhost:3000" } } ``` When `serve.running` is true, open a document in the Web UI with the frozen template `{serveUrl}/doc?uri=` (`serve.url` plus document URI; optional `#anchor`). See [document deep links](https://gno.sh/docs/web-ui#section-links). ### gno capture Capture writes a note into an editable collection. Inline content,`--stdin`, and `--file` are mutually exclusive. Capture accepts text only; binary-like file or stdin content is rejected before writing. With no path, folder, or title, captures land under `inbox/YYYY-MM-DD/capture-.md` using UTC time. ``` gno capture "thought to remember" gno capture --stdin --collection notes --preset source-summary --tags inbox,gno gno capture --file ./clip.md --source-url https://example.com --source-kind web --json gno capture --preset person --title "Jane Doe" --folder people/ gno capture --preset meeting --title "Weekly sync" --folder meetings/ gno capture "meeting note" --quiet ``` Preset IDs include `blank`, `project-note`, `research-note`, `decision-note`, `prompt-pattern`, `source-summary`, `idea-original`, `person`, `company-project`, and `meeting`. The typed second-brain presets keep current synthesis above `## Timeline` and dated evidence below it. JSON output returns a receipt with separate write, sync, and embed status. Capture syncs the note into text search; it does not imply embedding unless `embed.status` is `completed`. Capture writes fail instead of replacing a late-arriving file. ## Relationships: links, backlinks, similar, graph ### gno links, backlinks, similar These commands answer “what does this note point to?”, “what points back?”, and “what is semantically nearby?”. ``` gno links gno://notes/llm-memory.md gno backlinks gno://notes/llm-memory.md gno similar gno://notes/llm-memory.md --limit 8 ``` ### gno graph Builds a document graph from wiki links, markdown links, backlinks, unresolved links, and optional similarity edges. Use it to find hubs, isolated notes, communities, nearest neighbors, and paths between ideas. ``` gno graph --collection notes --json gno graph --neighbors gno://notes/llm-memory.md gno graph --from gno://notes/a.md --to gno://notes/b.md gno graph --include-similar --threshold 0.78 gno graph --dot > graph.dot gno graph --mermaid ``` - Scope with `--collection`, `--limit`, `--edge-limit`, `--include-isolated`. - Add semantic edges with `--include-similar`, `--threshold`, `--similar-top-k`. - Explore locally with `--neighbors`, `--direction`, `--from`, `--to`, `--max-depth`. Sync repairs affected incoming graph references across collections, including changed target identities and ambiguous names. An unchanged sync with a complete current projection skips broad mirror reads and identical edge writes; missing or interrupted inventory uses full reconciliation. Query-time graph expansion does not rebuild this inventory. No separate graph-rebuild command is needed. ## Services: serve and daemon ### gno serve Starts the local browser workspace and REST API. Use it when you want visual search, browsing, graph exploration, editing, or API access. Default serve is the production bundle; `--dev` enables the development bundle with HMR. ``` gno serve gno serve --dev gno serve --port 8080 gno serve --detach gno serve --status --json gno serve --stop ``` ### gno daemon Runs the headless watch/sync/embed loop plus the resident MCP gateway at `/mcp`. Use it when your CLI and AI tools need fresh search results but you do not need the browser open. Exact eligible file events always use content-hash synchronization. Atomic-save temp names, directory events, missing filenames, and recursive deletions use bounded filesystem/index reconciliation with durable retries. Only proven candidates and removals are applied; unsupported anchored handles or bounded overflow safely escalate to full collection sync. These guarantees cover supported local filesystems, not every network or removable volume. The resident also coalesces settled document-journal changes and reverifies affected saved Context Capsules in one bounded serial drain. Its durable high-water mark prevents duplicate work after restart; cursor expiry triggers one conservative bounded pass. Reverification writes no source or Capsule files and invokes no answer-generation model. ``` gno daemon --detach gno daemon --no-sync-on-start gno daemon --status gno daemon --stop ``` Lifecycle flags for both commands: `--detach`, `--status`, `--stop`, `--pid-file`, `--log-file`. `--json` is for `--status`. Serve and daemon are alternative owners of one resident index: a second process against the same data directory is rejected. Direct CLI commands own and dispose their native child for the command lifetime; they do not attach to the resident. Serve/daemon load native models lazily and reuse them only within the [idle grace](https://gno.sh/docs/configuration#model-timeouts). Cold first and post-idle requests include startup, model load, and context creation. Native failure is structured and never replayed automatically; a later explicit request can acquire a fresh child. Hybrid fallback reports whether vector retrieval actually succeeded. Resident shutdown uses one shared five-second drain, five-second abort-settlement phase, and at most one second to confirm forced owned-child exit. Completed checkpoints survive; unfinished embeddings remain pending for restart. See [the shutdown boundary](https://gno.sh/docs/architecture#resident) for event-loop, SQLite, and OS limits. ## Agents, models, publishing, and maintenance ### gno mcp and gno skill Use MCP when you want AI clients to call GNO tools automatically. Use skills when you want explicit `/gno` lookups with low context overhead. ``` gno mcp install --target claude-desktop gno mcp install --target cursor --scope project gno skill install --target all --scope user --force gno skill paths ``` ### gno agents Install a versioned GNO protocol block into each detected harness's global instruction file (Claude Code, Codex, Cursor, OpenCode, Hermes, OpenClaw; Grok is covered via Claude) so agents know the retrieval ladder before they reach for the skill. Backup-first, idempotent, symlink-aware; `--dry-run` shows the diff and `--extra-dir` handles nonstandard layouts. Exit 1 on malformed markers or an outdated block, 2 when a file cannot be read or written; on failure the complete block is printed for manual use. ``` gno agents install gno agents install --target claude --dry-run gno agents install --extra-dir ~/.claude-instances/work-cli gno agents verify --json gno agents update gno agents uninstall ``` ### models, publish, bench, cleanup These are supporting commands for model files, shared artifacts, retrieval evaluation, and housekeeping. ``` gno models list gno models use balanced gno models pull gno publish export atlas --out ~/Downloads/atlas.json gno bench fixture.json --modes bm25,hybrid --json gno cleanup gno completion zsh ``` ## Global options and output flags Global options work before the command name. Output flags are repeated on retrieval and read commands where they make sense. - `--index ` — use a named index instead of `default`. - `--config ` — load a specific config file. - `--offline` — use cached model files only. - `--json`, `--md`, `--csv`, `--files`, `--xml` — structured output. - `--verbose`, `--quiet`, `--no-color`, `--no-pager`, `--yes` — terminal and automation behavior. Long terminal output honors `$PAGER`. Without an override, GNO uses `less -R` on Unix and a built-in less-compatible pager on Windows, including backward scrolling and search. Use `--no-pager` for automation or direct output. --- # Packaging proof > How GNO proves the npm tarball users install contains the runtime files and doctor contract needed for release. Section: Reference Canonical: https://gno.sh/docs/packaging Markdown: https://gno.sh/docs/packaging.md The supported CLI distribution is the npm package installed through Bun. Before a release is published, GNO verifies the actual packed tarball instead of only testing the repository checkout. ## Local package smoke ``` bun run test:package ``` This command runs `scripts/package-smoke.ts`. It calls `npm pack`, installs from the generated npm tarball into isolated temporary `HOME`, `GNO_*`, npm cache, and npm prefix paths, then runs the packaged binary. ## Packed file proof The smoke checks the package allowlist and required runtime files. The required file proof includes `package.json`, `bunfig.toml`, `src/index.ts`, `src/sdk/index.ts`, `src/embed/retry.ts`, `src/serve/public/globals.built.css`, and `THIRD_PARTY_NOTICES.md`. Native inference also requires the packaged `src/llm/native-worker/entry.ts` entrypoint and a real Bun executable. The package runs source; a standalone compiled executable without that runtime fails explicitly instead of recursively starting itself. ## GNO 2.0 dependency boundary GNO 2.0 pins node-llama-cpp 3.20.0 and retains simulator initialization-failure cleanup and joined disposal beyond the upstream fix. Repository installs use Bun 1.4.2 for the lockfile; the declared consumer range remains Bun 1.3.0 or newer. AI SDK 6 remains maintained; SDK 7, TypeScript 7, Vitest 5, lint-stack, and Electrobun migrations are separate work. Unchanged upstream MarkItDown and Officeparser distributions ship under `vendor`, with corrected ordinary runtime dependency edges including SheetJS 0.20.3 and PDF.js 6.3.289. The recorded clean npm and Bun consumer installs resolved those parsers, converted XLSX/PPTX/PDF fixtures, and reported zero production advisories. Root-only overrides are not the consumer fix. Converter fingerprints advance, so cached conversions follow the new identities; there is no new parser toggle. See the [frozen release acceptance](https://github.com/gmickel/gno/blob/d450098db32934328e969e85723edc75467b9a96/.flow/artifacts/fn-154-gno-20-release-dependency-sweep-and/release-acceptance.md) for package, native, and browser evidence and retained failures. These receipts prove their pinned workloads, not universal performance or an installed registry version. ## Packaged CLI proof The release gate requires the installed tarball binary to pass `gno --version`, `gno --help`, verified `gno setup`, and `gno doctor --json` from the isolated install. Setup proves exact lexical evidence, idempotent reruns, closed receipts, stable semantic identity, live PID ownership, no-semantic non-replacement, all seven connector IDs, malformed-config recovery, and standalone semantic scheduling beside a live resident without changing resident admission, jobs, model, transport, reader, or generation counters. The doctor assertion is exact: output must include the `embedding-fingerprint` check and an `embeddingFingerprint` payload with `currentFingerprint`, `pendingChunks`, `legacyChunks`, `mixedGroups`, and `groups`. This proves the packaged install exposes the same embedding freshness contract as the repository build. --- # Web UI > The local browser workspace started by gno serve: search, browse, graph, edit, capture, API, and live indexing. Section: Reference Canonical: https://gno.sh/docs/web-ui Markdown: https://gno.sh/docs/web-ui.md `gno serve` is the loopback browser workspace: add folders, watch indexing, search, ask, browse, inspect the graph, and edit Markdown. `gno serve` binds loopback; the index, models, and edits stay in the local GNO data directory. ## What this is - **Workspace** — a dashboard, document browser, search UI, ask UI, graph, editor, collections screen, and connector setup. - **Local API server** — the same process exposes `/api/*` for scripts and internal tools. - **Live indexer** — while the workspace is running, file changes are watched and synced so recent notes become searchable. ## Launch and manage ``` gno serve # foreground, http://localhost:3000 gno serve --dev # development bundle with HMR gno serve --port 8080 # custom port gno serve --index research # named index gno serve --detach # background; prints pid + url gno serve --status --json # machine-readable status gno serve --stop # graceful stop ``` - Default `gno serve` is the production bundle (split chunks, prebuilt snapshot, no bundler wait at startup). `--dev` is the development/HMR switch; it does not apply to `--status` or `--stop`, and a detached child inherits the parent’s mode. - `--port` changes the browser/API port. - `--detach`, `--status`, `--stop`, `--pid-file`, and `--log-file` use the same lifecycle contract as `gno daemon`. - Use `gno daemon` instead when you want background indexing and resident MCP without the browser or full REST API. - Foreground Ctrl+C and SIGTERM wait for the HTTP server, background runtime, and SQLite handles to close before exit. ## Live refresh and status performance Exact watcher paths use content hashing. Ambiguous atomic-save, directory, missing-name, and recursive-delete events reconcile a bounded dirty scope against filesystem/index evidence, without routinely resyncing untouched siblings. Failure retains work; unsupported anchored handles or bounded overflow escalate to full collection sync. Graph reconciliation follows affected incoming references across collections; a complete unchanged projection avoids broad mirror reads and identical edge writes. Missing or interrupted inventory uses full recovery. Status queries use set-based aggregation, concurrent requests share one in-flight build, and the dashboard reuses that response for model readiness without keeping a stale cache. Production home loads a small split first JavaScript file; non-home routes lazy-load, and syntax-highlighting grammars, the PDF viewer, and graph libraries stay off that first file. Measured localhost cold-cache nearest-rank P95 first paint of home chrome is at most 200ms, and time to first interaction is at most 1s. Filled Dashboard health data is not part of either bar. Leaving the indexing view aborts its status polling and suppresses stale callbacks. Returning starts one polling loop. An accepted server indexing job keeps running after navigation or the accepting request disconnects; browser cleanup does not cancel server or native work. ## Workspace pages - **Dashboard** — first-run checklist, health center, lexical activation proof, independent semantic state, model download state, document counts, indexing state, and quick capture. - **Search** — BM25, vector, and hybrid retrieval with filters for collection, date, category, author, tags, intent, and query modes. - **Ask** — cited Q\&A over your local documents. Good for “what did I decide?” and “summarize these meeting notes” workflows. The optional **Verify** control builds a closed Context Capsule, shows per-claim verdicts and exact evidence spans, and withholds drafts below complete support. - **Browse** — cross-collection tree with folder detail panes and document quick switching. - **Doc View / Editor** — rendered document view, split-view Markdown editor, live preview, frontmatter metadata, heading outline with readable `#anchor` deep links, optional citation links with a bounded durable `st` selector, wiki-link autocomplete, presets, and safe editing rules. Rename and same-collection move show a complete reference-impact preview, then rewrite supported wiki and Markdown destinations in the same all-or-rollback filesystem transaction as the file move. - **Graph** — interactive network of wiki links, markdown links, backlinks, unresolved links, and similarity edges. - **Collections and Connectors** — add folders, reindex, tune collection settings, install agent integrations, and explicitly run a read-only retrieval check for installed MCP targets. Skill runtimes stay marked unverifiable because file installation alone cannot prove that a client consumed the skill. ## Quick capture Press `N` to capture a note into an editable collection. The basic path is still title plus content; open **Source** only when you want provenance fields such as kind, URL, author, observed time, or external id. Choose a preset when you want a scaffold; `idea-original`, `person`, `company-project`, and `meeting` are tuned for second-brain pages. Quick Capture writes structured `source:` frontmatter and shows the same receipt states as CLI, MCP, REST, and SDK capture: write result, FTS sync, and embedding. FTS sync may be pending, skipped, or failed independently from the file write. Embedding stays separate until you run embed or index. The typed presets use the same synthesis/timeline pattern as CLI capture: current assessment above `## Timeline`, raw notes and dated evidence below it. If `contentTypes` rules are configured, matching preset frontmatter or folder prefixes become `contentType` metadata in JSON search/query results. ## Readable anchors vs durable section targets Document outline **Copy link** stays human-readable: `/doc?uri=…#anchor`. The frozen integration template is `{serveUrl}/doc?uri=`, with an optional `#anchor`. `gno peek --json` exposes `serve.url` for that construction when detached serve is up. Older bookmarks keep working. Optional **Copy citation link** adds a versioned, size-bounded `st` query param with quote/context evidence for local recovery after heading edits. Citation links never embed a full section body and are not a public sharing format. Opening a citation link resolves conservatively through the shared core: exact and uniquely recovered targets navigate to the current anchor and show a short status; ambiguous, stale, missing, or invalid selectors never navigate and never silently cite a different section. Quick Switcher section jumps continue to use readable anchors only. ## Search and ask controls The Web UI exposes the same retrieval controls as the CLI. Use exact search for names and phrases, vector search for conceptual matches, hybrid for normal research, and the Ask page when you want a grounded answer with citations. Turn on **Verify** for the closed-Capsule path. Its expandable receipt shows supported, contradicted, insufficient, and uncertain claims, evidence gaps, and unavailable or degraded verifier state without dumping the entire Capsule into the page. Browser requests do not infer a filesystem project root. The Web UI therefore keeps project affinity at zero; use the local CLI when a trusted cwd or explicit project root should act as a bounded soft ranking signal. Configured content-type boosts still apply across Web, REST, MCP, SDK, and CLI retrieval. One matched rule contributes at most `±0.05`, cannot widen candidate retrieval or defer `minScore`, and cannot bypass collection, tag, date, category, author, or exclude filters. Hybrid applies the composed auxiliary score to normalized fusion before rerank blending. ``` term: "spaced repetition" intent: personal knowledge base learning loop hyde: A note explaining how repeated review turns saved notes into long-term memory. ``` ## Private trace history Trace history is a local, opt-in evidence ledger. The Web page lists metadata-only summaries, opens one bounded detail receipt, accepts explicit relevant, irrelevant, or missing-expected labels, exports selected terminal traces, and confirms per-trace deletion or full purge. Open, completed, partial, failed, and cancelled remain visibly distinct; GNO never treats a missing click or failed request as negative feedback. Qrels export retains only explicit judgments, canonical identities, exact line/hash provenance, ranks, capabilities, and outcomes. It never copies source or converted mirror text. Candidate replay fails closed when its saved manifest, linked receipt, or source hash has changed, and reports unchanged, stale, missing, inactive, or unindexed evidence state. ## Safe editing model Markdown and plain text stay editable. Converted binaries (PDF, DOCX, XLSX, PPTX) and logical export records stay read-only. Edit or regenerate the source export, or use **Create editable copy** in the doc view to spawn a markdown note with source provenance intact. ## Native PDF viewer PDFs stay read-only. **Pages** renders the original PDF with an aligned selectable text layer, page navigation, zoom, fit-width, fit-page, and **Download original**. A **Pages / Text** toggle keeps the indexed extracted text one click away. Rendering remains local and offline-first. GNO serves PDF.js, its worker, character maps, standard fonts, and the original document bytes from the same loopback origin. Long documents stay responsive because only pages near the viewport receive live canvases. If rendering fails and extracted text is available, GNO switches to Text and names the reason: corrupt file, password protection, network failure, or viewer bootstrap failure. Without extracted text, Pages keeps the designed error card with retry and download actions; selecting Text manually shows the explicit no-extracted-text state. Printing is not built in. Download the original and print it from a PDF reader. Page, zoom, fit mode, and Pages/Text choice reset when you leave the document. ## Keyboard shortcuts - `Cmd/Ctrl+K` — command palette and quick switcher - `N` — quick capture a new note - `/` — focus search - `T` — cycle search depth - `?` — shortcut reference ## Next steps - [Keep a collection fresh](https://gno.sh/docs/how-to#keep-fresh) - [REST API reference](https://gno.sh/docs/api) - [CLI serve and daemon reference](https://gno.sh/docs/cli#services) --- # REST API > HTTP endpoints exposed by gno serve for search, documents, graph data, models, jobs, and workspace automation. Section: Reference Canonical: https://gno.sh/docs/api Markdown: https://gno.sh/docs/api.md The REST API is the HTTP version of the local GNO engine. Start it with `gno serve`, then call `/api/*` from curl, scripts, desktop launchers, internal dashboards, or small apps. It is best when you want automation without embedding the SDK or installing an MCP client. ## What this is - **Search API** — BM25, vector, hybrid query, and cited ask endpoints. - **Workspace API** — documents, folders, collections, tags, links, graph, note presets, content-type metadata, and autocomplete. - **Operations API** — status, sync, jobs, model pull status, and connector detection. ## Launch the server ``` gno serve # default port 3000 gno serve --port 8080 gno serve --detach # browser workspace + API in background ``` ## Request lifetime and admission Disconnecting a REST query or Ask request propagates cancellation through retrieval, expansion, generation, and verification. Late success and successful fallback are suppressed. HTTP inference aborts its fetch; native generation receives an evaluation abort. Active noncooperative embedding or reranking keeps its capacity until actual settlement or controlled child exit. Cancellation never replays work. These are request-lifetime controls, not new JSON body fields. Accepted asynchronous jobs own a separate lifetime after job-ID delivery and survive normal initiating-request disconnect. Explicit job cancellation or resident shutdown stops subsequent work. Completed checkpoints remain durable and unfinished embedding work stays pending. Reader admission transfers released slots directly to queued readers; a canceled grant transfers or releases its slot once, preserving capacity. A full resident reader queue returns HTTP 429 `RATE_LIMITED`; unavailable or shutting-down resident admission returns HTTP 503 `UNAVAILABLE`. Retry as a new explicit request when capacity or service is available. See [shared shutdown bounds](https://gno.sh/docs/architecture#resident). ## Read endpoints - `GET /api/health` — process liveness only. A successful response does not claim that retrieval is ready. - `GET /api/status` — index stats, collection health, model state, background watcher state, onboarding state, and the shared`activation` object. Use `activation` for collection readiness: lexical proof, independent semantic state, persisted connector evidence, and projection completeness. - `GET /api/capabilities` — feature availability for the active install. - `GET /api/collections`, `GET /api/tags`, `GET /api/docs`, `GET /api/doc` — enumerate and fetch local content. - `GET /api/doc-asset` — stream original source bytes for a document. It supports `HEAD` and one HTTP `Range` request with `200`, `206`, or `416` responses; the native PDF viewer uses it for progressive same-origin loading and Download original. - `GET /api/doc/:id/sections` — extracted heading outline (anchor, level, line, title). Compatible with Web UI readable `#anchor` links and SDK `getSections()`. - `POST /api/doc/:id/section-targets` and `POST /api/doc/:id/section-targets/resolve` — create or conservatively resolve a durable `SectionTargetV1`. Exact and recovered responses include citation lines; ambiguous, stale, and missing omit citation and must not be navigated or cited. - `GET /api/doc/:id/links`, `GET /api/doc/:id/backlinks`, `GET /api/doc/:id/similar`, `GET /api/graph` — graph and relationship data. - `GET /api/events` — server-sent document change events for live UIs. - `GET /api/traces`, `GET /api/traces/:traceId`, and loopback-only mutation routes — inspect, label, export, delete, or purge private local retrieval receipts. Status is passive for connectors and models: it does not start MCP children, initialize or download models, or call remote inference. Connector evidence is a bounded projection of saved verification receipts. When `connectorProjection.truncated` is true, omitted target/collection pairs have no implied result and must not be treated as passed. Status also projects `contentTypeBoost.rules` as rule IDs plus normalized factors and `contentTypeBoost.rulesFingerprint` as the full ranking fingerprint. It never exposes configured path prefixes. ``` curl localhost:3000/api/doc-asset?uri=gno://notes/papers/spec.pdf \ -H 'Range: bytes=0-65535' -o spec.part.pdf ``` The pinned PDF.js worker, character maps, and standard fonts are also served same-origin under `/vendor/pdfjs/*`. Package-root containment and fixed file-type allowlists reject traversal and unknown assets; no CDN is involved. Model-file resolution, downloads, and native loading wait until first inference. Stored validated dimensions let an existing vector index start without loading its model; a new index discovers dimensions on first vector use. Capability flags describe configured functionality, not loaded weights. Native model counts are cached child lifecycle snapshots, not GPU-memory readings. Metadata polling does not prevent five-minute default idle retirement; later inference reloads lazily. ## Search endpoints ``` curl -X POST localhost:3000/api/search -d '{"query":"exact term"}' curl -X POST localhost:3000/api/vsearch -d '{"query":"concept"}' curl -X POST localhost:3000/api/query -d '{"query":"research question"}' curl -X POST localhost:3000/api/ask -d '{"query":"what changed?"}' curl -X POST localhost:3000/api/ask \ -H 'content-type: application/json' \ -d '{"query":"Who owns the launch decision?","verify":true}' ``` Search bodies mirror the CLI: `collection`, `limit`, `since`, `until`, `category`, `author`, `intent`, `exclude`, `tagsAny`, `tagsAll`, and mode-specific controls such as `noExpand`, `noRerank`, `candidateLimit`, and `queryModes`. Supported owner filters apply before the corresponding candidate budget. Vector and hybrid language filtering selects matching chunks; standalone lexical language remains reserved. Caller scope intersects filters, and an empty allowlist denies all. Excluded owners cannot consume the nearest-neighbor window, but score thresholds, deduplication, or limited eligible coverage can still produce short or empty results. Query/Ask evidence and generation budgets are unchanged. Exact-input vector partitions bind each eligible current owner to its formatted title/text and actual model/runtime identity. Same-body documents with different titles can have different vector ranks. Interrupted backfill retains legacy authority until initial atomic activation; later missing identity or a missing/corrupt active variant index is a semantic failure. Normal `gno embed` completes or repairs coverage. Hybrid fallback reports `meta.vectorsUsed: false` if no vector search succeeded and `meta.mode: "bm25_only"` for wholly lexical retrieval. A successful vector search with no matches can report `vectorsUsed: true`. Native reload failure is not a semantic no-match; preserve fallback diagnostics and use an explicit later request after recovery. Search results include `source.absPath` when the hit is a resolvable file-backed document. If `absPath` is absent, show the URI tail and do not offer file-open for that row. Default snippets skip leading YAML frontmatter and prefer document prose. A frontmatter-dominated FTS window falls back to stripped chunk prose. `line` follows that trimmed display range. The Web UI document page is a separate surface: `/doc?uri=`, not `GET /api/doc`. Retrieval bodies may include up to 16 `projectHints`. These values are opaque and untrusted: the server does not resolve or reflect them, does not probe the filesystem, and currently applies zero affinity. Omitting or supplying the field preserves the existing response contract exactly. In particular, REST diagnose stays on the closed `query-diagnose@1.0` shape and omits `affinity`; the affinity-bearing v1.1 branch is reserved for trusted local CLI diagnose. `POST /api/ask` keeps the existing raw Ask behavior when `verify` is absent or false. With `"verify": true`, it generates from one closed Context Capsule and returns the Capsule, freshness receipt, four-state per-claim verdicts, exact evidence IDs and line spans, coverage, gaps, semantic verifier state, and explicit abstention. The verified Ask body is closed: unknown fields fail validation. Every substantive claim must be supported for the draft to be returned. Otherwise the response withholds it and reports `answerStatus: "abstained"`. A contradiction requires positive conflicting evidence; missing evidence is `insufficient`, not contradicted. Unavailable or failed semantic verification remains visible rather than silently falling back to an unverified answer. ``` curl localhost:3000/api/query \ -H 'content-type: application/json' \ -d '{ "query": "authentication", "collection": "notes", "limit": 20, "tagsAny": ["security"] }' ``` ## Context Capsules `POST /api/context` compiles exact indexed evidence for one goal into a deterministic Capsule. The active server supplies the canonical index. The budget covers the complete payload—not each document separately—and the result includes exact URI/line spans, source and passage hashes, coverage gaps, omission counts, and requested capability fallbacks. It is returned to the caller and is not persisted. Tag filters are normalized, lowercased, deduplicated, and validated before retrieval. Result and candidate limits stay global across multi-collection requests: result admission is capped after the merged rank, while rerank and graph work is distributed deterministically in canonical collection order. ``` curl localhost:3000/api/context \ -H 'content-type: application/json' \ -d '{"goal":"Compare launch proposals","collections":["work"],"budgetTokens":12000, "depthPolicy":"fast"}' ``` `POST /api/context/verify` accepts a complete saved Capsule and returns a read-only receipt classifying evidence as unchanged, stale, or missing, with independent fingerprint and ranking state. Index mismatch and malformed Capsules fail before evidence reads. Add `"format":"md"` for the trust-delimited readable projection. Each untrusted block uses a collision-resistant Markdown fence derived from its content, so indexed text cannot forge the closing boundary. JSON is canonical by default. Context API errors are deliberate: invalid input, filters, budgets, or identity return `400`; no evidence returns `404`; source, index, context, mutation, and provenance conflicts return `409`; tokenizer unavailability returns `503`; retrieval, load, snapshot, and runtime failures return `500`. Error messages come from a fixed public catalog; internal paths, causes, and stack traces are not returned. ## Knowledge Delta ``` GET /api/changes?since=&collection=notes&limit=100 GET /api/diff?ref=&change= GET /api/impact?ref=&maxDepth=3&maxNodes=100&maxEdges=250 ``` These read-only endpoints share the CLI, MCP, and SDK contracts. Changes contain bounded identity, hash, lifecycle, and structural metadata—not source bodies. Diff discloses partial, expired, or unavailable retained history. Impact returns one bounded evidence path per dependent document. Saved-Capsule registration management remains CLI-only. The local `/api/events` stream can emit a closed `capsule-reverified` event after persistence, but never a question, label, path, URI, hash, receipt, credential, Capsule, passage, or source content. Restoring an identical source at its former path reactivates it during successful sync and commits one `reactivate` change with that transition. Unchanged syncs add no repeated restoration history. Graph repair includes affected incoming references outside the changed collection. The journal remains metadata-only with existing retention and partial-history semantics. ## Write and job endpoints - `POST /api/collections` and `DELETE /api/collections/:name` — add or remove indexed folders. - `POST /api/sync` — trigger reindexing from the browser or an automation. - `POST /api/capture` — capture a note with structured provenance, optional preset scaffolds, and a receipt that separates write, sync, and embed state. - `POST /api/docs`, `PUT /api/docs/:id`, `POST /api/docs/:id/refactor-plan`, `POST /api/docs/:id/rename`, `POST /api/docs/:id/move`, `POST /api/docs/:id/duplicate`, `POST /api/docs/:id/deactivate` — create and manage editable documents. - `POST /api/folders` — create a folder inside a collection. - `POST /api/models/pull`, `GET /api/models/status`, `GET /api/jobs/active`, `GET /api/jobs/:id` — model downloads and long-running job polling. - `GET /api/connectors` — inspect configured integration targets without starting them. `POST /api/connectors/verify` — explicitly run one read-only, collection-scoped retrieval proof for an installed MCP target. Reference-safe rename and move are deliberately two-step. Preview returns the canonical `file-refactor-preview@1.0` plan, including every examined reference, `canApply`, and a deterministic SHA-256 `planDigest`. Apply requires that exact digest, `schemaVersion: "1.0"`, and `confirmation: "apply"`. Current state is replanned before mutation, so stale, ambiguous, malformed, unsupported, read-only, occupied, and cross-collection plans fail closed. `applied_with_sync_pending` means the filesystem committed and only the later index refresh needs Update All; it is not a failed file move. ``` curl localhost:3000/api/connectors/verify \ -H 'content-type: application/json' \ -d '{"connectorId":"cursor-mcp","collection":"notes"}' ``` Connector verification is active only when this endpoint or the Web Connectors action is invoked. It does not edit client configuration. Skill targets return an explicit runtime-unverifiable result because GNO cannot prove that the client loaded or executed an installed skill file. Use `/api/capture` for second-brain capture with `source:` frontmatter and presets such as `person`, `company-project`, `meeting`, or `idea-original`. Use `/api/docs` for raw note creation without provenance capture semantics. REST capture starts an async sync job, so receipts usually return `sync.status` as `pending` with a job id. Capture content must be text, `/api/capture` does not accept legacy `overwrite`, and capture writes fail instead of replacing a late-arriving file. ## Security model - **Loopback only.** `gno serve` binds the API to the local loopback interface. The API token does not turn it into a remotely reachable server. - **CSRF protection.** Mutating browser requests need a same-origin local origin or an API token. - **Optional token.** Set `GNO_API_TOKEN` and send `X-GNO-Token` from non-browser clients. ``` export GNO_API_TOKEN="secret" gno serve curl -H "X-GNO-Token: secret" localhost:3000/api/status ``` --- # SDK > Import GNO directly into a Bun or TypeScript app with createGnoClient and the same local retrieval engine. Section: Reference Canonical: https://gno.sh/docs/sdk Markdown: https://gno.sh/docs/sdk.md The SDK is for apps that want GNO in-process. Use it when a local Bun or TypeScript app needs search, retrieval, document access, indexing, or graph navigation without shelling out to `gno` or running `gno serve`. ## What this is - Same retrieval core as CLI, Web UI, API, and MCP. - Direct control over config, database path, download policy, and lifecycle. - Best for local apps, research tooling, desktop shells, and private automation where HTTP is unnecessary. ## Install ``` bun add @gmickel/gno ``` ## Basic usage ``` import { createDefaultConfig, createGnoClient } from "@gmickel/gno" const config = createDefaultConfig() config.collections = [{ name: "notes", path: "/Users/me/notes", pattern: "**/*", include: [], exclude: [], }] const client = await createGnoClient({ config, dbPath: "/tmp/gno-sdk.sqlite", }) try { await client.index({ noEmbed: true }) const results = await client.search("authentication") for (const hit of results.results) { console.log(hit.uri, hit.score) } } finally { await client.close() } ``` The client owns indexing, policy, and stores in-process. Local GGUF embedding, generation, and reranking share one owned Bun child per adapter. Always close the client in `finally`; direct adapter owners call `LlmAdapter.dispose()`. Warm reuse ends at the five-minute default inactivity grace. The next inference reloads models and contexts; metadata calls do not keep them warm. HTTP inference uses the direct adapter path. A structured native failure is never replayed automatically; a later explicit call may acquire a fresh child. ## Cancellation and deadlines `search`, `vsearch`, `query`, and `ask` accept `signal?: AbortSignal` and `deadlineAt?: number` in their options. The deadline is an absolute Unix epoch time in milliseconds spanning admission, queueing, loading, evaluation, and publication. Nested retrieval and verification cannot relax it. Caller abort uses `INFERENCE_FAILED` with an `AbortError` cause; expiry uses `TIMEOUT` with a `TimeoutError` cause. Late success and fallback success are suppressed, while native capacity stays owned until settlement or controlled child exit. Supported owner filters apply before candidate budgets, including matching-language chunks for vector/hybrid retrieval. Short or empty results are valid. Hybrid fallback diagnostics distinguish unavailable semantic work from successful vector retrieval with no matches. Ask keeps its existing evidence, context, and generation budgets. Native embedding ports verify model artifacts, dimensions, effective context/truncation policy, and runtime identity. This metadata belongs to the child generation and must refresh after retirement. HTTP or custom ports may omit verified identity; an activated exact-input partition cannot be reused under an unverified or different identity. This is port metadata, not an additional `GnoClient` method. ## Client APIs - `client.search(query, opts?)` — BM25 keyword search for exact words, phrases, filenames, and identifiers. - `client.vsearch(query, opts?)` — vector similarity for conceptual matches. - `client.query(query, opts?)` — hybrid retrieval with expansion, default bounded graph candidates, fusion, and reranking controls. Pass `{ graph: false }` to skip graph expansion or `{ explain: true }` for a retrieval scoring receipt. - `client.ask(question, opts?)` — retrieval-only or cited answer generation. Pass `{ verify: true }` for the closed-Capsule claim-verification path and `{ explain: true }` for the same retrieval scoring receipt. - `client.get(ref)` and `client.multiGet(refs)` — fetch indexed documents by URI, doc ID, or path. - `client.getSections(ref)` — heading outline for a document. Readable anchors stay compatible with the Web UI. - `client.createSectionTarget(ref, selector)` and `client.resolveSectionTarget(ref, target)` — durable section locators with the same fail-closed citation semantics as REST and MCP. Prefer ordinary get/search for default retrieval. - `client.links(ref)`, `client.backlinks(ref)`, `client.similar(ref)` — navigate direct and semantic relationships. - `client.list()` and `client.status()` — inspect document inventory and index health. - `client.capture(input)` — write a note with provenance and an optional `presetId`, then return the same capture receipt shape as CLI, API, and MCP. Content is text-only, collision policies are runtime-validated, legacy `overwrite` is not accepted, and writes fail on late-arriving files. - `client.previewRenameNote()` / `client.previewMoveNote()`, followed by `client.renameNote()` / `client.moveNote()` — inspect a canonical impact plan, then apply only its exact version, digest, and confirmation. Supported reference edits and the source move share one all-or-rollback filesystem boundary. - `client.update()`, `client.embed()`, `client.index()` — sync files, embed chunks, or do both. - `client.close()` — release file handles and SQLite connections. Retrieval options may include up to 16 `projectHints`. SDK hints are opaque and untrusted, are never resolved or reflected, never trigger filesystem access, and currently have zero ranking effect. Leaving the option absent preserves existing results exactly. ``` const verified = await client.ask("Who owns the launch decision?", { verify: true, contextBudgetTokens: 12_000, }) if (verified.verification?.claims.answerStatus === "abstained") { console.log(verified.verification.claims.abstentionReason) } ``` Verified SDK results use the same contract as CLI, REST, MCP, and Web: the closed Capsule and freshness receipt, exact evidence IDs, lines, and hashes, four-state claim verdicts, 100% support threshold, and explicit semantic-verifier degradation. Raw `client.ask()` behavior remains compatible when `verify` is not true. Indexed URIs such as `gno://notes/plan.md?index=research` select and read that named database, even when the client was created for another index. Missing indexes fail without being created. Keep each `multiGet()` batch on one index. When private retrieval tracing is enabled, search, query, ask, get, and Context Capsule results carry a non-enumerable `RETRIEVAL_TRACE_METADATA` symbol. It exposes the local receipt ID without changing JSON output. Read it with `getRetrievalTraceMetadata(result)`, then pass `traceId` to `client.get()` to record the exact opened line range against an open query receipt. ``` const receipt = await client.capture({ collection: "notes", title: "Customer call", content: "Follow up on renewal timeline.", presetId: "meeting", tags: ["customer", "follow-up"], source: { kind: "meeting", title: "Customer call", }, }) console.log(receipt.uri, receipt.contentHash) ``` ``` const plan = await client.previewRenameNote({ ref: "gno://notes/old-note.md", name: "new-note.md", }) if (plan.canApply) { const result = await client.renameNote({ ref: "gno://notes/old-note.md", name: "new-note.md", schemaVersion: plan.schemaVersion, planDigest: plan.planDigest, confirmation: "apply", }) console.log(result.status) } ``` ## Configuration patterns Define collections in code when your app owns the workspace, or point at an existing GNO config when the user already has one. ``` const fromExisting = await createGnoClient({ configPath: "/Users/me/Library/Application Support/gno/config/index.yml", }) const noDownloads = await createGnoClient({ config, downloadPolicy: { offline: false, allowDownload: false }, }) ``` ## Lifecycle Always call `await client.close()` when your process is shutting down. After close, further calls throw a GNO SDK error. This matters for desktop apps, tests, and short-lived automations because the SDK holds SQLite connections and file handles. --- # MCP integration > Install GNO automatically as a local MCP server for exactly 10 named clients; configure Raycast and other compatible clients manually. Section: Reference Canonical: https://gno.sh/docs/mcp Markdown: https://gno.sh/docs/mcp.md GNO’s MCP server exposes search, get, Context Capsule, and related tools over the local SQLite index. Claude, Cursor, Codex, and the other named install targets call those tools against the local index. `gno_ask` generates locally only when the caller sets `verify: true`. ## What this is - **Read tools** — search, vector search, hybrid query, deterministic Context Capsules, opt-in verified Ask, document fetch, Knowledge Delta reads, scoped memory recall, tags, status, egress checks, links, backlinks, similar docs, graph exploration, integrity audits, and job inspection. There are 34 read-only tools by default; the opt-in `core` profile advertises 7 of them, selected at runtime with `gno mcp --tool-profile core` or once per client with `gno mcp install --target --tool-profile core`. - **Write tools** — capture notes, remember facts, add/remove collections, sync, embed, index, workspace edits, egress policy changes, and private-trace mutations. All 19 are disabled by default, for 53 tools total when explicitly enabled; the `core` profile adds only `gno_capture` and `gno_remember`. - **Resources** — documents addressable as `gno://` URIs for precise follow-up reads. ## Install ``` gno mcp install --target claude-desktop gno mcp install --target claude-code gno mcp install --target cursor gno mcp install --target codex gno mcp install --target zed gno mcp install --target windsurf gno mcp install --target opencode gno mcp install --target amp gno mcp install --target lmstudio gno mcp install --target librechat --scope project gno mcp status ``` These are the 10 automatic targets. Raycast is MCP-compatible but has no `gno mcp install --target raycast` path; add the GNO MCP command manually in Raycast instead. Default scope is user-level when the client supports it. Use `--scope project` for project-local configuration in clients such as Claude Code, Cursor, Codex, OpenCode, and LibreChat. Restart the client after install. ## Installed configuration - GNO records the absolute Bun executable and the entrypoint inside the package that performed the install. It does not depend on a desktop client finding `gno` on `PATH`, nor does it invoke `bunx` later. - The active `--index` and absolute `--config` path are included in the server arguments. Absolute `GNO_DATA_DIR` and `GNO_CACHE_DIR` roots are included as `env` for standard MCP clients and as `environment` for OpenCode. - Codex uses its official `~/.codex/config.toml` at user scope and `.codex/config.toml` at project scope. OpenCode uses its canonical `opencode.json` or existing `opencode.jsonc`. LibreChat installation is project-only and writes the project’s `librechat.yaml`. These workspace environment fields are deliberately narrow: only the absolute data and cache roots are accepted. Extra environment keys, relative paths, control characters, and unsupported execution fields fail closed. ## Server command - `gno mcp` or `gno mcp serve` — run the stdio MCP server directly. - `gno mcp install` — write the selected client config. - `gno mcp uninstall` — remove GNO from a client config. - `gno mcp status` — inspect configured targets. - `--enable-write` or `GNO_MCP_ENABLE_WRITE=1` — allow mutating tools. Installed stdio commands are standalone processes. Their adapter owns its native child and disposes it when the server ends; they do not automatically attach to a running daemon. The absolute Bun executable and package-entry installer contract above remains unchanged. ## Resident HTTP gateway `gno serve` and `gno daemon` expose the same stateful Streamable HTTP MCP endpoint at `http://127.0.0.1:3000/mcp`. Each client session is isolated while the resident process reuses its store, job runtime, and adapter model lifecycle. Models load lazily; warm reuse lasts only until their idle grace expires (five minutes by default), and the next inference reloads. Metadata calls do not renew that grace. The stdio `gno mcp` command remains supported; existing client configurations do not require a migration. - `gno serve` is always loopback-only because it also exposes the browser and full REST API. - Only `gno daemon` accepts an explicit non-loopback bind, and only with a restrictive bearer-token file plus exact Host and Origin allowlists. - Bearer authentication never grants write access. Mutating MCP tools still require the separate `--mcp-enable-write` option. - `/api/resident/status` and `serve|daemon --status --json` expose only redacted lifecycle and capacity data—never paths, tokens, queries, content, or caller identity. Full `/api/status` includes local index and configuration details, so a daemon serves it only on loopback. MCP protocol cancellation and transport disconnect propagate through participating inference stages and suppress late results or successful fallback. Active noncooperative native work retains its lease and capacity until settlement or controlled child exit. Queued operations are not replayed on a replacement child; retry explicitly after a structured failure. Accepted asynchronous jobs survive the initiating transport closing after job-ID delivery and stop subsequent work on explicit job cancellation or resident shutdown. Resident HTTP boundary errors retain HTTP 429 for rate, request, queue, or session pressure and HTTP 503 for shutdown, revoked credentials, or unavailable runtime. Authentication and write/egress checks remain separate. No native queue or turn-size option is added. ## Verification Status surfaces are passive and never launch a connector child. `gno mcp status` reports configuration presence; `gno status`, `gno doctor`, and `/api/status` can report saved verification receipts. To prove a connector works now, open Web **Connectors** and run its explicit read-only verification action. GNO launches the configured command, checks its tools and status, and proves collection-scoped retrieval. A cached receipt is evidence from its recorded run, not a fresh probe. Search-tool candidate budgets apply after supported collection/path, tag, date, author, category, exclusion, visibility, and memory owner filters. Vector and hybrid retrieval select matching-language chunks; standalone lexical language remains reserved. Caller scope intersects filters and empty allowlists deny all. Score thresholds, deduplication, and limited eligible coverage may still return fewer than the limit. Hybrid `vectorsUsed` is true only if a vector search succeeded, even when it found no matches; wholly lexical fallback reports `mode: "bm25_only"`. Native failure must not be described as a semantic no-match. ## Tool playbook Read-tool inputs may include up to 16 `projectHints`. MCP treats them as opaque, untrusted values: no path resolution, filesystem probing, reflection, or ranking contribution occurs. Leaving the field absent preserves the existing tool result contract. - `gno_context` — compile one deterministic, token-budgeted evidence Capsule with exact line spans, provenance, coverage gaps, omissions, and capability fallbacks. Use `gno_context_verify` before reusing a saved Capsule. GNO never saves Capsules implicitly. - `gno_changes`, `gno_diff`, and `gno_impact` — read bounded metadata-only history, retained structural diffs, and explainable dependency paths. These are read-only and share the CLI, REST, and SDK contracts. - `gno_ask` — generate from one closed Context Capsule and verify every substantive claim against exact retained spans. The input object is closed and requires literal `verify: true`. It reports supported, contradicted, insufficient, and uncertain claims; drafts below 100% support are withheld. This is read-only and does not grant trace or corpus mutation authority. - `gno_query` — default for most questions. Hybrid retrieval returns URIs, snippets, scores, line anchors, and optional `context` guidance. Default snippets skip leading YAML frontmatter and prefer document prose. - `gno_search` — exact phrases, titles, identifiers, and error strings. File-backed hits include `source.absPath`. - `gno_vsearch` — conceptual matches where wording may differ. - `gno_get` and `gno_multi_get` — retrieve exact context after search. Prefer bounded line ranges when available. - `gno_section` — create or resolve a durable `SectionTargetV1` when citation identity matters after edits. Not the default retrieval path. Follow exact/recovered citation lines with the tool's ready-to-use `gno_get` guidance (`fromLine = lineStart`; `lineCount = lineEnd - lineStart + 1`); never cite ambiguous, stale, or missing results. - `gno_links`, `gno_backlinks`, `gno_similar`, `gno_graph`, `gno_graph_neighbors`, `gno_graph_path` — navigate relationship context. - `gno_peek` — cheap `peek@1.0` snapshot (counts, backlog, 10 recents with `docid` and `absPath`, pid-file serve detection). Same payload as `gno peek --json`. `serve.running` is true only for `gno serve --detach`. - `gno_status`, `gno_list_tags`, `gno_job_status`, `gno_list_jobs` — diagnose what exists or inspect async work. - `gno_capture`, `gno_sync`, `gno_embed`, `gno_index`, `gno_add_collection`, `gno_remove_collection`, `gno_rename_note`, and `gno_move_note` — write-enabled operations. Verified Ask is evidence verification, not a universal fact-check or factual guarantee. It judges a generated draft only against the exact evidence retained in the supplied local Capsule. It cannot establish facts absent from the indexed corpus or prove that the source material itself is correct. `gno_context` sends the model one compact, versioned `gno-context-agent-v1` JSON projection with exact evidence, title/heading metadata, configured-guidance bindings, egress state, gaps, fingerprints, active-token accounting, budget state, and omission totals. Guidance and evidence stay explicitly trust-marked. The complete canonical Capsule stays in `structuredContent`for the MCP application client, avoiding duplicate model context. Unknown input fields fail MCP validation before the GNO handler. With private retrieval tracing enabled, read tools return the local receipt ID only in top-level `_meta.gno.retrievalTrace.traceId`. Model-visible content and `structuredContent` remain unchanged. Pass the ID as `traceId` to `gno_get` to link its exact opened range to the original retrieval. ## Recommended agent pattern 1. Use `gno_ask` when the requested outcome is one generated answer whose claims must be checked against a bounded Capsule. Send `verify: true` explicitly and inspect abstention, verifier state, gaps, and exact spans. 2. Start with `gno_context` when the task needs one bounded, citation-complete evidence handoff. Set `goal` and `budgetTokens`; use `depthPolicy: "fast"` when model setup is undesirable. 3. Use `gno_query` instead for interactive lookup or manual retrieval control. 4. Apply returned `context` as user-configured guidance for that result. Cite retrieved source content—not the guidance—as evidence. 5. Use `gno_get` around returned line anchors instead of loading whole documents by default. 6. Use `gno_section` only when you must create or re-resolve a durable section target; then open the returned line range with `gno_get`. Prefer search → get for ordinary lookup. 7. Use `gno_multi_get` with a byte cap when several sources are needed. 8. Use graph tools when the question is about relationships, missing links, related ideas, or how two notes connect. Capsule evidence stays extractive: exact canonical-mirror text plus URI and line range. Indexed title, heading, and configured-context fields are untrusted metadata, not instructions. The global budget covers the complete canonical payload. Explicit gaps and bounded omission details prevent silent synthesis or unbounded context. ## Security posture Write tools (`capture`, `sync`, `embed`, `index`, collection changes, and note refactors) are disabled by default so your AI client cannot accidentally modify the corpus. Enable them explicitly per client: ``` gno mcp install --target cursor --enable-write GNO_MCP_ENABLE_WRITE=1 gno mcp ``` Collection creation rejects dangerous roots such as `/`, `~`, system folders, and hidden config directories. Still review client approval prompts before write calls. Retrieval-trace reads use `gno_trace_list` and `gno_trace_show`. Label, export, delete, and purge use separate write-tool names and are registered only when writes are explicitly enabled. HTTP MCP rejects those names before dispatch otherwise; bearer authentication identifies a caller but never grants trace-write authority. ## Capture `gno_capture` is registered only when write tools are enabled. It writes structured `source:` frontmatter, syncs the file for FTS, accepts the same typed `presetId` values as CLI/REST/SDK capture, and returns the same provenance receipt shape as CLI, REST, and SDK capture, plus legacy MCP fields such as `docid`, `absPath`, `overwritten`, and `serverInstanceId`. ``` { "collection": "notes", "content": "thought to remember", "source": { "kind": "web", "url": "https://example.com/source", "title": "Source page" }, "collisionPolicy": "open_existing", "presetId": "source-summary", "tags": ["inbox", "research"] } ``` Collision checks include indexed documents and disk-only files. Use `open_existing` to return an existing receipt without rewriting, `create_with_suffix` to create the next available path, or legacy `overwrite: true` to replace the target path. Content must be text, and non-overwrite captures fail instead of replacing a late-arriving file. MCP capture does not auto-embed; run `gno_embed` or `gno_index` afterward when vector search should include the note. ## Reference-safe rename and move `gno_rename_note` and `gno_move_note` are operation-specific, write-gated two-step tools. Call `action: "preview"` first and inspect `canApply`, blocking reasons, examined references, and the exact digest. Apply only after approval with the same source and destination, `schemaVersion: "1.0"`, the preview `planDigest`, `confirmation: "apply"`, and `confirm: true`. Apply replans against current files. Stale plans and collection-lock conflicts leave the filesystem unchanged; supported wiki and Markdown references commit atomically with the source move. If the receipt is `applied_with_sync_pending`, do not repeat the mutation: run `gno_sync` or `gno_index` to converge the index. Duplicate and create-folder do not retarget backlinks. Tool annotations are approval hints, never authorization. ## Resource URIs GNO exposes every document as an MCP resource, so clients can fetch a file by URI without going through a tool call. Indexed URIs select the named database for resources and read tools; missing indexes fail without creating an empty database. Split mixed-index `gno_multi_get` batches by index. ``` gno://notes/projects/plan.md gno://notes/projects/plan.md?index=research ``` ## Related - [Agent skills reference](https://gno.sh/docs/skills) - [Connect your AI tools](https://gno.sh/docs/how-to#connect-ai) --- # Agent skills > Install GNO as a progressive agent skill for Claude Code, Codex, OpenCode, OpenClaw, Hermes Agent, and compatible clients. Section: Reference Canonical: https://gno.sh/docs/skills Markdown: https://gno.sh/docs/skills.md GNO skills teach agents how to use the `gno` CLI without permanently loading a large tool schema into their context. Use them for explicit `/gno` lookups from Claude Code, Codex, OpenCode, OpenClaw, Hermes Agent, and other skill-capable clients. ## What this is - **Progressive instructions** — the agent discovers the GNO workflow only when you invoke the skill or ask for local knowledge retrieval. - **CLI-backed** — skill commands call the installed `gno` binary, so results match the terminal. - Ask the agent to run `/gno` over notes, project docs, PDFs, or meeting notes before it answers. - **Second-brain recipes** — installed playbooks route agents through lookup, capture, meetings, email context, source summaries, ideas, and citation/provenance workflows. ## Install ``` gno skill install --scope user # Claude Code default gno skill install --target codex --scope user gno skill install --target opencode --scope user gno skill install --target openclaw --scope user gno skill install --target hermes --scope user gno skill install --target all --scope user --force ``` - `--target` — `claude`, `codex`, `opencode`, `openclaw`, `hermes`, or `all`. - `--scope` — `user` for every project or `project` for the current repo. - `--force` — overwrite an existing installed copy after upgrading GNO. ## Skill management commands - `gno skill install` — copy the bundled skill into the selected target. - `gno skill uninstall` — remove it. - `gno skill show` — preview the generated skill files. - `gno skill show --file recipes/brain-first-lookup.md` — preview a nested recipe playbook. - `gno skill paths` — show target install locations. ## Using the skill ``` /gno search "deployment checklist" /gno query "what did I save about spaced repetition?" /gno ask "summarize my notes on local-first software" /gno graph --neighbors gno://notes/llm-memory.md ``` Natural language works too: “search my notes for the latest pricing decision,” “find related docs before you edit this file,” or “use GNO to retrieve my notes about this client.” ## Second-brain recipes Recipes are agent-facing guidance files, not native connectors. Email, calendar, chat, and web material must be user-supplied or exported unless a separate tool provides it. ``` gno skill show --file recipes/brain-first-lookup.md gno skill show --file recipes/capture-and-file.md gno skill show --file recipes/meeting-ingestion.md gno skill show --file recipes/email-context.md gno skill show --file recipes/source-summary.md gno skill show --file recipes/idea-capture.md gno skill show --file recipes/citation-and-provenance.md ``` Write-flavored recipes include provenance, privacy, prompt-injection handling, and post-write verification with `gno index`, `gno embed`, `gno search`, `gno query`, or `gno get`. ## Instruction block: teach every agent the retrieval ladder A skill only helps once the agent decides to call it. `gno agents install` writes one compact, versioned GNO protocol block into the global instruction file of every harness detected on the machine (Claude Code's `~/.claude/CLAUDE.md`, Codex's `~/.codex/AGENTS.md`, Cursor's `~/AGENTS.md`, OpenCode, Hermes, OpenClaw; Grok Build is covered through its Claude import). The block teaches the retrieval ladder, the writing contract, gno:// citations, and points at the `/gno` skill. Everything outside its markers is yours and stays byte-identical. ``` gno agents install # every detected harness gno agents install --dry-run # unified diff, writes nothing gno agents install --extra-dir ~/.claude-instances/work-cli gno agents verify # exactly one block, version + hash current gno agents update # after a gno upgrade gno agents uninstall ``` Backup-first (`.gno-agents.bak.`), atomic, idempotent, symlink-aware, and never guesses: nonstandard layouts use the repeatable `--extra-dir` flag. If a file cannot be updated (malformed markers, not UTF-8, unwritable), the command prints the complete block so you can paste it yourself. - Use **skills** for explicit slash-command lookups and low context overhead. - Use **MCP** when you want the AI client to automatically call tools during conversation. - Installing both is normal: skills for direct control, MCP for deeper agent integration. --- # Agent instructions > gno agents install keeps one versioned, marker-managed GNO protocol block in the global instruction file of every harness on the machine: the harness matrix with its evidence, what the markers and the version stamp guarantee, and what the block teaches. Section: Reference Canonical: https://gno.sh/docs/agents-install Markdown: https://gno.sh/docs/agents-install.md An agent uses GNO when its instruction file tells it how, and a hand-pasted paragraph falls behind the CLI it describes. `gno agents install` writes one compact protocol block, bounded by stable markers and stamped with a version and a content hash, into the global (user-scope) instruction file of every harness it detects. `verify` compares the stamp against the installed release, `update` replaces an older block in place, and `uninstall` removes block and markers. Everything outside the markers is yours and stays byte-identical. The block is a knowledge protocol you configure, not a note-taking convention: it names the commands and their order, and it names no collection, no path, and no folder layout. Which collections exist, which scopes memory uses, and which harnesses receive the block are your settings. ``` gno agents install # every harness detected on this machine gno agents verify # deterministic per-target checks gno agents update # refresh after a gno upgrade gno agents uninstall # remove block and markers # every verb: --target , --extra-dir (repeatable), --json # install, update, uninstall: --dry-run prints a unified diff and writes nothing ``` ## Harness matrix: who reads which file Detection is the presence of the harness's standard config directory. Only documented locations are discovered; nonstandard and multi-instance layouts are served by `--extra-dir`. | Harness | Target id | Global instruction file | Detected by | Notes | | ------------ | ---------- | --------------------------------- | ----------------------- | ------------------------------------------------------------------------------------------------------- | | Claude Code | `claude` | `~/.claude/CLAUDE.md` | `~/.claude` | Honors `CLAUDE_CONFIG_DIR` when set. | | Codex | `codex` | `~/.codex/AGENTS.md` | `~/.codex` | Honors `CODEX_HOME` when set. | | Cursor Agent | `cursor` | `~/AGENTS.md` | `~/.cursor` | The CLI discovers `AGENTS.md` walking from the working directory toward home. | | OpenCode | `opencode` | `~/.config/opencode/AGENTS.md` | `~/.config/opencode` | | | Grok Build | `grok` | imports the Claude global file | `~/.grok` | `grok inspect` shows the import; the installer reports `covered via claude` and writes no second block. | | Hermes Agent | `hermes` | `~/.hermes/SOUL.md` | `~/.hermes` | A marker-managed block inside your own SOUL.md. | | OpenClaw | `openclaw` | `~/.openclaw/workspace/AGENTS.md` | `~/.openclaw/workspace` | Existing workspaces only. | ### Evidence behind the matrix - **File locations and fresh-session behavior:** a hand-managed reference deployment across three hosts and all seven harnesses (2026-09). In each harness a fresh session asked for its loaded knowledge protocol described the GNO retrieval ladder. That deployment decided the matrix; the installer generalizes it. - **The installer itself:** the release test suite runs the real CLI against an isolated home with every harness directory present: fresh install, idempotent re-run, `verify`, in-place migration of an older block, and an uninstall that leaves the file byte-identical, hash-checked. The same suite covers the Grok import chain, `--extra-dir`, symlinked files, a UTF-8 BOM with CRLF content, refusal of a file that is not valid UTF-8, malformed markers, and an unwritable target. The live verification of the shipped installer ran in that isolated home, not against an operator's production instruction files. - **Hermes Agent and OpenClaw:** the memory adapters (separate from the block) were verified live: the Hermes provider against Hermes v0.20.5 on a real host, the OpenClaw plugin against OpenClaw 2026.8.1 in an isolated sandbox workspace. See [Memory: adapters](https://gno.sh/docs/memory#adapters). Import-chain dedupe is data in the matrix (Grok to Claude today), so a future chain is one more row in the matrix. ## Markers and the version stamp ``` ...ladder + writing contract... ``` - **Markers are stable across versions.** `` and `` never change once shipped, so a block installed by any release is found by every later one. - **The stamp carries the content version and a hash.** The block body is static: identical on every machine, with no filesystem paths. A block is current exactly when its stamp version matches the installed release and the hash matches its body. At v3 the body is 1,491 characters, under the 1,500-character budget the test suite enforces. - **Owned block only.** Install, update, and uninstall touch the text between the markers and nothing else. A fresh install appends the block after one blank line; uninstall removes the block and that blank line. Edits inside the markers are overwritten on the next update; your conventions live outside them. - **Malformed markers fail closed.** Zero or one of each marker is a clean state; any other count, or an END before a BEGIN, is an error with guidance. The installer never guesses or repairs. ### What verify reports `gno agents verify` is deterministic: exactly one marker block per target, stamp version and hash equal to the installed release. Per target it reports one of `ok`, `outdated` (older version or a body that no longer matches its hash), `missing` (no file or no block), `malformed`, `error` (the file could not be read), `covered` (another target owns the same file, via an import chain or a shared real file), or `not-detected`. Exit code 1 on any `outdated`, `missing`, or `malformed` target; exit 2 when the only failures are unreadable files. Install and update report per-target actions the same way: `install`, `update`, `current`, `covered`, `not-detected`, `error`; uninstall reports `remove` or `absent`. A behavioral check stays a manual operator practice: after installing, start a fresh session in each harness and ask for the loaded knowledge protocol. The agent should describe the GNO retrieval ladder. Verification in this release is deterministic only. ## Installer guarantees - **Backup-first, atomic.** An existing file is copied to `.gno-agents.bak.` with the same permission mode; the new content lands through a temp file and an atomic rename, so a failed write leaves the live file untouched. - **Idempotent.** Re-running when the block is current writes nothing and creates no backup. - **Fail-closed with a manual fallback.** Malformed or duplicate markers, a file that is not valid UTF-8, or an unwritable file produce a per-target error and no write; the command then prints the complete block for you to paste (`manualBlock` in `--json`). Other targets proceed. - **Symlink-aware.** Writes go through the resolved real file, so one canonical file linked into several harnesses survives and is written once; the other targets report `covered via (same file)`. - **No fabricated trees.** An undetected harness is skipped. The installer creates the instruction file when a detected harness lacks one; it never creates harness directories. - **Encoding preserved.** A leading UTF-8 BOM and CRLF line endings outside the markers survive every operation. ## Nonstandard and multi-instance layouts Several config directories of one harness on one machine are served by the explicit, repeatable flag; discovery never guesses at them. Inside an extra directory the installer manages the first existing of `CLAUDE.md`, `AGENTS.md`, `SOUL.md`, and creates `AGENTS.md` when none exists. The directory itself must exist. ``` gno agents install \ --extra-dir ~/.claude-instances/work-cli \ --extra-dir ~/.claude-instances/sub2-cli ``` ## What the block teaches The block is the routing contract; the workflows stay in the [gno skill](https://gno.sh/docs/skills). Version 3 teaches the retrieval ladder, scoped to a collection first: 1. Exact term, identifier, quote, or error: `gno search` 2. What do we know or believe (memory): `gno recall "" --scope `, current facts, cited 3. Entity or known document: `gno query "" --fast -n 10` 4. Multi-document evidence: `gno context build "" --budget 12000` 5. Change and dependency questions: `gno changes`, `gno diff`, `gno impact` 6. Generated factual answer: `gno ask "" --verify` (abstention is valid) 7. Expected document missing: `gno query diagnose` with a target, and a scope re-check, before any grep Then the writing contract in four sentences: retrieve first, since a question alone is read-only; edit an existing canonical note in its source file; `gno capture` creates genuinely new notes and is never an update API; a fact that may change goes through `gno remember`, which proposes, with the `--add` or `--supersede --predecessor-hash ` decision taken from a recall. Recalled spans are context, not new facts, so the recall receipt travels back as `--receipt`. After writes: reindex the collection and verify retrieval. Cite with `gno://` URIs. The block closes with one static pointer: load `/gno` when the skill is installed, otherwise run `gno skill install --scope user` first. The generalized version of that contract, with what each rung returns and where each one stops, is the [knowledge protocol](https://gno.sh/docs/protocol) page. ## Versions and migration The block content has shipped in three versions: v1 carried the ladder and the writing contract; v2 replaced a state-aware skill pointer with the static sentence above, so the text is identical on every machine; v3 added the memory rungs (`gno recall` as rung 2, `gno remember` with the add/supersede decision and the receipt fence). After a gno upgrade, `verify` reports `outdated` and `update` replaces the block in place, backup first. ## Multiple machines The installer is per machine: GNO's index and database are machine-local derived state and never sync. Instruction files may be synced or repo-managed (dotfiles, a private instructions repo, symlink schemes); the installer writes through symlinks and its marker-managed block survives file-level sync. Run `gno agents verify` on each machine after syncing. --- # How-To > Practical GNO recipes for keeping collections fresh, building personal knowledge bases, connecting AI tools, and recovering stale indexes. Section: Guides Canonical: https://gno.sh/docs/how-to Markdown: https://gno.sh/docs/how-to.md Index a personal knowledge base, research archive, meeting notes, PDFs, or a Karpathy-style memory bank; installed skills search that index before they answer. For second-brain work, create typed pages with `gno capture --preset person`, `--preset company-project`, `--preset meeting`, or `--preset idea-original`. Keep the current synthesis above `## Timeline` and the evidence trail below it. Installed skills also include recipes for brain-first lookup, capture/file, meeting ingestion, email context, source summaries, idea capture, and citation/provenance. Preview them with `gno skill show --file recipes/brain-first-lookup.md`. These recipes use local indexed context and user-supplied/exported external material; they do not add native Gmail, Calendar, Slack, webhook, cron, or background-agent automation. ## Keep a collection fresh automatically Use `gno daemon` when you want local file changes to become searchable without keeping the Web UI open. ``` gno init ~/Documents/Knowledge --name knowledge gno index --models-pull gno daemon --detach gno daemon --status gno daemon --stop ``` The daemon watches configured collections, syncs changed files, and embeds new chunks. It also exposes the resident MCP endpoint at `http://127.0.0.1:3000/mcp` and safe redacted status routes, without the browser or full REST API. Use `--no-sync-on-start` if you only want future changes handled. For git-backed folders, run `gno update --git-pull` or `gno index --git-pull` when you want remote commits pulled in. Atomic replacements and recursive deletions settle automatically on supported local filesystems. Exact paths retain content-hash authority; ambiguous notifications use bounded, failure-safe reconciliation and preserve untouched siblings. Network and removable filesystems are not universally guaranteed; run `gno update` after reconnecting or remounting them. When a deleted source reappears at the same path, the next successful sync reactivates it and journals the transition once, even if its bytes are identical. Matching formatted input and model identity can reuse proven vectors; changed title/text or identity needs embedding coverage. Run `gno embed` after `gno update` when semantic work remains. Interrupted work resumes from completed checkpoints. Sync also repairs affected incoming references across collections; incomplete graph inventory selects full recovery. ## Build a personal AI memory bank 1. Put notes, PDFs, docs, exports, and research into one folder or a few topic folders. 2. Add them as GNO collections with clear names. 3. Run `gno index`, then keep them fresh with `gno daemon --detach`. 4. Install MCP or skills so your AI assistant can retrieve from that memory before answering. ``` contentTypes: - id: person prefixes: [people/] preset: person - id: meeting prefixes: [meetings/] preset: meeting ``` ``` gno collection add ~/Documents/Research --name research gno collection add ~/Documents/Notes --name notes gno collection add ~/Downloads/Papers --name papers gno index gno mcp install --target claude-desktop gno skill install --target all --scope user --force ``` ## Connect your AI tools Pick the integration by how you want the assistant to behave. - [MCP](https://gno.sh/docs/mcp): automatic tool calls from Claude Desktop, Claude Code, Cursor, Codex, Zed, Windsurf, OpenCode, Amp, LM Studio, LibreChat, and compatible clients. - [Agent skills](https://gno.sh/docs/skills): explicit `/gno` lookups with low context overhead. - [REST API](https://gno.sh/docs/api): scripts, launchers, dashboards, and custom local apps. ``` gno mcp install --target cursor --scope project gno skill install --target codex --scope user ``` ## Use GNO without living in a terminal Start the local workspace, then add folders and manage indexing from the browser. ``` gno serve open http://localhost:3000 ``` Use Search for retrieval, Ask for cited answers, Browse for document navigation, Graph for relationships, and Collections for folder management. ## Fix stale or missing results 1. Confirm the files are indexed: `gno ls --collection notes`. 2. Rescan changed files: `gno update`. 3. Refresh embeddings: `gno embed notes`. 4. Run the full path: `gno index`. 5. Diagnose system issues: `gno doctor`. If you changed the embedding model, clear stale collection embeddings before rebuilding them: ``` gno collection clear-embeddings notes gno embed notes ``` ## Research with filters and graph context Combine filters when your archive grows beyond simple search. ``` gno query "learning loops" --collection research --tags-any ai,pkm gno ask "what are my strongest notes on retrieval?" --since "last month" --answer gno graph --neighbors gno://notes/llm-memory.md --include-similar gno graph --from gno://notes/a.md --to gno://notes/b.md ``` ## Export a note for gno.sh Local GNO stays private. When you intentionally want to publish a note or collection, export an artifact and upload it through gno.sh Studio. ``` gno publish export atlas --out ~/Downloads/atlas.json ``` Then open [/studio](https://gno.sh/studio), import the artifact, and pick public, secret-link, invite-only, or encrypted sharing. --- # How search works > BM25, vector, default bounded graph expansion, fusion, and reranking, end to end. Section: Guides Canonical: https://gno.sh/docs/how-search-works Markdown: https://gno.sh/docs/how-search-works.md GNO hybrid search runs BM25 and vector retrieval, fuses by rank, optionally expands one hop of wiki/markdown links, then cross-encoder-reranks. Exact identifiers and quoted phrases skip HyDE; `--fast` returns fused BM25+vector; default mode adds bounded graph expansion and rerank. Latency depends on the corpus, model, hardware, and whether native models must reload after idle. ## The pipeline 1. **Query expansion** — optionally expand the query with HyDE (hypothetical document embeddings) and lexical variants. GNO skips expansion when it has a strong signal. 2. **BM25 retrieval** — classical full-text search over the inverted index. Fast and precise for exact terms, technical identifiers, and quoted phrases. 3. **Vector retrieval** — cosine similarity over dense embeddings. Handles synonyms and conceptual matches. 4. **Reciprocal rank fusion** — merges BM25 and vector results by rank position, not raw score, so the two score scales never have to be comparable. 5. **Bounded graph expansion** — by default, GNO resolves only outgoing wiki/markdown links and backlinks touching the top seeds, then adds those bounded one-hop neighbors after initial fusion. Active filters still apply, existing chunk positions are preserved, and explicit links are weighted above inferred or ambiguous matches. Semantic similarity remains in the vector stage; query-time graph expansion never rebuilds the full collection graph. `--no-graph`and `--fast` skip the stage. 6. **Second fusion pass** — graph candidates join the BM25/vector ranked inputs before reranking, so linked evidence can boost the right chunk instead of duplicating a document-level hit. 7. **Cross-encoder reranking** — rescores the fused top-N with a cross-encoder over query+document together. This stage runs in Thorough and default modes, not `--fast`. 8. **Return** — the reranked top-K is returned with scores, snippets, and optionally the retrieval pipeline trace. Supported active-owner, collection/path, tag, date, category, author, exclusion, visibility, and memory filters apply before the relevant candidate budget. Vector and hybrid retrieval also select matching-language chunks; standalone lexical language remains reserved. Whole-document exclusions inspect every chunk, including other languages. Ineligible nearest neighbors cannot crowd out an eligible owner. Thresholds, deduplication, or limited coverage can still yield fewer than K results; this is not a fixed-overfetch or recall guarantee. Local reranker capacity is sized from complete native-formatted query/passage pairs, tokenization, padding, and model limits. Compatible contexts can be reused, grown, or shrunk; unsupported formatters safely use native automatic sizing. Candidate selection and prepared input text stay unchanged. Smaller contexts do not imply a universal speed or whole-device memory reduction. ## Speed modes - **Fast** — skip query expansion, graph expansion, and reranking; return fused BM25+vector. - **Balanced** — default. Hybrid retrieval with moderate budgets and bounded graph expansion. - **Thorough** — larger query expansion budget, bounded graph expansion, and deeper rerank. ``` gno query "topic" --fast gno query "topic" # balanced gno query "topic" --thorough gno query "topic" --no-graph ``` ## GNO 2.0 evidence boundaries The [paired feature evidence](https://github.com/gmickel/gno/blob/70a7880f20cb1d28561638b67968cfaf1ffa01d6/.flow/artifacts/fn-146-cancellation-and-bounded-background/aggregate-handoff/README.md) compares complete deterministic results, scores, provenance, scopes, and actual model inputs per case; generated prose is assessed separately. Historical control failures, incomplete warm/native rows, crashes, and expansion fallback remain part of that record. Lexical or model-double tests do not establish native acceptance. The final dependency cohort uses Bun 1.4.2 and node-llama-cpp 3.20.0. Its [physical CUDA and Heimdall comparison](https://github.com/gmickel/gno/blob/d450098db32934328e969e85723edc75467b9a96/.flow/artifacts/fn-154-gno-20-release-dependency-sweep-and/native-qa/README.md) retains changed CUDA scores, ordering, and internal generated claims; all 29 existing labeled CUDA queries kept their recorded quality metrics. Heimdall Metal matched complete native inputs/outputs and public response projections in its pinned workload. Verified Ask abstained with an actual judge call on each side; that is not a supported-answer result. Slower samples remain visible. Earlier allocation figures retain their original backend, hardware, and context/compute metric boundaries and are not new-backend RSS or universal memory savings. ## Benchmark fixtures For repeatable retrieval checks, create a fixture with queries and relevant document URIs, then run `gno bench `. The command evaluates BM25, vector, and hybrid modes against the same corpus and prints metrics that make model or pipeline regressions visible before you switch defaults. ``` gno bench docs/examples/bench-fixture.json gno bench fixture.json --modes bm25,vector,hybrid --json ``` The [frozen Context Capsule agent-outcome demo](https://gno.sh/features/benchmarks#context-capsule-agent-outcome) runs one exact-identifier task through the lexical-only baseline, current GNO query/get primitives, and the Context Capsule using the same task, agent, corpus, effective index, trial, seed, and cold lifecycle. It publishes exact evidence, stop outcome, calls, context bytes, token availability, latency, method, variance, and the complete normalized receipts. Task `t0a1b2c3` is the sole cold current-GNO-failure / Capsule-success case among the authoritative 24-task cohort. It was selected to demonstrate that behavioral difference, not as a representative sample or general superiority claim. The Capsule lane is an evaluation-only lexical prototype; its latency is not the shipped Context Capsule path and is not product-equivalent. Capsule result: `INC-4827` from `gno://c001/d001.md:3` in `1` agent call and `1295` model-visible UTF-8 bytes. Tokens were unavailable without one pinned comparable tokenizer. The separately labeled 22-pair Verified Ask artifact is answer-enforcement evidence; its answer metrics are not retrieval metrics. ## --explain Pass `--explain` to Query or Ask to see exactly what happened: expansion output, BM25 hits, vector hits, graph expansion status, fusion order, rerank scores, and stage timings including `graphMs`. When a non-neutral content-type rule applies, the receipt also shows the raw/base score, configured factor, bounded contribution, shared auxiliary cap, final score, rule source, and full ranking-rules fingerprint. Explain metadata stays outside canonical Context Capsule bytes. ``` gno query "topic" --explain gno ask "summarize the meeting" --verify --explain ``` ## Bounded auxiliary ranking One configured `contentTypes[].searchBoost` can contribute `-0.05..+0.05`. Trusted local CLI project affinity can contribute up to `+0.03`. They compose once under a shared `±0.08` cap, and the final score remains in `0..1`. BM25 and vector only adjust candidates that already survived retrieval and `minScore`; content-type boosts alone never widen either candidate set. Hybrid applies the composed auxiliary score to normalized fusion before rerank blending. Rerank ordering and lexical top-hit protection remain the final authority; content-type preference cannot override either safeguard. Boost factors accept `0.5..2`; omitted or `1` is neutral. A canonical configured frontmatter type wins over longest-prefix matching. Categories, unknown type text, and overlapping prefixes cannot stack or manufacture a boost. The signal never creates a candidate and never bypasses collection, tag, date, category, author, or exclude filters. ## Strong signal detection When your query contains exact identifiers or quoted phrases, the pipeline recognizes the strong signal and skips expansion — no point hallucinating a HyDE document when the user already told you exactly what they want. ## Multilingual scope and evidence Query-language classification uses an explicit 34-language allowlist to choose prompt language. Indexed-document detection is a separate seven-language path covering `en`, `de`, `fr`, `it`, `zh`, `ja`, and `ko`. Neither count is a retrieval-quality guarantee. The immutable April 6, 2026 FastAPI-docs fixture used 15 documents in five corpus languages and 13 queries. It measured bge-m3 at vector nDCG\@10 `0.3503` and hybrid `0.642` in the [bge-m3 evidence](https://github.com/gmickel/gno/blob/main/evals/fixtures/general-embedding-benchmark/2026-04-06-bge-m3-incumbent.md), versus Qwen3 Embedding 0.6B at vector `0.8594` and hybrid `0.947` in the [Qwen evidence](https://github.com/gmickel/gno/blob/main/evals/fixtures/general-embedding-benchmark/2026-04-06-qwen3-embedding-0-6b.md). A separate [July 21, 2026 screen](https://github.com/gmickel/gno/blob/main/research/embeddings/2026-07-21-nemotron-3-embed-1b.md) reran the same 13-query lane after runtime/profile changes: Qwen measured `0.9891` vector / `0.9891` hybrid, and Nemotron 3 Embed 1B measured `0.9023` / `0.9461`. Nemotron used a temporary PyTorch HTTP adapter while Qwen used GNO’s production GGUF path, so timings are not comparable and no official production Nemotron GGUF was validated. These small fixtures support keeping Qwen as the default; they do not prove general language superiority. Degraded lexical behavior has separate evidence. The immutable [July 22, 2026 CJK benchmark](https://github.com/gmickel/gno/blob/main/evals/fixtures/cjk-lexical-benchmark/2026-07-22.md) used 25 same-language queries across Chinese, Japanese, and Korean. The Chinese lane includes a genuine rank-7 retrieval fixture. Production BM25 Recall\@10/nDCG\@10 and zero-result results, followed by the frozen promotion floors: - **Chinese:** baseline Recall\@10 `0.2222`, nDCG\@10 `0.1481`, zero-result `0.7778`; promotion Recall\@10 `0.4722`, nDCG\@10 `0.3981`, maximum zero-result `0.5278`. - **Japanese:** baseline Recall\@10 `0.125`, nDCG\@10 `0.125`, zero-result `0.875`; promotion Recall\@10 `0.375`, nDCG\@10 `0.375`, maximum zero-result `0.625`. - **Korean:** baseline Recall\@10 `0.5`, nDCG\@10 `0.5`, zero-result `0.5`; promotion Recall\@10 `0.75`, nDCG\@10 `0.75`, maximum zero-result `0.25`. The [frozen promotion gates](https://github.com/gmickel/gno/blob/main/evals/fixtures/cjk-lexical-benchmark/promotion-gates.md) also bind MRR, non-regression, and cost requirements. This lexical baseline is not semantic evidence and does not select a future analyzer. All positive qrels use relevance `3`, so nDCG measures placement but not distinctions among positive gain grades. Production tokenization remains unchanged. ## Related - [Hybrid search feature](https://gno.sh/features/hybrid-search) - [Advanced retrieval](https://gno.sh/features/advanced-retrieval) - [Benchmarks](https://gno.sh/features/benchmarks) --- # Architecture > Bun, SQLite, local GGUF models via node-llama-cpp, and one retrieval core shared by CLI, Web UI, SDK, REST, and MCP. Section: Guides Canonical: https://gno.sh/docs/architecture Markdown: https://gno.sh/docs/architecture.md GNO is a TypeScript CLI package executed by Bun, with a SQLite-backed index, local model inference via node-llama-cpp, and a shared retrieval core that every surface (CLI, Web UI, SDK, REST API, MCP) plugs into. ## Runtime - **Bun** — TypeScript-first runtime and global package installation - **SQLite + sqlite-vec** — BM25 FTS plus vector similarity via a SQLite extension. One database file per GNO installation. - **node-llama-cpp** — local LLM inference for embedding, reranking, and answer generation. GGUF model format. One owned Bun child per adapter holds models, contexts, and backend allocations; the parent keeps policy, downloads, stores, and transports. There is no machine-wide model broker. ## Storage layout - `~/.config/gno/` — config files (index.yml, presets) - `~/.local/share/gno/` — SQLite database, model cache, asset cache - `~/.cache/gno/` — temporary artifacts, rerank scratchpad ## Surfaces Every GNO surface speaks to the same shared retrieval core: - **CLI** — `src/cli/*`, exposed as the `gno` executable by the installed Bun package - **Web UI** — `gno serve` launches a Bun HTTP server with the browser workspace and the REST API - **SDK** — package-root importable client, same core under the hood - **REST API** — exposed by `gno serve`, 35+ endpoints - **MCP server** — stdio transport, read/write tools, graph navigation, and resources for any MCP-compatible client - **Desktop** — a native window wrapping the web workspace ## Data flow 1. **Ingestion** — the file walker reads sources, parsers extract text and frontmatter, export adapters split containers into logical records, and the chunker splits documents into retrievable units. Code files get structural first-pass chunking for TypeScript, JavaScript, Python, Go, and Rust. 2. **Mirroring** — every source is normalized into a _canonical mirror_: LF line endings, NFC text, stable line numbering. All coordinates in the system address the mirror, not the original bytes, which is what makes “lines 40 to 48” mean the same thing for a Markdown file and a converted PDF. 3. **Embedding** — chunk text is encoded to dense vectors by the active embedding model, prefixed with the document title so the vector carries context beyond the chunk itself. 4. **Indexing** — chunks land in SQLite FTS5 and sqlite-vec tables; documents, links, tags, and typed edges land in relational tables. Change detection is SHA-256 per file. Unchanged active content can reuse storage; identical bytes restored at an inactive path still trigger reactivation and its journal event. 5. **Retrieval** — the query enters the pipeline, hits BM25 and vectors, optionally expands one hop through the graph, merges by reciprocal rank fusion, reranks with a cross-encoder, and returns. 6. **Compilation or answer** — a Capsule request adds facet derivation, coverage-driven selection, and global budgeting on top of retrieval. `ask` sends the selected evidence to the generation model with a citation-preserving prompt, and `--verify` adds a claim-classification pass against the closed Capsule. Plain lexical/vector retrieval loads selected chunk sequences where safe; intent steering and whole-document exclusions retain broader reads. One request-owned raw hydration is reused across retrieval, reranking, raw Ask preparation, and verified Capsule materialization, then released even on failure. Each stage still prepares its own selected input. Freshness verification independently reads the live index, preserving hash/drift checks. There is no cross-request cache, filesystem reread, or new post-generation freshness guarantee. Scoped sync reconciles changed sources and affected incoming references globally, including other collections and old/new target identities. A complete current inventory lets unchanged sync avoid broad mirror reads and identical edge writes. Missing or interrupted inventory, projection-version changes, and collection/graph-rule changes select full reconciliation. Completion is recorded only after successful projection. ## Identity and hashing Three hashes exist for every piece of evidence, and the distinction runs through the whole system: - **Source hash** — the original file bytes. Changes when the file changes at all. - **Mirror hash** — the canonical normalized form. Changes when the extracted text changes, which can happen from a converter upgrade even if the source is untouched. - **Passage hash** — the exact bytes of one span. Changes only when that specific passage moves. Keeping them separate is what lets verification say “the file changed but your cited paragraph did not”. Document IDs are derived from the source hash, so identity is content-addressed rather than path-addressed. Shared canonical chunks do not imply interchangeable embeddings. Proven vector reuse requires the complete formatted input, including title context, and actual model/runtime identity to match. Different titles can require distinct vectors for the same body. Restoring unchanged input preserves proven vectors; changed input requires matching coverage. Activation and one `reactivate` event commit atomically, with no event on repeated unchanged sync. Shadow backfill is resumable and only initially activates a partition after complete current coverage and an atomic mutation check. After activation, stale owners wait for embeddings; missing verified identity or a corrupt variant index cannot restore legacy authority. Checkpoints revalidate current input and runtime before committing. Stored variants can repair missing index materialization without new inference. Providers without verified identity retain conservative legacy rules before activation, including recomputation for ambiguous inactive title histories. ## The resident runtime `gno serve` and `gno daemon` are two front ends for one _resident runtime_: a single exclusive owner per data directory, holding the store, the watcher, the job queue, the model lifecycle, and a Streamable HTTP MCP gateway at `127.0.0.1:3000/mcp`. Several MCP clients share the store and matching adapter while keeping isolated sessions, cancellation, and configuration snapshots. Model files, downloads, and native initialization are deferred until inference. Warm reuse lasts within the five-minute default idle grace; the next request after retirement reloads. Model-specific leases keep active roles safe without retaining idle generation/reranking weights during background embedding. Metadata polling does not renew the grace. A second process against the same data directory is rejected. Shutdown stops admission and scheduling, then allocates one shared five-second drain, five-second abort-settlement period, and at most one second to confirm forced owned-child exit. Requests, jobs, background work, and listeners share the clock; no participant renews it. At the settlement deadline, suspended parent transactions roll back and their store access is revoked before database close. Completed checkpoints remain durable and unfinished embeddings remain pending. Unconfirmed OS termination is an error, not successful cleanup. Those bounds require a running parent event loop. Timers cannot preempt synchronous callbacks, blocked OS calls, or SQLite statements already executing. Ordinary store access caps busy waiting to the remaining settlement budget; cached raw DB handles outside that API do not inherit its per-access cap or transaction token. This is not a universal query deadline. Background embedding runs in internal turns of at most 32 pending chunks, checkpoints, releases native/model ownership, and yields. A whole job can span many turns. Foreground inference dispatches first; one pending background native request gets service after at most eight completed foreground native inference dispatches. Both share the 64-call waiting queue. Metadata operations and canceled caller delivery do not count as native completions, and active native batches are not preempted. Failed chunks stay pending while later pages can progress. There is no public capacity, priority, or turn-size knob. Reader slots transfer synchronously to queued work; canceled grants return or transfer ownership exactly once. Caller cancellation stops delivery but keeps noncooperative native capacity owned until actual settlement or controlled exit. A stuck canceled native operation has five seconds to settle before child retirement. A later explicit request can acquire a fresh child after structured failure; no queued operation is automatically replayed. HTTP inference remains outside the local child lifetime policy. ## Cross-cutting gates Three checks sit between a request and an effect, and they are independent by construction: - **Authentication** — who is calling. Non-loopback daemon access requires an explicit bearer-token file plus exact Host and Origin allowlists. - **Write authorization** — whether mutation tools exist at all. Read-only is the default everywhere; writes need an explicit opt-in and authentication alone never grants them. - **Egress** — whether content may cross a transport boundary. Owned by the collection, evaluated before transfer, and not overridable by either check above. - **Source availability** — whether source content may be materialized during indexing (`any` default or opt-in `local`). Distinct from egress. Local mode is evidence-qualified for tested macOS File Provider layouts only (Google Drive, iCloud Drive, and OneDrive only for the tested configuration and both validated immediate SharePoint library roots), uses hierarchical directory classification plus a guarded content recheck, and fails closed outside proven support. ## Ports and adapters The core defines ports — converter, store, embedding, rerank, generation — and adapters implement them. That is why an OpenAI-compatible HTTP endpoint can substitute for a local GGUF per model role without the retrieval core knowing, and why a per-collection embedding override is a configuration change rather than a code path. ``` ┌─────────────────────────────────────────────────┐ │ CLI / MCP / Web UI / REST / SDK / Desktop │ ├─────────────────────────────────────────────────┤ │ Ports: Converter, Store, Embedding, Rerank, Gen │ ├─────────────────────────────────────────────────┤ │ Adapters: SQLite, FTS5, sqlite-vec, llama.cpp, │ │ OpenAI-compatible HTTP │ ├─────────────────────────────────────────────────┤ │ Core: Identity, Mirrors, Chunking, Retrieval, │ │ Capsules, Journal, Egress │ └─────────────────────────────────────────────────┘ ``` ## Related - [How search works](https://gno.sh/docs/how-search-works) - [Context Capsules](https://gno.sh/docs/context-capsules) - [Collection egress policies](https://gno.sh/docs/collection-egress) - [Source availability](https://gno.sh/docs/configuration#source-availability) - [Privacy model](https://gno.sh/features/privacy-first) --- # Troubleshooting > Doctor output, Homebrew SQLite on macOS, model pulls, stale embeddings, and Windows llama.cpp startup. Section: Guides Canonical: https://gno.sh/docs/troubleshooting Markdown: https://gno.sh/docs/troubleshooting.md ## First stop: gno doctor ``` gno doctor ``` Start here: `gno doctor` runs the health checks GNO ships, including `embedding-fingerprint` (current fingerprint, pending/stale chunks, mixed stored groups). Read its output carefully before anything else. For embedding freshness, look for the `embedding-fingerprint` check. It reports the current fingerprint, pending/stale chunks, legacy empty-fingerprint vectors, and mixed stored fingerprint groups. ## Cold requests and native child failure First inference and the first request after five minutes of native inactivity include worker startup, model loading, and context creation. Status polling does not keep models warm. Check [model timeout settings](https://gno.sh/docs/configuration#model-timeouts) and compare the same query, model, collection, and options before and after idle. Cold expansion can still hit its separate stage budget and fall back without expansion; model timeout changes do not extend that budget. A startup, abnormal child exit, or invalid-response failure is structured and never automatically replayed. Preserve the full error, stderr, model URIs, runtime version, and lifecycle state, then issue a new explicit request after recovery. Hybrid `meta.vectorsUsed: false` means no vector search succeeded; wholly lexical fallback uses `meta.mode: "bm25_only"`. Successful vector retrieval may return no hits with `vectorsUsed: true`; reload failure is not a semantic no-match. GNO 2.0 uses node-llama-cpp 3.20.0 with its additional simulator initialization-failure cleanup and joined disposal. If you see `Unsupported node-llama-cpp simulator source`, use the dependency supplied with GNO rather than patching installed native files. Backend detection/build policy is separate from lifecycle recovery. A smaller reranker or successful Linux recovery does not establish that every historical Metal assertion is fixed. Resource measurements must include the owned child; parent RSS and loaded-model counts do not measure native allocations. ## Rare or missing filtered results Eligible owners now enter retrieval before candidate budgets. Check collection/path, tags, dates, category, author, exclusions, and memory visibility before increasing limits. Vector/hybrid language filters operate on chunks; standalone lexical language is reserved. Thresholds, deduplication, or limited coverage can legitimately leave fewer than K results. Use `gno query "your query" --explain` to inspect fallback and ranking; this correction does not change natural-language memory recall matching or guarantee a speedup for broad owner checks. ## Cloud placeholders skipped under sourceAvailability local Opt-in `sourceAvailability: local` (collection config) is distinct from `egressPolicy`. On tested macOS File Provider layouts it refuses content that would require materialization. Receipts may show `CLOUD_PLACEHOLDER`, `CLOUD_PARTIAL`, `DATALESS_DIRECTORY`, or fail-closed `SOURCE_AVAILABILITY_*` codes. Indexed descendants under unproven prefixes are preserved. Evidence covers Google Drive, iCloud Drive, and OneDrive only for the tested configuration and both validated immediate SharePoint library roots — not Windows/Linux cloud filesystems. GNO does not pin, evict, or download as product behavior. See [Configuration → Source availability](https://gno.sh/docs/configuration#source-availability). ## Retrieval activation is blocked or degraded Check `gno doctor`, `gno status --json`, or the dashboard Health Center. A ready collection has completed a bounded, corpus-derived lexical search and returned its expected document. Semantic search may still be pending independently while models or embeddings are prepared. - `no_documents` or `no_probe_term` — add a supported text document or fix the collection filters, then run `gno index --no-embed`. - `index_out_of_sync` or `retrieval_mismatch` — rebuild that collection’s lexical index, then rerun doctor. - Connector failures — open Web **Connectors** and run its explicit read-only verification action again after repairing the configured MCP command. Skill installations remain runtime unverifiable; that is not a passed connector proof. - A truncated connector projection is incomplete by definition. Omitted target/collection pairs have no result, so status stays warning/non-green instead of guessing. - Wrong workspace in a connector — reinstall it from the intended GNO workspace. The installer pins the active index and absolute config, data, and cache roots; passive status does not rewrite a stale client entry. Technical integrity boundary: supported GNO writers maintain the FTS synchronization marker transactionally, and database migration validates legacy mirror bodies once before backfilling it. Direct, out-of-band mutation of an FTS body after migration bypasses that owned-writer contract and is not detectable by the metadata-only passive fingerprint. Repair by rebuilding the affected collection; do not edit GNO’s FTS tables directly. ## `Error: database is locked` or exit code 4 Since v1.38.0, concurrent writers queue on one shared write lease. The bare `Error: database is locked` message no longer appears for CLI/MCP overlap. Exit code 4 means another writer held the lease past `--lock-wait` (default 120s). This is contention, not corruption — retry the command. Raise `--lock-wait` for long reindexes, or pass `--no-wait` in scripts that prefer failing fast. Reads do not take the write lease, but resident reader admission still has bounded capacity. A full reader queue returns HTTP 429; shutdown or unavailable admission returns HTTP 503. `chunks deferred by index contention` means rerun `gno embed` after the other writer finishes. On pre-1.38 versions the fix is upgrading. ## Vector search fails on macOS Symptom: `gno vsearch` or hybrid queries fail with a SQLite extension loading error. Cause: the stock Apple SQLite doesn’t support loading extensions. GNO needs the Homebrew build. ``` brew install sqlite3 gno doctor ``` ## Models fail to download Symptom: the first `gno query` or `gno ask` stalls during a model pull. Solutions: - Run `gno models pull` explicitly to see real-time progress and errors. - HTTP rerank endpoints are external services, so model pulls skip them instead of treating them as downloadable GGUF files. - If you’re offline or behind a firewall, set `GNO_NO_AUTO_DOWNLOAD=1` and download model files by hand into the cache. - Clear a stuck download with `gno models clean `. - If a cached download is reported as non-GGUF or intercepted HTML, fix network access and rerun `gno models pull --force`. ## Results feel stale after editing Re-scan the index: ``` gno update ``` Or run `gno daemon` in the background for continuous indexing. Restored identical files reactivate on successful sync with one atomic `reactivate` journal event. Unchanged formatted input retains proven embeddings; changed title/text or model/runtime identity needs matching coverage. Run `gno doctor` and normal `gno embed` before an intentional `gno embed --force`. Missing or corrupt activated variant indexes require repair; they do not authorize legacy-vector reuse. Interrupted backfills and embedding passes resume from durable checkpoints. Backlog owner counts are not native-call counts. ## Update reports an invalid PDF The PDF is incomplete or damaged. GNO isolates it as a non-fatal `CORRUPT` document, continues indexing the collection, and keeps the Web UI available. It does not retry the unchanged file on every update. ``` qpdf --check /path/to/file.pdf ``` Replace or re-export the PDF, then run `gno update` or **Update All**. A changed source hash makes GNO try the repaired file again. ## Results feel off after switching models Vector-based search uses the embedding model that was active when the index was built. Doctor now makes this visible through the `embedding-fingerprint` check. After switching embeddings, re-embed: ``` gno doctor gno embed # re-embed stale/pending chunks gno embed notes # or one collection ``` `gno embed` retries transient embedding failures within the same run. If doctor still reports stale, legacy, or mixed vectors after a normal embed, force a full refresh: ``` gno embed --force ``` `gno embed --force` uses the same same-run retry path. If a run still fails, rerun with verbose output so GNO prints sample failures and the retry hint: ``` gno --verbose embed --force ``` ## Check which GPU backend is detected Before forcing a backend, see what `node-llama-cpp` actually detects. This works on Linux, Windows, and macOS and reports the active GPU backend (CUDA, Vulkan, or Metal), available VRAM, and which prebuilt binary is in use: ``` bunx --bun node-llama-cpp inspect gpu ``` (`npx --no node-llama-cpp inspect gpu` works too.) If CUDA or Vulkan shows as available here but GNO still runs on CPU, the backend is being selected or initialized incorrectly — see below. If it is not available here, the GPU driver or toolchain is the problem, not GNO. ## Windows model startup hangs Symptom: `gno index`, `gno embed`, or `gno doctor` appears stuck while loading `node-llama-cpp`, often around a Vulkan backend load test. GNO now defaults to prebuilt local-model backends, times out backend initialization, and retries CPU on Windows when automatic GPU backend selection fails. Run diagnostics first: ``` gno doctor ``` To force CPU mode for a constrained Windows machine, run: ``` GNO_LLAMA_GPU=false gno embed --yes ``` If CPU embedding still consumes too much memory, keep the adaptive default or set an explicit small context pool. On CPU-only systems, GNO defaults to one context on low-memory Windows machines and at most two contexts elsewhere: ``` GNO_EMBED_CONTEXTS=1 gno embed --yes ``` Advanced CPU tuning is available when you want to trade throughput, memory, and per-context parallelism: ``` GNO_EMBED_CONTEXTS=2 GNO_EMBED_THREADS=4 gno embed --yes GNO_EMBED_CONTEXT_SIZE=512 gno embed --yes ``` Only opt into source builds when you intentionally have Visual Studio Build Tools and a working native toolchain: ``` GNO_LLAMA_BUILD=autoAttempt gno doctor ``` ## Still stuck? - Open an issue: [github.com/gmickel/gno/issues](https://github.com/gmickel/gno/issues) - Include your `gno doctor` output and the exact command you ran. --- # Publish a note > Sign up for gno.sh, import an exported artifact, and publish a versioned reading-first snapshot. Section: gno.sh Publishing Canonical: https://gno.sh/docs/publish-quickstart Markdown: https://gno.sh/docs/publish-quickstart.md Export a local note or collection with `gno publish export`, import the artifact in Studio, and publish a versioned snapshot at a gno.sh URL. ## 1. Create an account Open [the signup page](https://gno.sh/signup) and create a free account. No credit card. You’ll get a verification email and land on your dashboard. ## 2. Open the publish studio Go to [the publish studio](https://gno.sh/studio). Studio lists sources, visibility modes, metadata projection, and the import drop zone. ## 3. Drop or import a file Canonical path: export from local GNO first, then upload the artifact. ``` gno publish export atlas --out ~/Downloads/atlas.json ``` Then open [/studio](https://gno.sh/studio) and drop that compiled GNO artifact JSON into the import zone. The markdown path is still useful for quick single-note shares in dev, but the artifact JSON is the real hosted transport for larger collections. Supported local PNG, JPEG, GIF, WebP, and AVIF references travel in the artifact with content hashes and deduplication. Public readers use immutable generation-bound image URLs; secret links authorize each image request and disable caching. Encrypted exports keep image bytes inside ciphertext and create temporary Blob URLs only after browser decryption and AVIF decode preflight. Hosted ingest also proves AVIF AV1 decodability before storage. Invite-only bundled-image delivery is not yet available and fails closed; use an asset-free invite, secret link, or encrypted share when local images are required. For public, secret-link, and invite-only uploads, the studio can now create a new space, overwrite an existing space, or append the new notes into an existing space so the left-hand navigator grows over time. Encrypted shares still update via fresh encrypted upload only. ## 4. Pick a visibility mode - **Public** — a plain URL anyone can read - **Secret link** — an unguessable token. Rotate, revoke, or expire at will. - **Invite only** — members of your org sign in to read - **Encrypted** — client-side passphrase. We store ciphertext only when the artifact was encrypted locally before upload. ## 5. Press publish A receipt appears with the share URL. Open the share URL to see typography, outline, scoped search, and keyboard navigation. ## Agent-readable public spaces Public artifacts exported with GNO’s agent manifest keep the human reader and add deterministic, no-JavaScript resources for agents: ``` /share///llms.txt /share///manifest.json /share///.md ``` The manifest lists only the imported public projection. Every document includes a content hash and an exact line-range evidence locator. Secret-link, invite-only, and encrypted spaces never expose these endpoints. ## Republish Re-importing the same route slug replaces the existing share with a new snapshot. If you want to grow a published collection instead of replacing it, choose **Append to existing** in the studio. Readers keep the same URL in either case; append adds notes to the navigator, overwrite replaces the snapshot. ## Related - [Publish platform overview](https://gno.sh/publish) - [Visibility modes in depth](https://gno.sh/docs/publish-visibility) - [Publish feature page](https://gno.sh/features/publish-sharing) --- # Visibility modes > Choose public URL, secret-link token, org invite, or client-side passphrase encryption. Section: gno.sh Publishing Canonical: https://gno.sh/docs/publish-visibility Markdown: https://gno.sh/docs/publish-visibility.md gno.sh ships four visibility modes. ## Public URL A plain, guessable URL. Anyone with the link can read. No auth, no gate. Good for open research notes, client-facing overviews, and anything you’d otherwise post on a blog. URL shape: ``` https://gno.sh/share// ``` When the imported artifact carries a valid public-agent manifest, this same space also serves `llms.txt`, `manifest.json`, and exact Markdown evidence URLs. These routes are derived only from the declared public projection; gno.sh does not guess or expose other note paths. ## Secret link A long, unguessable token appended to the URL. Readers with the token open the page; anyone without it gets a 404. You can rotate the token at any time (old links stop working), revoke access entirely, or expire in 24 hours. Bundled image requests re-check the secret capability every time and use `Cache-Control: no-store`; the object-store key is never sent to the browser. URL shape: ``` https://gno.sh/secret/ ``` ## Invite only Readers must be signed in to gno.sh and be an accepted member of your organization. Good for team reference spaces, internal research, or client deliverables where you want an audit trail of who opened the page. Invite-only note text still publishes, but bundled-image delivery is not supported yet and fails closed. Prefer an asset-free invite, a secret link, or an encrypted share when local images must render. URL shape: ``` https://gno.sh/private/ ``` ## Encrypted Export an encrypted artifact from local GNO with a passphrase you choose, then upload it to gno.sh. Only ciphertext lands on gno.sh servers. Readers enter the passphrase in their browser to decrypt and read. gno.sh stores ciphertext only and cannot recover a lost passphrase. Store it yourself. To update an encrypted share, export a fresh encrypted artifact from local GNO and upload it again. Hosted republish does not rebuild encrypted shares from source. Supported bundled images remain inside ciphertext. After successful local decryption the reader validates assets structurally, allocates scoped Blob URLs, browser-decodes AVIF before render, and revokes those URLs when the share is replaced or the reader unmounts. URL shape: ``` https://gno.sh/locked/ ``` ## Picking the right mode - Sharing with the world? **Public** - Sharing with one person or one team, casually? **Secret link** - Sharing with a named audience inside your org? **Invite only** - Sharing something you don’t want even gno.sh to be able to read? **Encrypted** ## Related - [Publish quickstart](https://gno.sh/docs/publish-quickstart) - [Publish feature page](https://gno.sh/features/publish-sharing) --- # Structured query syntax > Multi-line query documents with term, intent, and hyde for explicit retrieval behavior. Section: Reference Canonical: https://gno.sh/docs/syntax Markdown: https://gno.sh/docs/syntax.md For complex queries, GNO supports a multi-line query document syntax on `gno query` and `gno ask`. Use typed lines to steer the retrieval pipeline without reaching for CLI flags. ## What this is Structured query syntax is a small text format for telling GNO which parts of a question are exact terms, which parts describe intent, and which parts should act like a hypothetical ideal answer. It helps when a natural-language question is ambiguous or when your personal knowledge base uses inconsistent wording. ## Example ``` auth flow term: "refresh token" -oauth1 intent: how token rotation works hyde: Refresh tokens rotate on each use and previous tokens are invalidated. ``` ## Rules - Structured syntax is only activated for multi-line input. - Blank lines are ignored. - Recognized typed lines: `term:`, `intent:`, `hyde:`. - At most one `hyde:` line is allowed per document. - Unknown prefixes (e.g. `vector:`) are rejected. ## Base query resolution Every query document needs a base query. GNO picks the base in this order: 1. Plain untyped lines joined together 2. Otherwise all `term:` lines joined together 3. Otherwise all `intent:` lines joined together `hyde:` lines are expansion-only; they are not searched as terms. ## Supported surfaces - CLI: `gno query`, `gno ask` - REST: `/api/query`, `/api/ask` - MCP: `gno_query` - Web UI: Search and Ask text boxes - SDK: `client.query(...)`, `client.ask(...)` ## CLI example ``` gno query $'auth flow\nterm: "refresh token"\nintent: token rotation' ``` --- # Fine-tuned models > GNO ships gno-expansion-slim-retrieval-v1 as the expand role in slim-tuned (nDCG@10 0.925, Ask Recall@5 0.875). It does not train on your corpus. Section: Reference Canonical: https://gno.sh/docs/fine-tuned-models Markdown: https://gno.sh/docs/fine-tuned-models.md GNO publishes `gno-expansion-slim-retrieval-v1`, a fine-tuned retrieval expansion model trained locally on Apple Silicon with MLX LoRA. ## What this is The expansion model rewrites or augments difficult queries before retrieval. It is the local `expand` GGUF in `slim-tuned`. Embeddings and standalone answers use other roles. Promoted fixture: nDCG\@10 0.925, Ask Recall\@5 0.875. ## The numbers - **nDCG\@10 0.925** on the canonical benchmark corpus - **Ask Recall\@5 0.875** on the ask-style answer benchmark - Shipped via Hugging Face, pulled on first run ## Install it ``` gno models use slim-tuned gno models pull --expand ``` ## Contributor training workflow End users select or download the shipped model; GNO does not train on an indexed corpus. Contributors developing replacement expansion models can use the research harness in the main GNO repo under `research/`, then benchmark and export a portable GGUF. ## Benchmarks Before promoting a model change, run the benchmark suite. Use `gno bench` for a public CLI check against your own fixture, and see the [benchmarks feature page](https://gno.sh/features/benchmarks) for the fixture workflow and result metrics. ``` gno bench docs/examples/bench-fixture.json gno bench fixture.json --json ``` --- # Browser clipper > Capture a visible selection or Reader-style page into local GNO with previewed Markdown and exact provenance. Section: Integrations Canonical: https://gno.sh/docs/browser-clipper Markdown: https://gno.sh/docs/browser-clipper.md The GNO Browser Clipper is a local, unpacked Chromium Manifest V3 extension shipped with the GNO npm package. It captures only after you open the popup and request a selection or Reader extraction from the active top-level tab. You preview the normalized Markdown, destination, tags, collision result, warnings, and provenance before confirming a write. This is an unpacked local extension, not a Chrome Web Store listing. Firefox packaging and parity are not claimed. ## Install the unpacked extension 1. Install or update GNO with `bun install -g @gmickel/gno`. 2. Open `chrome://extensions` in Chromium or Chrome and enable **Developer mode**. 3. Choose **Load unpacked** and select `~/.bun/install/global/node_modules/@gmickel/gno/browser-extension/dist`. If you installed with npm, use `$(npm root -g)/@gmickel/gno/browser-extension/dist`. 4. Pin the GNO Browser Clipper if you want it on the toolbar. The manifest version follows the installed GNO package version. The package also contains `browser-extension/artifacts/gno-browser-clipper-v.zip` and the adjacent `.zip.sha256` checksum. You can verify and unzip that reproducible archive into a stable local directory instead of loading `browser-extension/dist` directly. Keeping the same unpacked directory preserves the extension identity. Moving it to a different path can produce a different Chromium extension ID; pair again if that happens. ``` cd ~/.bun/install/global/node_modules/@gmickel/gno/browser-extension/artifacts shasum -a 256 -c gno-browser-clipper-v.zip.sha256 ``` ## Update ``` bun install -g @gmickel/gno # Then reload the extension from browser-extension/dist ``` Return to `chrome://extensions` and click **Reload** on GNO Browser Clipper. If the package manager or a manual copy changed the unpacked directory, remove the old extension, load the new directory, and complete pairing again. ## Pair with local GNO ``` gno serve ``` 1. Open the clipper popup and pair with `http://127.0.0.1:3000`. 2. Chrome 142 and newer may first ask whether the extension can access the local network. Approve that browser prompt. The user-opened popup sends the closed pairing-start request so Chrome can show the permission, then passes the response to the service worker. 3. The service worker validates and retains that transient five-minute pairing, then opens the local GNO approval page. Compare the eight-digit code in the popup, type it into that page, and approve. 4. The approval page uses same-origin CSRF protection. The service worker sends a one-time POST for the high-entropy pair ID and receives an origin-bound, capture-only grant. The approval page and content script never receive or display that grant. Pairing is separate from the REST API and MCP credentials. A REST or MCP bearer token cannot authorize clipping, and enabling gateway writes does not create a clipper grant. ## Preview and capture 1. Select rendered text on the active page, or leave no selection to request the visible Reader-style extraction. 2. Open the clipper. Review or edit the Markdown, select a collection and path or folder, add tags, and choose the collision policy. 3. Request a preview. Any content, source metadata, destination, tag, extraction mode, or authenticated-content change makes that preview stale and requires a fresh one. 4. Confirm the unchanged preview to write the note. Selection mode preserves the exact selected text in provenance. Reader mode sends a constrained visible-content AST: paragraphs, headings, quotes, lists, code, horizontal rules, text, and validated HTTP(S) links. GNO renders canonical Markdown on the server. Raw HTML is never a trusted wire format. Duplicate planning reports one of `created`, `opened_existing`, `created_with_suffix`, `overwritten`, or `conflict`. GNO opens an existing note only when its stored clip identity matches. Changed provenance or a changed final body conflicts instead of silently merging unrelated evidence. ## Provenance and warnings Browser-clip provenance has four hashes with distinct ownership: - `extractionHash` — canonical extracted selection or Reader content before user edits - `finalBodyHash` — final Markdown after allowed edits - `clipIdentity` — stable identity used for safe duplicate handling - `previewDigest` — server-owned digest binding the exact preview to the write Warning codes are `authenticated_visible_content`, `canonical_url_differs`, `edited_content`, `line_endings_normalized`, `reader_partial`, `selection_truncated`, `spa_snapshot`, and `unicode_normalized`. Authenticated-visible means you chose to capture content already rendered for your signed-in browser; GNO does not transfer the browser session or bypass access controls. ## Interrupted writes and recovery Before committing, the service worker stores at most one pending `{payload, previewDigest, idempotencyKey}` logical write. Reopening the popup shows its destination and source. Choose **Retry saved write** to reuse the same payload, digest, and key, or **Stop recovery** to discard it. While that write is pending, the popup hides normal extraction controls so a different capture cannot replace the recovery state. If a restart removed the server preview, GNO refreshes the preview only for that same payload and resumes with the same idempotency key. Receipt replay is safe. A changed payload, path, file, plan, or recovery key fails closed; recovery does not choose another suffix or destination. ## Revoke access Use **Revoke** in the popup. Revocation persists in GNO, and the extension clears its local grant and pending write. Expired, revoked, or server-restarted pairing state requires a new visible pairing when no usable grant remains. ## Privacy and storage - Extension traffic goes only to the configured `http://127.0.0.1` GNO listener. - `chrome.storage.session` holds the transient pair ID, code, expiry, exact extension origin, and approval route. - Trusted-context-only `chrome.storage.local` holds the loopback origin; grant ID, plaintext grant token, and expiry; and at most one pending payload, preview digest, and idempotency key. A pending selection or Reader extract can therefore remain locally stored until you retry or discard it. - GNO’s SQLite store retains only the grant-token hash, exact extension origin, capture scope, expiry/revocation state, and bounded idempotency receipts. The extension does not read browser history, cookies, session tokens, background tabs, arbitrary iframe documents, images, media, raw HTML, or hidden page content. It does not use OAuth, sync captured content to a cloud service, send telemetry, fetch the source URL from GNO, or capture autonomously. ## Local gateway boundary The clipper routes exist only on `gno serve`’s loopback listener. Every extension request must come from an actual loopback peer, use the exact listener Host, and carry the exact paired `chrome-extension://` Origin. CORS and Local/Private Network Access preflights allow only that origin, with no wildcard or credentials mode. Chrome Local Network Access is an additional browser permission. Service workers cannot trigger its prompt, so only the user-activated popup performs the exact-origin, `credentials: "omit"` pairing-start request. Grant polling, preview, write, and revoke remain service-worker-only. The safe CSRF-token GET accepts a browser-omitted Origin only when`Sec-Fetch-Site: same-origin` proves the request came from the local approval page. Approval POST still requires the exact same-origin Origin plus `X-GNO-CSRF`. Request bodies, rates, and concurrency are bounded. Unfinished pairings, one-time plaintext grant delivery, CSRF state, and preview tickets stay in memory and disappear when `gno serve` restarts. Non-loopback and public binds do not expose clipper routes. ## Routes and response contract - `POST /api/clipper/pair/start` — begin pairing - `GET /api/clipper/pair/csrf` — obtain the same-origin approval token - `POST /api/clipper/pair/approve` — approve the displayed code - `POST /api/clipper/pair/:pairId` — poll once for the grant - `POST /api/capture/clip/preview` — validate and plan without writing - `POST /api/capture/clip` — commit the unchanged preview - `POST /api/clipper/revoke` — revoke the scoped grant Versioned success bodies use `schemaVersion: "1.0"` and reject unknown fields. A valid `opened_existing` receipt uses HTTP 200. `created`, `created_with_suffix`, and `overwritten` use HTTP 202. A valid provenance `conflict` receipt uses HTTP 409. Other failures use the closed `clipper-error@1.0` code/status matrix; unknown versions, fields, codes, non-JSON bodies, and impossible status/body combinations fail closed. `CLIPPER_OFFLINE`, `CLIPPER_INVALID_RESPONSE`, and `CLIPPER_CLIENT` are local client classifications, not wire error codes. --- # Claude Code integration > Use GNO with Claude Code via the SKILL.md install or the MCP server. Section: Integrations Canonical: https://gno.sh/docs/claude-code Markdown: https://gno.sh/docs/claude-code.md Claude Code supports two integration paths. **Skills** install GNO as a `/gno` slash command. Tool definitions load only when the command is invoked. **MCP** exposes the same retrieval tools through the Model Context Protocol so Claude can call them automatically. ## Quickstart ``` bun install -g @gmickel/gno gno setup ~/notes --name notes # Install the skill (preferred — zero context overhead) gno skill install --target claude --scope user # Optional: also install MCP for automatic tool calls gno mcp install --target claude-code ``` `gno setup` returns only after lexical search proves a real result from the folder you just indexed, so a successful exit means retrieval works rather than that files were copied. Semantic embeddings continue independently in the background. You can also do both steps at once with `gno setup ~/notes --name notes --connector claude-code-skill`. The skill target is called `claude` (Claude Code is the default). Use `--scope user` to install globally, or omit it for project-local install. ## Using the skill After installing the skill, Claude Code exposes a slash command: ``` /gno search "authentication patterns" /gno query "how does our API handle errors" /gno ask "what's our deployment process" ``` Skills are preferred for coding agents because they have zero context window overhead — the tool definitions only load when the slash command is invoked. Use `gno skill install --target all` to install across Claude Code, Codex, OpenCode, OpenClaw, and Hermes Agent at once. ## Using MCP With MCP installed, Claude Code can call `gno_query` / `gno_search` without a slash command. Example: > “Search my notes for deployment procedures” > “Find my architecture docs and summarize the relevant parts for this change” Claude picks the right tool (`gno_query`, `gno_search`, etc.) based on the request. ## Which one should you install? | Want | Install | | ----------------------------------------------------------------------- | --------------------------- | | Lowest context overhead, explicit lookups | Skill | | Claude decides when to retrieve, without being asked | MCP | | Context Capsules, Knowledge Delta, and verified Ask as structured tools | MCP | | Both, which is the common setup | Both — they do not conflict | ## Project scope For project-specific knowledge, install at the project scope. This writes a `.claude/settings.json` in the current project instead of the user-level config. ``` gno mcp install --target claude-code --scope project ``` Pair this with a committed [project profile](https://gno.sh/docs/project-profiles) so the repository declares what should be indexed and everyone who clones it gets the same retrieval setup. ## Context Capsules from Claude Code Ask Claude to compile one [Context Capsule](https://gno.sh/docs/context-capsules) for a goal, reason only from that evidence, and cite `evidenceId` values. You get a bounded, auditable payload instead of five searches filling the window. > “Build a Context Capsule for why we dropped the queue rewrite, then answer only from its evidence and tell me if coverage is incomplete.” The bundled skill recipes encode this and related workflows. Preview one with `gno skill show --file recipes/brain-first-lookup.md`. ## Verifying and troubleshooting - `gno skill paths` shows exactly where the skill was written; `gno mcp status` reports configuration presence. - Neither command proves the client loaded anything. The real check is asking Claude Code for something only your corpus knows and seeing a citation into your files. - No results at all? Run `gno doctor`. Lexical activation and semantic readiness are reported separately, and semantic can be legitimately pending while embeddings run. - Tools missing after a GNO upgrade? Reinstall with `--force`, then restart the client. - Wrong workspace? `gno mcp install --dry-run --json` prints the exact command, arguments, index, config, data, and cache paths that would be recorded. --- # Cursor integration > Install GNO as an MCP server in Cursor for hybrid retrieval while you code. Section: Integrations Canonical: https://gno.sh/docs/cursor Markdown: https://gno.sh/docs/cursor.md Cursor supports MCP servers natively. One-command install gives Cursor access to GNO’s 34 read-only tools by default (search, query, verified Ask, Context Capsules, memory recall, graph, backlinks, similar). Nineteen write tools are opt-in (53 total). ## Quickstart ``` bun install -g @gmickel/gno gno setup ~/notes --name notes gno mcp install --target cursor ``` After install, restart Cursor. The GNO MCP server will appear in the MCP settings panel automatically. ## Using it in Cursor Composer and chat can invoke GNO tools. Example: > “Search my notes for the retry logic we discussed” > “Find related notes to this file and summarize them” Cursor picks the appropriate GNO tool and cites the source docs in its response. ## Project scope For project-specific MCP configuration, install at the project scope. This writes a `.cursor/mcp.json` in the current project. ``` gno mcp install --target cursor --scope project ``` ## Share the setup with your team Project-scope MCP config says _that_ Cursor should talk to GNO. A committed [project profile](https://gno.sh/docs/project-profiles) says _what_ it should index: collection root, include and exclude globs, contexts, content types, and model preset, all repository-relative and portable. ``` gno profile diff # preview what applying would change gno setup . --apply-profile # apply, then prove retrieval ``` Nothing is applied implicitly, and GNO’s database, model cache, and locks never go into the repository. ## Tuning retrieval for code Code and prose want different embeddings. Rather than compromising globally, override per collection: ``` gno collection add ~/work/service/src --name service-code \ --pattern "**/*.{ts,tsx,go,rs,py}" --exclude node_modules ``` Source files also get structural first-pass chunking for TypeScript, JavaScript, Python, Go, and Rust, so a retrieved chunk tends to be a function rather than an arbitrary window. See [configuration](https://gno.sh/docs/configuration) for per-collection `models.embed` overrides. ## Manual configuration If auto-install fails, add to `~/.cursor/mcp.json`: ``` { "mcpServers": { "gno": { "command": "gno", "args": ["mcp"] } } } ``` This minimal form relies on `gno` being on Cursor’s `PATH`, which is often not the same `PATH` your shell has. Prefer the installer, which records an absolute entrypoint plus the active index, config, data, and model-cache locations. Run `gno mcp install --target cursor --dry-run --json` to see those exact values before writing them. ## Verifying and troubleshooting - Restart Cursor after installing. The server appears in the MCP settings panel. - `gno mcp status` reports configuration presence. For a real retrieval proof, run the explicit read-only check on the Connectors page of `gno serve`. - Server present but returning nothing? The index is probably empty for that collection. `gno doctor` separates lexical activation from semantic readiness. - Clients explicitly configured for the [resident HTTP gateway](https://gno.sh/docs/mcp#resident-http) share the daemon adapter within its idle grace; models reload after expiry. Direct CLI commands and installed stdio MCP remain standalone and do not automatically attach to that gateway. --- # Claude Desktop integration > Install GNO as an MCP server in Claude Desktop for hybrid retrieval over your local documents. Section: Integrations Canonical: https://gno.sh/docs/claude-desktop Markdown: https://gno.sh/docs/claude-desktop.md `gno mcp install --target claude-desktop` adds GNO to Claude Desktop’s MCP config so Claude can run hybrid search over your local index in conversation. This page is the Claude Desktop target only. ## Quickstart ``` bun install -g @gmickel/gno gno setup ~/notes --name notes gno mcp install --target claude-desktop ``` Quit and reopen Claude Desktop to pick up the new server. ## Using it in conversation > “Search my notes for anything about the quarterly review process” > “What did I write about the deployment architecture last month?” > “Find related notes to this PDF and give me a summary” Claude picks the right tool and cites the source document in the response. ## Manual configuration If the auto-install fails, add GNO to Claude Desktop’s config manually. Location depends on your OS: - **macOS**: `~/Library/Application Support/Claude/claude_desktop_config.json` - **Windows**: `%APPDATA%\Claude\claude_desktop_config.json` ``` { "mcpServers": { "gno": { "command": "gno", "args": ["mcp"] } } } ``` The minimal form depends on `gno` being on the `PATH` a GUI application inherits, which on macOS is frequently not your shell’s `PATH`. The installer avoids the problem by recording an absolute Bun and package entrypoint. Inspect what it would write first: ``` gno mcp install --dry-run --json ``` ## What Claude can actually read The index includes PDF, DOCX, XLSX, PPTX, plain text, source code, and imported mail, calendar, transcript, and JSONL [exports](https://gno.sh/docs/file-export-adapters). Converted binaries stay read-only, so Claude can cite a page of a PDF but cannot edit it. Retrieval is read-only by default. The nineteen mutating tools (create, update, move, capture, remember, reindex) require the explicit write opt-in, and authentication alone never enables them. ## Verifying and troubleshooting - Quit and reopen Claude Desktop after installing. A reload is not enough. - `gno mcp status` confirms configuration. The Connectors page in `gno serve` runs an explicit read-only retrieval check against the configured target. - Server shows up but every answer is generic? Ask a question with a phrase that appears only in your corpus. If it still answers from general knowledge, the tool is not being called; say “search my notes for …” explicitly. - Empty results across the board? Run `gno doctor`; lexical activation and semantic readiness are reported separately. --- # Use cases > Obsidian vaults, Claude Code memory, client corpora under local_only, Capsule-backed agent answers, and export-adapter records. Section: Guides Canonical: https://gno.sh/docs/use-cases Markdown: https://gno.sh/docs/use-cases.md Point GNO at a folder, prove retrieval with `gno setup`, then search, ask, or hand an agent a Capsule from that index. Examples: ## Obsidian vault Point GNO at your Obsidian vault. You keep editing in Obsidian. GNO adds BM25 + vector + reranking, a CLI, and an MCP server over the same vault. ``` gno setup ~/Documents/Obsidian --name vault gno mcp install --target claude-desktop ``` ## Memory for Claude Code Install GNO as a skill for Claude Code. Your coding agent can query your notes, docs, and project files on demand without pasting everything into every prompt. ``` gno skill install --target claude --scope user # Then in Claude Code: # /gno query "how does our auth flow work" ``` Standing facts the agent should look up later go through `gno remember` and `gno recall` under explicit scopes, with supersession and a recall receipt. See [memory](https://gno.sh/docs/memory). ## Research + synthesis Research corpus on disk, query via CLI, pipe results to `jq` or to a spreadsheet automation tool, and get cited AI answers from local models. ``` gno query "Q4 budget projections" --json | jq '.results[0]' gno ask "what did we conclude about pricing" --answer ``` ## Due diligence and client work Index a client’s mixed-format document set (Markdown, PDFs, Office docs, mail exports), pin the collection so it can never leave the machine, and share only the compiled slice you meant to share. ``` gno setup ~/clients/acme --name acme gno collection policy set acme local_only # Compile the evidence behind a finding, with exact spans gno context build "vendor lock-in exposure" --collection acme \ --budget 16000 --json --output finding-3.json # Months later, is that evidence still accurate? gno context verify finding-3.json --md ``` The combination that matters here is [egress policy](https://gno.sh/docs/collection-egress) plus [Capsules](https://gno.sh/docs/context-capsules): the corpus is pinned local, and the artifact behind each finding is reproducible and re-checkable long after the engagement ends. Publish a deliverable as an invite-only or encrypted space when the client needs a URL. ## Agent work you can defend When an agent writes a PR description, an ADR, or a report, the question is always “where did that come from”. Give it a Capsule and require it to answer from that evidence only. ``` gno context build "why we chose the queue over cron" \ --collection eng-docs --budget 12000 --json --output why.json # Generation that stops when the evidence stops gno ask "why did we choose the queue over cron" --verify --show-sources ``` If the corpus does not support a claim, verified Ask withholds the draft and names the gap instead of producing a confident paragraph you have to fact-check by hand. ## Meetings and mail as searchable records Export the transcript and the mail thread, and index them as individually citable records rather than as one opaque blob. ``` gno collection add ~/exports --name exports \ --pattern "**/*.{vtt,srt,eml,mbox,ics}" gno update gno query "what did we agree about the migration date" --collection exports ``` Each message, event, and cue keeps its own participants, timestamps, thread identity, and anchors. See [file and export adapters](https://gno.sh/docs/file-export-adapters). ## Team wiki with git sync Point GNO at a git-synced team wiki directory and run `gno daemon --detach`. The index stays fresh as people push, and everyone gets the same retrieval behavior in their local CLI and AI tools. Commit a [project profile](https://gno.sh/docs/project-profiles) so the repository itself declares what to index, and `gno setup . --apply-profile` reproduces the setup on a new machine in one command. ## Retrieval that gets measurably better When a search misses something you know exists, capture it instead of shrugging. Label the miss, export a content-free fixture, and replay candidate pipelines against it before changing a model. ``` gno trace label --label missing-expected \ --target gno://notes/postmortem-q3.md gno trace export --format qrels --output recall.json gno trace replay --candidate hybrid --md ``` See [private retrieval learning](https://gno.sh/docs/retrieval-learning). ## Capture with provenance `gno capture` writes a note with `--source-kind` and you can filter it later with `--since`. ``` gno capture "Vendor quoted 14 week lead time" --collection notes \ --source-kind meeting --title "Acme lead time" gno query "lead time" --collection notes --since "last month" ``` --- # Context Capsules > What a Capsule is, how GNO compiles one, every field it contains, how to verify it later, and when to use one instead of a plain query. Section: Guides Canonical: https://gno.sh/docs/context-capsules Markdown: https://gno.sh/docs/context-capsules.md A Context Capsule is a compiled, self-describing evidence bundle for one stated goal. It contains the passages that answer the goal, each carrying the exact line range and content hashes needed to prove it came from where it says, all inside a single token and byte budget, plus an explicit record of what was left out and what could not be found at all. The point is to replace a loop with an artifact. Without a Capsule, an agent searches, reads a document, searches again with better words, reads two more, and eventually stops because its context window is full rather than because it has enough. Each of those reads costs a round trip, and nothing at the end records which bytes actually supported the answer. A Capsule does the retrieval, deduplication, selection, and budgeting once, and hands over one payload you can audit months later. ## When to use one | Situation | Use | | ----------------------------------------------------------------------------------------------------------- | --------------------------------------------- | | You know the exact string, identifier, or error | `gno search` | | You want the most relevant documents for a question | `gno query` | | You want a written answer with citations | `gno ask --verify` | | You need evidence across several documents, with a budget, that someone else (or an agent) will reason over | `gno context build` | | You need to prove months later which bytes supported a decision | `gno context build` then `gno context verify` | The rule of thumb: reach for a Capsule when the answer spans documents and the cost of being wrong is higher than the cost of one extra second. For a single lookup, `gno query` is cheaper and the Capsule machinery buys you nothing. ## Building one ``` gno context build "why did we drop the queue rewrite" \ --collection work-docs \ --budget 12000 \ --json --output capsule.json ``` `--budget` is the global token ceiling for the whole canonical payload, not a per-document allowance. Everything competes for the same space, which is what makes selection meaningful. `--output` writes the file; GNO never saves a Capsule implicitly. Progress goes to stderr so stdout stays clean for a pipe. Useful flags: `--query` separates the retrieval query from the stated goal when the natural phrasing of the goal is bad search input. Repeatable `--query-mode term:…`, `intent:…`, and `hyde:…` entries steer retrieval and are frozen into the request. Scope filters (`--collection`, `--uri-prefix`, `--tags-all`, `--tags-any`, `--category`, `--author`, `--lang`, `--since`, `--until`) are hard filters and are recorded in the Capsule. `--fast` skips model loading; default and `--thorough` use semantic and rerank capabilities when available and record a fallback when one was attempted but unavailable. ## How compilation works 1. **Facet derivation.** The goal is decomposed into facets deterministically, with no model call: quoted phrases, capitalised entities, comparison structures (`X vs Y`, `compare A and B`), and temporal signals like “last month”. Facets are what coverage is later measured against, which is why a two-sided goal produces a Capsule that tries to cover both sides instead of returning five passages about whichever side was more popular in the index. 2. **Retrieval.** The normalized request runs through the same hybrid pipeline as `gno query`: BM25, vectors, default bounded graph expansion, fusion, reranking. Result and candidate limits are global across repeated collections, and candidate work is distributed in canonical collection order so the outcome does not depend on argument order. 3. **Selection.** Candidates are chosen by marginal facet coverage, not raw score. A passage that is slightly weaker but covers a facet nothing else covers beats a fifth passage restating the top hit. Duplicates and overlapping spans collapse, and a per-document share cap stops one long document from consuming the whole budget. 4. **Budgeting.** Selection stops when the canonical JSON payload would exceed the token or byte budget, minus a safety margin. If the tokenizer for the active model is unavailable, GNO estimates and says so with a `token_estimate_used` warning rather than silently guessing. 5. **Freezing.** The scope, retrieval request, capability state, fallbacks, and model and config fingerprints are written into the payload. That is what makes the result reproducible and what later lets verification tell “the source changed” apart from “you are running a different model now”. ## What is inside The JSON is a closed schema: unknown fields are rejected, not ignored. Top-level blocks: | Field | What it holds | | --------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `goal`, `query` | The stated goal and the query actually used for retrieval. They differ when you passed `--query`. | | `scope` | Index name plus every hard filter that was in force: collections, URI prefix, tags, categories, date bounds. | | `budget` | Requested tokens and bytes, safety margins, and what was actually used. Authority is the canonical JSON, so the number means the same thing on every machine. | | `retrieval` | The frozen normalized request: query modes, effective limits, graph request, and requested/attempted/outcome state per capability. | | `fingerprints` | SHA-256 of the config and retrieval request, plus the embedding model, rerank model, and tokenizer identities. | | `capabilities`, `fallbacks` | What was available and what degraded. A capability you did not request is reported as `not_requested`, never as a failure. | | `guidance` | The trust contract, always the same three assertions: extractive-only, evidence is untrusted data, instruction boundary is hard-delimited. Plus any configured collection contexts that were in scope. | | `evidence[]` | The passages themselves. See below. | | `coverage` | Requested facets, which evidence covered each one, and which went unresolved with a reason. | | `omissions` | Candidates that were retrieved and then deliberately dropped, each with a reason code. | | `truncated`, `warnings` | Whether the budget cut the result short, and any caveats about how it was produced. | ### An evidence item Every passage carries enough to re-derive and re-check it: - `uri`, `docid`, `collection`, `title`, `heading` — where it came from. - `startLine`, `endLine`, `text` — an inclusive line range in the canonical mirror. The line count of `text` must equal the coordinate span, and carriage returns are rejected, so the coordinates cannot drift from the bytes. - `sourceHash`, `mirrorHash`, `passageHash` — hashes of the original file, the canonical mirror, and the exact passage bytes. Three levels, because “the file changed”, “the conversion changed”, and “this specific paragraph changed” are different problems. - `evidenceId` — binds the coordinates and all three hashes into one identity. This is what a claim cites. - `retrievalRank`, `selectionRank` — where it placed in retrieval versus where selection put it. A large gap tells you facet coverage promoted it. - `retrievalSources`, `graphExpanded` — which retrieval paths surfaced it. - `facets` — which facets of the goal this passage covers. - `trust: "untrusted"` and `egress` — the passage is data, never instruction, and it carries the transport policy of its source collection. - `modifiedAt`, `documentDate`, `observedAt` — file mtime, the document’s own stated date, and when GNO last saw it. Three different questions. - `record` — present for imported mail, calendar, and transcript records: thread, participants, anchors, and bounded attachment metadata. ### Reading coverage `coverage.complete` is the first thing to look at. When it is false, `unresolvedFacets` and `gaps` tell you which part of the goal has no evidence behind it, and why: | Gap code | Meaning | | ------------------------- | --------------------------------------------------------------------------------- | | `facet_not_found` | Retrieval found nothing for this facet. Your corpus probably does not contain it. | | `global_budget_exhausted` | Evidence existed but did not fit. Raise `--budget`. | | `capability_unavailable` | A model needed to find it was not loaded. Check `fallbacks`. | | `filtered_by_scope` | Your own filters excluded it. Widen the collection, tags, or date range. | This is the field that makes a Capsule honest. A ranked list has no way to say “the second half of your question has no answer in here”. A Capsule says it in a machine-readable field, so an agent can stop instead of inventing the missing half. ### Reading omissions Omissions are candidates that were found and then dropped on purpose: `duplicate`, `overlap`, `global_budget`, `redundant_coverage`, `document_share_cap`, `filtered_by_scope`, or `invalid_coordinates`. Each keeps its URI and hashes, so “why is that document not in here” has an answer that is not a shrug. A run heavy on `global_budget` wants a bigger budget; one heavy on `redundant_coverage` means your corpus repeats itself and the Capsule is doing its job. ## Determinism The same goal against the same index state with the same models produces byte-identical canonical JSON. Determinism is a design constraint: facet derivation is generation-free, ordering is canonical, and collection order is normalized. Determinism is what makes the fingerprints useful — if a rebuilt Capsule differs, either the corpus moved or the model did, and the fingerprints say which. ## Verifying later ``` gno context verify capsule.json --json cat capsule.json | gno context verify - --md ``` Verification is non-generative and never rewrites your file. It re-reads the sources and reports, per evidence item, a content status and a ranking status: | Status | Codes | What it means | | ----------- | ---------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------- | | `unchanged` | `verified_unchanged` | The exact bytes are still there. | | `stale` | `source_stale`, `mirror_stale`, `passage_stale`, `mirror_corrupt`, `chunk_corrupt` | Something changed. The specific code tells you whether the file, the conversion, or that one passage moved. | | `missing` | `source_missing`, `mirror_missing`, `chunk_missing` | The evidence is gone. | Ranking is reported separately as `unchanged`, `reranked`, or `unavailable`. Stale or missing content is never ranked. Fingerprint drift is reported independently of both, so a model swap does not masquerade as corpus change. Verification opens the Capsule’s own saved index by default. An explicit `--index` must match, and a mismatch fails before GNO opens a store. A Capsule built with an active tokenizer requires that tokenizer to verify; a runtime without it returns `tokenizer_unavailable` rather than trusting the saved token count. ## Keeping a Capsule fresh ``` gno context watch capsule.json --question "Who owns launch?" --label launch gno context watches --json gno context reverify capsule-abc123 --json gno context unwatch capsule-abc123 ``` Registration stores identity and evidence hash references, never the Capsule body or passage text. The file stays yours; GNO does not rewrite it. When `serve` or `daemon` is running, it coalesces settled index changes and reverifies only registrations whose evidence actually moved, resuming from a durable high-water mark across restarts. `--notify` publishes a local `capsule-reverified` event after the result is stored. The event is metadata only: identity, status, affected-question state, timestamp. No passages, no paths, no hashes. Manual `gno context reverify` exits `0` only for a completed operation. A persisted failure prints its code and exits `2`, so a script cannot mistake a stored failure for success. These lifecycle commands are CLI-only; REST, MCP, and the SDK do not add persistent watch endpoints. ## Using Capsules from an agent Over MCP, `gno_context` builds one and `gno_context_verify` checks a saved one. The SDK and REST (`POST /api/context`) expose the same contract. The intended shape of an agent turn is: build one Capsule for the goal, reason only over its evidence, cite `evidenceId` values, and stop when `coverage.complete` is false rather than filling the gap from memory. `gno ask --verify` is this pattern with the loop closed: generate against one closed Capsule, classify every substantive claim against the retained evidence, and withhold the draft below full support. ## The trust boundary Indexed content is untrusted input. Markdown projections delimit every passage with a collision-resistant fence whose width and character are derived from that block, so a document containing fence characters cannot forge a closing boundary and escape into instruction space. Titles, headings, and configured context text stay JSON-escaped; passage bytes stay exact. The `guidance` block restates this inside the payload so a model reading the Capsule sees the contract too. ## Limits - Evidence is extractive: exact bytes from your files, never paraphrase. - It proves a passage exists at a location with given content. Whether the document is true is outside the Capsule. - It is a snapshot; freshness is `verify` and `watch`. - Compilation costs more than one `gno query`. Use query for a single lookup. ## The measured result Against 48 paired tasks in the agentic retrieval benchmark, the promoted Capsule lane retained 100% task completion accuracy while reducing outer-agent retrieval calls by 48.94% and model-visible context by 44.12%, with 100% of substantive claims linked to an exact span and deterministic replay. The raw receipts, the pinned corpus, and the stated limitations ship in the repository — see [benchmarks](https://gno.sh/features/benchmarks) for the artifacts and the single-task outcome demo. --- # Private retrieval learning & replay > Turn a real retrieval miss into a content-free regression fixture, then replay a candidate pipeline against it before you change anything. Section: Guides Canonical: https://gno.sh/docs/retrieval-learning Markdown: https://gno.sh/docs/retrieval-learning.md Trace recording is local and off by default. Only labels you apply count; exported qrels carry identities and outcomes, not source text; `gno trace replay` always returns `applied: false`. You capture a miss, replay a candidate pipeline, and decide whether to promote. Ranking that learns from clicks cannot reconstruct why scores moved; GNO records nothing until you switch it on. ## The lifecycle 1. **Record.** With tracing enabled, retrieval operations emit a receipt ID on stderr. A trace spans the query, any Context Capsule built from it, document reads, and which evidence was opened, cited, or pinned. 2. **Judge.** You label outcomes. Nothing is inferred. 3. **Export.** Completed traces become a deterministic, content-free qrels file: identities and outcomes, no passages. 4. **Replay.** A candidate pipeline runs against that frozen baseline and reports what changed. 5. **Decide.** Replay can recommend promotion. It always returns `applied: false`. You apply it or you do not. ## Inspecting traces ``` gno trace list --md gno trace show --json ``` Traces are bounded and retention-limited. Listing is paginated with opaque cursors. A trace stays _open_ while its operation is still in flight and only terminal traces can be exported, which stops a half-finished query from becoming evidence. ## Labelling honestly ``` gno trace label --label relevant \ --target gno://notes/decision.md gno trace label --label missing-expected \ --target '#abcdef' ``` Three labels, and the distinction between them matters: | Label | Means | Constraint | | ------------------ | ----------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------- | | `relevant` | This result was actually useful. | Must match evidence the trace already recorded. | | `irrelevant` | This result was returned and was noise. | Must match evidence the trace already recorded. | | `missing-expected` | The document that should have ranked did not appear at all. | Accepts a `gno://` URI, a docid, or an immutable source hash. Document text is never copied into the judgment. | `missing-expected` is the one that pays for the whole feature. It encodes the recall failure you noticed, which is exactly the case a click-based system can never see, because you cannot click a result that was not shown. Repeating a label is idempotent. A correction is appended rather than rewriting history, so the record of what you believed and when stays intact. Absence of a label is never a negative: a result you simply did not judge stays unjudged forever. ## Exporting a fixture ``` gno trace export --output traces.json gno trace export --format qrels --output qrels.json ``` Qrels export has a higher bar than plain export: it needs replay-mode receipts with complete query, filter, rank, hash, and exact-span provenance. What it writes is identities and outcomes. Source and mirror text are not copied, which is what makes a fixture safe to keep in a repository, attach to an issue, or hand to someone else, even when the underlying corpus is confidential. Completed, partial, failed, and cancelled outcomes stay distinct in the export. None of them silently becomes a negative label. ## Replaying a candidate ``` gno trace replay --candidate bm25 --md gno trace replay --candidate hybrid \ --candidate-limit 100 --no-expand --json ``` Replay verifies the local aggregate manifest before it runs, then: - reports final rank separately from planner rank, so you can see whether a change came from retrieval or from reranking; - classifies every source as `unchanged`, `stale`, `missing`, `inactive`, or `unindexed`, so a corpus that moved under the fixture is disclosed rather than quietly scoring worse; - preserves capability and fallback truth, so a comparison run without a rerank model does not read as a pipeline regression; - performs no network upload and mutates no ranking, prompt, model, configuration, trace, or user file. The output can say a candidate looks better. It cannot enact that. Promotion is a human action, deliberately. ## Retention, deletion, and purge ``` gno trace delete gno --yes trace purge --json ``` The purge receipt reports `physicalCleanup` as `completed`, `wal_busy`, or `failed`. Only `completed` confirms the SQLite write-ahead log was actually truncated: a purge that says it deleted your data while the bytes are still recoverable in the WAL would be a lie, so GNO reports the difference. Recording can be turned off independently of managing receipts you already stored. ## A worked example You search for the incident postmortem and the wrong quarter’s document ranks first. The right one exists, you know its path, and it is nowhere in the results. ``` # 1. The query printed a receipt ID on stderr gno trace show tr_9f2c --json # 2. Record both facts: what was wrong, what was missing gno trace label tr_9f2c --label irrelevant --target gno://notes/postmortem-q1.md gno trace label tr_9f2c --label missing-expected --target gno://notes/postmortem-q3.md # 3. Freeze it gno trace export tr_9f2c --format qrels --output incident-recall.json # 4. Does thorough mode fix it? gno trace replay qx_51ab --candidate hybrid --candidate-limit 100 --md ``` Keep `incident-recall.json` and the next time you change an embedding model, rerun it. That is a regression test for retrieval quality, built from a real failure rather than a synthetic one, and it contains none of your text. ## Related For fixtures you author from scratch rather than capture, see [benchmarks](https://gno.sh/features/benchmarks) and `gno bench`. For diagnosing a single miss without building a fixture at all, `gno query diagnose "…" --target ` reports which retrieval stage dropped the document. --- # Knowledge Delta > Answer change-shaped questions directly: what moved since Tuesday, what structurally changed in this note, and which conclusions depended on it. Section: Guides Canonical: https://gno.sh/docs/knowledge-delta Markdown: https://gno.sh/docs/knowledge-delta.md A knowledge base rots quietly. Someone edits the decision note, and the three documents that cite it keep looking authoritative. A runbook picks up a step, and the Capsule you built for last month’s review still says what it said. `gno changes`, `gno diff`, and `gno impact` answer what moved since a cursor, what headings/links/typed edges changed in a note, and which documents reach it through those links. The journal stores bounded metadata and structural summary, never source bodies, and notifications never carry content. Search answers current state; these commands answer change. Freshness machinery connects them to saved Context Capsules. ## The three questions | Question | Command | | ------------------------------------------------------ | ------------- | | What moved since the last release / meeting / Tuesday? | `gno changes` | | What structurally changed inside this document? | `gno diff` | | What else depends on this document? | `gno impact` | ## gno changes ``` gno changes --since 2026-07-20T00:00:00Z --json gno changes --since --json ``` A metadata-only lifecycle journal: documents created, updated, removed, reactivated. `--since` takes either an ISO-8601 timestamp or an opaque cursor returned by an earlier response, which is how you build a “what is new since I last looked” loop without re-scanning. Retention is bounded, and this is where it gets careful: if retention has expired your cursor, GNO does not invent the gap. The response returns no fabricated history and tells you the earliest cursor still available, so a script can restart honestly instead of silently skipping a week. An identical file restored at its previous path becomes active on successful sync. Its activation and one `reactivate` event commit together; subsequent unchanged syncs add no restoration history. Existing chunk identity and proven identical embedding inputs survive restoration. Changed title/text or model/runtime identity still needs matching vector coverage. This does not expand journal retention or turn the journal into a source-body archive. ## gno diff ``` gno diff gno://notes/plan.md --json gno diff gno://notes/plan.md --change --json ``` This is a _structural_ diff, not a text diff. It reports what changed about the document’s shape: headings added, removed, or renamed; links appearing or disappearing; typed relationships from frontmatter changing. That is deliberate. Source bodies are never retained, so GNO cannot show you a line-level patch, and pretending otherwise would mean keeping a copy of every version of every private note. Structural is usually the level you want anyway. “The Decision heading disappeared from the RFC” is more actionable than forty lines of prose churn. Where prior structure is missing, `history` and `structureDelta.truncated` disclose it rather than presenting a partial view as complete. Scoped sync repairs affected incoming references globally, including cross-collection and ambiguous targets. A complete unchanged projection avoids broad mirror reads and identical edge writes; an interrupted or outdated inventory requires full reconciliation. Impact still reads the current bounded graph and does not reconstruct unavailable historical dependencies. ## gno impact ``` gno impact gno://notes/plan.md --max-depth 3 --max-edges 250 --json ``` Impact walks _inbound_ dependencies: what points at this document, then what points at those, following typed relations, wiki links, and Markdown links. Every result carries an evidence path: this note reaches that one through exactly these typed, wiki, or Markdown links. Depth, node, edge, frontier, and visited-row caps are always enforced. A knowledge graph with one hub note would otherwise return most of your vault and tell you nothing; bounded traversal keeps the answer usable and the runtime predictable. ## Capsule freshness The three commands above tell you what changed. Freshness closes the loop back to conclusions you already drew. ``` gno context watch capsule.json --question "Who owns launch?" gno context watches --json gno context reverify capsule-abc123 --json ``` A registered Capsule is watched by evidence identity, not by content: GNO stores hash references, never the passages. When `gno serve` or `gno daemon` is running, it coalesces settled journal changes and reverifies only the registrations whose evidence actually moved. Restart resumes from a durable high-water mark; if that cursor has expired, it makes one conservative bounded pass rather than skipping work. The stored result is the same canonical, non-generative receipt `gno context verify` produces. Reverification never invokes answer generation, so a background freshness check cannot quietly rewrite a conclusion. `--notify` emits a local `capsule-reverified` event carrying identity, status, affected-question state, and a timestamp, and nothing else. ## A useful pattern Run this after a week of edits to find decisions that may have moved under you: ``` # What changed this week gno changes --since "$(date -v-7d +%Y-%m-%dT00:00:00Z)" --json > week.json # For a document that changed, what depended on it gno impact gno://notes/pricing-decision.md --max-depth 2 --md # And which saved evidence bundles are now stale gno context watches --json ``` ## Everywhere else `changes`, `diff`, and `impact` have equivalent REST, MCP (`gno_changes`, `gno_diff`, `gno_impact`), and SDK reads with the same bounds and the same opaque cursors. The machine-readable contracts are `changes.schema.json`, `document-diff.schema.json`, and `impact.schema.json`. Saved-Capsule watch lifecycle is CLI-only by design; it is a durable local registration, not a request-scoped read. Explicitly empty filters and selectors are rejected across every surface rather than being treated as “everything”, because an accidental empty filter that returns the whole journal is a worse failure than an error. --- # Verified setup & project profiles > gno setup returns only after a corpus-derived BM25 proof. Commit .gno/index.yml for portable collection/context/content rules; the SQLite DB, model cache, and locks stay out of the repo. Section: Guides Canonical: https://gno.sh/docs/project-profiles Markdown: https://gno.sh/docs/project-profiles.md `gno setup` does not return until lexical search, using a term derived from the folder it just indexed, returns the expected document. A repository can also carry that intent in `.gno/index.yml` so a clone reproduces the same collections without a setup wiki. ## Setup that proves itself ``` gno setup ~/notes --name notes gno setup ~/notes --no-semantic gno setup ~/notes --connector cursor-mcp --connector codex-skill gno setup ~/notes --json ``` `gno setup` does not return until it has derived a bounded term from the corpus it just indexed and confirmed that lexical search returns the expected document for it. The proof comes from your content, not from a fixture, so it cannot pass on an empty or mis-walked collection. Rerunning is safe: the same canonical folder and collection are reused. Semantic readiness is tracked as a separate, resumable concern. Embeddings may still be downloading or running when setup returns, and GNO will say so rather than blocking or pretending. `--no-semantic` records an explicit skip. A pending semantic stage never invalidates the lexical proof you already have. The same activation result appears in `gno status --json`, `gno doctor`, `/api/status`, and the Web Health Center. Note the distinction from `/api/health`, which proves only that the server process is alive. ### Connectors Repeatable `--connector` flags install and check supported agent integrations as part of setup: Claude Code, Claude Desktop, Cursor, Codex, OpenCode, OpenClaw, and Hermes. Installation is install-once and its result composes alongside the unchanged setup result rather than replacing it. One honesty note: GNO can prove an MCP target retrieves, because it can run a bounded read-only retrieval against it. It cannot prove a client actually loaded an installed _skill_, so that step reports what was written rather than claiming runtime success. ## Project profiles A profile is a `.gno/index.yml` file committed to a repository, declaring what that repository wants indexed and how. It holds intent only. GNO’s database, model cache, receipts, and runtime locks stay outside the repository, and validation rejects any attempt to point them inside it. ``` schemaVersion: "1.0" collection: name: project-docs root: docs include: - "**/*.md" - "**/*.pdf" exclude: - generated languageHint: en modelPreset: slim-tuned contexts: - file: AGENTS.md - text: Prefer primary project decisions. contentTypes: people: prefixes: [people] preset: person graphHints: [works_at, mentions] affinityDefaults: enabled: true contribution: 0.02 recommendedCapabilities: - workspace.read ``` Every path is repository-relative and portable across POSIX and Windows. `.gno` is always excluded from the declared collection. ### Inspect before you apply ``` gno profile check gno profile show gno profile diff ``` All three are read-only. Discovery walks upward to the first Git boundary and picks the nearest profile; a nested monorepo profile shadows an ancestor and profiles are never merged, so what applies is always one file you can point at. A worktree `.git` file counts as a boundary. Pass an exact directory or `.gno/index.yml` path to disable upward fallback. Remote SDK, REST, MCP, and Web inputs cannot trigger profile discovery. Nothing reachable over the network gets to make GNO probe your filesystem for config. ### Applying ``` gno profile apply gno setup . --apply-profile ``` Profiles are never applied implicitly. Plain `gno setup` detects a nearby profile, prints preview guidance, and changes nothing. Application is create/update-only: unrelated collections, documents, and contexts in your index survive untouched, and reapplying an unchanged profile is a no-op that does not advance timestamps. `--apply-profile` fails closed. Once setup has discovered a valid profile for an explicit request, applying it is a prerequisite: if apply fails, throws, or cannot return a complete collection receipt, setup stops before the ordinary folder transaction and before any connector work. An inspection transport failure stops even earlier, leaving config, index, and store state unchanged. A late failure may have left durable create/update-only state; rerunning `gno profile apply` resumes idempotently and gives the detailed diagnostic. `--apply-profile` cannot be combined with explicit `--name` or `--exclude` overrides, because a profile that silently loses to a flag is worse than an error. An invalid or absent profile never makes profiles mandatory: ordinary folder setup continues, and with `--json` you get `status: completed_with_actions` plus `profile.apply: null` saying the optional action did not run. ### What validation rejects A profile is a file other people can commit to a repository you clone, so the schema is deliberately narrow. Rejected: absolute paths, path traversal, environment expansion, runtime database/model/lock paths, secret fields, arbitrary hooks, and symlink escapes. Also rejected: Windows-reserved names, trailing dots or spaces, unbalanced or negated globs, and likely-secret context paths such as `.env`, private keys, and credential files, including when a safe-looking symlink resolves to one of those inside the repository. Context files must be regular UTF-8 files of at most 64 KiB; `.gno/index.yml` itself is bounded at 1 MiB. Brace alternatives (`{a,b}`) are intentionally rejected so the runtime and the published schema enforce identical path rules; use separate `include` or `exclude` entries instead. ## Project-aware ranking `affinityDefaults` ties into GNO’s project affinity: when you run a trusted local CLI query from inside a repository, a matching collection receives one small, bounded, explainable ranking contribution (at most `+0.03`, sharing a `±0.08` cap with other auxiliary signals). The boundaries matter more than the number. It is a soft tie-breaker, not a filter: it can reorder near-equals, never create candidates or override collection, tag, date, exclude, or egress filters, and a clear base-score lead still wins. `--project-root` sets it explicitly, `--no-project-affinity` turns it off, and `--explain` shows the contribution with redacted aliases rather than raw paths. SDK, REST, MCP, and Web `projectHints` are opaque untrusted metadata with zero ranking effect: those surfaces never probe a filesystem. --- # File & export adapters > Index mail, calendar, transcript, browser, and JSONL exports as individually searchable records, with no account access and no live connectors. Section: Guides Canonical: https://gno.sh/docs/file-export-adapters Markdown: https://gno.sh/docs/file-export-adapters.md An mbox file is not one document. It is four thousand messages that happen to share a file, and indexing it as a single blob makes every one of them unfindable. The same is true of a calendar export, a subtitle file, and a JSONL dump. Export adapters split those containers into _logical records_: one message, one event, one cue, one bookmark, one row. Each becomes independently searchable and independently citable, while keeping its export path, exact source locator, dates, participants, thread or session identity, attachment inventory, and anchors. These are **file adapters, not connectors**. They read export files you produced and placed somewhere. They do not authenticate to an account, inspect a live browser profile database or cookie store, fetch a URL, open an attachment, execute embedded content, or unpack an archive. If you want yesterday’s mail indexed, you export yesterday’s mail. ## What is supported | Source | File types | One record is | Notes | | --------------------------- | ---------------------------- | ------------------------------------------- | ------------------------------------------------------------------------------------------------------- | | JSON Lines | `.jsonl`, `.ndjson` | One valid object per line | Optional declarative field mapping; a malformed line is isolated rather than failing the file | | Mail | `.eml`, `.mbox` | One message | Bounded MIME nesting, body, and attachment counts; attachments are inventoried, never opened or indexed | | Calendar | `.ics` | One VEVENT or recurrence exception | Timezone-aware; recurrence anchors expand over a bounded local horizon rather than to infinity | | Transcripts | `.vtt`, `.srt` | One cue or segment | Speaker and timestamp anchors retained | | Browser exports | `.browser-export` | One bookmark, history, or reading-list item | Must contain a recognized export shape; live profile databases are rejected outright | | Explicit transcript exports | Configured `.json` or `.txt` | One segment or record | Opt-in only: generic JSON and text stay ordinary documents unless you declare otherwise | Markdown, PDF, Office, plain text, and source code continue through the existing one-file-one-document converter lane. Nothing about adapters changes how those are handled. ## Getting started For the automatic formats there is no configuration: add the export file or directory to a collection and index it. ``` gno collection add ~/exports --name exports \ --pattern "**/*.{jsonl,eml,mbox,ics,vtt,srt}" gno update ``` Collection `include` stays an extension allowlist: when it is non-empty, list the extensions you want. With the default empty `include`, an explicitly configured JSON transcript adapter automatically adds `.json` to the supported-extension scan. ### Mapping JSONL fields GNO recognises conventional `id`, `title`, `text`/`content`/`body`, and `author` names. When your export uses different ones, declare a closed mapping: ``` collections: - name: exports path: /Users/me/exports pattern: "**/*" include: [.jsonl, .eml, .mbox, .ics, .vtt, .srt, .browser-export] recordAdapters: jsonl: fieldMapping: id: /external_id title: /subject body: /payload/text author: /owner/name participants: /participants threadId: /thread_id dateFields: created: /created_at ``` Selectors are JSON Pointers, or ordered arrays of JSON Pointers when a field lives in different places across rows. They are data, not code: a selector cannot execute, traverse prototypes, read a file, or make a network request. ### Opting into JSON or text transcripts ``` recordAdapters: transcript: format: json # json, text, vtt, or srt ``` Generic JSON and text are never guessed as transcripts. Heuristic detection here would misclassify ordinary config and data files, so it is per-collection opt-in. ## Identity, updates, and deletions Each record gets an opaque key derived from the adapter identity plus the record’s stable export identity. Reimport with the same key and source hash is a no-op; a changed source hash updates the existing virtual document in place. Deletion is where export ingestion usually goes wrong, so GNO is strict. A _complete_ snapshot deactivates records that disappeared from it. A _partial_ snapshot never does. A malformed row, a truncated file, invalid framing, or any cap failure marks the import partial, and a damaged export is therefore incapable of authorizing deletion. A half-written mbox cannot wipe your mail history from the index. For JSONL, configure `fieldMapping.id` or provide a conventional `id` when updates must preserve identity. Without one, identity is derived from the row’s canonical content, so editing a row appears as one removal plus one addition rather than an in-place update. That is correct behaviour for content-addressed rows, but it will surprise you if you expected stable IDs, so set one. ## How records appear in results Search and `gno get` report the real container path in `source.relPath`, plus a `record` object with the bounded locator and metadata. The unique `gno://` URI addresses GNO’s internal virtual document: use that URI or its docid with `gno get`. Ask and Context Capsules carry the same record metadata alongside exact canonical-mirror line spans, so a claim can cite “message 14 of this mbox, lines 4 to 9” and be verified later. `record.adapter` holds the adapter ID, version, and configuration fingerprint that produced the record, which is what lets you tell “the export changed” apart from “my mapping changed”. Virtual documents live under the reserved `.gno/records/` URI namespace, and a physical directory of that name is always excluded from collection walking so real files can never collide with the reserved space. ## What this is good for - Searching a mail archive by meaning rather than by sender and date, with each message citable on its own. - Asking what was decided in a meeting when the only record is a subtitle file. - Pulling a calendar export into the same index as your notes, so “what did we agree the week of the offsite” has both halves available. - Indexing an application’s JSONL log or event export as individually retrievable records without writing an ingestion script. --- # Read-only integrity audits > Find broken local links, incomplete declared provenance, and source/index drift. Stable finding IDs; no automatic repair. Section: Guides Canonical: https://gno.sh/docs/integrity-audits Markdown: https://gno.sh/docs/integrity-audits.md `gno audit` reports unresolved local wiki/Markdown links, missing declared capture/record provenance, and source/index byte drift. It does not repair. ``` gno audit gno audit links --collection notes --path projects gno audit provenance --json gno audit freshness --max-age-days 90 --json --output audit.json ``` ## Three deterministic categories - **Links** finds unresolved or ambiguous local wiki and Markdown targets plus isolated documents under your explicit orphan roots and ignored prefixes. External URLs are not local graph edges. - **Provenance** checks only capture and logical-record contracts that a document explicitly declares. It does not invent citations or judge whether prose is true. - **Freshness** distinguishes missing/unreadable sources, source bytes that differ from the indexed revision, indexing errors, and optional age review signals. Age alone is never labelled false. ## Complete findings, honest gaps Human output and JSON use one report. Finding IDs are stable for the same rule, subject, location, and evidence. `--max-findings`bounds returned detail while exact totals remain visible. Exit 0 is clean, 4 is complete with findings, and 5 means evidence was partial, unavailable, inconclusive, cancelled, or kept changing after one bounded retry. The read-only MCP tool `gno_audit` returns the same report with collection, path, tag, age, and orphan-policy inputs. Both surfaces run offline. They do not write notes, config, index rows, graph edges, daemon state, findings, baselines, or suppressions. ## Bounds Audit v1 reports; it does not repair. There is no contradiction judge, citation generator, maintenance scheduler, hidden overnight job, or preview/apply mutation. Review the evidence and choose any follow-up yourself. `gno egress-audit` is unrelated: it manages content-free receipts for transport-policy decisions. --- # Memory > How gno remember and gno recall store and retrieve agent facts: the write-path taxonomy, explicit scopes, supersession, budgeted cited recall, context fencing and its limits, and what the memory slice deliberately does not do. Section: Guides Canonical: https://gno.sh/docs/memory Markdown: https://gno.sh/docs/memory.md `gno remember` stores one fact. `gno recall` returns the current facts that match a query, under a budget, with `gno://` cites and a receipt. Both are core contracts exposed on every surface with one shared schema: the CLI, the MCP tools `gno_recall` (read set) and `gno_remember` (write set, `--enable-write`), the REST endpoints `POST /api/memory/remember` and `POST /api/memory/recall`, and the SDK methods `client.remember()` and `client.recall()`. Results are the same objects everywhere; error codes (`MEMORY_*`) are identical and each surface maps them onto its own envelope. Memory lives in your own markdown files. The SQLite index stays derived and disposable, exactly as for every other collection. ``` gno remember "Prod deploys from main only" --scope project:gno gno remember "Prod deploys from main only" --scope project:gno --add gno recall "deploy branch" --scope project:gno gno recall "kindergarten" --scope family --max-facts 3 --max-tokens 256 --json ``` ## Restoring a memory file A deleted memory file restored at the same path with identical bytes becomes active on the next successful sync. Activation and one `reactivate` journal event commit together; unchanged repeat syncs add no restoration events. Proven unchanged formatted inputs retain embeddings, while title, content, or model/runtime changes require matching coverage. Sync restoration does not broaden scopes, remove receipt fencing, alter supersession, or change the default 8-fact/512-token recall budget. Natural-language recall matching remains unchanged. Sync source Markdown between hosts, never the derived SQLite database. ## Three write paths, one taxonomy - **edit** updates an existing canonical note: a document, changed in its file (editor, Web UI, `PUT /api/docs/:id`). - **capture** creates a genuinely new document with provenance: `gno capture`, `gno_capture`, `/api/capture`. - **remember** upserts one fact with supersession and current-state reduction: `gno remember`, `gno_remember`, `/api/memory/remember`. Remember is not a second capture. A fact is one sentence or two, at most 4096 bytes; anything longer is a document, and `remember` refuses it with `MEMORY_TEXT_TOO_LARGE` and points at `gno capture`. An existing note that is wrong: edit it. A new meeting, idea, or source: capture it. A standalone fact an agent should look up later: remember it. ## A memory-managed collection A collection accepts `remember` only when its config declares it memory managed. There is no CLI flag for it yet; edit the config: ``` collections: - name: memory path: /Users/you/notes/memory pattern: "**/*.md" memoryManaged: true ``` `remember` into any other collection fails with `MEMORY_COLLECTION_UNMANAGED`, and `recall` reads only memory-managed collections. With exactly one memory-managed collection configured the CLI defaults `--collection` to it. The flag changes nothing else: the collection is indexed, searched, and egress-governed like any other, so `gno search` and `gno query` see memory files as ordinary documents. ## The fact file One fact per markdown file, written by GNO at `facts//mem-<16 hex>.md` inside the collection. The frontmatter carries a `memory` block with `recordId`, `scopes`, `caller`, `session`, `createdAt`, `contentHash`, and the optional free-text `source` given at write time; a successor also carries `relations.supersedes` with its predecessor’s URI. The body is the fact text. - `contentHash` is the SHA-256 of the normalized text (NFC, whitespace collapsed, trimmed). It is also the span hash that appears in recall receipts. - `relations.supersedes` is the existing typed-edge mechanism; ingestion projects it into the graph like any other relation. There is no separate memory store. - Files are canonical. You may hand-edit them, but a record that no longer satisfies the contract (missing frontmatter, bad hash, empty body, invalid scopes) is excluded from managed recall and reported by `gno status` and `gno audit`. It stays visible to ordinary search. ## Scopes Every `remember` and `recall` call names its scopes explicitly. There is no implicit global scope: an unscoped call fails with `MEMORY_SCOPES_REQUIRED` on every surface. Shared visibility is something you configure by choosing a scope name that several callers agree on (`--scope shared`), never a default. - 1 to 8 scopes per call. Each is trimmed, lowercased, NFC-normalized, and deduplicated. Allowed characters: letters and digits, then `. _ : / @ -`; at most 64 characters. Examples: `project:gno`, `family`, `client/acme`, `user@host`. - Visibility is any-intersection: a fact is visible to a call when at least one of the call’s scopes appears in the fact’s scope list. - Scope filtering runs inside the retrieval query, not as a post-filter over a bounded candidate window, so a scope with few facts never comes back falsely empty behind a busier scope. Scopes are a visibility partition, not an access-control boundary. Anyone who can read the collection’s files can read every fact; [egress policy](https://gno.sh/docs/collection-egress), not scope, decides where derived output may travel. ## Identity Every call carries a `caller` and a `session`, recorded in the fact frontmatter and bound into every recall receipt. CLI: `--caller` and `--session`, else `$GNO_MEMORY_CALLER` / `$GNO_MEMORY_SESSION`, else `cli:` and `ppid:`. MCP: the client name from the `initialize` handshake and the Streamable HTTP session id (or the stdio server instance id). REST and SDK: the request’s `caller` and `session` fields. MCP tool arguments never carry identity; it is mapped from the connection, so a client cannot claim to be another one. ## Remember `remember` first searches the current facts in the same scopes for candidates: a BM25 pool of 16, then cosine similarity ≥ 0.83 when the collection’s embedding model is already cached, otherwise normalized-token Jaccard ≥ 0.5; the result’s `matching` block says which. Then: - A fact with the same normalized text exists: `existing`, the record. Nothing is written (idempotent). - No decision given: `candidates`, likely and weak matches. Nothing is written. - `--add` / `decision: "add"`: `added`, one fact file. - `--supersede --predecessor-hash ` / `decision: "supersede"`: `superseded`, one fact file with a `supersedes` edge. The caller decides. GNO never adjudicates a likely match with a model; it returns the candidates and waits for an explicit add or supersede. Success means more than a file on disk: the write and the lexical index sync complete under the shared write lease before the call returns, so the fact is retrievable the moment `sync.status` reads `completed`. A failed sync is reported as such (the file exists, the index lags); rerun `gno update` for that collection. ### Supersession A fact is replaced, never edited in place: 1. Recall the current fact and take its `uri` and `contentHash`. 2. `remember` the new text with `--supersede --predecessor-hash `. 3. GNO verifies, under the write lease, that the predecessor exists, that its hash still matches (`MEMORY_PREDECESSOR_HASH_MISMATCH` otherwise), and that nobody has superseded it yet. It then writes the successor carrying `relations.supersedes`. Two writers racing to supersede the same predecessor get one successor and one `MEMORY_SUPERSEDE_CONFLICT` (HTTP 409, CLI exit 4). The loser recalls again and decides against the new current fact. Two current branches of one fact cannot exist. Superseded facts stay on disk and in ordinary search; `recall` excludes them inside the query. Nothing is deleted by the memory contract. ## Recall `recall` is the fast path: BM25 over the memory collection, fused with the vector leg when the embedding model is already cached, with query expansion, graph expansion, and reranking off. It never downloads a model. The response `retrieval.mode` reports `hybrid` or `lexical` with the reason. The MCP adapter runs the lexical leg only, so a resident gateway does not load a model per call. - Only current facts come back; superseded records are excluded. - Budget: at most 8 facts under 512 estimated tokens by default (`--max-facts`, `--max-tokens`). Selection reuses the Context Capsule budget logic; `budget.omitted` counts facts that matched but did not fit. - Each fact carries `uri`, `text`, `scopes`, `caller`, `session`, `createdAt`, `contentHash`, `spanHash`, `supersedes`, `score`, and its `egressLineage`. The response-level lineage is the strictest policy across the returned facts; derived output inherits it. - With nothing in scope the response has an empty `facts` list and a hint naming the write path, verbatim on every surface, so a fresh agent learns `remember` from the empty read. Cite recalled facts by their `gno://` URI, exactly as for any retrieved document. ## Context fencing Agents that recall and then remember in the same loop tend to feed GNO’s own output back in as a “new” fact. The fence stops that loop where it can be stopped honestly. Every recall response includes a receipt: `caller`, `session`, `issuedAt`, `memoryIds`, `spanHashes` (the `contentHash` of every returned fact), and a `digest` over those fields. It is content-free; it carries no fact text. `remember` rejects, and writes nothing, when the normalized hash of the submitted text matches a `spanHashes` entry on the presented receipt (`MEMORY_FENCED_REPLAY`; CLI `--receipt ` pointing at a saved `gno recall --json` output, MCP/REST/SDK the `receipt` field), or when the submission declares a `gno://` origin in `derivedFrom` (`MEMORY_FENCED_DERIVED`). Non-GNO origins are fine and are recorded as declared. Receipts are surface-independent: a receipt issued by `gno_recall` fences a `gno remember --receipt`, and the reverse. ### What the fence cannot do A paraphrase without lineage cannot be fenced. If an agent recalls “Deploys go out from the main branch only”, rewrites it as “only main is deployed”, presents no receipt, and declares no `derivedFrom`, GNO sees an original fact and stores it. The fence is exact-span plus declared origin. It is a guard against the accidental replay loop, not a proof of provenance, and it depends on the calling agent passing the receipt it was given and declaring what it derived from. Treat receipts as part of the agent’s contract, not as a security boundary. ## Concurrency and consistency - Every memory write runs under the same shared write lease as `gno index`, `gno update`, and MCP writes, so an MCP `gno_remember` and a CLI `gno remember` serialise on one lease. A caller that cannot obtain it within the wait window gets `MEMORY_WRITE_LEASE_BUSY`. - A fact is current only after write plus lexical sync succeed. A supersede additionally requires its edge to be projected; if the projection fails the write reports `MEMORY_SUPERSEDE_PROJECTION_FAILED`, the predecessor still reads as current, and `gno update` retries. Vector embeddings for new facts arrive with the next `gno embed`; recall’s lexical leg finds the fact before that. - Synced vaults (iCloud, Syncthing, git) replicate the files. The index on another machine sees a new fact after its own `gno update`; GNO does not coordinate memory across machines. ## What memory does not do These are exclusions, not gaps. Each one is a decision. - No automatic capture. Nothing observes an agent’s turns and stores facts on its own. Every fact is an explicit `remember` call. - No model in the write path. GNO never extracts facts from prose, never decides whether a likely match is the same fact, and never merges records. Embeddings only rank candidates; the caller decides. - No consolidation or dedup jobs. Supersession is the only reduction. - No delete or forget. Facts are superseded, never removed by the contract. To remove one, delete the file yourself and run `gno update`. - No memory Web UI. Memory files are ordinary documents in the Web UI; there is no dedicated memory screen. - No implicit global scope. Every call names its scopes. - No cross-machine coordination. Files replicate through your vault sync; each index catches up on its own. - No write path outside the contract. The adapters below map harness slots onto the four surfaces; none of them adds a way to store a fact that bypasses `remember`. ## Adapters The `gno agents` protocol block (v3) carries the memory contract into every harness’s global instruction file, and the `gno` skill carries the workflows. Neither is a runtime adapter: they tell an agent when to call `recall` and `remember`, and the agent calls them like any other command. The retrieval ladder gains `gno recall "" --scope ` after exact search and before the document rungs; the writing contract states that `remember` proposes and the agent decides `--add` or `--supersede` from a recall, passing the receipt back. `gno skill install` ships three memory recipes: `recipes/memory-file-decision.md`, `recipes/memory-supersede-fact.md`, and `recipes/memory-scoped-recall.md`. - **Hermes Agent provider** (`integrations/hermes-gno-memory`, verified against Hermes v0.20.5): `prefetch` runs `gno recall --json` with the turn’s message and the configured scopes; a model-invoked `gno_remember` tool runs `gno remember --json` with `propose`, `add`, or `supersede` and presents the session’s latest recall receipt; Hermes’s own after-turn persistence never writes to GNO. Scopes come from the provider config only. Below the GNO version pin, or when `gno` is missing or returns malformed JSON, the provider reports memory unavailable and the session continues without it. - **OpenClaw plugin** (`integrations/openclaw-gno-memory`, verified against OpenClaw 2026.8.1): OpenClaw keeps writing its own memory files; the plugin retrieves. `memory_search` runs `gno search` scoped to the memory collection, `memory_get` runs `gno get`, and every search syncs the collection first so a file written a moment ago is retrievable. A failed sync marks the index stale and the tool response says so. ## Binding defaults - Scopes per call: 1 to 8; scope length: 64 characters. - Fact size: 4096 bytes. - Candidate pool (BM25): 16; semantic likely-match threshold: cosine 0.83; lexical likely-match threshold: Jaccard 0.5. - Recall budget: 8 facts / 512 tokens. The constants live in `src/core/memory-types.ts` in the GNO repository; the full error-code table with CLI exit codes and HTTP statuses is in the repository’s `docs/MEMORY.md`. --- # Knowledge protocol > The retrieval ladder and the writing contract an agent follows over your collections: which GNO command answers which kind of question, what each rung returns and where it stops, and when a write is an edit, a capture, or a remember. Section: Guides Canonical: https://gno.sh/docs/protocol Markdown: https://gno.sh/docs/protocol.md A knowledge protocol is the routing contract between an agent and your indexed collections: which command answers which kind of question, in which order to try them, and what a write is allowed to be. This page is the generalized contract. The [gno agents](https://gno.sh/docs/agents-install) block carries a 1,491-character version of it into each harness's global instruction file; the [gno skill](https://gno.sh/docs/skills) carries the workflows and recipes. Everything here applies to any collection layout: the protocol names commands, never folders. ## Ground rules - **Source files are the truth.** The index is derived, machine-local, and disposable; a rebuild changes no source. - **Scope first.** Pass `--collection` before reformulating a query. Most misses are scope misses. - **Cite by URI.** Retrieved material is cited by its `gno://collection/path` identifier, with a line span when quoting, never by a paraphrased filename. - **A question is read-only.** Answering never writes; a write needs an explicit request or a documented rule. ## The retrieval ladder Seven rungs, cheapest and most exact first. Each one is a different question shape, and each stops at a stated boundary. | Question shape | Command | Returns | | -------------------------------------------------------- | --------------------------------------------------- | ------------------------------------------------------------- | | 1. Exact term, identifier, quote, filename, error string | `gno search ""` | BM25 hits with URIs and matching spans | | 2. What do we know or believe about X | `gno recall "" --scope ` | Current facts only, cited, under a budget, with a receipt | | 3. An entity or a document you know exists | `gno query "" --fast -n 10` | Hybrid ranking over documents, fast preset | | 4. Evidence across several documents for one goal | `gno context build "" --budget 12000` | A Context Capsule: exact spans, hashes, budget, declared gaps | | 5. What changed, what differs, what depends on this | `gno changes`, `gno diff `, `gno impact ` | Bounded change history and dependency projections | | 6. A generated factual answer | `gno ask "" --verify` | A cited answer, or an abstention | | 7. A document you expected is missing from results | `gno query diagnose "" --target ` | The stage at which the target dropped out | ### 1. Exact search `gno search` is lexical: a term, an identifier, a quoted phrase, an error message. It runs without models and returns the matching spans with their URIs. When the wording is known, this rung settles the question and nothing further runs. ### 2. Recall `gno recall` reads memory-managed collections only and returns current facts: a fact replaced by a supersede is excluded in the query itself. The budget defaults to 8 facts under 512 estimated tokens; each fact carries its `gno://` URI, scopes, caller, session, and content hash. An empty result carries a hint naming the write path, so a fresh agent learns `remember` from the empty read. Recall runs the lexical leg always and adds the vector leg when the collection's embedding model is already cached; the response reports `mode: lexical` or `hybrid` with the reason, and it never downloads a model. Lexical-only recall matches every query term, so a question-shaped query can miss a fact the vector leg would find; embed the memory collection to close that gap. The full contract is on the [memory](https://gno.sh/docs/memory) page. ### 3. Query `gno query` fuses lexical and semantic retrieval over documents. `--fast` skips query expansion, graph expansion, and reranking, which is the right trade when the entity or document is known and ranking quality matters less than latency. Drop `--fast` for a vaguer question. Structured syntax, tag, date, and author filters, backlinks, and similarity are in the [query syntax](https://gno.sh/docs/syntax) reference. ### 4. Context build `gno context build` compiles a Context Capsule for one goal: exact source spans with hashes, deduplicated under one token budget, with every retrieval gap declared in the Capsule itself. It is the handoff for a decision that rests on more than one document, and it is the input to a verified answer. See [Context Capsules](https://gno.sh/docs/context-capsules). ### 5. Changes, diff, impact Change and dependency questions are a different shape from content questions. `gno changes` lists what moved in a window, `gno diff` shows how one document changed, and `gno impact` projects which documents a change may affect, all from GNO's bounded, metadata-first history. See [Knowledge Delta](https://gno.sh/docs/knowledge-delta). ### 6. Verified ask `gno ask --verify` generates an answer against one closed Capsule and classifies each substantive claim against its supporting spans. Complete support returns the answer with citations; anything less withholds the draft and reports the failing claim. Abstention is a valid result of this rung, and an agent treats it as one. ### 7. Diagnose before grep When a document you know exists is absent from results, `gno query diagnose` reports stage by stage whether the target appeared in lexical retrieval, vector retrieval, fusion, graph expansion, and reranking, so a candidate-generation miss is told apart from a ranking miss. Re-check the collection scope in the same step. A scoped grep or a direct file read is the fallback after that diagnosis, not before it. ## The writing contract Retrieve first. A write starts from what already exists, and the three write paths are distinct operations, chosen by what kind of thing is being written. | The thing being written | Path | How | | ------------------------------------------------------ | ------------ | ------------------------------------------------------------------------- | | An existing canonical note that is wrong or incomplete | **edit** | Change the source file directly: editor, Web UI, `PUT /api/docs/:id` | | A genuinely new note: a meeting, an idea, a source | **capture** | `gno capture` with collection, title or path, source kind, and provenance | | A standalone fact that may change later | **remember** | `gno remember "" --scope `, then `--add` or `--supersede` | - **Capture is creation, never an update API.** It creates a new document with provenance. Its receipt proves the mechanical write and nothing more: cross-links, index notes, and hub updates that your own conventions require are separate edits. - **Remember proposes; the agent decides.** A fact is one or two sentences, at most 4096 bytes; longer text is a document and belongs in capture. With no flag, `remember` reports likely matches from the scope and writes nothing. `--add` stores it beside them; `--supersede --predecessor-hash ` replaces one, and the hash check refuses a stale predecessor. Both values come from a recall. - **Recalled spans are context, not new facts.** Every recall carries a content-free receipt; passing it back as `--receipt` lets `remember` refuse a recalled span replayed as a new fact. A submission that declares a `gno://` origin is refused for the same reason. The fence is exact span plus declared origin: a paraphrase presented without receipt or origin is stored as an original fact, so the receipt is part of the agent's contract, not a security boundary. - **After a write: reindex, then verify.** Reindex the affected collection and confirm the title and one distinctive claim with `gno search` or `gno get`. A write that cannot be retrieved is not finished. ## Configuring the protocol for your setup The commands are fixed; the knowledge they run over is yours to shape. - **Collections** are the scope boundary the ladder climbs within: one per source root, each with its own matching, context hints, and egress policy. See [configuration](https://gno.sh/docs/configuration). - **Memory scopes** are strings you choose (a project, a team, a domain), one to eight per call, up to 64 characters each. Recall and remember both require them; a call without scopes is refused. One collection marked `memoryManaged: true` holds the facts. - **Harnesses** receive the block by detection or by `--target`; extra config directories by `--extra-dir`. Your own conventions, naming rules, and filing ceremonies live outside the markers, in the same file, and the installer leaves them byte-identical. - **Context hints** attached globally, per collection, or per path prefix steer ranking. They guide retrieval; they are never presented as evidence. ## Where the protocol stops - It is delivered by instruction text and a skill. There is no per-prompt hook: the agent follows the ladder because its instructions say so, and a behavioral check after install is a manual practice. - Nothing writes on its own. Every edit, capture, and remember is an explicit call by the agent; recall injected into a turn by a harness adapter stores nothing. - Verification is per claim, not per fact. `gno ask --verify` checks an answer against a Capsule; it does not check whether the source documents are themselves true. - The ladder is a default order, not a gate. An agent that already knows the wording starts at rung 1 and stops; one asked for a decision starts at rung 4. --- # Collection egress policies > Give each collection a fail-closed transport boundary that follows its content through inference, publishing, exports, Capsules, and traces. Section: Guides Canonical: https://gno.sh/docs/collection-egress Markdown: https://gno.sh/docs/collection-egress.md Each collection has a fail-closed transport policy (`local_only`, `lan`, `remote`) evaluated at transfer time, not at config time. Derived artifacts inherit the most restrictive source policy: one `local_only` passage makes a Capsule `local_only`. Most real setups are mixed: your open notes are fine on a LAN inference box, the client engagement is not, and the vendor contracts should never reach a remote endpoint under any circumstances. Egress is distinct from source availability: availability (`sourceAvailability: any|local`) controls whether source content may be materialized during indexing on tested macOS File Provider layouts; egress controls where derived data may travel. See [Source availability](https://gno.sh/docs/configuration#source-availability). ## The three levels | Policy | Content may reach | | ------------ | -------------------------------------------------------------------------------------------------- | | `local_only` | This machine. Loopback destinations only. No LAN model server, no remote inference, no publishing. | | `lan` | This machine plus private-network destinations, such as a GPU box in the same network. | | `remote` | Any configured destination, including a remote inference endpoint or gno.sh publishing. | Policies loosen in the order `local_only` → `lan` → `remote`. Existing collections migrated to `local_only`: fail-closed, so an upgrade could never widen a boundary you had not thought about. Migration preserves local retrieval and index data in full. ## Reading and checking a policy ``` gno collection policy get notes gno collection policy check --action export --destination remote \ --content-class retrieval_trace --collection notes \ --authenticated --authorized --explain-egress ``` `get` shows the effective policy, where it came from, and its numeric revision. `check` is a dry run: it answers “would this specific transfer be allowed” without attempting it, which is what you want in CI, in a runbook, or before wiring up a remote model. `--explain-egress` shows the reasoning. ## Relaxing a policy ``` gno collection policy set notes local_only gno collection policy set notes remote --confirm-relaxation 7 ``` Tightening is immediate. Loosening is never inferred: run `get`, look at the current value and its source, then pass that exact numeric `revision` to `--confirm-relaxation`. The revision is durable and single-use. Stale, replayed, cross-collection, and cross-target confirmations all fail closed. That handshake exists so a relaxation cannot be scripted blind. You have to have read the current state, in this collection, at this revision, to widen it. An agent that automates `policy set` without a fresh `get` simply fails. Tightening invalidates resident sessions and queued work. Jobs that were in flight under the older, looser policy must be retried and rechecked rather than completing under an assumption that no longer holds. ## Policy follows the content A policy that applied only to the original file would be trivially escaped: build a Capsule from a restricted collection, then publish the Capsule. Instead, derived artifacts inherit source policy. Snippets, embeddings, Context Capsules, retrieval traces, adapter records, and exports all carry the policy of what they came from. When evidence mixes several collections, the _most restrictive_ participating policy governs the whole thing. One `local_only` passage in a Capsule makes that Capsule `local_only`. Each Capsule evidence item exposes its own `egress` value and lineage, and the aggregate lineage must account for every contributing collection, so the boundary is inspectable rather than implicit. ## Three independent gates Authentication, write authorization, and egress are separate checks, and passing one never satisfies another: - **Authenticated** means GNO knows who is calling. It does not mean content may travel. - **Authorized for writes** means mutation tools are enabled. It does not mean content may travel. - **Egress** is owned by the collection and cannot be overridden by either of the above. A valid bearer token on a non-loopback daemon still cannot pull `local_only` content off the machine. ## How destinations are classified Classification is conservative by design and covers loopback, LAN, VPN, proxy, redirect, and remote destinations. Cases that would otherwise be laundering routes fail closed: DNS rebinding, redirects to a different class than the one you checked, mixed evidence, active streams, queued jobs, and stale relaxation confirmations. Denial reasons are stable and content-free across CLI, REST, MCP, SDK, and Web. An error message never leaks the passage it refused to send, the path it came from, or a credential. ## Audit receipts ``` gno egress-audit list gno egress-audit show gno egress-audit status gno egress-audit delete gno egress-audit purge ``` Receipts are local, bounded, and redacted: what action was attempted, against what destination class, with what outcome. Never the content. Audit inspection and deletion keep working even when an outbound action was denied, so a refusal is always diagnosable. ## A practical setup ``` # Client work never leaves the laptop gno collection policy set client-engagement local_only # Personal notes may use the GPU box on the LAN gno collection policy get notes # note the revision gno collection policy set notes lan --confirm-relaxation 3 # Verify before wiring a remote endpoint gno collection policy check --action remote_inference --destination remote \ --content-class passage --collection notes --explain-egress ``` One caution worth repeating: egress policy governs transport, not authorization to use content. It stops bytes crossing a boundary. It does not encode who is allowed to read what, and it is not a substitute for keeping confidential material in the right collection in the first place.