ExuluContext constructor takes a single options object. This page documents every option, verified against the current @exulu/backend source.
Identity
Unique identifier. Lowercased with spaces replaced by underscores, it becomes the Postgres table prefix:
<id>_items, <id>_chunks, and (with the entity layer) <id>_entities. Must start with a letter or underscore, contain only letters, digits, and underscores, and be at most 80 characters — treat 5 as the practical minimum.Human-readable name shown in the platform UI and logs.
What this context contains. Surfaced to users and agents choosing where to search.
Whether the context is active and available.
Fields
The custom schema for items, on top of the built-in columns (
id, name, description, tags, archived, external_id, created_by, ttl, rights_mode, embeddings_updated_at, last_processed_at, textlength, source, chunks_count, createdAt, updatedAt).Column name. Sanitized to lowercase with underscores. For
file fields, the actual column is <name>_s3key.One of
text, longText, shortText, number, boolean, code, json, enum, markdown, file, date, uuid. See the type table below for the Postgres column each maps to.Whether the field can be edited in the platform UI after creation.
Adds a unique constraint on the column.
Whether a value is required when creating items through the platform API.
Default value declared for the field. Surfaced through the context’s table definition (API and admin UI); the Postgres column itself is created without a database-level default.
Marks the field as computed (for example, filled by a processor) rather than user-provided.
Whether to index the field for faster filtering.
For
enum fields: the allowed values.For
file fields: the accepted file types (for example ["pdf", "docx"]).Field type reference
Embedder
A reference to a LiteLLM embedding model, plus an optional queue. Without an embedder, vector and hybrid search are unavailable — the context still works for structured storage and full-text search.
The
model_name of an embedding model declared in config.litellm.yaml. The model’s model_info must declare its dimensionality — the chunks table’s vector(n) column is sized from it, and table creation throws if it is missing.When set, embedding generation is scheduled as a BullMQ job on this queue instead of running inline. Required in practice for bulk generation: without a queue,
embeddings.generate.all() refuses to process more than 2,000 items.ExuluQueues.register(name, concurrency, ratelimit?, timeoutInSeconds?) registers a BullMQ queue and returns { use }; calling .use() yields the Promise<ExuluQueueConfig> the embedder, processor, and sources expect. Registering queues requires an Enterprise Edition license.Chunker
Splits an item into embeddable chunks before the embedder runs. When omitted, the built-in
defaultChunker (a sentence chunker) runs over the item’s content field — falling back to description — combined with name. Contexts with structured or file-backed content should supply their own.maxChunkSize is the per-chunk token budget, derived from the embedding model. utils.storage gives file-backed chunkers access to object storage. Chunk metadata lands in the chunks table’s JSONB column, so any JSON-serializable value (for example a page number) is allowed.
@exulu/backend also exports ready-made chunkers under ExuluChunkers (sentence, markdown, recursive) and the defaultChunker itself.Sources
Data sources that ingest items from external systems. Pass an empty array if the context has none.
Unique source ID — also used as the BullMQ job scheduler key.
Human-readable name.
What the source ingests.
Cron expression, for example
"0 */6 * * *" for every six hours. When the worker process starts (app.bullmq.workers.create()), it upserts a BullMQ job scheduler per source that has both a schedule and a queue. Sources without a queue log a warning and are skipped.The queue the source job runs on.
BullMQ retry attempts for a failed run.
Retry backoff strategy.
Declared input parameters (
name, description, optional default) for manual runs — surfaced in the platform UI when triggering the source by hand. Values arrive in execute’s inputs.Async function that fetches external data and returns an array of items (
ExuluItem). Each returned item is written with createItem: items carrying an external_id (or id) are upserted — existing rows with the same external_id are updated — while items without one are inserted fresh. Processor and embedding triggers apply as configured.Processor
Transforms items after they are written — extract text from an uploaded file, enrich a record, compute derived fields. The result is written back to the items table and can trigger embedding generation.
Processor name, used in job labels.
What the processor does.
Optional predicate. Return a falsy value to skip processing for an item — for example, when no file is attached yet.
The transformation. Receives the item and
utils.storage for reading files from object storage; must return the updated item, which is persisted with last_processed_at set.When the processor runs:
manual (only explicit processField() calls), or automatically on writes. Both createItem() and updateItem() run the processor when the trigger is onInsert, onUpdate, or always — currently the three non-manual values behave identically on both write paths.Run processing as a background job instead of inline.
Job timeout in queue mode.
When
true, embedding generation is triggered automatically after the processor finishes.Retrieval hooks
Rewrites the natural-language query before retrieval — for example, expanding it with an LLM. Applied inside the search pipeline whenever a
query is present.Declared hook for reordering retrieved chunks after search. Each chunk carries
chunk_content, chunk_index, chunk_id, chunk_source, chunk_metadata, chunk_created_at, chunk_updated_at, item_id, item_external_id, and item_name.Retrieval configuration
Retrieval and write behavior. When you omit the entire object, the defaults below apply. When you pass a partial object, only your keys are set — the per-key defaults are not merged in, so pass everything you rely on.
When embeddings are generated automatically: never (
manual), when items are created (onInsert), updated (onUpdate), or both (always). With manual, call embeddings.generate.one() / .all() yourself or pass the generateEmbeddingsOverwrite flag on writes.Fallback result limit used when a
search() call passes no limit.Default
rights_mode for new items — the items table column defaults to this value.Minimum relevance scores per search method. Results scoring below the cutoff are dropped. Can be overridden per
search() call.Number of neighboring chunks to include around each matched chunk, giving agents more surrounding context. Can be overridden per
search() call.Languages for the generated full-text search columns. Each language adds a
to_tsvector expression to the items and chunks tables, affecting stemming and stop words. Set before the tables are created — the columns are generated at table-creation time.Entity layer
Opt-in entity extraction over chunks. When present (or when an admin has configured entity types for the context in the UI), IMP extracts typed entities from embedded content into
<id>_entities, enabling entity filters and insights in search(). Absent → behavior is unchanged.Entity types declared in code, for example
{ name: "Person", description: "A natural person mentioned in the document." }. Merged (union) with types an admin declares in the UI.Model ID used for extraction. Falls back to a platform default when omitted.
Weight of the shared-entity boost term in retrieval ranking.
Mentions below this extractor confidence are dropped.
Target language for canonical entity names.
Complete example
Next steps
API reference
Search, item CRUD, embeddings, entity layer, and table methods.
ExuluApp
Register the context on the app.