Extras
At the end of this page you know which pip install "arche-core[...]" line buys which capability, what each one costs in packages and licence, and which names exist only so an old install line still resolves. pip install arche-core is 14 packages and no machine-learning stack; everything heavier is an extra you ask for by name.
pip install "arche-core[ledger]" # the base verbs plus a decision ledger
pip install "arche-core[resolve,detect2]" # Splink above the floor, a model in the detection path
The package counts below were resolved from scratch with uv pip compile against Python 3.12 on 2026-09-20, not estimated. "Added" is over the base wheel's 14. A number in a table is a claim about somebody else's release schedule, so re-run the script at the end when a dependency moves.
| extra | installs | enables | licence | added |
|---|---|---|---|---|
| (base) | rapidfuzz, jellyfish, networkx, pydantic, h3, phonenumbers, pyyaml, cryptography |
detect_pii, deidentify, compare, reconcile with arche's own engine, resolve_place_request, every African identifier validator, arche studio, arche redact, arche compare |
Apache-2.0 | 14 total |
pdf |
pypdf |
the text layer of a PDF: extract_text, arche.doc.assess_residence |
BSD-3-Clause | +1 |
pdf-mupdf |
pymupdf |
the same text layer through the copyleft reader, opt in | AGPL-3.0 | +1 |
docx |
python-docx |
.docx in extract_text and arche redact; resolve_documents reads .docx through [doc] instead |
MIT | +2 |
doc |
docling, which pulls torch, transformers, pandas |
layout, tables and reading order: arche.doc.parse, resolve_documents, POST /documents |
MIT | +99 |
doc-ocr |
[doc] plus rapidocr-onnxruntime |
scanned pages, through docling's ONNX OCR backend, no tesseract | MIT / Apache-2.0 | +103 |
parquet |
pyarrow |
parquet review packs in arche.review.read_pack; CSV and JSONL need nothing |
Apache-2.0 | +1 |
detect2 |
gliner2[local], which pulls torch, transformers |
backend="gliner2-pii" for detect_pii, deidentify, Pipeline; backend="gliner2" for extract; two model downloads of about 0.5 GB each on first use |
Apache-2.0 | +26 |
detect |
[detect2] |
the same, under the name an older install line used | Apache-2.0 | +26 |
presidio |
presidio-analyzer, presidio-anonymizer, which pull spacy |
nothing in arche calls them yet; see below | MIT | +46 |
service |
fastapi, uvicorn, python-multipart |
arche serve: the verbs over HTTP, file upload on /documents |
MIT / BSD-3-Clause | +9 |
mcp |
mcp (2.x) |
arche mcp: the verbs as tools an agent runtime calls, on stdio or streamable HTTP |
MIT | +21 |
resolve |
splink, duckdb, which pull pandas |
reconcile(backend="splink"), and backend="auto" handing scoring to Splink at 1,000 records and above; about 200 MB |
MIT | +20 |
ledger |
duckdb |
arche.attach("duckdb:///..."): the decision ledger, explain, replay, store= on every verb |
MIT | +1 |
runtime |
[ledger] |
the same, under its earlier name | MIT | +1 |
geo |
shapely, duckdb |
polygon joins (annotate_admin) and the Overture Places pull; H3 blocking is in the base wheel |
BSD-3-Clause, MIT | +3 |
llm |
openai, anthropic |
arche.llm providers openai and anthropic; ollama needs nothing |
Apache-2.0 / MIT | +11 |
litellm |
litellm |
the litellm provider, one client for many hosted models |
MIT | +50 |
ng ke za gh africa |
nothing | nothing: the African detectors are in the base wheel | +0 | |
all |
[pdf,docx,detect,presidio,resolve,llm,mcp] |
everything above except doc, doc-ocr, pdf-mupdf, parquet, geo, service and litellm |
mixed, no AGPL | 108 total |
Three extras pull torch: detect2 (and detect), doc and doc-ocr. If a deployment cannot carry it, those are the ones to leave out, and the base wheel plus [pdf], [ledger], [resolve] and [service] still covers record resolution, the ledger, proof of address, Splink and the basic detector path, which needs no model at all.
A line of Python says which of these an environment has. The output below is from the machine this page was written on, so yours will differ.
import importlib.util
extras = [
("ledger", "duckdb"), ("resolve", "splink"), ("detect2", "gliner2"),
("doc", "docling"), ("pdf", "pypdf"), ("service", "fastapi"), ("mcp", "mcp"),
]
for extra, module in extras:
state = "installed" if importlib.util.find_spec(module) else "not installed"
print(f"{extra:<8} {state}")
ledger installed
resolve installed
detect2 installed
doc not installed
pdf installed
service installed
mcp installed
gliner2[local], not gliner2
The [local] marker on the detect2 extra is load-bearing. Bare gliner2 installs an API client that posts text to a hosted service. Declaring it without [local] would ship a code path that looks exactly like on-device extraction while sending customer text off the machine. arche-core[detect2] pins gliner2[local], the on-device stack, and a test in the suite asserts the marker is there. If you install the model backend by hand rather than through the extra, write the marker yourself.
detect is detect2, and GLiNER v1 is gone
detect used to install GLiNER v1 (gliner with ONNX runtime, 31 packages). That model was removed in 0.9.0. The name is kept so an existing pip install "arche-core[detect]" still resolves, and it now installs the GLiNER 2 family: GLiNER 2.5 (fastino/gliner2.5-base-v1) as the general extractor behind extract(), and GLiNER2-PII (fastino/gliner2-privacy-filter-PII-multi), 42 personal-data labels in seven European languages, as the proposer behind detect_pii, deidentify and Pipeline.
The model proposes; it never decides. The validators, the statute pack and the merge rule run after every backend, and a checksummed identifier always outranks a model span. backend="gliner" raises and names its replacement.
backend= |
what runs | extra |
|---|---|---|
basic |
the name lexicon (13,342 entries), the address parser, the identifier, phone and email patterns with their checksums and cue gates | none |
gliner2-pii |
GLiNER2-PII proposing, the validators deciding | detect2 |
gliner2 |
GLiNER 2.5, extract() only, labels are the caller's |
detect2 |
auto |
basic plus the model when the extra is installed; a one-line notice when it is not |
none required |
What the model buys and costs is measured on the detection benchmark: basic recalls 0.818 at 4 ms a text and has no rule for dates of birth, bank accounts or passwords; gliner2-pii recalls 0.990 at 618 ms a text and adds false positives on order numbers the validators do not govern.
resolve, and the 1,000-record floor
[resolve] installs Splink and DuckDB. It is behind an extra because the base wheel is a library, and the pair scoring for a batch under a thousand records does not need a trained model. Two things change once it is installed.
reconcile(backend="splink", splink_settings=..., threshold=...) hands the scoring to Splink and keeps everything arche puts around a score: decision ids, pins, evidence, refusal and the review pack. splink_settings and threshold are required rather than inferred, because a derived configuration orders pairs about as well as a hand-written one and cannot calibrate them.
backend="auto", the default, chooses. Below AUTO_SPLINK_FLOOR (1,000 records) it is arche's engine, exactly as without the extra. At the floor and above, when the entity has a shipped recipe that is enabled for auto and the records carry the recipe's columns, it is Splink; otherwise the engine again. The choice and its reason come back as result["backend"], on the result and not in the pins, so no frozen decision id moves. The floor is a measurement: below it the engine makes fewer false merges than Splink, above it the engine's precision turns while Splink's holds. The size floor has the four sizes.
doc and doc-ocr: two ways to read a document
Both [pdf] and [doc] read PDFs and they are not interchangeable.
arche-core[pdf] |
arche-core[doc] |
|
|---|---|---|
| installs | pypdf, pure Python |
docling, with torch, transformers, pandas |
| added packages | +1 | +99 |
| reads | the text layer | layout, tables, reading order |
| entry point | arche.extract_text, arche.doc.assess_residence |
arche.doc.parse, resolve_documents |
| use it when | you need the words on the page | you need the structure of the page |
The proof-of-address check sits on the light one on purpose: a KYC check that needs a two-gigabyte stack to read an energy bill is a check that does not get deployed. If you install only [pdf] and hand resolve_documents a PDF, it raises rather than returning an empty report, because a report of zero records reads as "these documents contain nothing", which is a different statement from "I could not read them". Plain text needs neither: .txt and .md are read directly, and the provenance records parser: "text" rather than parser: "docling".
[doc-ocr] adds rapidocr-onnxruntime for scanned pages. It is docling's ONNX OCR backend, chosen because it needs no system tesseract. [pdf-mupdf] is the AGPL reader that [pdf] used to install; it moved to a name that says what it is, _extract_pdf prefers pypdf and falls back to pymupdf, so an older environment keeps working and simply stops being the one that pulls copyleft.
service and mcp: the two front doors that are not Python
arche studio needs no extra. It is the standard library's http.server and one HTML file, in the base wheel, bound to 127.0.0.1.
arche serve needs [service]: the same verbs behind FastAPI for a container, a sidecar or a tool that speaks HTTP. python-multipart is what lets POST /documents take a file upload. It has no authentication of its own; Serve over HTTP says so and what to put in front of it.
arche mcp needs [mcp], new in 0.9.0. The server used to be a second package, arche-mcp, with its own release, changelog and a closed pin on arche-core that had to be moved by hand every minor. It was one module and an optional import, so it is arche.mcp now, behind this extra the way serve is behind service. The arche-mcp command remains for configurations written against the old name. The pin is mcp>=2.0,<3 because the SDK removed mcp.server.fastmcp in 2.0 and the server uses mcp.server.MCPServer. MCP server is the guide; MCP tools lists the tools.
ledger and runtime
[ledger] is one package, duckdb, and it is what arche.attach("duckdb:///...") needs: store= on any verb, explain, replay, the review queue and the entities the decisions have linked. The file is on your disk; nothing leaves the machine. [runtime] is the earlier name for the same extra and installs the same thing. Keep, explain, replay is what you do with it.
presidio installs packages nothing calls
[presidio] installs Microsoft Presidio's analyzer and anonymizer, and spacy beneath them, 46 packages. It is not a backend=. The extra installs the packages and nothing in arche calls them: arche.detect.presidio is an empty module. It stays listed because a caller may want Presidio beside arche in one environment; it is not a claim that arche uses it.
llm and litellm
[llm] installs the openai and anthropic SDKs for the arche.llm providers of the same names. A language model is an additional proposer in the same position as GLiNER: it proposes entities and the validators decide, so the output is typed evidence with a validator status whatever the source. The ollama provider talks HTTP to a local Ollama and needs no extra. [litellm] installs litellm for its provider, which fronts many hosted models behind one client; it is the largest extra that does not pull torch.
Names kept for compatibility
| name | installs | since |
|---|---|---|
detect |
[detect2] |
GLiNER v1 removed in 0.9.0 |
runtime |
[ledger] |
earlier name |
ng, ke, za, gh, africa |
nothing | forward-compatible namespaces, empty |
Both aliases keep working through 1.x.
The v0.1 names gliner, pii and splink were removed at 1.0. They had been aliases since v0.3, no page here used them, and an install command that names one now fails at resolution instead of quietly installing something else. Use [detect2], [presidio] and [resolve].
The country extras are empty on purpose. Nigerian, Kenyan, South African and Ghanaian identifier detection needs no dependency, so pip install "arche-core[ng]" installs exactly what pip install arche-core does. They exist so a requirements.txt written against an earlier expectation still resolves, and so a caller can pin to one country's changes if those bundles ever carry something.
Reproducing the counts
python - <<'EOF'
import re, subprocess, tempfile, pathlib
for extra in ["", "pdf", "ledger", "service", "mcp", "resolve", "detect2", "presidio", "doc"]:
spec = f"./packages/arche-core[{extra}]" if extra else "./packages/arche-core"
with tempfile.NamedTemporaryFile("w", suffix=".in", delete=False) as fh:
fh.write(spec + "\n"); req = fh.name
out = subprocess.run(["uv", "pip", "compile", req, "--quiet", "--no-header",
"--python-version", "3.12"],
capture_output=True, text=True).stdout
pathlib.Path(req).unlink()
print(f"{extra or '(base)':<10} {len(re.findall(r'^[A-Za-z0-9_.-]+==', out, re.M)):>4}")
EOF
(base) 14
pdf 15
ledger 15
service 23
mcp 35
resolve 34
detect2 40
presidio 60
doc 113
Where to read next
| You want to | Read |
|---|---|
| the install lines in order, with what each one unlocks | Install |
what backend="auto" decides and why |
Backends |
| the numbers behind the floor and the model | Benchmarks |
| the verbs over HTTP | Serve over HTTP |
| the verbs as tools for an agent | MCP server |