Configuration management for Arcana.
Handles parsing and resolving configuration for embedders, chunkers, and other pluggable components.
Redacting Sensitive Values
Use Arcana.Config.redact/1 to wrap any config value for safe inspection:
config = Application.get_env(:arcana, :llm)
inspect(Arcana.Config.redact(config))
# => {"zai:glm-4.7", [api_key: "[REDACTED]"]}Embedder Configuration
# Default: Local Bumblebee with bge-small-en-v1.5
config :arcana, embedder: :local
# Local with different model
config :arcana, embedder: {:local, model: "BAAI/bge-large-en-v1.5"}
# OpenAI (requires req_llm and OPENAI_API_KEY)
config :arcana, embedder: :openai
config :arcana, embedder: {:openai, model: "text-embedding-3-large"}
# Custom function
config :arcana, embedder: fn text -> {:ok, embedding} end
# Custom module implementing Arcana.Embedder behaviour
config :arcana, embedder: MyApp.CohereEmbedder
config :arcana, embedder: {MyApp.CohereEmbedder, api_key: "..."}Chunker Configuration
# Default: text_chunker-based chunking
config :arcana, chunker: :default
# Default chunker with custom options
config :arcana, chunker: {:default, chunk_size: 512, chunk_overlap: 100}
# Custom function (receives text, opts; returns list of chunk maps)
config :arcana, chunker: fn text, _opts ->
[%{text: text, chunk_index: 0, token_count: 10}]
end
# Custom module implementing Arcana.Chunker behaviour
config :arcana, chunker: MyApp.SemanticChunker
config :arcana, chunker: {MyApp.SemanticChunker, model: "..."}PDF Parser Configuration
# Default: poppler's pdftotext
config :arcana, pdf_parser: :poppler
# Custom module implementing Arcana.FileParser.PDF behaviour
config :arcana, pdf_parser: MyApp.PDFParser
config :arcana, pdf_parser: {MyApp.PDFParser, some_option: "value"}Search Defaults
Set defaults for Arcana.search/2. Per-call options override these.
Any option accepted by Arcana.Search.search/2 can be set globally.
config :arcana, search: [
limit: 10,
threshold: 0.0,
mode: :vector, # :vector | :keyword | :hybrid
vector_weight: 0.5, # for hybrid mode
keyword_weight: 0.5, # for hybrid mode
rewriter: &MyApp.rewrite/1, # query rewriter function
hnsw_ef_search: 100, # pgvector only, see Arcana.VectorStore.Pgvector
]Ask Defaults
Set defaults for Arcana.ask/2. Per-call options override these.
Any option accepted by Arcana.Ask.ask/2 can be set globally.
config :arcana, ask: [
limit: 5,
mode: :semantic,
threshold: 0.0,
prompt: &MyApp.custom_prompt/3
]Reranker Configuration
Set a global reranker that will be applied automatically by Arcana.search/2
and Arcana.ask/2. Per-call :reranker options override this. Pass
reranker: false per-call to disable for a single request.
# Global reranker module
config :arcana, reranker: Arcana.Reranker.CrossEncoder
# With options (e.g. over_fetch multiplier, threshold)
config :arcana, reranker: {Arcana.Reranker.CrossEncoder, over_fetch: 3}
# Custom function: fn question, chunks, opts -> {:ok, reranked} end
config :arcana, reranker: &MyApp.rerank/3
Summary
Functions
Returns the configured chunker as a {module, opts} tuple.
Returns the current Arcana configuration.
Returns the configured embedder as a {module, opts} tuple.
Returns the configured fallback parser as {module, opts}, or nil.
Returns the configured file parsers as a map of extension to
{module, opts}.
Returns the value for key from opts, falling back to the global app env.
Returns the value for key from the :arcana app env.
Returns whether GraphRAG is enabled globally or for specific options.
Merges global keyword-list config under app_key with per-call opts.
Returns the configured PDF parser as a {module, opts} tuple.
Wraps a config value for safe inspection with sensitive data redacted.
Resolves the Ecto repo configured for Arcana's mix tasks.
Returns the repo from opts or the global config, raising when neither is set.
Returns the configured reranker, resolving per-call opts and global config.
Resolves chunker from options, falling back to global config.
Resolves embedder from options, falling back to global config.
Returns whether strict collection scoping is enabled.
Functions
Returns the configured chunker as a {module, opts} tuple.
Returns the current Arcana configuration.
Useful for logging, debugging, and storing with evaluation runs to track which settings produced which results.
Example
Arcana.Config.current()
# => %{
# embedding: %{module: Arcana.Embedder.Local, model: "BAAI/bge-small-en-v1.5", dimensions: 384},
# vector_store: :pgvector
# }
Returns the configured embedder as a {module, opts} tuple.
Returns the configured fallback parser as {module, opts}, or nil.
Consulted for any extension without a native or registered parser:
config :arcana, fallback_parser: {MyApp.ExtractionService, []}nil and false both mean "no fallback".
Returns the configured file parsers as a map of extension to
{module, opts}.
Extensions are normalized to lowercase with a leading dot, so
%{"docx" => ...} and %{".DOCX" => ...} both register ".docx".
config :arcana, file_parsers: %{".docx" => {MyApp.DocxParser, []}}Mapping an extension to false disables it: nothing parses it, not the
built-in route and not the :fallback_parser. Such entries come back
as nil.
config :arcana, file_parsers: %{".pdf" => false}
Returns the value for key from opts, falling back to the global app env.
Used to thread configuration like :repo and :llm from per-call opts
with a fallback to config :arcana, key: value.
Examples
repo = Arcana.Config.get(opts, :repo)
llm = Arcana.Config.get(opts, :llm)
Returns the value for key from the :arcana app env.
All runtime configuration reads in Arcana go through this function. Test
suites can install a custom reader with install_env_reader/1 to shadow
keys per-process instead of mutating global state.
Returns whether GraphRAG is enabled globally or for specific options.
Checks the :graph option in the provided opts first, then falls back
to the global configuration.
Examples
# Check global config
Arcana.Config.graph_enabled?([])
# Override with per-call option
Arcana.Config.graph_enabled?(graph: true)
Merges global keyword-list config under app_key with per-call opts.
Per-call opts override the global config. Used to thread namespace
configs like :search, :ask, and :graph.
Examples
# Reads `config :arcana, search: [limit: 10]` and merges
opts = Arcana.Config.merge_app_opts(opts, :search)
# Reads `config :arcana, ask: [limit: 5]` and merges
opts = Arcana.Config.merge_app_opts(opts, :ask)
Returns the configured PDF parser as a {module, opts} tuple.
Wraps a config value for safe inspection with sensitive data redacted.
Returns a struct that implements the Inspect protocol and automatically
redacts sensitive keys like :api_key, :token, :password, etc.
Example
iex> config = {"zai:glm-4.7", [api_key: "secret123"]}
iex> inspect(Arcana.Config.redact(config))
~s|{"zai:glm-4.7", [api_key: "[REDACTED]"]}|
Resolves the Ecto repo configured for Arcana's mix tasks.
Accepts either configuration shape:
# Explicit repo key
config :arcana, repo: MyApp.Repo
# Per-repo configuration (e.g. custom priv directory)
config :arcana, MyApp.Repo, priv: "priv/my_repo"When only the per-repo shape is present and exactly one repo is
configured, that repo is used (with a note printed to stderr). Raises
ArgumentError when no repo can be resolved, or when several per-repo
entries exist without an explicit :repo key to disambiguate.
repo: nil means "not set" and falls through to the per-repo scan.
repo: false is an explicit "no repo", so it raises the same "no Ecto
repo configured" error instead of quietly picking a per-repo entry.
Called without arguments, the :repo key is read through get_env/2 so
process-scoped overrides installed via install_env_reader/1 are honored.
Pass an explicit env keyword list to resolve against it directly.
Returns the repo from opts or the global config, raising when neither is set.
Returns the configured reranker, resolving per-call opts and global config.
Returns nil if no reranker is set or if explicitly disabled with
reranker: false. Otherwise returns {module_or_fun, opts}.
Resolves chunker from options, falling back to global config.
Resolves embedder from options, falling back to global config.
Returns whether strict collection scoping is enabled.
When strict, an unknown collection name is an error
({:error, {:unknown_collection, name}}) instead of silently widening
the operation to every collection. Checks the :strict_collections
option in the provided opts first (so strict_collections: false can
override a global true per call), then falls back to
config :arcana, strict_collections: true. Defaults to false; the
default will flip to true in Arcana 3.0.