Runtime flags
Scope
Two things configure a running Mailwoman: environment variables, and the defaults on the mechanisms inside the pipelinestaged pipelineMailwoman's runtime architecture: a sequence of pure-function stages (normalize → query-shape → locale-gate → kind-classifier → phrase-grouper → classifier → decoder) connected by typed handoffs. Each stage is published as its own npm package.. This page covers both, restricted to what a consumer of the published packages can act on.
The boundary matters, because the repository's own environment schema is wider than this page. That schema splits its variables by whether they are safe to log rather than by whether a consumer should set them, so it also declares the release-publishing settings, the weightsparameterA single learned number inside a model — one weight or bias. Mailwoman's encoder has roughly 30 million of them; training is the search for good values. dev-linking overrides, the corpuscorpusThe BIO-labeled training data used to train Mailwoman's neural classifier. Assembled from real sources (OpenAddresses, National Address Database) and synthetic shards (boundary stress, order variants, negative space). Managed by @mailwoman/corpus. fetch knobs, and the switches the evaluationevalRunning the model against a held-out golden dataset and computing per-component F1, exact-match, calibration, and resolved-coordinate error. scripts read. None of those does anything in an installed package, and several are declared but read nowhere. If a variable is not on this page, setting it changes nothing you can observe.
Behavior defaults are listed after the variables. They are not environment variables — each is an
option on createRuntimePipeline, geocodeAddress, or the resolverresolverThe component that converts parsed address components (locality, region, postcode) into coordinates by looking them up in the gazetteer. The resolver ranks candidates by name match, population, and proximity, and returns the best-matching place with its centroid or polygon., and the table states where.
Environment variables
Every variable below is read by shipped runtime code. Each has no default unless the table says so.
| Variable | Default | Effect | Set it when |
|---|---|---|---|
MAILWOMAN_DATA_ROOT | a built-in path | The root directory for every downloaded artifact: gazetteersgazetteerA geographical index that maps place names and postcodes to real-world coordinates. Mailwoman uses a custom-built Who's On First (WOF) SQLite database as its gazetteer — the 'atlas' half of the grammar/atlas architecture., shardsshardA partial output file of the corpus build, written in Parquet format. The training pipeline streams shards row by row., POIpoint of interest (POI). A named place that is not strictly an address — landmark, transit stop, venue, amenity, or franchise. Mailwoman tags these as venue and resolves them through the gazetteer. layerlayerOne transformer block — attention plus a feed-forward network, with normalization and residual connections — applied to every position. Stacking layers lets the model build up richer representations; Mailwoman's encoder has 6. | Your data lives anywhere but the default. Run mailwoman doctor to see the resolved value |
MAILWOMAN_CANDIDATE_DB | <data root>/wof/candidate.db | Path to candidate.db, overriding the convention path. none pins the FTS backend instead | Your copy lives outside the data root, or you want the FTS backend |
MAILWOMAN_WOF_DB | unset | Path to a full Who's On FirstWOF (Who's On First). An open-source gazetteer of places maintained by Mapzen/whosonfirst. Mailwoman builds a custom SQLite database from WOF GeoJSON repos, extended with postcode data, importance scores, and coincident-role relations. SQLite distribution, used by the search backend | You resolve against a full distribution rather than candidate.db |
MAILWOMAN_WOF_ADMIN_DB | unset | Path to the full WOFWOF (Who's On First). An open-source gazetteer of places maintained by Mapzen/whosonfirst. Mailwoman builds a custom SQLite database from WOF GeoJSON repos, extended with postcode data, importance scores, and coincident-role relations. distribution for mailwoman reverse | You reverse geocode |
MAILWOMAN_WOF_POLYGONS_DB | unset | Path to the polygon sidecar. Without it every reverse result is approximate | You need polygon-exact containment |
MAILWOMAN_POSTAL_CITY_ALIAS_DB | unset | Path to the postal-citylocalityThe city / town / settlement component of an address: a populated place sitting between region and neighborhood in the hierarchy. alias database, which adds an alias-aware scoring pass | You geocode United States mailing addresses at volume |
MAILWOMAN_FST_BIN | unset | Path to the gazetteergazetteerA geographical index that maps place names and postcodes to real-world coordinates. Mailwoman uses a custom-built Who's On First (WOF) SQLite database as its gazetteer — the 'atlas' half of the grammar/atlas architecture. index mailwoman autocomplete reads | You run autocomplete against an index outside a weightsparameterA single learned number inside a model — one weight or bias. Mailwoman's encoder has roughly 30 million of them; training is the search for good values. package |
MAILWOMAN_MODEL_CARD | the package's card | Path to a model cardmodel cardA JSON metadata file (model-card.json) shipped with each weights bundle. It declares the model version, lineage, label set, required inference channels (anchor, gazetteer), calibration data, and training provenance., read by the server's /health report | You serve a modelneural classifierThe machine learning model at the core of Mailwoman's parser — a transformer encoder (~30M parameters) trained from scratch to do BIO token classification over addresses. It learns the 'grammar' of address formats; the gazetteer supplies the 'atlas.' whose card is not beside it |
MAILWOMAN_COARSE_PLACER_DIR | the bundled placer | Directory holding the coarse countrycountryThe top-level address component (an ISO country). Closed-vocabulary, so it is best handled by a deterministic matcher feeding a proposal rather than a retrained model head. placer | You replace the bundled placer |
MAILWOMAN_BATCH_MAX | 1000 | The row cap on POST /v1/batch under mailwoman serve | You batchbatch sizeHow many examples the model processes before each parameter update. Larger batches give smoother gradients but cost more memory; gradient accumulation simulates a big batch on a small GPU. more than 1000 rows per request |
MAILWOMAN_CANDIDATE_DB is the variable most installs no longer need to set. Since 8.7.0 the
candidate gazetteergazetteerA geographical index that maps place names and postcodes to real-world coordinates. Mailwoman uses a custom-built Who's On First (WOF) SQLite database as its gazetteer — the 'atlas' half of the grammar/atlas architecture. is the default backend, and it is discovered rather than configured. Every
surface that resolves places — parse, geocode, serve, poi, registry, the MCP server, and
the nominatim and photon drop-ins — reads an explicit --candidate-db, then this variable, then
the convention path <data root>/wof/candidate.db, taking the first that exists on disk.
mailwoman data pull candidate writes that path, so a bare pull is the whole setup. (The libpostal
drop-in never appears in that list: it parsesaddress parsingThe process of decomposing a free-text postal address string into structured components — house number, street name, locality, region, postcode, and country — so a geocoder can resolve them to coordinates. and expands, and resolves nothing.)
Two things the variable is still for. Point it at a copy that lives outside the data root, or set it
to the literal none (equivalently --candidate-db none) to pin the older FTS backend over a full
Who's On FirstWOF (Who's On First). An open-source gazetteer of places maintained by Mapzen/whosonfirst. Mailwoman builds a custom SQLite database from WOF GeoJSON repos, extended with postcode data, importance scores, and coincident-role relations. distribution. data pull still prints an export line on success; it is a leftover
from when the export was required, and following it changes nothing unless your file is elsewhere.
The change has a real edge: a machine that had candidate.db sitting at the convention path while
running on the FTS backend switches backends on upgrade, with no configuration edited. none is the
way back.
Setting both MAILWOMAN_CANDIDATE_DB and MAILWOMAN_WOF_DB is not an error, and the candidate
backend wins. With a reachable candidate.db, mailwoman parse --resolve and mailwoman geocode
need no gazetteergazetteerA geographical index that maps place names and postcodes to real-world coordinates. Mailwoman uses a custom-built Who's On First (WOF) SQLite database as its gazetteer — the 'atlas' half of the grammar/atlas architecture. path at all. mailwoman registry run is the exception: it checks for
MAILWOMAN_WOF_DB or --resolve-db at startup and refuses to run without one, then ignores the path
it insisted on and resolves against the candidate database anyway. Give it any valid path to get past
the check.
The batchbatch sizeHow many examples the model processes before each parameter update. Larger batches give smoother gradients but cost more memory; gradient accumulation simulates a big batch on a small GPU. cap has two values, and both are correct. @mailwoman/api used as a library defaults to
500; mailwoman serve passes MAILWOMAN_BATCH_MAX, which defaults to 1000.
Precedence
A command-line flag beats an environment variable, which beats the built-in default. The flag names are on CLI; each flag's description names the variable it falls back to.
--resolve-db <path> > $MAILWOMAN_WOF_DB > error, with the fix printed
--candidate-db <path> > $MAILWOMAN_CANDIDATE_DB > <data root>/wof/candidate.db > the search backend
--data-root <path> > $MAILWOMAN_DATA_ROOT > a built-in path
The candidate row has one wrinkle the other two do not. Each position is used only if the file it
names is on disk, so a stale $MAILWOMAN_CANDIDATE_DB pointing at a deleted file does not fall
through to the convention path — it resolves to nothing and you land on the search backend. And
none at either of the first two positions is a pin, not a path: it stops the search there.
A .env file in the working directory is read once at startup and the live environment layerslayerOne transformer block — attention plus a feed-forward network, with normalization and residual connections — applied to every position. Stacking layers lets the model build up richer representations; Mailwoman's encoder has 6. on top
of it, so an exported variable beats a .env entry.
Behavior defaults
Every mechanism below is on by default. Each cleared a gate against the shipped modelneural classifierThe machine learning model at the core of Mailwoman's parser — a transformer encoder (~30M parameters) trained from scratch to do BIO token classification over addresses. It learns the 'grammar' of address formats; the gazetteer supplies the 'atlas.' on the first-class localeslocaleThe combination of language and country an address comes from. en-US and fr-FR are the locales Mailwoman ships weights for. before it was promoted, so the defaults are the measured configuration and turning one off is the change that needs a reason. Each is an option, not an environment variable.
| Mechanism | Where | Effect | Turn it off when |
|---|---|---|---|
spanRescore | ResolveOpts | On an UNRESOLVED tree only, recovers a localitylocalityThe city / town / settlement component of an address: a populated place sitting between region and neighborhood in the hierarchy. the subword tokenizertokenizerThe component that converts a raw address string into a sequence of numeric token IDs the model can process. Mailwoman's tokenizer is a SentencePiece unigram model trained specifically on postal addresses. split | You need output identical to a build without it |
postcodeConsistency | ResolveOpts | A resolved postcodepostcodeThe country-specific postal code (US ZIP, French code postal, etc.). Mailwoman handles postcode parsing entirely by rule classifier — a regex problem, not an ML one. point pulls a same-named localitylocalityThe city / town / settlement component of an address: a populated place sitting between region and neighborhood in the hierarchy. to the right one | Your postcodespostcodeThe country-specific postal code (US ZIP, French code postal, etc.). Mailwoman handles postcode parsing entirely by rule classifier — a regex problem, not an ML one. are unreliable |
hierarchyCompletion | ResolveOpts | Recovers a localitylocalityThe city / town / settlement component of an address: a populated place sitting between region and neighborhood in the hierarchy. dropped when one name plays two administrative roles | Never, in normal use |
parentFallback | ResolveOpts | Retries once without the parent constraint when a filtered lookup comes back empty | Never, in normal use |
adminCoherence | ResolveOpts, GeocodeDeps | Picks the administratively consistent combination rather than the most populous | You want the older population-first ranking |
placeCountry | CreateRuntimePipelineOpts, GeocodeDeps | A confident whole-string countrycountryThe top-level address component (an ISO country). Closed-vocabulary, so it is best handled by a deterministic matcher feeding a proposal rather than a retrained model head. guess biases ranking. It never filters | You already pin the countrycountryThe top-level address component (an ISO country). Closed-vocabulary, so it is best handled by a deterministic matcher feeding a proposal rather than a retrained model head. and want no prior at all |
hardPlaceCountry | CreateRuntimePipelineOpts, GeocodeDeps | Promotes that guess to a filter, inside a coveragecoverageThe fraction of a population or region for which a data source has real, non-placeholder entries — e.g. 47% rooftop coverage on Texas addresses. Distinct from accuracy on the rows that are present. safelist | You geocode outside the safelist and want recallrecallOf the spans whose gold label is a given tag, the fraction the model found. High recall means few misses. Paired with precision to compute F1. over precisionprecisionOf the spans the model labeled as a given tag, the fraction it got right. High precision means few false positives. Paired with recall to compute F1. |
normalizeCase | pipelinestaged pipelineMailwoman's runtime architecture: a sequence of pure-function stages (normalize → query-shape → locale-gate → kind-classifier → phrase-grouper → classifier → decoder) connected by typed handoffs. Each stage is published as its own npm package., classifier, GeocodeDeps | Title-cases detected all-caps ASCII input before the modelneural classifierThe machine learning model at the core of Mailwoman's parser — a transformer encoder (~30M parameters) trained from scratch to do BIO token classification over addresses. It learns the 'grammar' of address formats; the gazetteer supplies the 'atlas.' | Your input's casing carries meaning |
enforceWordConsistency | the pipelinestaged pipelineMailwoman's runtime architecture: a sequence of pure-function stages (normalize → query-shape → locale-gate → kind-classifier → phrase-grouper → classifier → decoder) connected by typed handoffs. Each stage is published as its own npm package.'s classify call | Arbitrates disagreeing tags inside one word | You call the classifier directly and want raw per-tokentokenOne word or subword in the tokenized input. For the neural classifier, tokens come from SentencePiece (subword units); for the rule classifiers, tokens are whitespace- and punctuation-separated words. labelscomponent tagOne of the 25 labels in Mailwoman's address schema — street, locality, region, postcode, house_number, unit, po_box, country, venue, intersection, and others. Each parsed span carries exactly one component tag. |
postcodeRepair | the pipelinestaged pipelineMailwoman's runtime architecture: a sequence of pure-function stages (normalize → query-shape → locale-gate → kind-classifier → phrase-grouper → classifier → decoder) connected by typed handoffs. Each stage is published as its own npm package.'s classify call | A deterministic postcodepostcodeThe country-specific postal code (US ZIP, French code postal, etc.). Mailwoman handles postcode parsing entirely by rule classifier — a regex problem, not an ML one. repair pass | You call the classifier directly. It is off there by default |
spanProposer | classifier config | SpanspanA contiguous range of characters or tokens in the input string, tagged with an address component type (street, locality, postcode, etc.). Parsed addresses are represented as collections of spans, possibly nested in a tree.-proposal priors from StagestageOne of the dataflow stages in the runtime pipeline (normalize, locale gate, kind classify, phrase group, token classify, sequence correct, reconcile, resolve). Distinct from tier (model vocabulary) and phase (plan milestone). 2.7 | You need output identical to a build without it |
poiQueryKind | CreateRuntimePipelineOpts | Detects a POIpoint of interest (POI). A named place that is not strictly an address — landmark, transit stop, venue, amenity, or franchise. Mailwoman tags these as venue and resolves them through the gazetteer. query and extracts its intent, without executing it | You only ever parseaddress parsingThe process of decomposing a free-text postal address string into structured components — house number, street name, locality, region, postcode, and country — so a geocoder can resolve them to coordinates. addresses and want the earlier kind classification |
| GazetteergazetteerA geographical index that maps place names and postcodes to real-world coordinates. Mailwoman uses a custom-built Who's On First (WOF) SQLite database as its gazetteer — the 'atlas' half of the grammar/atlas architecture. index auto-load | CreateRuntimePipelineOpts.fst | Loads the index from the classifier's weightsparameterA single learned number inside a model — one weight or bias. Mailwoman's encoder has roughly 30 million of them; training is the search for good values. package and biases emissions | You need output identical to a build without the index |
Two mechanisms are off by default and worth knowing about:
| Mechanism | Where | Effect | Turn it on when |
|---|---|---|---|
calibrate | ParseOpts | Maps raw spanspanA contiguous range of characters or tokens in the input string, tagged with an address component type (street, locality, postcode, etc.). Parsed addresses are represented as collections of spans, possibly nested in a tree. confidence through the shipped calibration table | You threshold on confidence. See Library API |
addressPoints, interpolation | ResolveOpts | The rooftoprooftopGeocoding precision at the building or parcel level — coordinates within a few meters — the highest tier of the geocode cascade. Sourced from address-point and situs data. and interpolationinterpolationA geocoding technique that estimates a coordinate along a street segment based on the house number range. Used as the middle tier of Mailwoman's geocode cascade when exact address-point data is unavailable. coordinate tiers | You have pulled the streetstreetThe named linear feature along which house numbers are ordered. Decomposes into a name plus street affixes; one of the Tier 2 fine labels. shardsshardA partial output file of the corpus build, written in Parquet format. The training pipeline streams shards row by row. for your regionregionThe first-level administrative subdivision of a country — a US state, a French region, a province. The component between country and locality. |
The coordinate tiers are gated on data rather than on a measurement. They stay off because the shardsshardA partial output file of the corpus build, written in Parquet format. The training pipeline streams shards row by row. are a 41.3 GB download for the United States, not because they cost accuracy.
For every boolean option above, false is the disable signal and it is not the same as omitting the
option: omitting means "give me the default", while false means "run as though this mechanism did
not exist". The three non-boolean options work differently. calibrate takes a calibrator function,
and addressPoints and interpolation take lookup objects, so for those three, omitting is the
only way to leave the mechanism off.
Errors
| Condition | Message or symptom | Next step |
|---|---|---|
| No gazetteergazetteerA geographical index that maps place names and postcodes to real-world coordinates. Mailwoman uses a custom-built Who's On First (WOF) SQLite database as its gazetteer — the 'atlas' half of the grammar/atlas architecture. reachable on a resolving command | A startup error naming $MAILWOMAN_WOF_DB and --resolve-db | Run mailwoman data pull candidate. registry run also wants a --resolve-db it then ignores |
candidate.db downloaded but a command still uses the search backend | $MAILWOMAN_CANDIDATE_DB is set to a path that is not there | Unset it. A variable naming a missing file does not fall through to the convention path |
| A reverse geocode reports approximate containment | MAILWOMAN_WOF_POLYGONS_DB is unset | Point it at the polygon sidecar |
A batchbatch sizeHow many examples the model processes before each parameter update. Larger batches give smoother gradients but cost more memory; gradient accumulation simulates a big batch on a small GPU. request answers 413 batch too large | The request exceeded MAILWOMAN_BATCH_MAX | Raise the variable, or chunk the request |
| A variable you set has no effect | It is outside this page's boundary | Check the table above. Repository-only variables do nothing installed |
mailwoman doctor reports which of these are resolved, and prints the one command that fixes each
gap.
Rationale
The parsingaddress parsingThe process of decomposing a free-text postal address string into structured components — house number, street name, locality, region, postcode, and country — so a geocoder can resolve them to coordinates. and geocodinggeocodingThe process of converting an address into geographic coordinates (latitude and longitude). Mailwoman geocodes in a multi-tier cascade: exact address-point match → street interpolation → locality centroid. Each tier is progressively coarser but more widely available. commands gate resolution on an environment variable rather than on a file existing at a conventional path, because adopting a database silently would change every result on the machine that downloaded it. A geocoder that answers differently depending on what happens to be on disk is not one you can reason about. The cost is the step this page keeps repeating: download, then export. The two drop-in servers take the opposite trade and read the convention path, because a drop-in that needs a second setup step is not a drop-in.
The behavior defaults are on rather than opt-in because a default nobody turns on is a mechanism that
does not exist. Each one shipped on by default only after clearing a gate against the shipped modelneural classifierThe machine learning model at the core of Mailwoman's parser — a transformer encoder (~30M parameters) trained from scratch to do BIO token classification over addresses. It learns the 'grammar' of address formats; the gazetteer supplies the 'atlas.',
and turning one off takes false rather than a rebuild.
The environment schema is broader than this page because its split is about logging safety — a variable is in the non-secret half when printing it cannot leak a credential. That is the right axis for a log line and the wrong axis for a configuration reference, so this page draws the line somewhere else and says where.
See also
- CLI — every flag, including the ones that override these variables.
- Library API — the options tables these defaults belong to.
- Improve geocode precision — turning the coordinate tiers on.
- Tune confidence thresholds — turning calibration on.