Skip to main content

Library API

Scope

This page describes the five entry points a consumer calls from TypeScript: createRuntimePipeline, NeuralAddressClassifier, the 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. functions in mailwoman/geocode-core, 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. iterator in mailwoman/geocode-stream, and createCalibrator. Each section carries a full runnable file and the output that file produced.

It does not describe the 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). packages (@mailwoman/normalize, @mailwoman/query-shape, @mailwoman/locale-gate, @mailwoman/kind-classifier, @mailwoman/phrase-grouper). Those are wired by createRuntimePipeline with production defaults, and a consumer who calls them directly is building a 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. rather than using one. For the command line, see CLI. For HTTP, see HTTP APIs.

Every example below ran under Node 26 against the packages in this repository at the version this page documents. The options tables are a subset: bias-magnitude and gate-threshold knobs that exist to be swept during evaluationevalRunning the model against a held-out golden dataset and computing per-component F1, exact-match, calibration, and resolved-coordinate error. are omitted, and their defaults are the shipped behavior. Where a table is a subset, it says so and says what it left out.

Import map

mailwoman exports eight import paths, one of which takes a wildcard suffix. On Node the package serves TypeScript source directly, so no build step stands between an installed package and a running script.

ImportWhat it carries
mailwomancreateRuntimePipeline, plus everything @mailwoman/core re-exports
mailwoman/geocode-coregeocodeAddress, parseForGeocode, ShardProvider, the result types
mailwoman/geocode-streamgeocodeStream
mailwoman/resolver-backendcreateResolverBackend, resolveCandidateDBPath, data-root path helpers
mailwoman/cli-kitInk and Pastel helpers for building a command
mailwoman/test-kitThe parser test helpers
mailwoman/poi-overpassOverpassQL export for a matched 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. intent
mailwoman/gazetteer-pipelineGazetteergazetteerA 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. build internals, plus a wildcard subpath for its modules

geocodeAddress and its result types are reachable only through mailwoman/geocode-core. They are not re-exported from the bare specifier.

createRuntimePipeline

function createRuntimePipeline(
opts?: CreateRuntimePipelineOpts
): (raw: string, runOpts?: PipelineOpts) => Promise<PipelineResult>

The factory is synchronous and the returned function is async. Every lazy load — 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, 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, 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.-morphology matcher, 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.-evidence index — happens on the first call to the returned function, not in the factory.

Options

Two stagesstageOne 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). take an injected implementation. The rest carry production defaults.

OptionTypeDefaultEffect
classifierAddressClassifiernoneStagestageOne 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). 3. Without it 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. runs the structural stagesstageOne 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). only
resolverResolvernoneStagestageOne 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). 6. Without it the tree carries no coordinates
fstFSTMatcher or falseauto-loadGazetteergazetteerA 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. emission priorsemission priorA log-probability bias injected into the model's emission logits from an external signal — gazetteer frequency, an FST, a Wikipedia-importance score — combined with the learned weights at decode time.. Loaded 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
streetMorphologyFSTMatcher or falseauto-loadSignal source for the street-context gatestreet-context gateThe decode-time seam that zeroes locality evidence on inputs with no street-painter hits — bare lookups must not have city names painted into street structure. Every measured evidence win class carries street words, so the gate costs nothing.
streetEvidenceStreetLocalityEvidence, falseauto-loadReranks 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. on atlas-confirmed evidence. Requires a 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.-headattention headOne of several parallel attention computations in a layer, each free to focus on a different kind of relationship between tokens. Their outputs are concatenated — 'multi-head attention'. Mailwoman uses 4 heads. 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.'
placeCountryfunction or falsethe bundled coarse placerA confident 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 becomes a soft ranking prior. It never filters
poiQueryKindboolean or { poiDatabasePath }true (intent only)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. The object form also executes it
normalizeCasebooleanonTitle-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.'
hardPlaceCountrybooleanonPromotes a confident 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 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
hardCountrySafelistReadonlySet<string>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.'s own manifestWhich countries the hard filter applies to. Falls back to a built-in list
detectLocalefunction@mailwoman/locale-gateStagestageOne 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
classifyKindfunction@mailwoman/kind-classifierStagestageOne 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.5. An explicit override wins over the 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.-aware default
groupPhrasesfunction@mailwoman/phrase-grouperStagestageOne 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

Passing false to fst, streetMorphology, streetEvidence, placeCountry or poiQueryKind suppresses both the auto-load and any explicit value, which is how a caller gets output identical to a build without that mechanism.

Per-call options

The second argument to the returned function is PipelineOpts. A per-call value overrides the factory default.

FieldTypeDefaultEffect
localestringderived by the locale gatelocale gateStage 2 of the runtime pipeline: rule-based locale detection from the query shape's script and known-format signals. Returns a LocaleHint with the top candidate and alternatives, surfacing disagreement with an explicit --locale flag.BCP-47 tag, for example en-US
inputMode"fragmented" or "formatted"derived from the kindWhich registerinput modeThe Decision-A register switch: 'fragmented' (human-typed fragments — feeds the evidence channels) vs 'formatted' (complete records — runs the trained absence identity). Explicit on CLI/API; per-endpoint defaults (batch→formatted, autocomplete→fragmented); kind-derived otherwise. the evidence channelsevidence channelA dedicated model input that injects externally computed per-token features (confidence-scaled, own projection) at the embedding layer: postcode anchor, gazetteer, country, street-type, locality-surface. The clue informs; the model decides (model-first). run in
resolveOptsResolveOptsnonePassed through to 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.
normalizeCasebooleanthe factory valueOverrides the factory default for this call
hardPlaceCountrybooleanthe factory valueOverrides the factory default for this call
forceFullPipelinebooleanoffDisables the structural fast paths. A debugging aid
jointReconcilebooleanoffRetired as a default in 2026-06. Kept for comparison runs
signalAbortSignalnoneCancels the call

Return shape

FieldTypeMeaning
inputstringThe raw string as passed
normalizedNormalizedInputLiteStagestageOne 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). 1 output
queryShapeQueryShapeLiteCharacter classcharacter classA token's character category — digit, alpha, CJK, Cyrillic, Arabic, mixed — used by the query-shape stage as a structural signal for locale and kind inference., segmentation, known-format hits
localeLocaleHintTag, confidence, alternatives, and whether it was detected or given
kindQueryKindResultThe query kindquery kindThe coarse category the kind classifier assigns to the whole input — postcode_only, locality_only, structured_address, intersection, po_box, landmark, or vague — used to route processing., for example structured_address
phraseProposalsPhraseProposal[]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 proposals. Empty when a fast path skipped the 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).
treeAddressTreeThe 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.
poiIntentPOIIntentOutcome or absentPresent only when path is "poi"
timingRecord<string, number>Milliseconds per 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).
path"fast-path", "full", or "poi"Which route the input took

Example

import { decodeAsJSON } from "@mailwoman/core/decoder"
import { NeuralAddressClassifier } from "@mailwoman/neural"
import { createRuntimePipeline } from "mailwoman"

const classifier = await NeuralAddressClassifier.loadFromWeights({ locale: "en-US" })
const pipeline = createRuntimePipeline({ classifier })
const result = await pipeline("350 5th Ave, New York, NY 10118")

console.log(JSON.stringify(decodeAsJSON(result.tree), null, 2))
console.log(result.kind.kind, "|", result.path, "|", result.locale.locale)

Output:

{
"region": "NY",
"locality": "New York",
"street": "5th",
"house_number": "350",
"street_suffix": "Ave",
"postcode": "10118"
}
structured_address | full | en-US

decodeAsJSON flattens the tree to a tag-to-value object and drops the containment nesting. Read result.tree directly when the nesting matters.

NeuralAddressClassifier

Reach for the classifier directly in three cases: you need the labelcomponent 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. distribution rather than the argmax tree, you are serving several localeslocaleThe combination of language and country an address comes from. en-US and fr-FR are the locales Mailwoman ships weights for. from one process and want to hold each 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.' open, or you are running 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.' in an environment createRuntimePipeline does not fit. For a single 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., 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. is the shorter path and it applies the structural stagesstageOne 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). 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.' was trained beside.

static async loadFromWeights(opts?: {
locale?: string
modelPath?: string
tokenizerPath?: string
modelCardPath?: string
tier?: "server" | "pocket"
cacheRoot?: string
postcodeAnchorLookup?: AnchorLookup
executionProviders?: string[]
intraOpNumThreads?: number
}): Promise<NeuralAddressClassifier>

Resolution runs in one order: an explicit cacheRoot holding both binaries, then explicit paths in opts, then the installed @mailwoman/neural-weights-<locale> package, then the user-level 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. cache that mailwoman parse --download-weights writes, then a single actionable error naming all of them. A package that resolves but ships no binaries fails loudly rather than falling through to the cache — that is the metadata-only checkout trap, and silence there would look like a working install.

The method is Node-only: it imports onnxruntime-node and node:fs dynamically. In a browser, use loadNeuralClassifierFromURLs from @mailwoman/neural/web-loader. Both runtimes are optional peer dependencies, so whichever side you are on, install it yourself: onnxruntime-node on a server, onnxruntime-web in a browser build.

intraOpNumThreads defaults to 4, which is a cap rather than a core count. Measured over 120 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. on 2026-08-03: one threadthreadA parallel workstream within a release. Threads compose; they are not sequential milestones like phases. costs 18.3 ms per 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., two cost 12.5 ms, four cost 9.2 ms, and all cores cost 9.3 ms — so the cap is free. Pin it to 1 only when you are running several classifier instances in one process and want to bound total threadthreadA parallel workstream within a release. Threads compose; they are not sequential milestones like phases. count, and expect twice the latency.

One classifier instance holds one localelocaleThe combination of language and country an address comes from. en-US and fr-FR are the locales Mailwoman ships weights for.. Construct one per localelocaleThe combination of language and country an address comes from. en-US and fr-FR are the locales Mailwoman ships weights for. you serve.

MethodReturnsUse it for
parse(text, opts?)Promise<AddressTree>The nested tree
parseJSON(text, opts?)Promise<Partial<Record<ComponentTag, string>>>A flat tag-to-value object
parseTuples(text, opts?)Promise<Array<[ComponentTag, string]>>Ordered tag/value pairs
parseXML(text, opts?)Promise<string>An XML projection
parseWithLogits(text, opts?)Promise<ParseWithLogitsResult>The tree plus 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. logitslogitA raw, unnormalized per-label score the model outputs before softmax. Priors and biases are added in logit space, then softmax turns logits into probabilities. and piece offsets
traceParse(text, opts?)Promise<NeuralParseTrace>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).-by-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). diagnostics

Three readonly properties surface paths and grammar the caller's 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. consumes: fstPath, streetMorphologyPath, and spanGrammar. @mailwoman/neural deliberately carries no 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. dependency, so it reports where 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 is and leaves deserialization to the caller. createRuntimePipeline reads all three.

Parse options

These are the fields of ParseOpts a consumer sets. ParseOpts has 20 fields; the ten omitted here are the FSTFST (finite-state transducer). A compact automaton that reads an input sequence and emits an output sequence. Mailwoman encodes gazetteer names and street affixes as FSTs for fast prefix matching and prior injection without search overhead. bias magnitudes and gate thresholds (fstBiasScale, fstStreetContextGate and their siblings, four of which the source marks internal), the queryShapeBiasScale magnitude, the morphology-prior override, the pre-v4.4.0 bridgePunctuationGaps switch, and trailingLocality, which is deprecated and scheduled for deletion at the next major.

FieldTypeDefaultEffect
fstFSTMatcherLikenoneGazetteergazetteerA 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. matches become additive emission biasesadditive biasA logit adjustment added before softmax from a prior or external knowledge source, typically soft-capped so it influences but never overrides the model's prediction. The mechanism behind shallow fusion.
inputMode"fragmented" or "formatted""fragmented"Which registerinput modeThe Decision-A register switch: 'fragmented' (human-typed fragments — feeds the evidence channels) vs 'formatted' (complete records — runs the trained absence identity). Explicit on CLI/API; per-endpoint defaults (batch→formatted, autocomplete→fragmented); kind-derived otherwise. the evidence channelsevidence channelA dedicated model input that injects externally computed per-token features (confidence-scaled, own projection) at the embedding layer: postcode anchor, gazetteer, country, street-type, locality-surface. The clue informs; the model decides (model-first). run in
queryShapeQueryShapeLikenoneKnown-format hits become additive emission biasesadditive biasA logit adjustment added before softmax from a prior or external knowledge source, typically soft-capped so it influences but never overrides the model's prediction. The mechanism behind shallow fusion.
normalizeCasebooleanonTitle-cases detected all-caps ASCII input
calibrateCalibratoroffMaps 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 a calibration table
enforceWordConsistencyboolean or WordConsistencyOptsonPer-word BIO vote, skipping byte-fallback words
postcodeRepairbooleanoffDeterministic 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
unitRepairbooleanoffDeterministic unitunitA subdivision of a building — apartment, suite, floor — that refines a street address. Mailwoman's unit component; a designator plus identifier forms a subpremise. repair pass
spanProposerbooleanonSpanspanA 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
addressSystemConventions"auto" or a system codefrom the 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.Which address-system conventions apply
placetypePairPlacetypePairPriorOpts or falsethe 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's pair indexOmitting it inherits the package. Only false disables it

The table above is the classifier's own defaults, and createRuntimePipeline pins two of them on every call it makes: postcodeRepair: true, and the shipped word-consistency settings. enforceWordConsistency is on either way — the pin only removes the caller's ability to change it mid-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.. postcodeRepair is the one that differs: off on a bare classifier call, on through 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..

Wiring the gazetteer index on a bare call

fst is the option a bare classifier call has to pass, and the one whose absence is hardest to notice. 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 turns a 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. match into an additive emission biasadditive biasA logit adjustment added before softmax from a prior or external knowledge source, typically soft-capped so it influences but never overrides the model's prediction. The mechanism behind shallow fusion., and it is what tells 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.' that a bare 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. naming a real place is a localitylocalityThe city / town / settlement component of an address: a populated place sitting between region and neighborhood in the hierarchy. rather than a streetstreetThe named linear feature along which house numbers are ordered. Decomposes into a name plus street affixes; one of the Tier 2 fine labels.. Nothing loads it for you outside createRuntimePipeline: 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. reads the index out of 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 on its first call and passes it to every 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., while a classifier you call directly receives no index at all. geocodeAddress does not wire it either, and GeocodeDeps has no field for it.

The 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. still succeeds without it. It is a prior, not a 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)., so most inputs are unaffected and the failure is silent — which is why this section exists rather than a note on the table row.

Wire it from the path the classifier already resolved. fstPath is optional, because a localelocaleThe combination of language and country an address comes from. en-US and fr-FR are the locales Mailwoman ships weights for. overlay that ships 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. index leaves it undefined, so guard it rather than reading it straight into readFileSync.

import { readFileSync } from "node:fs"

import { NeuralAddressClassifier } from "@mailwoman/neural"
import { deserializeFST } from "@mailwoman/resolver-wof-sqlite/fst-serialize"

const classifier = await NeuralAddressClassifier.loadFromWeights({ locale: "en-US" })

// `fstPath` is optional — a locale overlay that ships no gazetteer index leaves it undefined.
const fst = classifier.fstPath ? deserializeFST(readFileSync(classifier.fstPath)) : undefined

for (const input of ["Hollywood", "big spring"]) {
console.log(input)
console.log(" without fst:", JSON.stringify(await classifier.parseJSON(input)))
console.log(" with fst: ", JSON.stringify(await classifier.parseJSON(input, { fst })))
}

Output:

Hollywood
without fst: {"street":"Hollywood"}
with fst: {"locality":"Hollywood"}
big spring
without fst: {"street":"Big","street_suffix":"Spring"}
with fst: {"locality":"Big Spring"}

resolveWeights from @mailwoman/neural/weights returns the same fstPath without constructing a classifier. It is synchronous, so do not await it, and its fstPath is optional for the same reason.

This is the main reason to prefer 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. for a single 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.: it wires the index, 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.-morphology gate and 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.-evidence rerank, and a bare classifier call gets none of the three.

Geocoding

mailwoman/geocode-core turns a string into a coordinate with a resolution tier and an uncertainty radius.

function geocodeAddress(input: string, deps: GeocodeDeps): Promise<GeocodeResult>

geocodeAddress always returns a result. With no coordinate shardsshardA partial output file of the corpus build, written in Parquet format. The training pipeline streams shards row by row. wired it returns the admin tier rather than failing. It throws only on a fatal 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. or resolve error, so 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. callers catch per row.

Dependencies

GeocodeDeps has 18 fields. The 16 below are the ones a consumer sets; osmShards and hardCountrySafelist are omitted as evaluationevalRunning the model against a held-out golden dataset and computing per-component F1, exact-match, calibration, and resolved-coordinate error. and build-time wiring.

FieldTypeDefaultEffect
classifierGeocodeClassifierrequiredThe parser
inputMode"fragmented" / "formatted"from the query kindquery kindThe coarse category the kind classifier assigns to the whole input — postcode_only, locality_only, structured_address, intersection, po_box, landmark, or vague — used to route processing.Which registerinput modeThe Decision-A register switch: 'fragmented' (human-typed fragments — feeds the evidence channels) vs 'formatted' (complete records — runs the trained absence identity). Explicit on CLI/API; per-endpoint defaults (batch→formatted, autocomplete→fragmented); kind-derived otherwise. the evidence channelsevidence channelA dedicated model input that injects externally computed per-token features (confidence-scaled, own projection) at the embedding layer: postcode anchor, gazetteer, country, street-type, locality-surface. The clue informs; the model decides (model-first). run in
resolverResolverrequiredThe 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. walk
shardsShardResolvernonePer-state 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. lookups
nationalShards(country) => StateShardsnonePer-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. shardsshardA partial output file of the corpus build, written in Parquet format. The training pipeline streams shards row by row., for example the French 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. shardshardA partial output file of the corpus build, written in Parquet format. The training pipeline streams shards row by row.
defaultCountrystringnoneScopes 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. to one 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.
biasproximity pointsnoneSoft re-rank toward a viewport or a user location
interpCalibrationnumber or a tablethe shardshardA partial output file of the corpus build, written in Parquet format. The training pipeline streams shards row by row.'s own valueMultiplier on the 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. tier's uncertainty radius
normalizeCasebooleanonTitle-cases detected all-caps input
normalizeInputbooleanonRuns the normalizenormalizeStage 1 of the runtime pipeline: deterministic input preprocessing (Unicode NFC, punctuation normalization, whitespace collapse). Returns a NormalizedInput with an offsetMap that maps normalized positions back to the raw input. 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).
placeCountryfunction or falsethe bundled placerSoft 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. prior
hardPlaceCountrybooleanonHard 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. filter inside the 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
adminCoherencebooleanonJoint admin-consistency re-pick
postcodeCountryPriorbooleanonPostcodepostcodeThe 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. shape informs 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.
retryAlternateRegisterbooleanonRetries the 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. in the other input registerinput modeThe Decision-A register switch: 'fragmented' (human-typed fragments — feeds the evidence channels) vs 'formatted' (complete records — runs the trained absence identity). Explicit on CLI/API; per-endpoint defaults (batch→formatted, autocomplete→fragmented); kind-derived otherwise. on a weak result
parsedTreeAddressTreenoneSkips the 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. when you already have the tree

Resolution tiers

The tier states which artifact produced the coordinate, best first. Gate any house-grade rendering on the tier, not on the presence of house_number: the parsed 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. is populated whatever tier answered.

TierCoordinate sourceuncertainty_m
address_pointRooftoprooftopGeocoding 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. or parcelparcelA property polygon or record carrying a situs (site) address and often a separate owner mailing address. County GIS parcel aggregations are a training source for address-point variety and situs-vs-owner divergence. centroidA small floor, about 1 m
interpolatedHouse-number estimate along a streetstreetThe named linear feature along which house numbers are ordered. Decomposes into a name plus street affixes; one of the Tier 2 fine labels.The calibrated bracket 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.
streetStreetstreetThe named linear feature along which house numbers are ordered. Decomposes into a name plus street affixes; one of the Tier 2 fine labels. centroid for a streetstreetThe named linear feature along which house numbers are ordered. Decomposes into a name plus street affixes; one of the Tier 2 fine labels. queryHalf 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. bounding-box diagonal
adminAdmin centroid from 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.null — no sub-localitydependent localityA sub-locality (neighborhood or borough) hierarchically inside a larger locality — e.g. Brooklyn within New York City. Provides finer geographic specification below the primary locality. estimate exists

Result

FieldTypeMeaning
inputstringThe raw string as passed
lat, lonnumber or nullThe resolved coordinate
resolution_tierResolutionTierWhich tier produced it
uncertainty_mnumber or nullRadius in meters. null on the admin tier
localitystring or nullParsed localitylocalityThe city / town / settlement component of an address: a populated place sitting between region and neighborhood in the hierarchy. 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.
regionstring or nullParsed regionregionThe first-level administrative subdivision of a country — a US state, a French region, a province. The component between country and locality. 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.
postcodestring or nullParsed 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. 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.
house_numberstring or nullParsed house numberhouse numberThe numeric or alphanumeric identifier of a building on a street. Mailwoman's house_number component; its position relative to the street name flips between locales., whatever the tier
streetstring or nullParsed streetstreetThe named linear feature along which house numbers are ordered. Decomposes into a name plus street affixes; one of the Tier 2 fine labels., reassembled from prefix, base and suffix
venuestring or nullParsed venuevenueA named, non-address place — a business, building, park, or stadium. Mailwoman's free-text point-of-interest component, added as a Tier 2 fine label. 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.
dependent_localitystring or nullParsed sub-localitydependent localityA sub-locality (neighborhood or borough) hierarchically inside a larger locality — e.g. Brooklyn within New York City. Provides finer geographic specification below the primary locality. 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.
countryCodestring or nullISO 3166 alpha-2 of the deepest resolved node
hierarchyarray, most specific firstThe resolved admin chain, each with a name and a 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. place ID
candidatesarray, winner firstRanked alternatives for the primary place

hierarchy is the resolved view and carries only nodes 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. decorated. The flat 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. fields are the parsed view. The two disagree whenever the 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. found something 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. did not.

Shards

ShardProvider opens per-state 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. databases on demand, caches the handles, and swaps them atomically when the data release changes.

class ShardProvider {
constructor(factory: ShardLookupFactory, dataRoot: string)
readonly for: ShardResolver
versions(): DataReleaseManifest | null
reload(): DataReleaseManifest | null
close(): void
}

The constructor is positional. factory is the @mailwoman/resolver-wof-sqlite module namespace in practice. for is a property rather than a method so it can be passed unbound as deps.shards.

Example

This file resolves against a downloaded candidate.db with no 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. wired, so it answers on the admin tier. It also runs without 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. emission priorsemission priorA log-probability bias injected into the model's emission logits from an external signal — gazetteer frequency, an FST, a Wikipedia-importance score — combined with the learned weights at decode time.: geocodeAddress never wires the index, and GeocodeDeps has no field for it — see Wiring the gazetteer index on a bare call.

import { NeuralAddressClassifier } from "@mailwoman/neural"
import { createWOFResolver } from "@mailwoman/resolver"
import { WOFCandidateTableLookup } from "@mailwoman/resolver-wof-sqlite"
import { geocodeAddress } from "mailwoman/geocode-core"

const classifier = await NeuralAddressClassifier.loadFromWeights({ locale: "en-US" })
// Replace <CANDIDATE_DB> with the path `mailwoman data pull candidate` printed.
const lookup = new WOFCandidateTableLookup({ databasePath: "<CANDIDATE_DB>" })
const resolver = createWOFResolver(lookup)

const result = await geocodeAddress("350 5th Ave, New York, NY 10118", { classifier, resolver })

console.log(JSON.stringify(result, null, 2))
lookup.close()

Output:

{
"input": "350 5th Ave, New York, NY 10118",
"lat": 40.694457,
"lon": -73.93045,
"resolution_tier": "admin",
"uncertainty_m": null,
"locality": "New York",
"region": "NY",
"postcode": "10118",
"house_number": "350",
"street": "5th Ave",
"venue": null,
"dependent_locality": null,
"countryCode": "US",
"hierarchy": [
{
"tag": "locality",
"value": "New York",
"name": "New York",
"lat": 40.694457,
"lon": -73.93045,
"placeID": "wof:85977539"
},
{
"tag": "region",
"value": "NY",
"name": "New York",
"lat": 42.921227,
"lon": -75.596537,
"placeID": "wof:85688543"
}
],
"candidates": [
{
"name": "New York",
"tag": "locality",
"lat": 40.694457,
"lon": -73.93045,
"countryCode": "US",
"placeID": "wof:85977539"
}
]
}

Batch

function geocodeStream(
records: AsyncIterable<SourceRecord> | Iterable<SourceRecord>,
opts: GeocodeStreamOptions
): AsyncIterableIterator<SourceRecord>

geocodeStream runs a worker pool over a record stream and yields enriched records in completion order, not input order. 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. once per row and shares the tree between the returned components and the geocode.

OptionTypeDefaultEffect
mappingColumnMappingrequiredWhich columns hold the address
geocodeGeocodeStreamConfigrequiredwofDBPath, dataRoot, locale, country
concurrencynumberMath.min(4, availableParallelism())Worker count
batchSizenumber32Records handed to a worker at a time
workerstring or URLthe bundled workerA replacement worker entry point

One constraint decides whether this function fits your setup. Its worker constructs a WOFSqlitePlaceLookup directly, so it resolves against 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 and cannot use a candidate.db. If your setup is the candidate.db one the tutorials teach, run your own pool over geocodeAddress instead — Batch geocode at volume has that loop.

Concurrency is low on purpose. A measured sweep over a single 4 GB database on a 16-core host peaked at two workers, about 1.4 times baseline, and degraded above that.

Confidence

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. confidences from 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.' are under-confident. createCalibrator builds the mapping that corrects them.

function createCalibrator(table: CalibrationTable | CalibrationBin[]): Calibrator
type Calibrator = (rawConfidence: number) => number

The returned function clamps its input to the range 0 to 1, mapping a non-numeric input to 0. Below the first bin center and above the last it returns that bin's calibrated value. Between two centers it interpolates linearly. It is not a nearest-bin lookup, and it does not return the input unchanged anywhere.

The table ships inside each 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 as calibration.json, and a per-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. sibling ships as calibration-per-locale.json. The per-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. file has no top-level table key, so pass one of its tables entries to the bare-array form.

import { readFileSync } from "node:fs"

import { createCalibrator } from "@mailwoman/core/decoder"

// Replace <WEIGHTS_DIR> with your node_modules/@mailwoman/neural-weights-en-us directory.
const table = JSON.parse(readFileSync("<WEIGHTS_DIR>/calibration.json", "utf8"))
const calibrate = createCalibrator(table)

for (const raw of [0, 0.25, 0.5, 0.75, 0.9, 0.99, 1]) {
console.log(raw.toFixed(2), "->", calibrate(raw).toFixed(4))
}

Output:

0.00 -> 0.0444
0.25 -> 0.6341
0.50 -> 0.8258
0.75 -> 0.9354
0.90 -> 0.9631
0.99 -> 0.9908
1.00 -> 0.9908

A raw 0.50 is worth 0.83 after calibration, which is the under-confidence this table corrects. The curve saturates at 0.9908, the top bin's calibrated value, so a calibrated score never reaches 1.

Pass the calibrator per 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. as ParseOpts.calibrate. It is opt-in: omitting it leaves the raw softmaxsoftmaxThe function that converts a vector of logits into a probability distribution summing to 1, applied after priors and biases are added to the emission logits. confidences, which is the byte-stable default.

Errors

ConditionWhat happensNext step
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. package for a localelocaleThe combination of language and country an address comes from. en-US and fr-FR are the locales Mailwoman ships weights for. is absentloadFromWeights throws one actionable error naming the packagenpm install @mailwoman/neural-weights-<locale>
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. package resolves but 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.' fails to loadloadFromWeights throws with the underlying error preservedReinstall the package. A partial or truncated bundleevidence bundleThe pair of retrieval-augmented input channels (street-type + locality-surface) that feed lexicon membership as soft per-token evidence alongside the text. Shipped in 6.7.0; trained natively from step 0 in the from-scratch base line. is the usual cause
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. declares a channel the package does not shipThe classifier warns once and runs that channel offReinstall. A soft-fed channel changes accuracy, not correctness
createRuntimePipeline has no classifierThe 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. runs the structural stagesstageOne 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). only; tree may be emptyPass a classifier
createRuntimePipeline has no resolverThe tree carries no coordinatesPass a createWOFResolver instance
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 fails to deserializeA warning on stderr, and the 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. runs without 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. priorsReinstall 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. package
createCalibrator gets an empty tableThrows createCalibrator: empty calibration tablePass the parsed calibration.json, not an empty array
geocodeAddress hits a fatal 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. or resolve errorThrowsCatch per row. Every non-fatal case returns a result on the admin tier

Rationale

The classifier and 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. are the two stagesstageOne 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). with no default, and that is deliberate rather than unfinished. 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.' is a 39 MB download and 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. is 1.65 GB. A factory that acquired either implicitly would make import "mailwoman" an unpredictable amount of disk and network for a caller who wanted to 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. one string.

Everything else defaults on. Each mechanism that reached default-on 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., so the shipped defaults are the measured configuration and a deviation from them is the thing that needs justifying.

false rather than omission is the disable signal for the auto-loading options because omission has to keep meaning "give me the default". A caller who needs byte-identical output against a build without a mechanism has one unambiguous way to say so.

See also

  • CLI — the same 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. behind a command.
  • Component tags — what each tag in a 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. means.
  • Runtime flags — the environment variables these functions read.
  • Understand a parse — the same calls, walked through.
  • Tune confidence thresholds — using the calibrator against your own data.