Embeddings
Text-to-vector generation, embedding configs, backfills, and text-in semantic search.
The embeddings module turns string fields into vectors and searches by query text. It does not own vector storage. Database owns Vector fields, vector indexes, capabilities, and raw-vector search. Client apps call authenticated POST /embeddings/search only.
Use cases
Search by meaning
Find articles or tickets from a natural-language query instead of keyword match
Keep vectors current
Generate embeddings on create/update and skip unchanged documents via source hashes
Backfill existing data
Queue a bounded onlyMissing backfill instead of scanning in the request thread
Operator canary
Run Admin text search against a scoped set before opening Client search
Fail-closed authz search
Authorization-enabled schemas still require an authenticated user or scope
Capabilities
- Text-to-vector generation (OpenAI-compatible HTTPS provider)
- Embedding configs (schema, source fields, target field)
- Vector + source-hash schema extensions
- Incremental jobs on database mutations
- Queued backfills (onlyMissing, cancel, resume)
- Text-in semantic search (Client + Admin)
- Capability and status inspection
- Convict enabled default false (workers and search)
Example: Config, backfill, then text search
Walkthrough
- Deploy the embeddings process with module convict enabled still false (compose --profile embeddings or Helm install.embeddings.enabled)
- Call get_embeddings_capabilities and confirm storage, indexing, and search for Atlas Vector Search or pgvector
- Patch the provider catalogue with patch_config_embeddings (endpoint, apiKey, models, defaultModel)
- Create an extendable, non-system schema (CMS enabled or cms unset) and post_embeddings_configs with enabled: false
- Wait until the target vector index is queryable (get_embeddings_status / get_embeddings_configs_id)
- Enable the config, then set convict enabled: true. Backfill, resume, and text search fail closed while convict enabled is false
- Start a bounded post_embeddings_backfills with onlyMissing: true
- App calls POST /embeddings/search with schemaName and text — never a raw vector, never caller-supplied userId, scope, or adminOperator
curl -X POST http://localhost:3000/embeddings/search \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{"schemaName":"Article","text":"how vector indexes become queryable","limit":10}'curl -X POST http://localhost:3030/embeddings/configs \
-H "Authorization: Bearer YOUR_ADMIN_JWT_OR_cdt_TOKEN" \
-H "Content-Type: application/json" \
-d '{"schemaName":"Article","sourceFields":["title","body"],"targetField":"embedding","enabled":false}'How it works
Ownership
| Concern | Module | Surface |
|---|---|---|
| Text → vector, configs, backfills, text-in search | Embeddings | Admin /embeddings/*, Client POST /embeddings/search |
Vector fields, indexes, capabilities, raw-vector search | Database | Schema fields; Admin POST /database/schemas/:schemaName/vector-search |
Embeddings adds a vector schema extension for targetField and a hidden source-hash field used to skip unchanged documents. Changing dimensions in place is rejected — create a new targetField and run an explicit backfill.
similarity is cosine (default), euclidean, or dotProduct. Changing similarity recreates the vector index. Changing sourceFields does not.
Two enablement flags
| Flag | Default | Effect |
|---|---|---|
Workload: compose --profile embeddings or Helm install.embeddings.enabled | off | Starts or stops the embeddings process. Health can stay serving while workers are off so you can configure the module. |
Convict enabled | false | Starts generation workers and mutation subscriptions. Backfill start, backfill resume, and text search fail closed while this is false. This is not the Helm flag. |
Production containers require a non-empty GRPC_KEY.
Safe lifecycle
- Deploy the process disabled.
docker compose --profile mongodb --profile embeddings upwith a non-emptyGRPC_KEY, or Helminstall.embeddings.enabled=true. Leave convictenabled: false. Confirm the process is registered with Core. - Inspect capabilities.
get_embeddings_capabilities(orGET /embeddings/capabilities). Databasestorage,indexing, andsearchmust be true for MongoDB Atlas Vector Search or Postgres pgvector. Saving a disabled config may succeed with capability warnings; activation must not. - Configure the provider catalogue.
patch_config_embeddingswithendpoint,apiKey, and a models catalogue (name+dimensions).GRPC_KEYcomes from the deployment, not from module settings. - Create the config disabled.
post_embeddings_configswithschemaName,sourceFields,targetField, andenabled: false. The first upsert provisions the vector index when Database indexing is available. If indexing is unavailable, status reports a manual index lifecycle warning — create the index before enabling. - Wait for a queryable index. Poll
get_embeddings_status/get_embeddings_configs_iduntil the index fortargetFieldis ready (not pending or failed). - Enable the config and the module. Set the config
enabled: true, thenpatch_config_embeddingswith convictenabled: true. Backfill, resume, and text search stay fail-closed until convictenabledis true. - Bounded
onlyMissingbackfill.post_embeddings_backfillswithonlyMissing: trueand a boundedbatchSize(capped byqueue.maxBatchSize, default 500). Backfills persistBackfillRunstate and never scan in the request thread. Cancel and resume from the stored cursor. - Monitor. Watch
get_embeddings_backfills_idcounts (scanned/queued/processed/failed) andget_embeddings_statusqueue depths. - Canary text search. Admin
post_embeddings_searchor ClientPOST /embeddings/searchwith a scoped query. Confirm authorization-enabled schemas fail closed without an authenticated user or scope.
Rollback: set convict enabled: false and per-config enabled: false (generation and search stop; vectors remain), then stop the workload (docker compose stop embeddings or Helm install.embeddings.enabled=false). Rollback retains vector fields, indexes, EmbeddingConfig documents, BackfillRun records, and Redis/BullMQ queue state. Data and index removal is a separate operator action.
Target schema
The schema must be:
- CMS enabled or cms unset (
conduit.cms.enabledtrue, orcmsomitted) - Extendable (
conduit.permissions.extendable: true) - Non-system — not Database internals (
_DeclaredSchema,CustomEndpoints, …), not core/router/authorization-owned, not embeddings-owned (EmbeddingConfig,BackfillRun), not names starting with_, not auth secret schemas (AccessToken,RefreshToken,AdminApiToken, …)
Owner-controlled business schemas, including authentication User / Team, are allowed when they pass those checks.
Source fields
Each sourceFields entry must exist on the schema, be string-like (String or an array of strings), and use a valid field name. Hidden fields (select: false) and sensitive-looking names (password, secret, token, apiKey, …) are rejected unless they appear on security.sourceFieldAllowlist (or a platform-admin sourceFieldAllowlist on upsert). Caller-supplied allowlists are ignored for non-admin gRPC callers.
Backfill filter
Admin/MCP backfill filter is a document query, not a search query. Allowed: equality, comparisons ($eq, $ne, $gt, $gte, $lt, $lte), bounded $in/$nin, and $and. Rejected: regex, $or, $not, $like. Semantic-search filter does not use this allowlist — it is passed through as a Database vector-search filter.
Config deletion
delete_embeddings_configs_id removes the config document only. Vector fields and indexes stay on the schema until you delete them through Database.
Search split
| Caller | Path | Body | Identity | Limit |
|---|---|---|---|---|
| Client app | POST /embeddings/search | Required schemaName + text. Optional targetField, filter, limit. | Router user / scope. Body must not include userId, scope, or adminOperator. | Max 50 |
| Admin / MCP | post_embeddings_search | Same body shape. | Operator context | Not the Client cap |
| Database Admin | POST /database/schemas/:schemaName/vector-search | Raw vector array | Operator | Database vector-search limits |
Do not send a raw vector on either embeddings search path. Client search requires authMiddleware. Both embeddings search paths generate a query embedding, then delegate to Database vector search.
Configure
Two independent switches:
| Switch | Default | What it does |
|---|---|---|
Helm install.embeddings.enabled / compose --profile embeddings | off | Deploys or removes the embeddings process. Does not start workers. |
Module convict enabled | false | Turns on generation workers, mutation subscriptions, and search. Backfill start, backfill resume, and text search fail closed while this is false. Patch via MCP after the index is queryable. |
Production images require a non-empty GRPC_KEY. Image tags and the compose profile are on Docker Compose.
Enable MCP with ?modules=embeddings, then patch via patch_config_embeddings:
| Key | Default | Meaning |
|---|---|---|
enabled | false | Workers, mutation subscriptions, and search |
defaultProvider | openai-compatible | Provider id used when a config omits provider |
providers.openai-compatible.endpoint | "" | HTTPS embeddings endpoint |
providers.openai-compatible.apiKey | "" | Provider API key (sensitive) |
providers.openai-compatible.models | [] | Catalogue of { name, dimensions } |
providers.openai-compatible.defaultModel | "" | Default model from the catalogue |
queue.concurrency | 2 | Generation worker concurrency |
queue.attempts | 3 | Generation retry attempts |
queue.maxBatchSize | 500 | Max jobs accepted from one enqueue or backfill request |
security.sourceFieldAllowlist | [] | Source fields allowed even when hidden or sensitive-named |
provider, model, and dimensions on a config default from this catalogue when omitted. Provider output dimensions must match the configured vector dimensions.
similarity is cosine (default), euclidean, or dotProduct. Changing similarity recreates the vector index. Changing sourceFields does not.
Client API
Authenticated only (authMiddleware). User and scope come from the router context.
| Method | Path | Body |
|---|---|---|
| POST | /embeddings/search | { schemaName, text, targetField?, filter?, limit? } |
| Rule | Detail |
|---|---|
| Vectors | Do not send a raw vector. |
| Identity | Do not send userId, scope, or adminOperator. |
| Limit | Positive integer; Client max 50. |
| Authz | Search requires an authenticated user or scope from context. |
Configs, backfills, capabilities, and status are not Client routes.
Admin API
Operator routes on ADMIN_BASE_URL/embeddings/... (admin JWT or cdt_ token):
| Method | Path | Purpose |
|---|---|---|
| GET | /embeddings/configs | List configs (schemaName, id) |
| POST | /embeddings/configs | Create or update a config |
| GET | /embeddings/configs/:id | Get one config |
| DELETE | /embeddings/configs/:id | Delete config — does not drop vector fields or indexes |
| GET | /embeddings/capabilities | Database vector storage, indexing, and search |
| GET | /embeddings/status | Readiness, provider/index warnings, queue counts |
| GET | /embeddings/backfills | List BackfillRun records |
| POST | /embeddings/backfills | Start a queued backfill (onlyMissing, batchSize, configId, optional filter) |
| GET | /embeddings/backfills/:id | Get one backfill (counts, cursor, state) |
| POST | /embeddings/backfills/:id/cancel | Cancel a queued or running run |
| POST | /embeddings/backfills/:id/resume | Resume from the stored cursor |
| POST | /embeddings/search | Operator text-in search (no raw vectors) |
Admin backfill filter allows equality, comparisons, bounded $in/$nin, and $and. It rejects regex, $or, $not, and $like. This subset applies to backfill only — semantic-search filter is a Database vector-search filter (JSON object), not that allowlist.
Database raw-vector search stays on Admin POST /database/schemas/:schemaName/vector-search.
MCP
Enable with ?modules=embeddings in your MCP server URL. Hermes converts every embeddings Admin route (none set mcp: false).
| Tool | Purpose |
|---|---|
get_embeddings_configs | List embedding configs |
post_embeddings_configs | Create or update a config. First upsert provisions the vector index when Database indexing is available. Save enabled: false until the index is queryable. |
get_embeddings_configs_id | Get one config by id |
delete_embeddings_configs_id | Delete a config. Does not drop vector fields or indexes. |
get_embeddings_capabilities | Vector storage, index, and search capabilities plus warnings |
get_embeddings_status | Module readiness, provider/index warnings, generation and backfill queue counts |
get_embeddings_backfills | List persisted backfill runs |
post_embeddings_backfills | Start a queued cursor-based backfill. Prefer onlyMissing: true and a bounded batchSize. Optional filter uses the backfill allowlist (not the search filter). |
get_embeddings_backfills_id | Get one backfill run |
post_embeddings_backfills_id_cancel | Cancel a queued or running backfill |
post_embeddings_backfills_id_resume | Resume a failed or canceled run from its cursor |
post_embeddings_search | Operator semantic search by text |
get_config_embeddings | Read module convict config |
patch_config_embeddings | Patch module convict config (provider, enabled, queue) |
That is 12 embedding route tools plus the two core-injected config tools.