Skip to content

The Config Object

Config is one point in the grid — one parser, one chunker, one everything. It’s a frozen (immutable) dataclass, written as spec strings, so a configuration is readable, diffable, and paste-able:

import contextgrid as cg
config = cg.Config(chunker="structural:512", index="bm25", reranker="lexical")
print(config)
Config(parser='markdown', chunker='structural:512', embedder='tfidf', index='bm25', transform=None, retrieval=None, reranker='lexical', k=10, candidates=50, ingestion=None, generator=None)

Only chunker, index, and reranker were named. Everything else — including parser, which comes first — sits at its own default.

Every field

This is the declared order (also the positional order, if you construct one without keyword arguments):

FieldTypeDefaultSpec grammar covered on
parserstr"markdown"Parsers
chunkerstr"recursive:512"Chunkers
embedderstr | None"tfidf"Embedders
indexstr"dense"Indexes
transformstr | NoneNoneTransforms
retrievalstr | NoneNoneRetrieval
rerankerstr | NoneNoneRerankers
kint10how many results search() returns
candidatesint50how many results the retriever hands the reranker
ingestionstr | NoneNone (meaning plain)Ingestion
generatorstr | NoneNone (no generation)Generating an Answer

ingestion and generator sit last in the declared order on purpose, even though ingestion is the first thing to run — putting a new field ahead of parser would silently shift every positional argument anyone had already written against Config.

Config is frozen

Fields can’t be reassigned — build a changed copy with .with_() instead:

base = cg.Config()
variant = base.with_(chunker="structural:256", reranker="mmr")
print(base)
print(variant)
Config(parser='markdown', chunker='recursive:512', embedder='tfidf', index='dense', transform=None, retrieval=None, reranker=None, k=10, candidates=50, ingestion=None, generator=None)
Config(parser='markdown', chunker='structural:256', embedder='tfidf', index='dense', transform=None, retrieval=None, reranker='mmr', k=10, candidates=50, ingestion=None, generator=None)

Trying to set an attribute directly raises FrozenInstanceError, not a silent no-op.

config.label is a short, human-readable identifier — the string a leaderboard row shows — built from whichever fields aren’t at a “does nothing” value: "markdown · structural:512 · tfidf · bm25 · lexical@50" for the config above. config.as_dict() gives the same fields back as a plain dict, which is what gets written into a report.

Round-tripping back to code

cg.config_to_python(config) takes a built configuration and writes real, runnable Python that reconstructs it — the whole point being that it actually runs, not that it merely reads correctly:

config = cg.Config(chunker="structural:512", index="bm25", reranker="lexical")
print(cg.config_to_python(config))
"""The winning configuration, as context-grid found it."""
import contextgrid as cg
# markdown · structural:512 · tfidf · bm25 · lexical@50
# Any field not named below is at its default; `cg.Config()` puts it back.
config = cg.Config(
chunker="structural:512",
index="bm25",
reranker="lexical",
)
# Placeholder: this export was not told where the documents are.
corpus = cg.Corpus.from_dir("./documents")
pipeline = cg.build(config, corpus)
for chunk_id in pipeline.search("your question here"):
print(chunk_id)

Only fields that differ from Config()’s own defaults are written out — the same rule this page’s own table follows, read straight off the dataclass rather than hand-maintained, so it can’t drift out of sync with a field that gets added later.

config_to_python is what the CLI writes into report.out/ when report: formats: [python] is set — see Reports for config_to_yaml and winning_config_to_yaml, the two sibling exporters that write YAML instead.

This page covers cg.Config — one point in the grid. For the YAML experiment file the CLI reads (corpus:, grid:, run:, and its own plugins: key for registering your own chunker, embedder, or metric), see CLI Reference and Writing a Custom Plugin.