Orion · 1.0.0
Deterministic, replayable index operations for any full-text engine.
Orion is not a search engine. It sits on Elasticsearch, SolrCloud, OpenSearch and Meilisearch and owns the part everyone hand-rolls and gets wrong: the index lifecycle. Schema as code, drift detection, deterministic migration plans, zero-downtime reindex by replaying a transactional outbox, versioned indices behind an alias, and a signed receipt for every operation, with a thin hybrid query layer on top, for any PHP application. Every engine adapter passes the same conformance suite, on 8 engine versions in CI.
bin/orion apply products --schema=products.yaml --bootstrap=orion.php --json bin/orion reindex products --schema=products.yaml --dry-run bin/orion outbox:drain && bin/orion verify --json Elasticsearch · 9.5 / 8.19
orion-search/elasticsearch
new ElasticsearchEngine($client) on elasticsearch/elasticsearch; strict mappings, externally versioned writes.
SolrCloud · 10 / 9.11
orion-search/solr
SolrEngine on solarium/solarium, with Orion's configset; ORION_ENGINE=solr in the module.
OpenSearch · 3.9 / 2.19
orion-search/opensearch
OpenSearchEngine::connect($url); vectors through the bundled k-NN plugin, hybrid fusion in core.
Meilisearch · 1.56 / 1.13
orion-search/meilisearch
MeilisearchEngine::connect($url, $apiKey); schema as settings, versions kept by Orion, aliases emulated by core.
Why Orion
The engine is a disposable projection
Your database is the source of truth. The outbox row commits with your entity write, on the same connection (PostgreSQL, MySQL and SQLite through PDO, or the host's own), so a reindex is a replay, not a reconciliation.
Deterministic lifecycle, honest ranking
Plan, apply, reindex and swap are dry-runnable and reproducible, each with a signed receipt. Result order is not deterministic, and Orion never claims it is.
Proven on every engine
Every adapter passes the same engine conformance suite, with the tenancy isolation, determinism and fault-injection harnesses, on 8 engine versions in CI.
Dumb adapters, smart neutral core
Diffing, reindex, alias swap, replay and fusion live once in core. Each adapter is its own package with its own client, and bin/check-imports keeps it that way.
Features
The index lifecycle, owned once, in neutral code.
Each area is specified in the documentation and implemented by
orion-search/core or one of the other 10
packages on its version line.
Schema as code
Declare an index in PHP or in an api/<name>/search.yaml manifest. Every change is classified as additive or breaking, and an unrecognised one fails closed as breaking.
Plans and drift
A plan is a pure diff of the declared schema against the live index. Additive changes apply in place; breaking ones never touch a live index and route to a reindex. orion drift reports where they part ways.
Zero-downtime reindex
Versioned physical indices behind a stable alias. A reindex replays the outbox into the next version, version-stamped writes converge, and the alias swaps atomically.
/docs/spec/orion-spec/Transactional outbox
Record into the outbox as the last statement of your transaction, on your connection. Offsets stay in commit order; the drain retries and keeps dead letters.
/docs/spec/revision/Signed receipts
Every apply and reindex issues an Ed25519-signed receipt in a hash chain. orion verify walks the chain; an auditor verifies with public keys only.
Tenancy on a shared index
An explicit choice at boot, with no default. Under a resolver the tenant filter is injected beneath every query, the escape hatch included; the tenant can come from the Polaris token.
/docs/spec/orion-spec/A thin hybrid query layer
A neutral query AST for the common case, keyword plus vector with deterministic reciprocal rank fusion in core, the engine's native query for the rest, and a typed UnsupportedClause instead of a silent wrong result.
Endpoint and CLI
The search: endpoints as a PSR-15 middleware with RFC 9457 problems, and bin/orion for plan, apply, reindex, drift, verify and the outbox drain, in YAML or deterministic JSON.
An agent surface
compile_query, search, list_indices, describe_index, capabilities, plan, apply, reindex as tools, compile_query first: the native request search() would send, never sent. apply and reindex preview until confirmed.
Origin
Orion was specified in June 2026 as a search module for
Univeros. On October 25, 2026 it was re-cut
to be framework-agnostic from the start, modelled on polaris-core:
a framework-free core with ports and working defaults, host integrations as packages, and the
Univeros module,
univeros/orion, in the same monorepo
(its documentation), proven by the same CI run.
1.0.0 was tagged on October 27, 2026, with every work package of the specification done.
Version 1.0.0
Every package shares one version line, 1.x, tagged v1.0.0 in the monorepo. The per-package read-only repositories and their Packagist registration are the next step; until then, install from a clone with path repositories, as examples/univeros does. Roadmap · Security
Get started
Put Orion on your engine.
Elasticsearch, SolrCloud, OpenSearch, Meilisearch, from any PHP application, with storage on PostgreSQL, MySQL, SQLite or the Univeros module.