| 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 |
GNO configuration reference.
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: falseProject-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.
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.
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.
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.
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_DIRECTORYor 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_onlyInspect 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_onlyThe 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 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 archiveThe 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.
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: 300000Wildcard 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.
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.
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: 16777216metadata 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 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.
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 define what gets indexed.
| 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 |
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
- .txtNote:
includecontrols 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
statbefore GNO reads file bytes.
Files without extensions (e.g., Makefile, LICENSE) and dotfiles (e.g., .env, .gitignore) are always excluded.
exclude:
- .git
- node_modules
- .venv
- .idea
- dist
- build
- __pycache__
- .DS_Store
- Thumbs.dbMarkdown 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: deMixed documentation folder:
- name: project-docs
path: /Users/you/project/docs
pattern: "**/*"
include:
- .md
- .txt
exclude:
- node_modules
- dist
- draftsNote: Exclude patterns match path components (directory or file names), not globs. Use
distto exclude adist/directory, not*.js.
With update command:
- name: wiki
path: /Users/you/wiki
updateCmd: "git pull"Contexts add semantic hints to improve search relevance.
| Type | Key Format | Example |
|---|---|---|
global |
/ |
Applies to all documents |
collection |
name: |
Applies to collection |
prefix |
gno://collection/path |
Applies to path prefix |
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 specsContexts 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.
Model configuration for embeddings and AI answers.
| 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.
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:
- collection role override
- active preset role
- 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.embedon 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
The immutable April 2026 FastAPI-docs run used 15 documents in five corpus
languages (en, de, fr, es, zh) and 13 queries:
- bge-m3 incumbent: vector nDCG@10
0.3503, hybrid nDCG@100.642 - Qwen3 Embedding 0.6B: vector nDCG@10
0.8594, hybrid nDCG@100.947
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 embedpass because their old vectors were created withbge-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@100.1481, zero-result0.7778; promotion Recall@100.4722, nDCG@100.3981, maximum zero-result0.5278 - Japanese: baseline Recall@10
0.125, nDCG@100.125, zero-result0.875; promotion Recall@100.375, nDCG@100.375, maximum zero-result0.625 - Korean: baseline Recall@10
0.5, nDCG@100.5, zero-result0.5; promotion Recall@100.75, nDCG@100.75, maximum zero-result0.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.
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.
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:
GNO_EDITOR_URI_TEMPLATEeditorUriTemplateinindex.yml- 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 (1when 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.
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: trueFields:
| 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
presetreferences warn and the content type entry is dropped - exact duplicate prefixes are deduped
- overlapping prefixes are retained, for example
people/andpeople/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.
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.ggufModel URIs support:
hf:org/repo/file.gguf- Hugging Face downloadfile:/path/to/model.gguf- Local filehttp://host:port/path#modelname- Remote HTTP endpoint (OpenAI-compatible)
Model provisioning follows one of three modes:
- default: auto-download allowed on first use
- offline: cached models only (
HF_HUB_OFFLINE=1orGNO_OFFLINE=1) - manual: no auto-download, but explicit
gno models pullstill works (GNO_NO_AUTO_DOWNLOAD=1)
The dashboard bootstrap panel reflects the active mode in plain language.
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.ggufNotes:
- 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
expanddrives retrieval-time query expansiongendrives standalone answer generation (gno ask --answer, Web Ask)
See Fine-Tuned Models for the full workflow and troubleshooting notes.
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
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)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 unicode61Override 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.
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.
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.ymlAfter manual edits, run gno update to apply changes.