{"id":51159564,"url":"https://github.com/i-rocky/corvid","last_synced_at":"2026-06-26T12:31:51.804Z","repository":{"id":361198315,"uuid":"1253501001","full_name":"i-rocky/corvid","owner":"i-rocky","description":"Embedded multi-modal database in Rust — vector + full-text + filter + graph + geo behind one fluent builder API. A vibe-coded personal experiment; solid and usable.","archived":false,"fork":false,"pushed_at":"2026-05-29T15:04:02.000Z","size":333,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"master","last_synced_at":"2026-05-29T16:18:12.946Z","etag":null,"topics":["ai","bm25","database","embedded-database","embeddings","full-text-search","hnsw","mcp","redb","rust","vector-database","vector-search"],"latest_commit_sha":null,"homepage":"https://i-rocky.github.io/corvid/","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/i-rocky.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-05-29T14:26:47.000Z","updated_at":"2026-05-29T15:04:36.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/i-rocky/corvid","commit_stats":null,"previous_names":["i-rocky/corvid"],"tags_count":2,"template":false,"template_full_name":null,"purl":"pkg:github/i-rocky/corvid","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/i-rocky%2Fcorvid","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/i-rocky%2Fcorvid/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/i-rocky%2Fcorvid/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/i-rocky%2Fcorvid/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/i-rocky","download_url":"https://codeload.github.com/i-rocky/corvid/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/i-rocky%2Fcorvid/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34817640,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-26T02:00:06.560Z","response_time":106,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ai","bm25","database","embedded-database","embeddings","full-text-search","hnsw","mcp","redb","rust","vector-database","vector-search"],"created_at":"2026-06-26T12:31:50.999Z","updated_at":"2026-06-26T12:31:51.794Z","avatar_url":"https://github.com/i-rocky.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"# corvid\n\nAn embedded, multi-modal data store for AI applications, with a fluent builder\nAPI instead of SQL. One in-process dependency that does vector search,\nfull-text search, metadata filtering, and rank fusion — composed into a single\ncall.\n\n\u003e **What this is.** A personal experiment, and an honest one: corvid was\n\u003e *entirely vibe coded* — built by directing an AI coding agent, not hand-written\n\u003e line by line. It is not a product, has no roadmap, and comes with no support\n\u003e promises.\n\u003e\n\u003e **What it isn't.** A toy. The code is solid and genuinely usable: ~390 tests,\n\u003e \u003e90% line coverage, zero-warning clippy, criterion benchmarks on the hot\n\u003e paths, and a correctness-first design (filters are true predicates, indexes\n\u003e are never stale, writes are transactional). If a corner is rough, it's a\n\u003e missing feature, not a broken one.\n\u003e\n\u003e Status: **v0.1**, pre-1.0. The API changes freely until 1.0 — no\n\u003e backward-compatibility guarantees yet; a format change is migrated with\n\u003e `dump`/`load`, never silently. Built for the author's own use first; shared in\n\u003e the open under MIT. Use it, fork it, learn from it.\n\n## Why\n\nAI apps usually glue together a vector database, a full-text engine, and a\nmetadata store, then reconcile them in application code. corvid puts them\nbehind one embedded engine and one query builder, so a hybrid query is one\nchained call rather than three round trips and a reranker:\n\n```rust\nuse corvid::{Db, Metric, Value, field};\n\nlet db = Db::open(\"memory.corvid\")?;\nlet docs = db.collection(\"docs\");\n\n// Store a document (any JSON-like value; embeddings are first-class).\nlet mut doc = std::collections::BTreeMap::new();\ndoc.insert(\"category\".into(), Value::Text(\"blog\".into()));\ndoc.insert(\"body\".into(), Value::Text(\"rust embedded database design\".into()));\ndoc.insert(\"embedding\".into(), Value::Vector(vec![0.1, 0.9, 0.2]));\ndocs.insert(b\"post-1\", \u0026Value::Map(doc))?;\n\n// Hybrid query: filter + vector + text, fused and reranked, in one call.\nlet rows = docs\n    .query()\n    .filter(field(\"category\").eq(Value::Text(\"blog\".into())))\n    .vector(\"embedding\", vec![0.1, 0.9, 0.2], 100, Metric::Cosine)\n    .text(\"body\", \"rust embedded database\", 100)\n    .rerank_mmr(0.7)\n    .limit(10)\n    .run()?;\n# Ok::\u003c(), corvid::Error\u003e(())\n```\n\nThe filter runs *before* ranking, so it is a true predicate — the top-k is\ncomputed among matching documents, never a post-hoc trim.\n\n## What's here\n\n- **`corvid`** — the embedded engine (this is a library; strictly in-process,\n  no networking).\n- **`corvid-mcp`** — a sidecar that exposes a corvid store to agentic coding\n  tools over MCP (JSON-RPC on stdio). Run `corvid-mcp [PATH]` and point an MCP\n  client at it; tools: `store`, `patch`, `compare_and_set`, `get`, `delete`,\n  `delete_where`, `page`, `search`, `phrase_search`, `count`, `geo`, `join`,\n  `link`, `unlink`, `neighbors`, `in_neighbors`, `traverse`, `create_index`,\n  `create_text_index`, `create_scalar_index`, `create_compound_index`,\n  `create_geo_index`, `backup`, `dump`, `load`, `list_collections`,\n  `insert_auto`.\n\nA task-oriented walkthrough of every feature is in the **[user guide](docs/GUIDE.md)**.\nThe **[website](https://i-rocky.github.io/corvid/)** hosts an overview and the\nfull **[API reference](https://i-rocky.github.io/corvid/api/corvid/)**.\n\n## Capabilities (v0.1)\n\n| Area | Status |\n|---|---|\n| Transactional KV storage (redb), atomic multi-op transactions | ✅ |\n| Typed values + documents (incl. embeddings) | ✅ |\n| Vector search (cosine / dot / L2) | ✅ exact baseline |\n| Full-text search (BM25) | ✅ exact baseline |\n| Filter predicates (`field().gt()`, and/or/not, dotted paths) | ✅ |\n| Rank fusion (RRF) and MMR diversification | ✅ |\n| Fluent multi-modal query builder + projection + aggregation | ✅ |\n| Aggregations (sum/avg/min/max/distinct, grouped) | ✅ |\n| Predicates: in / between / starts_with / contains (+ indexed) | ✅ |\n| Nested/dotted-path field indexing | ✅ |\n| patch / update / compare-and-set; delete-by-query | ✅ |\n| Phrase / positional text search | ✅ |\n| k-nearest geo (`geo_nearest`) | ✅ |\n| Keyset (cursor) pagination (`page`) | ✅ |\n| Compound (multi-field) scalar index | ✅ |\n| Logical dump/load migration (`Db::dump`/`load`) | ✅ |\n| HNSW approximate index (`create_vector_index`) | ✅ in-memory, derived |\n| On-disk HNSW (`create_vector_index_ondisk`) | ✅ bounded memory, persists |\n| Vector quantization (binary ≈32×, scalar ≈4×) | ✅ in-memory **and** on-disk |\n| On-disk inverted text index (`create_text_index_ondisk`) | ✅ bounded memory, persists |\n| Scalar index (`create_scalar_index`): sub-linear eq/range filters | ✅ on disk, persists |\n| Directed property graph (`link`/`neighbors`/`traverse`) | ✅ |\n| Geospatial: radius / bounding-box / `within_km` filter | ✅ |\n| Spatial index (`create_geo_index`): sub-linear radius/bbox | ✅ on disk, persists |\n| Cross-collection lookup joins | ✅ |\n| Semantic (vector-keyed) cache | ✅ |\n| Probabilistic sketches (HyperLogLog, Bloom) | ✅ |\n| Reactive change feeds | ✅ |\n| Online consistent backup (`Db::backup`) | ✅ |\n| Optional declared schema (`set_schema`): types/required/unique | ✅ |\n| Per-record TTL / expiry (`insert_with_ttl`, `purge_expired`) | ✅ injected clock |\n| MCP sidecar over stdio | ✅ |\n| WASM build (engine, ≈0.2 MB gzipped, CI-enforced) | ✅ in-memory; OPFS persistence ⏳ |\n| Mobile cross-compile (aarch64 iOS/Android) | ✅ engine builds |\n\nImage search is vector search over image embeddings: embed in your app (CLIP\netc.), store the `$vector`, query — same engine as text vectors. corvid does\nnot run the embedding model itself (by design).\n\nVector and text search are **exact** (brute-force over a scan) by default — the\ncorrectness baseline. Calling `create_vector_index` registers an HNSW index\nthat `vector_search` then uses transparently (approximate, faster); the index\nis derived from the documents and rebuilt automatically after writes, so it is\nnever stale at query time.\n\nFor scale beyond what fits in RAM, the index can live on disk: an insert or\nsearch touches only the nodes/postings it needs, so memory is bounded by the\noperation, not the collection, and the index persists across reopen with no\nrebuild. `create_vector_index_ondisk` (graph nodes), `create_text_index_ondisk`\n(BM25 postings), and `create_scalar_index` (order-preserving keys for sub-linear\nequality/range filters and counts) all store their state as ordinary records.\nThe scalar index returns a verified candidate superset and falls back to a\nbounded scan when a filter isn't selective, so it never trades memory or\ncorrectness for speed.\n\n## Design\n\nSee [DESIGN.md](DESIGN.md) for the architecture, the cross-modal consistency\ninvariant, the layer map, and the decision log. Working rules are in\n[CLAUDE.md](CLAUDE.md).\n\nNon-goals (permanent): SQL, networking/replication in the engine, distributed\ntransactions, a hosted service.\n\n## Building\n\n```sh\ncargo test            # all tests\ncargo run -p corvid-mcp   # start the MCP sidecar (in-memory)\n```\n\nRequires a recent stable Rust (2024 edition).\n\n## License\n\nMIT.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fi-rocky%2Fcorvid","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fi-rocky%2Fcorvid","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fi-rocky%2Fcorvid/lists"}