autumn-search
Keyword and vector search for autumn-web applications: mark a model searchable, get an index that stays in sync automatically, and query it — by keyword or by semantic similarity — through one engine-agnostic API.
The autumn-shaped answer to Laravel Scout, with vectors first-class rather than bolted on.
Installation
One command adds the dependency at a version compatible with your app's
autumn-web, mounts SearchPlugin in your autumn_web::app() builder chain,
and prints the follow-up steps (mark a model #[searchable], register the
index, backfill). It is safe to re-run, and it refuses — before touching any
file — to install into an app on an incompatible autumn-web version. See
docs/plugins.md.
Manual install
If you would rather wire it yourself (or autumn plugin add could not find your
builder chain and printed these lines for you):
[]
= "0.10"
= "0.10"
What you write
use Arc;
use ;
// 1. Mark the model searchable. `embed` nominates the field to embed.
// 2. Keep the index in sync from the record lifecycle. `#[repository]` takes a
// plain type NAME for `hooks`, so alias the generic first.
type ArticleSearchHooks = ;
// 3. Mount the plugin.
app
.plugin
.run
.await;
What you get
// The plugin installs the client as an `AppState` extension.
let search = state..expect;
// ranked + paginated keyword search, as a `Page`
let page = search..await?;
// semantic "find similar" / RAG retrieval
let hits = search..await?;
let neighbours = search..await?;
// authorization-aware: the filter is pushed *into* the engine query
let page = search..await?;
Creating, updating, or deleting an Article enqueues a durable reindex job.
There is no hand-written index-sync code anywhere.
Backfill
Backends
| Backend | Keyword | Vector | Notes |
|---|---|---|---|
PostgresSearchStore |
tsvector + ts_rank_cd |
pgvector, or a portable double precision[] fallback |
The default. Reuses the in-core FTS from #842. |
MemorySearchBackend |
in-process, weighted | in-process cosine | Dev and tests; no Docker, no network. |
| yours | — | — | Implement SearchBackend. |
SearchBackend is plain data in, plain data out, so an external engine
(Meilisearch, Tantivy, a vector store) is a new impl, not a fork.
Embeddings
autumn-search orchestrates embeddings; it ships no model, runtime, or
vendor SDK. Implement Embedder over whatever you use and install it with
SearchPlugin::embedder(...). Two implementations ship, and neither is a
model:
NoEmbedder— the default; refuses, so a missing provider is a typed error rather than meaningless vectors.HashingEmbedder— deterministic, dependency-free lexical vectors for dev and tests.
Configuration
[]
= "search" # the #[job] queue reindex/backfill run on
= 500 # rows per backfill batch
= true # false ⇒ index writes are no-ops (incident switch)
= 768 # enables the pgvector fast path
The plugin reads this itself at boot, so enabled = false is a config change
rather than a deploy. Resolution goes through the same profile layering the
runtime uses — base autumn.toml, then [profile.<name>.search], then
autumn-<profile>.toml, then AUTUMN_SEARCH__* env vars — so the kill switch
works per environment:
[]
= false
AUTUMN_SEARCH__ENABLED=false
Pass SearchPlugin::config(...) (or any of the builder overrides) to configure
it in code instead.
Documentation
See docs/guide/search.md
for the full guide.
License
MIT OR Apache-2.0