Skip to content

Latest commit

 

History

History
1017 lines (795 loc) · 41.5 KB

File metadata and controls

1017 lines (795 loc) · 41.5 KB
title Configuration
description Configure collections, models, exclusions, remote inference endpoints, and runtime behavior for GNO's local knowledge workspace.
keywords gno config, local search configuration, collections config, model presets, remote inference config

Configuration

GNO configuration reference.

Config File

Location varies by platform (see File Locations below). Run gno doctor to see your resolved config path.

version: "1.0"

# FTS tokenizer (set at init, cannot change)
ftsTokenizer: snowball english

# Trusted local CLI project affinity
projectAffinity:
  enabled: true
  contribution: 0.03

# Collections
collections:
  - name: notes
    path: /Users/you/notes
    pattern: "**/*.md"
    egressPolicy: local_only
    # Source content availability (distinct from egressPolicy):
    # any (default) = legacy reads; local = opt-in no-materialization guard
    # for tested macOS File Provider layouts only.
    sourceAvailability: any
    include: []
    exclude:
      - .git
      - node_modules
    languageHint: en

  - name: work
    path: /Users/you/work/docs
    pattern: "**/*"
    exclude:
      - dist
      - build

# Contexts (semantic hints)
contexts:
  - scopeType: global
    scopeKey: /
    text: Personal knowledge base and project documentation

  - scopeType: collection
    scopeKey: notes:
    text: Personal notes and journal entries

  - scopeType: prefix
    scopeKey: gno://work/api
    text: API documentation and specifications

# Model configuration
models:
  activePreset: slim-tuned

# Optional schema-lite content type rules
contentTypes:
  - id: person
    prefixes:
      - people/
      - contacts/
    preset: person
    graphHints:
      - mentions
      - works_at
    searchBoost: 1.15
  - id: meeting
    prefixes:
      - meetings/
    preset: meeting
    temporal: true

# Optional terminal hyperlink target template for CLI search output
editorUriTemplate: "vscode://file/{path}:{line}:{col}"

# Optional resident Streamable HTTP MCP gateway
gateway:
  host: 127.0.0.1
  enableWrite: false

# Private local retrieval receipts are absent/off by default.
retrievalTraces:
  enabled: false

Project-profile apply also maintains optional projectProfileBindings entries in this local config. Each timestamp-free entry binds a canonical absolute .gno/index.yml path to its SHA-256 fingerprint and projected collection. These machine-local provenance records are written under the shared config lock; they are never copied into the tracked profile or exposed by public profile receipts.

Project affinity

projectAffinity.enabled defaults to true and controls only the fallback cwd-derived signal from user config. Set it to false to disable that fallback. Explicit --project-root values and a valid nearest project profile retain their higher-precedence request-local behavior. Use --no-project-affinity to disable every affinity source for one request. projectAffinity.contribution defaults to 0.03 and must stay within 0..0.03.

Only canonicalized local CLI roots can match configured collection paths. Explicit --project-root values replace profile/cwd inference. When no explicit root is supplied, the nearest valid .gno/index.yml contributes its compiled, request-local affinityDefaults; otherwise the user config applies to the cwd-derived root. Profile defaults never overwrite this user default, and source metadata/content types never become project identity. Overlapping/duplicate roots never stack. SDK, REST, MCP, and Web UI projectHints are opaque/untrusted (maximum 16) and deliberately produce zero affinity without filesystem probing. All auxiliary contributions share the ±0.08 cap; collection/tag/date/exclude/egress filters remain hard.

See Project-Local Retrieval Profiles.

File and export adapters

Collections automatically recognize .jsonl, .ndjson, .eml, .mbox, .ics, .vtt, .srt, and explicit .browser-export files. Optional recordAdapters configuration provides closed JSONL field mappings and explicit JSON/text transcript selection; it cannot execute code. See File and Export Adapters for the support matrix, fixed resource and 60-second adapter deadline caps, partial-import receipts, snapshot/tombstone semantics, and no-live-account security boundary. When include is empty, configuring recordAdapters.transcript.format: json also makes .json files discoverable. A nonempty include remains an explicit allowlist and must list .json.

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 the policy migration retain their indexed documents and lexical/vector data, but their cached provenance is legacy_default; newly synchronized collections without an explicit value report config_default. Neither default can imply lan or remote.

Policy Permitted destination
local_only Local process, local files, loopback clients, and loopback model servers only
lan local_only plus authenticated, proven private-network peers
remote lan plus authenticated public transport and pinned HTTPS model providers

Authentication and write permission remain separate gates. A token does not relax collection policy; gateway.enableWrite does not relax it either. Mixed evidence and derived artifacts use the most restrictive participating collection. Explicit partial checks disclose every omitted collection and reason; normal operations never silently drop restricted evidence.

Source availability

collections[].sourceAvailability is optional and independent of egressPolicy. Exact values: any | local. Omitted means any.

Mode Behavior
any Default. Legacy source reads; no no-materialization guard.
local Opt-in. Indexes only content that is already local; refuses cloud-placeholder materialization on the macOS File Provider layouts covered by physical evidence. Unsupported setup fails closed.

What local does (macOS File Provider, evidence-qualified):

  • Establishes a process-scoped no-materialization I/O policy (IOPOL_TYPE_VFS_MATERIALIZE_DATALESS_FILES) for content reads.
  • Classifies directories hierarchically (memoized per operation) before descent; does not add one availability syscall per discovered file.
  • Rechecks at the content boundary (sniff, hash, conversion, record import, targeted sync, and watch-triggered ingestion share the same guard).
  • Skips cloud placeholders / partial content as CLOUD_PLACEHOLDER / CLOUD_PARTIAL (not conversion errors).
  • Refuses descent into dataless or availability-unknown directories (DATALESS_DIRECTORY or fail-closed codes) and preserves previously indexed descendants under those unproven prefixes rather than proving deletion.

Evidence scope (do not over-claim):

  • Proven independently for Google Drive, iCloud Drive, and OneDrive on the tested macOS/provider configuration.
  • OneDrive is claimed only for both installed immediate SharePoint library roots under the SharedLibraries domain — not the aggregation root, not arbitrary deeper trees, not untested library layouts.
  • No Windows Cloud Files or Linux/FUSE guarantee.
  • Metadata or provider bookkeeping may still occur. GNO local mode does not pin, evict, or download as product behavior.
  • Availability controls source materialization; egress controls where derived data may travel.

Measured scan cost: on the controlled 5,000-file all-local Markdown corpus (2 warmups, 9 retained interleaved samples per lane), production traversal measured 215.1020 ms for pre-implementation any, 212.6756 ms for current any (-1.1280%, within the 3% budget), and 215.1938 ms for hierarchical local (+1.1841% versus current any, within the 10% budget). Conversion and embedding were not applicable to this corpus; raw receipts are tracked under research/file-provider/evidence/.

collections:
  - name: drive-notes
    path: /Users/you/Library/CloudStorage/GoogleDrive-…/My Drive/notes
    pattern: "**/*"
    sourceAvailability: local
    egressPolicy: local_only

Inspect and change one policy with:

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

The relaxation revision must exactly match the current get result. It is single-use and becomes stale after any intervening policy change. Tightening needs no confirmation and invalidates resident sessions, active streams, queued jobs, and saved authorization state; callers must retry against the new policy. Removing an explicit policy does not restore network access—it returns to the fail-closed local default.

Migration does not recall data already disclosed. Tightening a collection blocks future GNO-controlled transfers, but an artifact previously uploaded to a remote service may require deletion or takedown at that service. For gno.sh, revoke or expire supported private links in Studio; public-space deletion is not yet self-service, so request takedown before creating and uploading a new artifact. Encrypted artifacts remain client-encrypted; gno.sh never receives the passphrase and cannot decrypt or recover them.

Policy decisions create bounded, content-free local audit receipts. Use gno egress-audit list|show|status|delete|purge; receipts contain stable reason codes and redacted collection identity, never query text, document content, credentials, target URLs, or sensitive absolute paths.

Knowledge-integrity audit policy

Knowledge-integrity audits are intentionally run-scoped in v1. There is no configuration key, persisted baseline, suppression list, schedule, or automatic repair. Supply an age review threshold only when wanted:

gno audit freshness --max-age-days 90
gno audit links --orphan-root gno://notes/index.md \
  --orphan-ignore-prefix templates --orphan-ignore-prefix archive

The equivalent MCP fields are maxAgeDays, orphanRoots, and orphanIgnorePrefixes. Age is a review signal, not a factual-truth judgment. gno audit reads the effective collection definitions from this config but does not change them. Do not confuse its content-bearing local findings with the content-free egress policy receipts above.

Resident HTTP MCP Gateway

gno serve and gno daemon expose /mcp. The default configuration binds literal 127.0.0.1, derives exact 127.0.0.1:<port> and localhost:<port> Host/Origin allowlists, and leaves mutation tools disabled.

gateway:
  host: 0.0.0.0
  tokenFile: ~/.config/gno/mcp-token
  allowedHosts:
    - workstation.local:3000
  allowedOrigins:
    - https://trusted-client.example
  enableWrite: false
  limits:
    maxBodyBytes: 1048576
    maxRequestsPerMinute: 120
    maxConcurrentRequests: 64
    maxQueuedRequests: 16
    maxSessions: 32
    sessionIdleTimeoutMs: 300000

Wildcard or non-loopback binding requires tokenFile, allowedHosts, and allowedOrigins; every allowlist value is exact and wildcards are rejected. gno serve remains loopback-only because its Web and REST surfaces share the listener; use gno daemon for authenticated non-loopback MCP access. An explicitly configured missing token file is generated with a random 256-bit token and mode 0600 on POSIX. Authentication and mutation authorization are separate: enableWrite must be true before HTTP write tools are registered or dispatched. CLI gateway flags override config values for one invocation.

Upgrading from a stdio-only setup requires no client-config migration: gno mcp remains supported. Start gno serve or gno daemon only for clients that can use the resident URL http://127.0.0.1:3000/mcp. Stop any resident owner for the same data directory before switching between serve and daemon.

Browser clipper boundary

The browser clipper is not enabled by a gateway write flag. It exists only on loopback gno serve, uses a dedicated visibly approved, origin-bound capture grant, and is structurally absent from non-loopback listeners. MCP bearer tokens, GNO_API_TOKEN, and gateway.enableWrite never authorize clipping.

The extension targets literal http://127.0.0.1:<port>; its unpacked manifest grants only activeTab, scripting, storage, and http://127.0.0.1/*. There is no configuration for remote clipper access, cookie/history access, background surveillance, or source-URL fetching. See Browser Clipper for install, pairing, storage, and recovery details.

Private Retrieval Traces

Retrieval trace recording is local, opt-in, and disabled when retrievalTraces is absent or enabled: false. Enabling it requires an explicit redaction mode and every retention bound:

retrievalTraces:
  enabled: true
  redactionMode: metadata
  retention:
    maxAgeDays: 30
    maxTraces: 1000
    maxRecordsPerTrace: 10000
    maxBytes: 16777216

metadata stores content-free query/goal/filter shapes plus validated evidence identity such as source hashes, docids, ranks, and exact line spans. It does not store raw query, goal, filter values, passages, filesystem paths, or external URLs, and it is not replay-capable.

replay is separate, explicit consent to retain the normalized raw query, goal, and validated retrieval filters. Even in replay mode, event/run payloads use closed evidence schemas: no source passages, absolute paths, or external URLs are accepted. Receipts stay in the active local index database; the recorder has no telemetry or upload path.

Each traced application request creates one local session at the CLI, REST, MCP, or SDK boundary. It records normalized retrieval stages, exact canonical source spans, explicit open/cite/pin outcomes, capability fallbacks, and a terminal outcome. Search-result planner details remain internal and do not change public result JSON. Ask records only citations retained after final citation validation; failures, partial answers, and cancellations are terminal states, never implicit relevance judgments.

Random trace identity is response metadata only: CLI stderr, the X-GNO-Trace-ID REST header, MCP _meta.gno.retrievalTrace.traceId, or the SDK's non-enumerable RETRIEVAL_TRACE_METADATA symbol. It never enters a canonical Context Capsule or changes capsuleId. Retrieval-only CLI calls may be continued with gno get --trace-id <id>.

Retention uses epoch-millisecond timestamps and deterministically removes expired traces first, then traces exceeding the per-trace record limit, then the oldest traces until count and logical-storage byte bounds are satisfied. Changing maxAgeDays applies the shorter current policy to existing receipts.

Per-trace deletion removes every owned run, event, judgment, and export link transactionally, but SQLite WAL history may remain until checkpointed. Full purge enables SQLite secure deletion for the transaction and requires a successful truncating WAL checkpoint before reporting physical cleanup complete. User-created exports and external backups remain user-owned and must be deleted separately.

Disabling retrievalTraces.enabled stops new capture and fingerprint work; it does not make existing local receipts unmanageable. gno trace, the SDK, and the loopback REST/Web surfaces can still inspect, explicitly label, export, or delete stored receipts. Metadata-mode label references use an index-local, random redaction secret persisted in database metadata so retries stay stable across restarts without exposing the secret through any surface.

Trace schema upgrades and recovery

Trace storage is database schema v14. Existing v12 and v13 indexes upgrade transactionally: a failed migration preserves the prior schema version and does not leave partial trace tables. Stop the active resident owner and back up the SQLite database together with live -wal/-shm companions before moving an important index between GNO versions; never copy a database while it is being written.

There is no in-place downgrade command. Disabling recording is reversible and does not delete receipts. Use explicit export first when evidence must be retained, gno trace delete for one receipt, or gno --yes trace purge --json for all local trace rows. Only a purge receipt with physicalCleanup: completed proves WAL truncation; exported artifacts and external backups remain outside the purge boundary.

Verified Folder Setup State

gno setup <folder> is the preferred first activation path. It may create the default config, but the transaction itself stays direct and standalone: it does not discover or attach to a resident listener. Its fixed lexical stages are preflight, config_saved, store_synced, lexical_indexed, lexical_proved, and completed.

Private state lives outside the indexed folder:

<dataDir>/setup-receipts/<index>/<folder-fingerprint>.json
<dataDir>/setup-semantic/<index>/<folder-fingerprint>.json
<dataDir>/setup-semantic/<index>/<folder-fingerprint>.log

The closed FolderSetupReceipt@1.0 contains no semantic-worker or connector fields. setup-command-result@1.0 composes it with setup-semantic@1.0; setup-activation-result@1.0 wraps that unchanged result only when explicit connectors are selected. Stable semantic source identity ignores timestamps, stage tokens, and created/reused disposition, but changes with material folder, index, or activation evidence. --no-semantic starts no new work; a live one-shot worker keeps ownership of its canonical receipt and PID.

Connector setup never overwrites an existing entry. Malformed configuration is preserved for repair. Connector failures or unverifiable skill runtimes report completed_with_actions after lexical proof without rolling back the collection.

Collections

Collections define what gets indexed.

Collection Fields

Field Type Default Description
name string required Unique identifier (lowercase)
path string required Absolute path to directory
pattern glob **/* File matching pattern
include array see below Extension allowlist
exclude array see below Patterns to skip
updateCmd string - Shell command before indexing
languageHint string - BCP-47 language code
models object - Per-collection model overrides

Default Include Extensions

When include is empty (default), only supported document types are indexed:

  • .md - Markdown
  • .txt - Plain text
  • .pdf - PDF documents
  • .docx - Word documents
  • .pptx - PowerPoint
  • .xlsx - Excel spreadsheets

To override the default and index only specific supported types:

include:
  - .md
  - .txt

Note: include controls which files are scanned, but files must still have converter support. Specifying unsupported extensions will result in conversion errors.

Files larger than the conversion size limit (100MB default) are skipped via filesystem stat before GNO reads file bytes.

Files without extensions (e.g., Makefile, LICENSE) and dotfiles (e.g., .env, .gitignore) are always excluded.

Default Excludes

exclude:
  - .git
  - node_modules
  - .venv
  - .idea
  - dist
  - build
  - __pycache__
  - .DS_Store
  - Thumbs.db

Examples

Markdown notes:

- name: notes
  path: /Users/you/notes
  pattern: "**/*.md"

Code docs with language hint:

- name: german-docs
  path: /Users/you/docs/german
  pattern: "**/*.md"
  languageHint: de

Mixed documentation folder:

- name: project-docs
  path: /Users/you/project/docs
  pattern: "**/*"
  include:
    - .md
    - .txt
  exclude:
    - node_modules
    - dist
    - drafts

Note: Exclude patterns match path components (directory or file names), not globs. Use dist to exclude a dist/ directory, not *.js.

With update command:

- name: wiki
  path: /Users/you/wiki
  updateCmd: "git pull"

Contexts

Contexts add semantic hints to improve search relevance.

Scope Types

Type Key Format Example
global / Applies to all documents
collection name: Applies to collection
prefix gno://collection/path Applies to path prefix

Examples

contexts:
  # Global context
  - scopeType: global
    scopeKey: /
    text: Technical knowledge base for software development

  # Collection context
  - scopeType: collection
    scopeKey: notes:
    text: Personal notes and daily journal entries

  # Path prefix context
  - scopeType: prefix
    scopeKey: gno://work/api
    text: REST API documentation and OpenAPI specs

Contexts are operational retrieval guidance, not labels stored and forgotten. Structured CLI, REST, MCP, and SDK search results include an optional context field whenever a scope matches. GNO composes matching text deterministically: global first, collection second, then path prefixes from broadest to most specific. Duplicate text is included once, and prefix matching respects path segments (projects/a does not match projects/ab).

Context does not affect matching or ranking. Grounded Ask uses it as trusted user configuration, delimited separately from retrieved document content. A result with no matching context keeps the historical shape and omits the field.

Models

Model configuration for embeddings and AI answers.

Presets

Preset Best For
slim-tuned Current default; tuned query expansion
slim Untuned slim query expansion
balanced Qwen2.5 3B expansion and answers
quality Qwen3 4B expansion and standalone AI answers

Actual download and cache use depends on the selected artifacts, quantization, and files already present. Treat UI size labels as orientation, not measured clean-install footprints.

Note: When using GNO standalone with --answer, the quality preset is required for documents containing Markdown tables or other structured content. The smaller models in slim/balanced presets cannot reliably parse tabular data. When GNO is used via MCP, skill, or CLI by AI agents (Claude Code, Codex, etc.), the agent handles answer generation, so any preset works for retrieval.

Per-collection model overrides

Collections can override model roles without replacing the global preset system.

Guides:

Example:

collections:
  - name: work
    path: /Users/you/work/docs
    models:
      rerank: "file:/models/work-rerank.gguf"
      expand: "file:/models/work-expand.gguf"

Resolution order:

  1. collection role override
  2. active preset role
  3. built-in default fallback

Notes:

  • overrides are partial; you only set the roles you need
  • global preset remains the base layer for everything else
  • collection-scoped overrides are only meaningful when an operation resolves a specific collection
  • the Web UI Collections page can now edit these overrides directly and shows effective per-role model resolution
  • use collection overrides when one collection should intentionally diverge from the workspace default
  • if a future benchmark shows a different code-specific embedding model wins on source-code retrieval, prefer using models.embed on code collections instead of replacing the global default for every collection

This still uses normal GNO model provisioning rules:

  • it auto-downloads on first use by default
  • it respects GNO_NO_AUTO_DOWNLOAD / offline policy the same way preset models do
  • it is most useful when one collection should diverge from the global default or when migrating older configs explicitly

Current general multilingual benchmark signal

The immutable April 2026 FastAPI-docs run used 15 documents in five corpus languages (en, de, fr, es, zh) and 13 queries:

A separate July 2026 Nemotron screen measured Qwen at 0.9891 vector / 0.9891 hybrid nDCG@10 and Nemotron at 0.9023 / 0.9461 on the same 13-query lane after runtime/profile changes. Nemotron used a temporary PyTorch HTTP adapter, so timings are not comparable; the screen did not validate an official production GGUF for Nemotron.

Qwen3-Embedding-0.6B-GGUF is the embedding model in all four built-in presets.

Operational consequences:

  • existing users who upgrade may need a fresh gno embed pass because their old vectors were created with bge-m3
  • GNO now counts readiness/backlog against the active embed model, so the need to re-embed is visible immediately after a preset/default change
  • if a future release changes the formatting profile for an active embedding model, re-embed is also required because the stored document vectors were produced differently

Scope matters: query-language classification is distinct from indexed-document language detection (en, de, fr, it, zh, ja, ko), and this small semantic fixture covers only five languages.

Model-free lexical fallback has a separate immutable July 22, 2026 CJK benchmark. Production BM25 lexical results and frozen 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 promotion-gates.md also binds MRR, non-regression, and cost requirements. The Chinese fixture includes a genuine rank-7 retrieval failure. These lexical results do not describe semantic retrieval or select an implementation, and no production analyzer/configuration changed. All positive qrels use relevance 3, so nDCG measures placement but not distinctions among positive gain grades.

The legacy multilingual Evalite lane is a four-case BM25-only sanity check, not a release gate.

Model Details

All presets use:

  • Qwen3-Embedding-0.6B for embeddings (multilingual)
  • Qwen3-Reranker-0.6B for reranking (scores best chunk per document)
Preset Embed Rerank Expand Gen
slim-tuned Qwen3-Embedding-0.6B-Q8 Qwen3-Reranker-0.6B-Q8 GNO slim retrieval tune Qwen3-1.7B-Q4
slim Qwen3-Embedding-0.6B-Q8 Qwen3-Reranker-0.6B-Q8 Qwen3-1.7B-Q4 Qwen3-1.7B-Q4
balanced Qwen3-Embedding-0.6B-Q8 Qwen3-Reranker-0.6B-Q8 Qwen2.5-3B-Q4 Qwen2.5-3B-Q4
quality Qwen3-Embedding-0.6B-Q8 Qwen3-Reranker-0.6B-Q8 Qwen3-4B-Q4 Qwen3-4B-Q4

Reranking scores the best retrieved chunk per document, capped at 4K characters. The model's larger advertised context window does not mean GNO sends complete documents to the reranker.

Terminal Hyperlinks

CLI retrieval commands (gno search, gno vsearch, gno query) can emit OSC 8 hyperlinks in terminal output when stdout is a TTY.

Configure the target URI template in YAML:

editorUriTemplate: "vscode://file/{path}:{line}:{col}"

Or override it via environment:

export GNO_EDITOR_URI_TEMPLATE="vscode://file/{path}:{line}:{col}"

Precedence:

  1. GNO_EDITOR_URI_TEMPLATE
  2. editorUriTemplate in index.yml
  3. default fallback file://{path}

Supported placeholders:

  • {path} absolute filesystem path
  • {line} best-effort line number from the result snippet, when available
  • {col} best-effort column placeholder (1 when line is available)

If the chosen template requires {line} but a result has no line hint, GNO falls back to plain text for that result instead of inventing :1.

Content Types

contentTypes is an opt-in, schema-lite typing layer for second-brain pages. It is not a mutable ontology. Empty or absent contentTypes keeps legacy behavior.

contentTypes:
  - id: person
    prefixes: [people/, contacts/]
    preset: person
  - id: meeting
    prefixes: [meetings/]
    preset: meeting
    temporal: true

Fields:

Field Type Description
id string Stable content type ID, such as person or meeting
prefixes string[] Relative path prefixes that map documents to this type
preset string Note preset used by future type-aware creation and ingestion behavior
temporal boolean Accepted metadata flag for time-oriented pages
searchBoost number Bounded soft ranking factor from 0.5 to 2; default/neutral is 1
graphHints string[] Ordered typed-edge hints for link projection, traversal, and diagnose

Validation is warning-based after YAML parsing:

  • unknown preset references warn and the content type entry is dropped
  • exact duplicate prefixes are deduped
  • overlapping prefixes are retained, for example people/ and people/team/
  • rules are normalized longest-prefix-first for matching and edge derivation

searchBoost applies only after a document is already a valid retrieval candidate. One canonical configured type wins: a configured frontmatter type ID takes precedence, otherwise longest-prefix matching applies. Boosts never stack and arbitrary categories cannot trigger them. Factors map linearly onto a contribution from -0.05 through +0.05; project affinity and all other auxiliary signals share the final ±0.08 cap. BM25 and vector apply the contribution after score normalization and before their existing cutoff/order; hybrid applies it to normalized fusion before rerank blending, so rerank and lexical top-hit protection remain the final ordering authority. Content-type rules do not widen retrieval or disable minScore. Scores stay clamped to 0..1; collection, tag, date, category, author, and exclude filters remain hard.

Use gno query --explain or gno ask --explain to inspect raw/base score, configured factor, requested/capped contribution, combined auxiliary cap, final score, rule source, and ranking fingerprint. gno query diagnose exposes the same component as schema v1.2 when active. gno status --json, REST status, MCP gno_status, and SDK client.status() show the effective rule IDs/factors and fingerprint without exposing configured path prefixes. A boost-only config edit takes effect immediately and does not reconvert documents or rebuild vectors.

graphHints vocabulary is centralized in the config API. Supported hints are mentions, works_at, attended, decided, and related_to. Hints do not create standalone edges because they have no target. Instead, the first hint types projected wiki/markdown links for matching documents, and remaining hints surface in gno graph query and gno query diagnose metadata. Editing graphHints changes the content-type fingerprint, so unchanged documents are reprocessed on the next sync and typed edges are re-derived.

Custom Models

Need a more example-driven guide?

models:
  activePreset: custom
  presets:
    - id: custom
      name: My Custom Setup
      embed: hf:user/model/embed.gguf
      rerank: hf:user/model/rerank.gguf
      expand: hf:user/model/expand.gguf
      gen: hf:user/model/gen.gguf

Model URIs support:

  • hf:org/repo/file.gguf - Hugging Face download
  • file:/path/to/model.gguf - Local file
  • http://host:port/path#modelname - Remote HTTP endpoint (OpenAI-compatible)

Download Policy

Model provisioning follows one of three modes:

  • default: auto-download allowed on first use
  • offline: cached models only (HF_HUB_OFFLINE=1 or GNO_OFFLINE=1)
  • manual: no auto-download, but explicit gno models pull still works (GNO_NO_AUTO_DOWNLOAD=1)

The dashboard bootstrap panel reflects the active mode in plain language.

Using A Fine-Tuned Local Model

Fine-tuned expansion models can be paired with a separate answer model via a custom preset:

models:
  activePreset: slim-tuned
  presets:
    - id: slim-tuned
      name: GNO Slim Tuned
      embed: hf:Qwen/Qwen3-Embedding-0.6B-GGUF/Qwen3-Embedding-0.6B-Q8_0.gguf
      rerank: hf:ggml-org/Qwen3-Reranker-0.6B-Q8_0-GGUF/qwen3-reranker-0.6b-q8_0.gguf
      expand: hf:guiltylemon/gno-expansion-slim-retrieval-v1/gno-expansion-auto-entity-lock-default-mix-lr95-f16.gguf
      gen: hf:unsloth/Qwen3-1.7B-GGUF/Qwen3-1.7B-Q4_K_M.gguf

Notes:

  • training backend may be Mac-only (for example MLX LoRA on Apple Silicon)
  • exported artifacts remain portable if you fuse and convert to GGUF
  • keep embed/rerank unchanged unless you have benchmark evidence for changing them too
  • expand drives retrieval-time query expansion
  • gen drives standalone answer generation (gno ask --answer, Web Ask)

See Fine-Tuned Models for the full workflow and troubleshooting notes.

HTTP Endpoints

GNO supports remote model servers using OpenAI-compatible APIs. This allows offloading inference to a more powerful machine (e.g., a GPU server on your network).

Remote endpoints receive the text sent to their configured role: queries and document chunks for embedding/reranking, generated expansion input for expand, or retrieved answer context for gen. Use HTTPS and server-side access controls outside a trusted network; remote inference is not part of the local privacy boundary.

Every inference port requires an explicit participating-collection scope; corpus-wide use is represented explicitly rather than inferred from an omitted filter. An empty or unknown scope fails before DNS. For a valid scope, GNO first performs bounded DNS-only classification without sending HTTP headers, request bodies, credentials, or model metadata, then intersects the proven endpoint zone with every participating collection's policy. local_only permits loopback model servers, lan permits private-address literals and hostnames whose complete DNS answer is homogeneously private, and remote permits pinned HTTPS public providers. DNS answers are pinned and rechecked before connection. Mixed, public-for-LAN, special-use, or rebound answers fail before request transfer. Redirects must remain on the same origin and are re-evaluated at every hop; credentials and request bodies are never forwarded cross-origin.

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"

URI Format: http://host:port/path#modelname

Component Description
http(s):// Protocol (HTTP or HTTPS)
host:port Server address
/path API endpoint (e.g., /v1/chat/completions)
#modelname Optional model identifier sent in requests

Supported Endpoints:

Model Type API Path OpenAI-Compatible API
embed /v1/embeddings Embeddings API
rerank /v1/completions Completions API (text only)
expand /v1/chat/completions Chat Completions API
gen /v1/chat/completions Chat Completions API

Example with llama.cpp server:

# Start llama-server for generation
llama-server -m model.gguf --host 0.0.0.0 --port 8083

# Configure GNO to use it
# gen: "http://192.168.1.100:8083/v1/chat/completions#my-model"

Benefits:

  • Offload inference to a GPU server
  • Share models across multiple machines
  • Use larger models than local hardware supports
  • Keep local machine responsive during inference

Timeouts

models:
  loadTimeout: 60000 # Model load timeout (ms)
  inferenceTimeout: 30000 # Inference timeout (ms)
  expandContextSize: 2048 # Context window used for query expansion generation
  warmModelTtl: 300000 # Keep-warm duration (ms)

FTS Tokenizer

Set at gno init, cannot be changed without rebuilding.

Tokenizer Description
snowball english English Snowball stemmer (default)
unicode61 Unicode-aware, no stemming
porter English-only stemming (legacy)
trigram Substring matching

The exposed Snowball tokenizer is specifically snowball english; it enables English word-form matching such as "running" → "run" and "scored" → "score". Use unicode61 for language-neutral Unicode tokenization without stemming.

# Initialize with unicode61 (no stemming)
gno init --tokenizer unicode61

Environment Variables

Override paths (applied before platform defaults):

Variable Description
GNO_CONFIG_DIR Override config directory
GNO_DATA_DIR Override database directory
GNO_CACHE_DIR Override model cache

Runtime/model env vars:

Variable Description
GNO_LLAMA_GPU Local llama backend: auto, metal, vulkan, cuda, or CPU off
NODE_LLAMA_CPP_GPU Compatibility alias used when GNO_LLAMA_GPU is unset
GNO_LLAMA_BUILD Backend build mode: default never; set autoAttempt to opt in
GNO_LLAMA_INIT_TIMEOUT_MS Backend initialization timeout; default 30000 ms
GNO_EMBED_CONTEXTS Override CPU embedding context count, clamped to 1-4
GNO_EMBED_CONTEXT_SIZE Override native embedding context size; minimum 128
GNO_EMBED_THREADS Override CPU threads per embedding context
GNO_NO_AUTO_DOWNLOAD Disable automatic model downloads; explicit models pull allowed

On Windows CPU-only runs, GNO defaults to one embedding context below 16GB RAM, and at most two contexts from 16GB upward. Increase GNO_EMBED_CONTEXTS only when memory headroom is clear and a real benchmark shows a gain.

File Locations

Linux (XDG):

Path Purpose
~/.config/gno/index.yml Config
~/.local/share/gno/index-default.sqlite Database
~/.cache/gno/models/ Model cache

macOS:

Path Purpose
~/Library/Application Support/gno/config/index.yml Config
~/Library/Application Support/gno/data/index-default.sqlite Database
~/Library/Caches/gno/models/ Model cache

Run gno doctor to see resolved paths for your system.

Editing Config

Edit directly or use CLI:

# Add collection via CLI
gno collection add ~/notes --name notes

# View config (Linux)
cat ~/.config/gno/index.yml

# View config (macOS)
cat ~/Library/Application\ Support/gno/config/index.yml

After manual edits, run gno update to apply changes.