GET /v1/search. It allows searching through prompts, skills, and tools across projects using both lexical (keyword) and semantic (vector) search, ranking them dynamically using Reciprocal Rank Fusion (RRF).
By separating the API contract from the underlying indexing infrastructure, px0 gives you the flexibility to start with zero-dependency PostgreSQL full-text search and scale up to enterprise-grade search engines or vector databases as your registry grows.
Search Architecture
The px0 search engine employs a hybrid retrieval pipeline designed for high precision, recall, and safety. When a client performs a search, the system coordinates multiple components:1. Dual-Retriever Slots
The search engine routes the natural-language queryq to two independent, isolated retriever slots:
- The FTS Retriever: Locates precise, keyword-based lexical matches.
- The Vector Retriever: Locates concept-based semantic matches using dense embedding vectors.
2. Reciprocal-Rank Fusion (RRF)
Rather than trying to compare raw, incompatible scores across different search technologies (e.g., matching cosine similarity scores from a vector database against full-text BM25 or Postgres FTS rank weights), px0 utilizes Reciprocal-Rank Fusion (RRF). RRF combines the ordered list of candidates from both retrievers using their rank positions rather than their absolute scores. This ensures a balanced, deterministic, and highly accurate unified results list.3. Hydration & Security Enforcement
Once RRF determines the candidate ranks, the fused references are hydrated through a project-scoped database query. This serves as a vital defense-in-depth boundary: even if a remote search provider is misconfigured or compromised, the hydration phase strictly filters results based on the requester’s actual RBAC scope, preventing any unauthorized exposure of entity metadata.Supported Search Providers
You can configure both the lexical and semantic engines out of the box using standard environment variables. This allows you to hot-swap search backends based on your hosting or performance requirements.Lexical Providers (SEARCH_FTS_PROVIDER)
The lexical engine focuses on keyword matches. Configure this using the SEARCH_FTS_PROVIDER environment variable:
Semantic Providers (SEARCH_VECTOR_PROVIDER)
The semantic engine leverages vector embeddings to find conceptually related entities. Configure this using the SEARCH_VECTOR_PROVIDER environment variable:
If a provider configuration is incomplete, px0 is designed to fail fast during startup rather than silently falling back to a different provider. This prevents silent misconfiguration issues in production environments.
PostgreSQL Full-Text Indexes (FTS)
When using the defaultpostgres lexical provider, search queries are powered by PostgreSQL’s native FTS system.
Generation & Indexing
To ensure peak search performance and eliminate stale search indexes, px0 implements a stored generatedtsvector column directly on the prompts, skills, and tools tables.
- Real-time updates: PostgreSQL recomputes the
tsvectorin the same database transaction as any insert or update. No asynchronous backfill workers or event queues are needed. - GIN Indexes: Each generated column has a GIN (Generalized Inverted Index) index associated with it. GIN indexes are specifically designed for inverted membership lookups (
tsvector @@ tsquery), avoiding expensive sequential row scans.
Weighted Relevance
Each document uses the English text search configuration and applies weighted attributes to prioritize direct matches:
During searches,
websearch_to_tsquery('english', q) is utilized to parse user queries safely, and ts_rank_cd is used to order matching candidates before merging them via RRF.
Configuration via Environment Variables
To configure your desired search providers, define the following variables in your environment or.env file:
Example: PostgreSQL FTS Only (Default)
Example: Hybrid FTS + Vector (Elasticsearch + Qdrant)
Code Customization & Extension
px0’s search infrastructure is highly modular. You can easily add new searchable entities or implement custom search providers.1. Adding a New Searchable Entity
To make a new registry entity searchable without altering the public API contract:- Add its singular name/value to
model.SearchEntityTypeand register it in the OpenAPItypeenum. - Create a new SQL migration adding a generated
tsvectorsearch column and a GIN index on the entity’s database table. - Update each implemented search retriever to support the new entity type with an authorization-scoped query.
- Add a corresponding hydration query to
store.GetSearchResultsin the persistence layer. - Write tests covering unfiltered search, type-filtered search, metadata updates, and RBAC isolation for the new entity.
2. Implementing a Custom Search Provider
You can add a custom lexical or semantic search provider by implementing a Go interface:- Implement the
search.Retrieverinterface defined in the codebase. - Wire the provider name and configuration initialization inside
internal/search/config.go. - Apply filter boundaries: Every retriever implementation receives the permitted project IDs and requested entity types and must apply both constraints at the provider boundary.
- If building a vector store provider, ensure that you persist
project_idandtypeas filterable metadata alongside each embedding vector.

