{"id":39873061,"url":"https://github.com/gmickel/gno","last_synced_at":"2026-04-19T09:03:44.177Z","repository":{"id":331212682,"uuid":"1117646847","full_name":"gmickel/gno","owner":"gmickel","description":"Local AI-powered document search and editing with first-in-class hybrid retrieval, LLM answers, WebUI, REST API and MCP support for AI clients.","archived":false,"fork":false,"pushed_at":"2026-04-16T13:03:07.000Z","size":23971,"stargazers_count":69,"open_issues_count":6,"forks_count":6,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-04-16T13:19:13.656Z","etag":null,"topics":["ai-assistant","bun","cli","code-search","document-search","embeddings","knowledge-base","llm","local-first","mcp","offline","pkm","rag","second-brain","semantic-search","typescript","vector-search"],"latest_commit_sha":null,"homepage":"https://www.gno.sh","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/gmickel.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":".github/CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":"AGENTS.md","dco":null,"cla":null}},"created_at":"2025-12-16T15:58:15.000Z","updated_at":"2026-04-16T12:57:38.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/gmickel/gno","commit_stats":null,"previous_names":["gmickel/gno"],"tags_count":88,"template":false,"template_full_name":null,"purl":"pkg:github/gmickel/gno","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gmickel%2Fgno","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gmickel%2Fgno/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gmickel%2Fgno/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gmickel%2Fgno/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/gmickel","download_url":"https://codeload.github.com/gmickel/gno/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gmickel%2Fgno/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32000742,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-18T20:23:30.271Z","status":"online","status_checked_at":"2026-04-19T02:00:07.110Z","response_time":55,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ai-assistant","bun","cli","code-search","document-search","embeddings","knowledge-base","llm","local-first","mcp","offline","pkm","rag","second-brain","semantic-search","typescript","vector-search"],"created_at":"2026-01-18T14:19:23.571Z","updated_at":"2026-04-19T09:03:44.138Z","avatar_url":"https://github.com/gmickel.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# GNO\n\n**Local search, retrieval, and synthesis for the files you actually work in.**\n\n[![npm](./assets/badges/npm.svg)](https://www.npmjs.com/package/@gmickel/gno)\n[![MIT License](./assets/badges/license.svg)](./LICENSE)\n[![Website](./assets/badges/website.svg)](https://gno.sh)\n[![Twitter](./assets/badges/twitter.svg)](https://twitter.com/gmickel)\n[![Discord](./assets/badges/discord.svg)](https://discord.gg/nHEmyJB5tg)\n\n\u003e [!TIP]\n\u003e **[gno.sh/publish](https://gno.sh/publish) is live.** Turn any GNO note or collection into a polished, reader-first URL — editorial typography, scoped search, and four visibility modes from public to encrypted-before-upload. **[See the reader →](#publish-to-gnosh)**\n\n\u003e **ClawdHub**: GNO skills bundled for Clawdbot — [clawdhub.com/gmickel/gno](https://clawdhub.com/gmickel/gno)\n\n![GNO](./assets/og-image.png)\n\nGNO is a local knowledge engine for notes, code, PDFs, Office docs, meeting transcripts, and reference material. It gives you fast keyword search, semantic retrieval, grounded answers with citations, wiki-style linking, and a real workspace UI, while keeping the whole stack local by default.\n\nUse it when:\n\n- your notes live in more than one folder\n- your important knowledge is split across Markdown, code, PDFs, and Office files\n- you want one retrieval layer that works from the CLI, browser, MCP, and a Bun/TypeScript SDK\n- you want better local context for agents without shipping your docs to a cloud API\n\n### What GNO Gives You\n\n- **Fast local search**: BM25 for exact hits, vectors for concepts, hybrid for best quality\n- **Real retrieval surfaces**: CLI, Web UI, REST API, MCP, SDK\n- **Local-first answers**: grounded synthesis with citations when you want answers, raw retrieval when you do not\n- **Connected knowledge**: backlinks, related notes, graph view, cross-collection navigation\n- **Shareable, not synced**: export a note or collection to [gno.sh](https://gno.sh/publish) as a polished reader page — public, secret, invite-only, or locally encrypted before upload\n- **Operational fit**: daemon mode, model presets, remote GPU backends, safe config/state on disk\n\n### One-Minute Tour\n\n```bash\n# Install\nbun install -g @gmickel/gno\n\n# Add a few collections\ngno init ~/notes --name notes\ngno collection add ~/work/docs --name work-docs --pattern \"**/*.{md,pdf,docx}\"\ngno collection add ~/work/gno/src --name gno-code --pattern \"**/*.{ts,tsx,js,jsx}\"\n\n# Add context so retrieval results come back with the right framing\ngno context add \"notes:\" \"Personal notes, journal entries, and long-form ideas\"\ngno context add \"work-docs:\" \"Architecture docs, runbooks, RFCs, meeting notes\"\ngno context add \"gno-code:\" \"Source code for the GNO application\"\n\n# Index + embed\ngno update --yes\ngno embed\n\n# Search in the way that fits the question\ngno search \"DEC-0054\"                            # exact keyword / identifier\ngno vsearch \"retry failed jobs with backoff\"     # natural-language semantic lookup\ngno query \"JWT refresh token rotation\" --explain # hybrid retrieval with score traces\n\n# Retrieve documents or export context for an agent\ngno get \"gno://work-docs/architecture/auth.md\"\ngno multi-get \"gno-code/**/*.ts\" --max-bytes 30000 --md\ngno query \"deployment process\" --all --files --min-score 0.35\n\n# Run the workspace\ngno serve\ngno daemon\n```\n\n---\n\n## Contents\n\n- [Quick Start](#quick-start)\n- [Installation](#installation)\n- [Daemon Mode](#daemon-mode)\n- [Search Modes](#search-modes)\n- [Agent Integration](#agent-integration)\n- [Web UI](#web-ui)\n- [Publish to gno.sh](#publish-to-gnosh)\n- [REST API](#rest-api)\n- [SDK](#sdk)\n- [How It Works](#how-it-works)\n- [Features](#features)\n- [Local Models](#local-models)\n- [Fine-Tuned Models](#fine-tuned-models)\n- [Architecture](#architecture)\n- [Development](#development)\n\n---\n\n## What's New\n\n\u003e Latest release: [v1.0.0](./CHANGELOG.md#100---2026-04-16)  \n\u003e Full release history: [CHANGELOG.md](./CHANGELOG.md)\n\n- **Publish to [gno.sh](https://gno.sh/publish)**: new `gno publish export` CLI and Web UI action produce a self-contained artifact you upload to the hosted reader — public, secret, invite-only, or locally encrypted before upload\n- **Retrieval Quality Upgrade**: stronger BM25 lexical handling, code-aware chunking, terminal result hyperlinks, and per-collection model overrides\n- **Code Embedding Benchmarks**: new benchmark workflow across canonical, real-GNO, and pinned OSS slices for comparing alternate embedding models\n- **Default Embed Model**: built-in presets now use `Qwen3-Embedding-0.6B-GGUF` after it beat `bge-m3` on both code and multilingual prose benchmark lanes\n- **Regression Fixes**: tightened phrase/negation/hyphen/underscore BM25 behavior, cleaned non-TTY hyperlink output, improved `gno doctor` chunking visibility, and fixed the embedding autoresearch harness\n\n### Upgrading Existing Collections\n\nIf you already had collections indexed before the default embed-model switch to\n`Qwen3-Embedding-0.6B-GGUF`, run:\n\n```bash\ngno models pull --embed\ngno embed\n```\n\nThat regenerates embeddings for the new default model. Old vectors are kept\nuntil you explicitly clear stale embeddings.\n\nIf the release also changes the embedding formatting/profile behavior for your\nactive model, prefer one of these stronger migration paths:\n\n```bash\ngno embed --force\n```\n\nor per collection:\n\n```bash\ngno collection clear-embeddings my-collection --all\ngno embed my-collection\n```\n\nIf a re-embed run still reports failures, rerun with:\n\n```bash\ngno --verbose embed --force\n```\n\nRecent releases now print sample embedding errors and a concrete retry hint when\nbatch recovery cannot fully recover on its own.\n\nModel guides:\n\n- [Code Embeddings](./docs/guides/code-embeddings.md)\n- [Per-Collection Models](./docs/guides/per-collection-models.md)\n- [Bring Your Own Models](./docs/guides/bring-your-own-models.md)\n\n### Fine-Tuned Model Quick Use\n\n```yaml\nmodels:\n  activePreset: slim-tuned\n  presets:\n    - id: slim-tuned\n      name: GNO Slim Tuned\n      embed: hf:Qwen/Qwen3-Embedding-0.6B-GGUF/Qwen3-Embedding-0.6B-Q8_0.gguf\n      rerank: hf:ggml-org/Qwen3-Reranker-0.6B-Q8_0-GGUF/qwen3-reranker-0.6b-q8_0.gguf\n      expand: hf:guiltylemon/gno-expansion-slim-retrieval-v1/gno-expansion-auto-entity-lock-default-mix-lr95-f16.gguf\n      gen: hf:unsloth/Qwen3-1.7B-GGUF/Qwen3-1.7B-Q4_K_M.gguf\n```\n\nThen:\n\n```bash\ngno models use slim-tuned\ngno models pull --expand\ngno models pull --gen\ngno query \"ECONNREFUSED 127.0.0.1:5432\" --thorough\n```\n\n\u003e Full guide: [Fine-Tuned Models](https://gno.sh/docs/FINE-TUNED-MODELS/) · [Feature page](https://gno.sh/features/fine-tuned-models/)\n\n---\n\n## Quick Start\n\n```bash\ngno init ~/notes --name notes    # Point at your docs\ngno index                        # Build search index\ngno daemon                       # Keep index fresh in background (foreground process)\ngno query \"auth best practices\"  # Hybrid search\ngno ask \"summarize the API\" --answer  # AI answer with citations\n```\n\n![GNO CLI](./assets/screenshots/cli.jpg)\n\n---\n\n## Installation\n\n### Install GNO\n\nRequires [Bun](https://bun.sh/) \u003e= 1.0.0.\n\n```bash\nbun install -g @gmickel/gno\n```\n\n**macOS**: Vector search requires Homebrew SQLite:\n\n```bash\nbrew install sqlite3\n```\n\nVerify everything works:\n\n```bash\ngno doctor\n```\n\n**Windows**: current validated target is `windows-x64`, with a packaged\ndesktop beta zip now published on GitHub Releases. See\n[docs/WINDOWS.md](./docs/WINDOWS.md) for support scope and validation notes.\n\nKeep an index fresh continuously without opening the Web UI:\n\n```bash\ngno daemon\n```\n\n`gno daemon` runs as a foreground watcher/sync/embed process. Use `nohup`,\nlaunchd, or systemd if you want it supervised long-term.\n\nSee also: [docs/DAEMON.md](./docs/DAEMON.md)\n\n### Connect to AI Agents\n\n#### MCP Server (Claude Desktop, Cursor, Zed, etc.)\n\nOne command to add GNO to your AI assistant:\n\n```bash\ngno mcp install                      # Claude Desktop (default)\ngno mcp install --target cursor      # Cursor\ngno mcp install --target claude-code # Claude Code CLI\ngno mcp install --target zed         # Zed\ngno mcp install --target windsurf    # Windsurf\ngno mcp install --target codex       # OpenAI Codex CLI\ngno mcp install --target opencode    # OpenCode\ngno mcp install --target amp         # Amp\ngno mcp install --target lmstudio    # LM Studio\ngno mcp install --target librechat   # LibreChat\n```\n\nCheck status: `gno mcp status`\n\n#### Skills (Claude Code, Codex, OpenCode)\n\nSkills integrate via CLI with no MCP overhead:\n\n```bash\ngno skill install --scope user        # User-wide\ngno skill install --target codex      # Codex\ngno skill install --target opencode   # OpenCode\ngno skill install --target openclaw   # OpenClaw\ngno skill install --target all        # All targets\n```\n\n\u003e **Full setup guide**: [MCP Integration](https://gno.sh/docs/MCP/) · [CLI Reference](https://gno.sh/docs/CLI/)\n\n---\n\n## Daemon Mode\n\nUse `gno daemon` when you want continuous indexing without the browser or\ndesktop shell open.\n\n```bash\ngno daemon\ngno daemon --no-sync-on-start\nnohup gno daemon \u003e /tmp/gno-daemon.log 2\u003e\u00261 \u0026\n```\n\nIt reuses the same watch/sync/embed runtime as `gno serve`, but stays\nheadless. In v0.30 it is foreground-only and does not expose built-in\n`start/stop/status` management.\n\n[Daemon guide →](https://gno.sh/docs/DAEMON/)\n\n---\n\n## SDK\n\nEmbed GNO directly in another Bun or TypeScript app. No CLI subprocesses. No local server required.\n\nInstall:\n\n```bash\nbun add @gmickel/gno\n```\n\nMinimal client:\n\n```ts\nimport { createDefaultConfig, createGnoClient } from \"@gmickel/gno\";\n\nconst config = createDefaultConfig();\nconfig.collections = [\n  {\n    name: \"notes\",\n    path: \"/Users/me/notes\",\n    pattern: \"**/*\",\n    include: [],\n    exclude: [],\n  },\n];\n\nconst client = await createGnoClient({\n  config,\n  dbPath: \"/tmp/gno-sdk.sqlite\",\n});\n\nawait client.index({ noEmbed: true });\n\nconst results = await client.query(\"JWT token flow\", {\n  noExpand: true,\n  noRerank: true,\n});\n\nconsole.log(results.results[0]?.uri);\nawait client.close();\n```\n\nMore SDK examples:\n\n```ts\nimport { createGnoClient } from \"@gmickel/gno\";\n\nconst client = await createGnoClient({\n  configPath: \"/Users/me/.config/gno/index.yml\",\n});\n\n// Fast exact search\nconst bm25 = await client.search(\"DEC-0054\", {\n  collection: \"work-docs\",\n});\n\n// Semantic code lookup\nconst semantic = await client.vsearch(\"retry failed jobs with backoff\", {\n  collection: \"gno-code\",\n});\n\n// Hybrid retrieval with explicit intent\nconst hybrid = await client.query(\"token refresh\", {\n  collection: \"work-docs\",\n  intent: \"JWT refresh token rotation in our auth stack\",\n  candidateLimit: 12,\n});\n\n// Fetch content directly\nconst doc = await client.get(\"gno://work-docs/auth/refresh.md\");\nconst bundle = await client.multiGet([\"gno-code/**/*.ts\"], { maxBytes: 25000 });\n\n// Indexing / embedding\nawait client.update({ collection: \"work-docs\" });\nawait client.embed({ collection: \"gno-code\" });\n\nawait client.close();\n```\n\nCore SDK surface:\n\n- `createGnoClient({ config | configPath, dbPath? })`\n- `search`, `vsearch`, `query`, `ask`\n- `get`, `multiGet`, `list`, `status`\n- `update`, `embed`, `index`\n- `close`\n\nFull guide: [SDK docs](https://gno.sh/docs/SDK/)\n\n---\n\n## Search Modes\n\n| Command            | Mode                | Best For                                  |\n| :----------------- | :------------------ | :---------------------------------------- |\n| `gno search`       | Document-level BM25 | Exact phrases, code identifiers           |\n| `gno vsearch`      | Contextual Vector   | Natural language, concepts                |\n| `gno query`        | Hybrid              | Best accuracy (BM25 + vector + reranking) |\n| `gno ask --answer` | RAG                 | Direct answers with citations             |\n\n**BM25** indexes full documents (not chunks) with Snowball stemming, so \"running\" matches \"run\".\n**Vector** embeds chunks with document titles for context awareness.\nAll retrieval modes also support metadata filters: `--since`, `--until`, `--category`, `--author`, `--tags-all`, `--tags-any`.\n\n```bash\ngno search \"handleAuth\"              # Find exact matches\ngno vsearch \"error handling patterns\" # Semantic similarity\ngno query \"database optimization\"    # Full pipeline\ngno query \"meeting decisions\" --since \"last month\" --category \"meeting,notes\" --author \"gordon\"\ngno query \"performance\" --intent \"web performance and latency\"\ngno query \"performance\" --exclude \"reviews,hiring\"\ngno ask \"what did we decide\" --answer # AI synthesis\n```\n\nOutput formats: `--json`, `--files`, `--csv`, `--md`, `--xml`\n\n### Common CLI Recipes\n\n```bash\n# Search one collection\ngno search \"PostgreSQL connection pool\" --collection work-docs\n\n# Export retrieval results for an agent\ngno query \"authentication flow\" --json -n 10\ngno query \"deployment rollback\" --all --files --min-score 0.4\n\n# Retrieve a document by URI or docid\ngno get \"gno://work-docs/runbooks/deploy.md\"\ngno get \"#abc123\"\n\n# Fetch many documents at once\ngno multi-get \"work-docs/**/*.md\" --max-bytes 20000 --md\n\n# Inspect how the hybrid rank was assembled\ngno query \"refresh token rotation\" --explain\n\n# Work with filters\ngno query \"meeting notes\" --since \"last month\" --category \"meeting,notes\"\ngno search \"incident review\" --tags-all \"status/active,team/platform\"\n\n# Export a publish artifact for gno.sh\ngno publish export work-docs --out ~/Downloads/work-docs.json\ngno publish export \"gno://work-docs/runbooks/deploy.md\" --out ~/Downloads/deploy.json\n# Or let GNO choose ~/Downloads/\u003cslug\u003e-\u003cYYYYMMDD\u003e.json automatically\ngno publish export work-docs\n```\n\nThe local web UI exposes the same export flow:\n\n- Collections page → collection menu → `Export for gno.sh`\n- Document view → `Export for gno.sh`\n\nBoth actions download the same JSON artifact the CLI writes, ready for upload at\n`https://gno.sh/studio`.\n\n### Retrieval V2 Controls\n\nExisting query calls still work. Retrieval v2 adds optional structured intent control and deeper explain output.\n\n```bash\n# Existing call (unchanged)\ngno query \"auth flow\" --thorough\n\n# Structured retrieval intent\ngno query \"auth flow\" \\\n  --intent \"web authentication and token lifecycle\" \\\n  --candidate-limit 12 \\\n  --query-mode term:\"jwt refresh token -oauth1\" \\\n  --query-mode intent:\"how refresh token rotation works\" \\\n  --query-mode hyde:\"Refresh tokens rotate on each use and previous tokens are revoked.\" \\\n  --explain\n\n# Multi-line structured query document\ngno query $'auth flow\\nterm: \"refresh token\" -oauth1\\nintent: how refresh token rotation works\\nhyde: Refresh tokens rotate on each use and previous tokens are revoked.' --fast\n```\n\n- Modes: `term` (BM25-focused), `intent` (semantic-focused), `hyde` (single hypothetical passage)\n- Explain includes stage timings, fallback/cache counters, and per-result score components\n- `gno ask --json` includes `meta.answerContext` for adaptive source selection traces\n- Search and Ask web text boxes also accept multi-line structured query documents with `Shift+Enter`\n\n---\n\n## Agent Integration\n\nGive your local LLM agents a long-term memory. GNO integrates as a Claude Code skill or MCP server, allowing agents to search, read, and cite your local files.\n\n### Skills\n\nSkills add GNO search to Claude Code/Codex without MCP protocol overhead:\n\n```bash\ngno skill install --scope user\n```\n\n![GNO Skill in Claude Code](./assets/screenshots/claudecodeskill.jpg)\n\nThen ask your agent: _\"Search my notes for the auth discussion\"_\n\nAgent-friendly CLI examples:\n\n```bash\n# Structured retrieval output for an agent\ngno query \"authentication\" --json -n 10\n\n# File list for downstream retrieval\ngno query \"error handling\" --all --files --min-score 0.35\n\n# Full document content when the agent already knows the ref\ngno get \"gno://work-docs/api-reference.md\" --full\ngno multi-get \"work-docs/**/*.md\" --md --max-bytes 30000\n```\n\n[Skill setup guide →](https://gno.sh/docs/integrations/skills/)\n\n### MCP Server\n\nConnect GNO to Claude Desktop, Cursor, Raycast, and more:\n\n![GNO MCP](./assets/screenshots/mcp.jpg)\n\nGNO exposes tools via [Model Context Protocol](https://modelcontextprotocol.io):\n\n| Tool            | Description                           |\n| :-------------- | :------------------------------------ |\n| `gno_search`    | BM25 keyword search                   |\n| `gno_vsearch`   | Vector semantic search                |\n| `gno_query`     | Hybrid search (recommended)           |\n| `gno_get`       | Retrieve document by ID               |\n| `gno_multi_get` | Batch document retrieval              |\n| `gno_links`     | Get outgoing links from document      |\n| `gno_backlinks` | Get documents linking TO document     |\n| `gno_similar`   | Find semantically similar documents   |\n| `gno_graph`     | Get knowledge graph (nodes and edges) |\n| `gno_status`    | Index health check                    |\n\n**Design**: MCP tools are retrieval-only. Your AI assistant (Claude, GPT-4) synthesizes answers from retrieved context. Best retrieval (GNO) + best reasoning (your LLM).\n\n[MCP setup guide →](https://gno.sh/docs/MCP/)\n\n---\n\n## Web UI\n\nVisual dashboard for search, browsing, editing, and AI answers. Right in your browser.\n\n```bash\ngno serve                    # Start on port 3000\ngno serve --port 8080        # Custom port\n```\n\n![GNO Web UI](./assets/screenshots/webui-home.jpg)\n\nOpen `http://localhost:3000` to:\n\n- **Search**: BM25, vector, or hybrid modes with visual results\n- **Browse**: Cross-collection tree workspace with folder detail panes and per-tab browse context\n- **Edit**: Create, edit, and delete documents with live preview\n- **Create in place**: New notes in the current folder/collection with presets and command-palette flows\n- **Ask**: AI-powered Q\u0026A with citations\n- **Manage Collections**: Add, remove, and re-index collections\n- **Connect agents**: Install core Skill/MCP integrations from the app\n- **Manage files safely**: Rename, reveal, or move editable files to Trash with explicit index-vs-disk semantics\n- **Refactor files safely**: Move, duplicate, and organize editable notes with reference warnings\n- **Switch presets**: Change models live without restart\n- **Command palette**: Jump, create, refactor, and section-navigate from one keyboard-first surface\n\n### Search\n\n![GNO Search](./assets/screenshots/webui-search.jpg)\n\nThree retrieval modes: BM25 (keyword), Vector (semantic), or Hybrid (best of both). Adjust search depth for speed vs thoroughness.\n\n### Document Editing\n\n![GNO Document Editor](./assets/screenshots/webui-editor.jpg)\n\nFull-featured markdown editor with:\n\n| Feature                 | Description                                  |\n| :---------------------- | :------------------------------------------- |\n| **Split View**          | Side-by-side editor and live preview         |\n| **Auto-save**           | 2-second debounced saves                     |\n| **Syntax Highlighting** | CodeMirror 6 with markdown support           |\n| **Keyboard Shortcuts**  | ⌘S save, ⌘B bold, ⌘I italic, ⌘K link         |\n| **Quick Capture**       | ⌘N creates new note from anywhere            |\n| **Presets**             | Structured note scaffolds and insert actions |\n\n### Document Viewer\n\n![GNO Document Viewer](./assets/screenshots/webui-doc-view.jpg)\n\nView documents with full context: outgoing links, backlinks, section outline, and AI-powered related notes sidebar.\n\n### Browse Workspace\n\n![GNO Collections](./assets/screenshots/webui-collections.jpg)\n\nNavigate your notes like a real workspace, not just a flat list:\n\n- Cross-collection tree sidebar\n- Folder detail panes\n- Create note and create folder from current browse context\n- Pinned collections and per-tab browse state\n- Direct jump from folder structure into notes\n\n### Knowledge Graph\n\n![GNO Knowledge Graph](./assets/screenshots/webui-graph.jpg)\n\nInteractive visualization of document connections. Wiki links, markdown links, and optional similarity edges rendered as a navigable constellation.\n\n### Collections Management\n\n![GNO Collections](./assets/screenshots/webui-collections.jpg)\n\n- Add collections with folder path input\n- View document count, chunk count, embedding status\n- Re-index individual collections\n- Remove collections (documents preserved)\n\n### AI Answers\n\n![GNO AI Answers](./assets/screenshots/webui-ask-answer.jpg)\n\nAsk questions in natural language. GNO searches your documents and synthesizes answers with inline citations linking to sources.\n\nEverything runs locally. No cloud, no accounts, no data leaving your machine.\n\n\u003e **Detailed docs**: [Web UI Guide](https://gno.sh/docs/WEB-UI/)\n\n---\n\n## Publish to gno.sh\n\nGNO is local-first, but sometimes you want a URL to send someone. [**gno.sh**](https://gno.sh/publish) is the hosted reader on top of GNO — a polished, reading-first page for a single note or a whole collection, without mounting your vault or syncing anything.\n\n![gno.sh publish reader](./assets/screenshots/publish-reader.jpg)\n\nThe workflow is deliberately explicit: **export locally → upload artifact → share URL**. Your private notes and metadata stay on your machine. Only what you export leaves.\n\n```bash\n# Export a single note\ngno publish export \"gno://work-docs/runbooks/deploy.md\" --out ~/Downloads/deploy.json\n\n# Export a whole collection\ngno publish export work-docs --out ~/Downloads/work-docs.json\n\n# Export an encrypted note (ciphertext is created locally before upload)\ngno publish export \"gno://work-docs/runbooks/deploy.md\" \\\n  --visibility encrypted \\\n  --passphrase \"correct horse battery staple\" \\\n  --out ~/Downloads/deploy-encrypted.json\n\n# Let GNO pick the path (~/Downloads/\u003cslug\u003e-\u003cYYYYMMDD\u003e.json)\ngno publish export work-docs\n```\n\nOr use the Web UI:\n\n- **Collections page** → collection menu → **Export for gno.sh**\n- **Document view** → **Export for gno.sh**\n\nUpload the artifact at [gno.sh/studio](https://gno.sh/studio) and pick a visibility mode:\n\n| Mode            | Use When                                                       |\n| :-------------- | :------------------------------------------------------------- |\n| **Public**      | Open URL, indexable — talks, blog posts, portfolios            |\n| **Secret link** | Unguessable token, rotate / revoke / expire                    |\n| **Invite-only** | Private space for specific people                              |\n| **Encrypted**   | GNO encrypts locally before upload; readers decrypt in-browser |\n\n**Reader experience**: editorial serif typography, drop caps, hanging punctuation, table of contents, keyboard shortcuts (`j/k`, `/`), scoped Pagefind-style search, and backlinks restricted to the published subset. Nothing leaks that you didn't publish.\n\nRepublishing a public, secret-link, or invite-only artifact updates the same URL. Encrypted shares should be replaced from a fresh local export so the server never needs your plaintext.\n\nEncrypted source-backed publish on `gno.sh` is intentionally disabled. For encrypted shares, use:\n\n- `gno publish export --visibility encrypted --passphrase ...`, or\n- the browser-side encrypted markdown upload path in `gno.sh/studio`\n\n\u003e **Full story**: [gno.sh/publish](https://gno.sh/publish) · **Try it**: [gno.sh/studio](https://gno.sh/studio)\n\n---\n\n## REST API\n\nProgrammatic access to all GNO features via HTTP.\n\n```bash\n# Hybrid search\ncurl -X POST http://localhost:3000/api/query \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"query\": \"authentication patterns\", \"limit\": 10}'\n\n# AI answer\ncurl -X POST http://localhost:3000/api/ask \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"query\": \"What is our deployment process?\"}'\n\n# Index status\ncurl http://localhost:3000/api/status\n```\n\n| Endpoint                      | Method | Description                 |\n| :---------------------------- | :----- | :-------------------------- |\n| `/api/query`                  | POST   | Hybrid search (recommended) |\n| `/api/search`                 | POST   | BM25 keyword search         |\n| `/api/ask`                    | POST   | AI-powered Q\u0026A              |\n| `/api/docs`                   | GET    | List documents              |\n| `/api/docs`                   | POST   | Create document             |\n| `/api/docs/:id`               | PUT    | Update document content     |\n| `/api/docs/:id/move`          | POST   | Move editable document      |\n| `/api/docs/:id/duplicate`     | POST   | Duplicate editable document |\n| `/api/docs/:id/refactor-plan` | POST   | Preview file-op warnings    |\n| `/api/docs/:id/deactivate`    | POST   | Remove from index           |\n| `/api/doc`                    | GET    | Get document content        |\n| `/api/doc/:id/sections`       | GET    | Get document sections       |\n| `/api/collections`            | POST   | Add collection              |\n| `/api/collections/:name`      | DELETE | Remove collection           |\n| `/api/folders`                | POST   | Create folder               |\n| `/api/sync`                   | POST   | Trigger re-index            |\n| `/api/status`                 | GET    | Index statistics            |\n| `/api/note-presets`           | GET    | List note presets           |\n| `/api/presets`                | GET    | List model presets          |\n| `/api/presets`                | POST   | Switch preset               |\n| `/api/models/pull`            | POST   | Download models             |\n| `/api/models/status`          | GET    | Download progress           |\n\nNo authentication. No rate limits. Build custom tools, automate workflows, integrate with any language.\n\n\u003e **Full reference**: [API Documentation](https://gno.sh/docs/API/)\n\n---\n\n## How It Works\n\n```mermaid\ngraph TD\n    A[User Query] --\u003e B(Query Expansion)\n    B --\u003e C{Lexical Variants}\n    B --\u003e D{Semantic Variants}\n    B --\u003e E{HyDE Passage}\n\n    C --\u003e G(BM25 Search)\n    D --\u003e H(Vector Search)\n    E --\u003e H\n    A --\u003e G\n    A --\u003e H\n\n    G --\u003e I(Ranked Results)\n    H --\u003e J(Ranked Results)\n    I --\u003e K{RRF Fusion}\n    J --\u003e K\n\n    K --\u003e L(Top 20 Candidates)\n    L --\u003e M(Cross-Encoder Rerank)\n    M --\u003e N[Final Results]\n```\n\n0. **Strong Signal Check**: Skip expansion if BM25 has confident match (saves 1-3s)\n1. **Query Expansion**: LLM generates lexical variants, semantic rephrases, and a [HyDE](https://arxiv.org/abs/2212.10496) passage\n2. **Parallel Retrieval**: Document-level BM25 + chunk-level vector search on all variants\n3. **Fusion**: RRF with 2× weight for original query, tiered bonus for top ranks\n4. **Reranking**: Qwen3-Reranker scores best chunk per document (4K), blended with fusion\n\n\u003e **Deep dive**: [How Search Works](https://gno.sh/docs/HOW-SEARCH-WORKS/)\n\n---\n\n## Features\n\n| Feature              | Description                                                                    |\n| :------------------- | :----------------------------------------------------------------------------- |\n| **Hybrid Search**    | BM25 + vector + RRF fusion + cross-encoder reranking                           |\n| **Document Editor**  | Create, edit, delete docs with live markdown preview                           |\n| **Web UI**           | Visual dashboard for search, browse, edit, and AI Q\u0026A                          |\n| **REST API**         | HTTP API for custom tools and integrations                                     |\n| **Multi-Format**     | Markdown, PDF, DOCX, XLSX, PPTX, plain text                                    |\n| **Local LLM**        | AI answers via llama.cpp, no API keys                                          |\n| **Remote Inference** | Offload to GPU servers via HTTP (llama-server, Ollama, LocalAI)                |\n| **Privacy First**    | 100% offline, zero telemetry, your data stays yours                            |\n| **MCP Server**       | Works with Claude Desktop, Cursor, Zed, + 8 more                               |\n| **Collections**      | Organize sources with patterns, excludes, contexts                             |\n| **Tag Filtering**    | Frontmatter tags with hierarchical paths, filter via `--tags-any`/`--tags-all` |\n| **Note Linking**     | Wiki links, backlinks, related notes, cross-collection navigation              |\n| **Multilingual**     | 30+ languages, auto-detection, cross-lingual search                            |\n| **Incremental**      | SHA-256 tracking, only changed files re-indexed                                |\n| **Keyboard First**   | ⌘N capture, ⌘K search, ⌘/ shortcuts, ⌘S save                                   |\n\n---\n\n## Local Models\n\nModels auto-download on first use to `~/.cache/gno/models/`. For deterministic startup, set `GNO_NO_AUTO_DOWNLOAD=1` and use `gno models pull` explicitly. Alternatively, offload to a GPU server on your network using HTTP backends.\n\n| Model                  | Purpose                               | Size         |\n| :--------------------- | :------------------------------------ | :----------- |\n| Qwen3-Embedding-0.6B   | Embeddings (multilingual)             | ~640MB       |\n| Qwen3-Reranker-0.6B    | Cross-encoder reranking (32K context) | ~700MB       |\n| Qwen3 / Qwen2.5 family | Query expansion + AI answers          | ~600MB-2.5GB |\n\n### Model Presets\n\n| Preset       | Disk   | Best For                                                |\n| :----------- | :----- | :------------------------------------------------------ |\n| `slim-tuned` | ~1GB   | Current default, tuned retrieval in a compact footprint |\n| `slim`       | ~1GB   | Fast, good quality                                      |\n| `balanced`   | ~2GB   | Slightly larger model                                   |\n| `quality`    | ~2.5GB | Best answers                                            |\n\n```bash\ngno models use slim-tuned\ngno models pull --all  # Optional: pre-download models (auto-downloads on first use)\n```\n\n## Fine-Tuned Models\n\nGNO now has a published promoted retrieval model for the default slim path:\n\n- model repo: `guiltylemon/gno-expansion-slim-retrieval-v1`\n- recommended preset id: `slim-tuned`\n- runtime URI:\n  - `hf:guiltylemon/gno-expansion-slim-retrieval-v1/gno-expansion-auto-entity-lock-default-mix-lr95-f16.gguf`\n\nUse it when you want the tuned retrieval expansion path immediately, without running local fine-tuning yourself.\n\nFor private/internal products, use the same workflow but keep the final GGUF private and point `gen:` at a `file:` URI instead of publishing to Hugging Face.\n\nSee:\n\n- [Fine-Tuned Models docs](https://gno.sh/docs/FINE-TUNED-MODELS/)\n- [Fine-Tuned Models feature page](https://gno.sh/features/fine-tuned-models/)\n\n### HTTP Backends (Remote GPU)\n\nOffload inference to a GPU server on your network:\n\n```yaml\n# ~/.config/gno/index.yml\nmodels:\n  activePreset: remote-gpu\n  presets:\n    - id: remote-gpu\n      name: Remote GPU Server\n      embed: \"http://192.168.1.100:8081/v1/embeddings#qwen3-embedding-0.6b\"\n      rerank: \"http://192.168.1.100:8082/v1/completions#reranker\"\n      expand: \"http://192.168.1.100:8083/v1/chat/completions#gno-expand\"\n      gen: \"http://192.168.1.100:8083/v1/chat/completions#qwen3-4b\"\n```\n\nWorks with llama-server, Ollama, LocalAI, vLLM, or any OpenAI-compatible server.\n\n\u003e **Configuration**: [Model Setup](https://gno.sh/docs/CONFIGURATION/)\n\nRemote/BYOM guides:\n\n- [Bring Your Own Models](./docs/guides/bring-your-own-models.md)\n- [Per-Collection Models](./docs/guides/per-collection-models.md)\n\n---\n\n## Architecture\n\n```\n┌─────────────────────────────────────────────────┐\n│            GNO CLI / MCP / Web UI / API         │\n├─────────────────────────────────────────────────┤\n│  Ports: Converter, Store, Embedding, Rerank    │\n├─────────────────────────────────────────────────┤\n│  Adapters: SQLite, FTS5, sqlite-vec, llama-cpp │\n├─────────────────────────────────────────────────┤\n│  Core: Identity, Mirrors, Chunking, Retrieval  │\n└─────────────────────────────────────────────────┘\n```\n\n\u003e **Details**: [Architecture](https://gno.sh/docs/ARCHITECTURE/)\n\n---\n\n## Development\n\n```bash\ngit clone https://github.com/gmickel/gno.git \u0026\u0026 cd gno\nbun install\nbun test\nbun run lint \u0026\u0026 bun run typecheck\n```\n\n\u003e **Contributing**: [CONTRIBUTING.md](.github/CONTRIBUTING.md)\n\n### Evals and Benchmark Deltas\n\nUse retrieval benchmark commands to track quality and latency over time:\n\n```bash\nbun run eval:hybrid\nbun run eval:hybrid:baseline\nbun run eval:hybrid:delta\n```\n\n- Benchmark guide: [evals/README.md](./evals/README.md)\n- Latest baseline snapshot: [evals/fixtures/hybrid-baseline/latest.json](./evals/fixtures/hybrid-baseline/latest.json)\n\n### Code Embedding Benchmark Harness\n\nGNO also has a dedicated harness for comparing alternate embedding models on code retrieval without touching product defaults:\n\n```bash\n# Establish the current incumbent baseline\nbun run bench:code-embeddings --candidate bge-m3-incumbent --write\n\n# Add candidate model URIs to the search space, then inspect them\nbun run research:embeddings:autonomous:list-search-candidates\n\n# Benchmark one candidate explicitly\nbun run research:embeddings:autonomous:run-candidate bge-m3-incumbent\n\n# Or let the bounded search harness walk the remaining candidates later\nbun run research:embeddings:autonomous:search --dry-run\n```\n\nSee [research/embeddings/README.md](./research/embeddings/README.md).\n\nIf a model turns out to be better specifically for code, the intended user story is:\n\n- keep the default global preset for mixed prose/docs collections\n- use per-collection `models.embed` overrides for code collections\n\nThat lets GNO stay sane by default while still giving power users a clean path to code-specialist retrieval.\n\nMore model docs:\n\n- [Code Embeddings](./docs/guides/code-embeddings.md)\n- [Per-Collection Models](./docs/guides/per-collection-models.md)\n- [Bring Your Own Models](./docs/guides/bring-your-own-models.md)\n\nCurrent product stance:\n\n- `Qwen3-Embedding-0.6B-GGUF` is already the global default embed model\n- you do **not** need a collection override just to get Qwen on code collections\n- use a collection override only when one collection should intentionally diverge from that default\n\nWhy Qwen is the current default:\n\n- matches or exceeds `bge-m3` on the tiny canonical benchmark\n- significantly beats `bge-m3` on the real GNO `src/serve` code slice\n- also beats `bge-m3` on a pinned public-OSS code slice\n- also beats `bge-m3` on the multilingual prose/docs benchmark lane\n\nCurrent trade-off:\n\n- Qwen is slower to embed than `bge-m3`\n- existing users upgrading or adopting a new embedding formatting profile may need to run `gno embed` again so stored vectors match the current formatter/runtime path\n\n### General Multilingual Embedding Benchmark\n\nGNO also now has a separate public-docs benchmark lane for normal markdown/prose\ncollections:\n\n```bash\nbun run bench:general-embeddings --candidate bge-m3-incumbent --write\nbun run bench:general-embeddings --candidate qwen3-embedding-0.6b --write\n```\n\nCurrent signal on the public multilingual FastAPI-docs fixture:\n\n- `bge-m3`: vector nDCG@10 `0.3508`, hybrid nDCG@10 `0.6756`\n- `Qwen3-Embedding-0.6B-GGUF`: vector nDCG@10 `0.9891`, hybrid nDCG@10 `0.9891`\n\nInterpretation:\n\n- Qwen is now the strongest general multilingual embedding model we have tested\n- built-in presets now use Qwen by default\n- existing users may need to run `gno embed` again after upgrading so current collections catch up\n\n---\n\n## License\n\n[MIT](./LICENSE)\n\n---\n\n\u003cp align=\"center\"\u003e\n  made with ❤️ by \u003ca href=\"https://twitter.com/gmickel\"\u003e@gmickel\u003c/a\u003e\n\u003c/p\u003e\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgmickel%2Fgno","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgmickel%2Fgno","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgmickel%2Fgno/lists"}