Configuration
September 6, 2026 · View on GitHub
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
# SQLite busy_timeout in ms (default 60000; range 1000-600000).
# Raise for long embedding passes on slow disks.
# busyTimeoutMs: 60000
# 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
# Memory substrate flag: only collections with memoryManaged: true accept
# gno remember writes (omitted = false).
# memoryManaged: true
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
toolProfile: full
# Private local retrieval receipts are absent/off by default.
retrievalTraces:
enabled: false
# Daemon-only scheduled findings pass (report-only audit -> records). Off by default.
# findings:
# enabled: true
# cadence: 6h
# collection: findings
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.
Memory-managed collections
collections[].memoryManaged is optional (true | omitted). It declares the
collection as a GNO-managed memory substrate: gno remember writes one fact
file per record there (facts/<date>/mem-<id>.md with memory: frontmatter
carrying record id, scopes, caller/session identity, timestamp, content hash,
and relations.supersedes edges) and refuses to write into any collection
without the flag. gno recall reads only from memory-managed collections.
Ordinary indexing, search, and egress policy are unaffected by the flag;
malformed hand-edited records are reported by gno status and gno audit.
collections:
- name: memory
path: /Users/you/notes/memory
pattern: "**/*.md"
memoryManaged: true
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_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_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, unpublish or delete the hosted item in Studio, including public publications. Unpublish denies access but retains source and history; deletion denies access before durable cleanup. Neither removes local files or independent copies. 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 run-scoped: there is no persisted baseline, suppression list, or automatic repair. The only schedule is the daemon's opt-in scheduled findings pass below, which runs the same read-only audit and writes findings as records. 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.
Scheduled findings pass
gno daemon can run the read-only audit on a cadence and write each finding as
a Markdown record into a collection you already configured. Off by default;
gno serve and the CLI ignore the block.
findings:
enabled: true # default false
cadence: 6h # <n>s|m|h|d between 10s and 30d (default 6h)
collection: findings # name of an existing entry in `collections`
| Field | Required when enabled | Notes |
|---|---|---|
enabled | - | false by default. The daemon never audits on cadence unless this is true. |
cadence | no | Run interval, validated at config parse. Cadence is a floor; an overrunning pass defers a tick. |
collection | yes | Must name an existing collection. The daemon never creates it or writes anywhere else. |
Startup fails closed with a clear message when enabled is true and
collection is unset or unknown, or when cadence is out of range. Records
are finding-<id>.md files with type: finding frontmatter and finding /
audit / category / severity tags; identity is the audit finding id (check +
target + evidence), so repeat runs upsert, vanished findings resolve, and
resolved records expire after 30 days (2000-record ceiling). Last-run state is
persisted next to the index database and surfaced by gno daemon --status
and gno doctor. Saved Context Capsule reverification is not part of this
schedule. Full contract: Daemon Mode.
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
toolProfile: full
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.
toolProfile (core | full, default full) picks the advertised MCP tool
set for every gateway client; --mcp-tool-profile overrides it, and the value
is read once at listener start, so changing it means restarting gno serve or
gno daemon. See Tool Profiles.
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:
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.
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
distto exclude adist/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:
- 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
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:
- 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.
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:
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. Default snippets skip leading YAML frontmatter, so this line follows the trimmed display range rather than the raw source fence.{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.
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
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.
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 downloadfile:/path/to/model.gguf- Local filehttp://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=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. Starting serve or daemon does not resolve or download models. An empty or offline model cache does not block listener startup, lexical search or metadata access. The first operation requiring inference, including background embedding, resolves its model under the policy captured for that context. Missing models or blocked downloads follow the operation's existing error or fallback contract.
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
expanddrives retrieval-time query expansiongendrives 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)
loadTimeout and inferenceTimeout accept integer milliseconds from 1 through
2,147,483,647; zero, negative, fractional and overflowing values fail configuration
validation. Neither setting has a disabled-by-zero mode.
inferenceTimeout starts at native evaluation, after model/context loading.
The child reports evaluation start using the current generation and request ID;
metadata and queued requests do not start that timer. loadTimeout bounds the
dispatched request's loading phase independently; the two timers are never added.
A caller's absolute deadlineAt covers queueing and loading through response
publication. Generation receives an evaluation abort signal. Embedding/reranking
evaluation may be noncooperative, so canceled active work retains capacity until
actual settlement. After five seconds without settlement, the parent retires its
isolated child; queued operations fail explicitly and are never replayed.
For remote HTTP inference, inferenceTimeout measures the complete request
from policy/DNS preparation through fetch and response-body consumption. The
client cannot observe the remote model's load/evaluation boundary. The caller's
deadlineAt remains the tighter outer limit. loadTimeout applies only to local
native loading; it does not configure a remote server.
The separate expansion-stage budget still falls back without expansion when it expires, while aborting its generation. A caller abort/deadline cannot become a successful lexical fallback. Operational cancellation options do not change sampling, model selection, candidate counts, or ranking.
The resident shutdown contract allocates a shared five-second drain, five-second abort-settlement period, then at most one second awaiting forced owned-child exit. Requests, accepted jobs, background scheduling and listener cleanup share those phases; individual participants do not restart the clock. Admission and scheduling stop first. At the abort deadline, suspended parent transactions are rolled back and their store access revoked before the database closes. Completed checkpoints remain durable; unfinished embedding work stays pending for restart. Only the owned native child can be forced to exit; an unconfirmed OS termination is reported as an error, never successful cleanup. See daemon shutdown.
These bounds apply while the parent event loop can run. JavaScript timers cannot preempt a synchronous callback, a blocked OS call or a SQLite statement already executing when the signal arrives. During shutdown, ordinary store access caps SQLite busy waiting to the remaining settlement budget. Raw database handles cached outside the store API do not inherit that per-access cap or transaction token; they become unusable when their connection closes. The bounds are not a universal query latency promise and have no new CLI/configuration setting.
Native embedding, generation and reranking share one child per LLM adapter.
warmModelTtl is the inactivity grace for each model and for the native child
(five minutes by default). Model-specific leases protect actual loading,
context creation, evaluation and cleanup. Background embedding does not renew
idle generation/reranking weights; they can expire while the same child remains
busy. A later call reloads the expired model and rebinds its context. Cached
metadata and status reads do not renew a model's idle grace.
Active inference, pending responses and model-use leases prevent idle retirement;
metadata-only access does not refresh native activity. Retirement exits the
child to reclaim its native process allocations. The next inference reloads
models. That complete cold request includes worker startup, model loading and
context creation; its cost depends on the model, backend and hardware. Changing
the idle grace does not change candidate counts, precision or input text.
Command/SDK disposal terminates the owned child. Explicit model disposal retires
the shared child, so other native roles reload lazily too. HTTP inference is
unaffected by this child lifecycle.
Background embedding runs in internal turns of at most 32 pending chunks. A scheduler run or accepted job may span many turns; it does not report completion after one page. Each turn checkpoints current inputs, releases native/model ownership and yields before continuing. Foreground requests dispatch first, with one pending background native request served after at most eight completed foreground native inference dispatches. Metadata init/dispose do not earn or reset that service credit. Both classes share the existing 64-call waiting queue. Native batches are not preemptible and this is not a total-query deadline. Failed chunks remain pending for a subsequent pass; later pages still progress. Notifications keep the existing 30-second debounce and five-minute maximum wait, and failed scheduler passes retry after debounce. No priority or turn-size configuration is exposed.
Resident model counters are cached child-reported lifecycle snapshots. Reading status sends no native request and does not extend the idle deadline. Loaded-model counts describe residency, not GPU-memory usage; capability flags describe configured functionality.
Native worker startup or inference failure returns a structured error without
automatically replaying the operation. The npm package and desktop source
runtime include the worker entrypoint. A standalone bun build --compile
executable without that source runtime cannot launch native inference and fails
explicitly instead of recursively launching itself.
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
SQLite busy timeout
busyTimeoutMs sets SQLite's busy_timeout pragma: how long a connection waits
for a lock before failing with SQLITE_BUSY. The default is 60000 (60
seconds). Valid values are integers from 1000 to 600000 milliseconds.
Raise this when embedding passes run for tens of seconds to minutes on slow disks, so a brief overlap with another writer queues instead of failing in 5 seconds. Invalid values are rejected at config load.
busyTimeoutMs: 120000
Inspect the live value (the pragma on the open database, not the config echo)
with gno doctor or gno doctor --json.
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.