# kurn > kurn is an in-memory search engine for fast fuzzy and exact retrieval over > application-owned collections. It runs as a Go library or one sidecar > binary, with declared analyzers, typed payload filters, atomic refresh, and > deterministic data-and-configuration versions. Open source (AGPL-3.0) at > github.com/kurn-dev/kurn. kurn retrieves short strings from resident collections. Character n-grams provide typo-tolerant fuzzy retrieval; exact mode provides whole-key membership and optional parent-domain fallback. Every answer names the exact version of each collection it used, so candidates and version come from one atomic snapshot and a result can be reproduced later. Application-owned short-string collections stay resident in memory on one node. Run independent replicas for availability or throughput; kurn does not shard collections or coordinate a search cluster. N-gram results are ordered by IDF-weighted string similarity, while exact-mode results represent normalized whole-key or configured parent-domain matches. ## Running it go install github.com/kurn-dev/kurn/cmd/kurnd@latest kurnd -data ./data # one static binary, listens on :8080 There is no hosted service and no account. kurn runs on your machine against your data; query strings and collections stay in your infrastructure. ## Using it curl -s localhost:8080/v1/query \ -d '{"q":"makita impakt drivr","lists":["catalog"]}' Queries may carry a filter — `{"filter":{"category":{"in":["hardware", "tools"]},"active":true}}` — over logical names a list declares in its configuration (name to payload dot-path, maximum 8). Names must be declared by every requested list or the whole query returns 400; a typo never silently becomes an unfiltered or empty query. Values are exact typed JSON strings, booleans, or numbers, or `{"in":[...]}` sets. Types do not coerce, names are ANDed, and IN alternatives are ORed. Filtering happens before the top-K cut and never changes scores. Nulls, nested values, empty sets, unknown or duplicate operators, and duplicate names fail closed. Payload JSON is opaque to similarity scoring and returned verbatim. When a list declares `filterable` paths, the strict evaluator reads only those paths; a missing path or reached value of another type is a non-match, while malformed stored payload fails the filtered query. An empty filter object equals omission and has no echo. A non-empty filter echo is canonical (IN order false, true, exact numbers, then UTF-8 strings; deduplication, singleton collapse, fixed-decimal numbers), so clients must compare it with their locally canonicalized expression. Nodes that predate filters omit the echo. Successful filtered responses also carry filter_stats: per-list counts of payload predicate evaluations performed and rejected. They are execution diagnostics, never list cardinality or proof a declared path exists; new clients must tolerate their absence on older nodes. - [Documentation](https://www.kurn.it/docs): ingestion, matching, filters, version identity, operation, API limits, and scoring semantics. - [OpenAPI specification](https://www.kurn.it/openapi.yaml): request and response schemas for all nine public operations — query, batch query, list management, entry mutation, compact, and reload. ## Calibrating a collection `kurn calibrate` sweeps 2–32 caller-chosen fuzzy thresholds over one immutable n-gram list snapshot and a human-labelled file corpus. For each threshold it reports truth-ID recall and misses, returned-candidate count, and truth rank. The command provides calibration evidence, not automatic threshold selection; threshold selection belongs to the evaluator's loss function. Exact matching has no fuzzy-threshold sweep. Returned-candidate burden is bounded by the resolved top-K: it counts the candidates actually returned within that cut, never every score-qualifying entry beyond it. `kurn-calibration/v1` separates deterministic identity and result fields from hardware-dependent timing and approximate HeapAlloc observations, and corpus results describe only the measured labels. - Walkthrough (v0.6.0): https://github.com/kurn-dev/kurn/blob/v0.6.0/docs/calibration/README.md - Report schema (v0.6.0): https://github.com/kurn-dev/kurn/blob/v0.6.0/bench/KURN_CALIBRATION_V1.md ## Published-feed recipe The repository includes mapping recipes for several public reference feeds. You fetch a publisher's own file and `kurn build` turns it into a content-addressed bundle. Those mappings are ingestion examples and the corpus for the measured evaluation below; they do not define the product category and kurn never takes custody of the data. ## Measured behaviour Measured 5 Aug 2026 on one idle 4 vCPU server over loopback. Recall after mangling real entries (40 per list): exact 100%, one letter dropped 99.5%, two letters swapped 95.5%, doubled letter 100%, vowels dropped 94%, name order reversed 100%, first+last only 98.5%, phonetic substitution 98.5%. False positives on 60 invented names, averaged over the five-list evaluation corpus: 5.7% at threshold 0.60, 25.7% at 0.50, 40.7% at 0.45 (per-list range at 0.60: 1.7%–11.7%). Latency p50 0.64 ms across all five lists (148,837 entries), median of three runs; 5,034 queries/second at 8 concurrent clients; 128 MB resident. These figures describe that corpus, hardware, date, and threshold, not a universal latency or quality promise. ## Retrieval and operating model kurn keeps application-owned short-string collections resident in memory on one node. Run independent replicas for availability or throughput; kurn does not shard collections or coordinate a search cluster. N-gram results are ordered by IDF-weighted string similarity, while exact-mode results represent normalized whole-key or configured parent-domain matches. Typed filters apply exact predicates to declared payload paths before top-K without changing scores. ## Contact Source, issues and releases: https://github.com/kurn-dev/kurn (AGPL-3.0). ops@kurn.it — for a commercial licence to embed the engine in a closed-source product, or anything else.