Swap in a drop-in for an existing client
You have a service that already calls a geocoder. It builds Photon query strings, reads Nominatim's
jsonv2 result array, or posts to libpostallibpostalAn open-source C address parser used by Pelias. Mailwoman's rule-based v0 and neural classifier supersede it.'s /parse. Change that caller to use Mailwoman's own
/v1 API would be extra work.
Three packages accept those request formats instead. By the end of this page you will have the Photon-compatible server running against your own 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., a geopy client pointed at it by changing one argument, the Nominatim and libpostallibpostalAn open-source C address parser used by Pelias. Mailwoman's rule-based v0 and neural classifier supersede it. variants running the same way, and a table of which request parametersparameterA 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. each drop-in reads. The tutorial takes about thirty minutes, most of it spent downloading.
Prerequisites
Read the last two items before you start. They determine whether this page can answer your question.
- Node.js 24.18.0 or later, and about 1.7 GB of free disk.
jqfor thecurloutput below. Remove the pipe if you prefer to read the raw JSON.- Python with
geopyfor step 4, in a disposable virtual environment. Skip that step if your client is in another language. In any language, the change is one constructor argument. - 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 a 1,652,916,224-byte download, and it is not on npm. Step 1 fetches it once. Everything after step 1 runs locally.
- The default ports conflict with the servers you are replacing. The defaults are 2322 for Photon,
8080 for Nominatim and 8081 for libpostallibpostalAn open-source C address parser used by Pelias. Mailwoman's rule-based v0 and neural classifier supersede it.. Those are the same ports your existing servers use. This
page moves two of them with
--port, because ports 2322 and 8080 were in use on the machine used to verify it. Run the drop-in next to the original on a spare port to test a swap anyway, because you can compare the two answers before you switch. /reverseneeds a database this page does not download. Reverse 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. on the Photon and Nominatim drop-ins runs point-in-polygon over a 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 at<data-root>/db/wof/admin-global-priority.db.mailwoman data pulldoes not provide one, so/reversereturns an empty result until you add it. Step 3 shows that output so that you do not mistake it for a broken install. Most callers use forward 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., and it works from step 1.- None of the servers has authentication, and
--hostdefaults to0.0.0.0. Bind127.0.0.1or put the server behind your own ingress before you expose it on a shared network.
1. Pull the gazetteer once
All three packages read one data root. Set it, and check the plan before you start the transfer.
--dry-run prints the URL, the size and the destination without using the network:
export MAILWOMAN_DATA_ROOT=/tmp/mailwoman-data
npx mailwoman data pull candidate --dry-run
✓ candidate: gazetteer/2026-07-07a/candidate.db: [dry-run] 1652.9 MB
https://public.mailwoman.ai/mailwoman/gazetteer/2026-07-07a/candidate.db →
/tmp/mailwoman-data/wof/candidate.db
PASS (1/1 checks)
Then remove the flag and run the download:
npx mailwoman data pull candidate
▸ pull https://public.mailwoman.ai/mailwoman/gazetteer/2026-07-07a/candidate.db (~1652.9 MB) → /tmp/mailwoman-data/wof/candidate.db
[DEBUG] (mailwoman data): HEAD: https://public.mailwoman.ai/mailwoman/gazetteer/2026-07-07a/candidate.db
[DEBUG] (mailwoman data): 200 (uncached) HEAD: https://public.mailwoman.ai/mailwoman/gazetteer/2026-07-07a/candidate.db
export MAILWOMAN_CANDIDATE_DB=/tmp/mailwoman-data/wof/candidate.db
✓ candidate: gazetteer/2026-07-07a/candidate.db: content-length verified (1652.9 MB) →
/tmp/mailwoman-data/wof/candidate.db
PASS (1/1 checks)
The paths in the transcripts on this page use the data root from the verification machine, so yours
will differ. The file is saved at <data-root>/db/wof/candidate.db, and every entry point finds it
there automatically, including the drop-ins, mailwoman geocode and mailwoman serve. The export
line that the pull prints is left over from 8.6.0, when only the drop-ins had that fallback. Run
it has no effect. Pass --candidate-db <path> if your copy is stored elsewhere.
Re-running the pull is safe. If the file is already on disk, it reports already present … skipped
and downloads no file, so you can leave this command in a provisioning script.
2. Start the Photon-compatible server
npx @mailwoman/photon serve --port 2323
[resolver] candidate-table backend (demo-parity, population-first): /tmp/mailwoman-data/wof/candidate.db
[@mailwoman/photon] listening on http://0.0.0.0:2323
wof: (none found — set MAILWOMAN_WOF_DB)
resolver: candidate gazetteer (worldwide) — /tmp/mailwoman-data/wof/candidate.db
cors: enabled (Access-Control-Allow-Origin: *)
endpoints: GET / GET /api GET /reverse GET /openapi.json
The four indented lines describe the deployment. Check them in the log when two hosts return different
answers. resolver: shows which 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. answers queries. wof: shows the reverse-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. database
from the prerequisites. That database is missing here. Only mailwoman serve reads the variable that line
suggests. This server looks only in <data-root>/db/wof/. Permissive CORS is on
by default because browser geocoder widgets call these endpoints cross-origin. --no-cors turns it
off when a reverse proxy already sets the headers.
Leave it running and open a second terminal.
3. Ask it what your client asks
GET /api is Photon's forward endpoint, and it returns a GeoJSON FeatureCollection.
curl -s "http://127.0.0.1:2323/api?q=1600+pennsylvania+ave+nw+washington+dc+20500&limit=1" | jq '.features[0]'
{
"type": "Feature",
"geometry": {
"type": "Point",
"coordinates": [-77.016216, 38.904831]
},
"properties": {
"osm_key": "place",
"osm_value": "city",
"type": "city",
"name": "Washington",
"city": "Washington",
"state": "District of Columbia",
"postcode": "20500",
"country": "United States",
"countrycode": "us"
}
}
osm_key, osm_value and type are always present, because Photon clients read them without
checking. They are derived from the resolved place's type instead of being read from OpenStreetMapOpenStreetMap (OSM). A community-curated global map database (ODbL-licensed) with addr:* tagged features and place hierarchies. A secondary corpus source and a source of street names.. The table in
step 7 has details.
The lat/lon parametersparameterA 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. apply a proximity bias, and an ambiguous query shows their effect. The same
query sent twice produces two orderings:
curl -s "http://127.0.0.1:2323/api?q=paris&limit=3" | jq -c '[.features[] | {name: .properties.name, cc: .properties.countrycode, coords: .geometry.coordinates}]'
curl -s "http://127.0.0.1:2323/api?q=paris&limit=3&lat=33.66&lon=-95.55" | jq -c '[.features[] | {name: .properties.name, cc: .properties.countrycode, coords: .geometry.coordinates}]'
[{"name":"Paris","cc":"fr","coords":[2.342841,48.856599]},{"name":"Paris","cc":"us","coords":[-95.54435,33.668553]},{"name":"Paris","cc":"us","coords":[-88.30661,36.293581]}]
[{"name":"Paris","cc":"us","coords":[-95.54435,33.668553]},{"name":"Paris","cc":"fr","coords":[2.342841,48.856599]},{"name":"Paris","cc":"us","coords":[-88.30661,36.293581]}]
Without a bias, Paris in France ranks first on population. With a bias toward a point in north-east Texas, the Texan Paris ranks first and France drops to second. The bias re-ranks results and never filters them, so both alternatives stay in the collection. If you pass your map center, a type-ahead orders results the way the person typing expects.
Now try the /reverse endpoint from the prerequisites:
curl -s "http://127.0.0.1:2323/reverse?lat=52.52&lon=13.405" | jq -c
{ "type": "FeatureCollection", "features": [] }
The route returns an empty collection instead of an error. This is the effect of the wof: (none found) line
from step 2. Without a 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 on disk, the server never constructs the reverse geocoder,
and the route returns the empty shape instead of a 500. To get real answers, put
admin-global-priority.db in <data-root>/db/wof/ and restart.
4. Point your existing client at it
The steps above did not use a client library. This step performs the swap. In geopy the swap is one argument. Install geopy in a disposable environment:
python3 -m venv /tmp/geopy-venv && /tmp/geopy-venv/bin/pip install geopy
Then pass the Photon geocoder a domain and a scheme so that it does not use the hosted service
by default:
from geopy.geocoders import Photon
photon = Photon(domain="localhost:2323", scheme="http")
loc = photon.geocode("1600 Pennsylvania Ave NW, Washington DC 20500")
print(loc.address)
print((loc.latitude, loc.longitude))
Washington, 20500, Washington, District of Columbia, United States
(38.904831, -77.016216)
Your code receives the same object it already handles, from a server you run. Every Photon client has an equivalent setting under some name, such as a base URL, a host or an endpoint override, because the hosted instance is a default and not a hard-coded constant.
5. The Nominatim shape
The Nominatim drop-in uses the same data root and the same download, with a different package and a different result format. Start it next to the Photon server:
npx @mailwoman/nominatim serve --port 8088
[resolver] candidate-table backend (demo-parity, population-first): /tmp/mailwoman-data/wof/candidate.db
[@mailwoman/nominatim] listening on http://0.0.0.0:8088
wof: (none found — set MAILWOMAN_WOF_DB)
resolver: candidate gazetteer (worldwide) — /tmp/mailwoman-data/wof/candidate.db
cors: enabled (Access-Control-Allow-Origin: *)
endpoints: GET / GET /search GET /reverse GET /lookup GET /status GET /openapi.json
A health check calls /status, which returns Nominatim's two-key object:
curl -s http://127.0.0.1:8088/status
{ "status": 0, "message": "OK" }
/search takes free text or the structured parametersparameterA 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., and addressdetails=1 adds the address
block:
curl -s "http://127.0.0.1:8088/search?q=10+Downing+Street,+London+SW1A+2AA&addressdetails=1" | jq '.[0]'
{
"place_id": 1178923677,
"licence": "Data © Who's On First, Overture Maps, OpenAddresses, US Census TIGER",
"lat": "51.500525578898",
"lon": "-0.109400835283853",
"display_name": "10, Downing Street, London, SW1A 2AA",
"address": {
"city": "London",
"postcode": "SW1A 2AA",
"house_number": "10",
"road": "Downing Street"
},
"annotations": {
"DMS": {
"lat": "51° 30′ 1.89″ N",
"lng": "0° 6′ 33.84″ W"
},
"MGRS": "30UYC0062309449",
"Maidenhead": "IO91wm",
"Mercator": {
"x": -12178.445276157312,
"y": 6710313.068983022
},
"geohash": "gcpuvx2k6",
"qibla": 119.00112658398905,
"sun": {
"rise": {
"apparent": 1785731284
},
"set": {
"apparent": 1785786464
}
}
}
}
The annotations block is an addition in OpenCage's format. Fields derived from only the coordinate
are always present: the coordinate formats, the qibla direction and the sun times. Three more fields,
flag, currency and callingcode, need a 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. in the resolved hierarchy. This result has none,
but ?q=Berlin,+Germany does. The IANA timezone, UN/LOCODE and EU NUTS codes are added when those
lookup databases are in the data root. A Nominatim client that ignores unknown keys is unaffected by
any of these fields.
countrycodes is applied as a hard restriction, so you can use it to override 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. when a bare
place nametoponymA proper name for a geographic place. resolves to the wrong one:
curl -s "http://127.0.0.1:8088/search?q=springfield&countrycodes=de" | jq -c
[]
The empty array means the restriction was applied and no place in Germany matched. A hard filter that returns no result is working correctly. Step 3's soft bias never removes results this way.
geopy's Nominatim geocoder takes the same two arguments as its Photon one, plus the user_agent
it requires:
from geopy.geocoders import Nominatim
nom = Nominatim(domain="localhost:8088", scheme="http", user_agent="swap-tutorial")
loc = nom.geocode("10 Downing Street, London SW1A 2AA", addressdetails=True)
print(loc.address)
print((loc.latitude, loc.longitude))
print(loc.raw["address"])
10, Downing Street, London, SW1A 2AA
(51.500525578898, -0.109400835283853)
{'city': 'London', 'postcode': 'SW1A 2AA', 'house_number': '10', 'road': 'Downing Street'}
6. The libpostal shape
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.-only drop-in needs 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., because the model weightsmodel weightsThe learned parameters of the neural classifier, shipped as ONNX files in the @mailwoman/neural-weights-* packages. Weights are locale-specific bundles that include the model, tokenizer, and a model-card.json metadata file. are installed as a package dependency. It starts even on a machine that never ran step 1:
npx @mailwoman/libpostal serve --port 8081
[@mailwoman/libpostal] listening on http://0.0.0.0:8081
cors: enabled (Access-Control-Allow-Origin: *)
endpoints: GET / POST/GET /parse POST/GET /expand GET /openapi.json
/parse returns libpostallibpostalAn open-source C address parser used by Pelias. Mailwoman's rule-based v0 and neural classifier supersede it.'s ordered [{label, value}] array, over GET or POST:
curl -s "http://127.0.0.1:8081/parse?query=1600%20Pennsylvania%20Ave%20NW%2C%20Washington%20DC%2020500"
curl -s -X POST http://127.0.0.1:8081/parse -H 'content-type: application/json' -d '{"query":"30 Rue de Rivoli, 75004 Paris"}'
[{"label":"house_number","value":"1600"},{"label":"road","value":"Pennsylvania Ave NW"},{"label":"city","value":"Washington"},{"label":"state","value":"DC"},{"label":"postcode","value":"20500"}]
[{"label":"house_number","value":"30"},{"label":"road","value":"Rue de Rivoli"},{"label":"postcode","value":"75004"},{"label":"city","value":"Paris"}]
/expand returns a set. The set is deliberately small:
curl -s "http://127.0.0.1:8081/expand?address=1600%20Pennsylvania%20Ave%20NW"
{ "expansions": ["1600 Pennsylvania Ave NW", "1600 Pennsylvania Avenue Northwest"] }
The route builds three strings (the input, its normalized form, and its abbreviation-expanded form)
and drops duplicates. That is why this address yields two. Mailwoman's normalization stagestageOne of the dataflow stages in the runtime pipeline (normalize, locale check, kind classify, phrase group, token classify, sequence correct, reconcile, resolve). Distinct from tier (model vocabulary) and phase (plan milestone). is
deterministic, so the result is one canonical alternative instead of the multi-variant hypothesis set
that libpostallibpostalAn open-source C address parser used by Pelias. Mailwoman's rule-based v0 and neural classifier supersede it.'s probabilistic expander produces. A caller that indexes every expansion gets fewer
keys per address here. A caller that takes expansions[0] or the last element sees no difference.
A missing parameterparameterA 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. returns a status code and a one-key object instead of a stack trace:
curl -s -i "http://127.0.0.1:8081/parse" | head -1
curl -s "http://127.0.0.1:8081/parse"
HTTP/1.1 400 Bad Request
{"error":"query is required"}
7. What each drop-in honors
The tables below list compatibility as of 8.7.0. The entries were read from the route handlers and
the engines behind them, then checked against a running server. Each request parameterparameterA 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. has one of
three verdicts:
- Honored — the parameterparameterA 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. changes the answer.
- Accepted, ignored — the request is valid and the parameterparameterA 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. is parsed, but no downstream stagestageOne of the dataflow stages in the runtime pipeline (normalize, locale check, kind classify, phrase group, token classify, sequence correct, reconcile, resolve). Distinct from tier (model vocabulary) and phase (plan milestone). reads it. Your client will not break, and it will get the unfiltered answer.
- Not read — the parameterparameterA 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. never reaches a handler.
Rows for response fields and whole routes have their own verdicts, and the third column explains each one.
Photon: /api and /reverse
| ParameterparameterA 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. or field | Verdict | What that means here |
|---|---|---|
q | Honored | Parsed and resolved. Empty or over 512 characters answers an empty collection |
limit | Honored | Caps the featuresfeatureAn input signal a model conditions on. Beyond the raw tokens, Mailwoman feeds soft features — gazetteer-membership channels and the postcode anchor — that inform predictions without overriding them. returned. /reverse returns at most one regardless |
lat + lon on /api | Honored | Soft proximity bias, both required. Re-ranks candidates, never filters |
format=jsonld | Honored, addition | Re-serializes the same collection as schema.org Place[]. Upstream Photon has no such format |
lang | Accepted, ignored | Names come back as 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. stores them. ?q=cologne&lang=en still answers Köln |
osm_tag | Accepted, ignored | The server applies no category filter. A request for amenity:cafe returns the same places as one without it |
layer | Accepted, ignored | The server applies no 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. filter |
radius on /reverse | Accepted, ignored | The reverse geocoder returns the containing place instead of running a radius search |
bbox | Not read | The handler 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. no bounding box. Use lat/lon for viewport influence |
osm_key/osm_value/type | Always present | Derived from the resolved place's type so clients can dereference them. Not OpenStreetMapOpenStreetMap (OSM). A community-curated global map database (ODbL-licensed) with addr:* tagged features and place hierarchies. A secondary corpus source and a source of street names. tag values |
osm_id / osm_type | Never set | No part of this is keyed to an OpenStreetMapOpenStreetMap (OSM). A community-curated global map database (ODbL-licensed) with addr:* tagged features and place hierarchies. A secondary corpus source and a source of street names. object.A client that stores them stores undefined |
/reverse without a 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 | Empty collection | See the prerequisites |
Nominatim: /search, /reverse, /lookup, /status
| ParameterparameterA 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. or field | Verdict | What that means here |
|---|---|---|
q | Honored | Free-text forward 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. |
street, city, county, state, country, postalcode | Honored | Joined into one query string in that order, then parsed. ?city=Berlin&country=Germany resolves |
countrycodes | Honored | Hard 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. restriction, first code only. Can legitimately answer [] |
addressdetails | Honored | Adds the address block |
format | Honored | geojson and jsonld change the envelope; jsonv2 (the default) and json both answer the result array. /lookup ignores jsonld — a preserved quirk |
limit | Accepted, capped | /search returns at most one result today, so limit=5 still answers one |
bounded | Accepted, ignored | The server applies no viewbox restriction |
accept-language | Accepted, ignored | Names behave the same way as with Photon's lang |
zoom on /reverse | Accepted, ignored | The detail level is whatever the containing hierarchy provides |
viewbox, extratags, namedetails, polygon_*, dedupe | Not read | The handlers 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. none of them |
place_id | Substituted | Forward results return a deterministic hash of coordinate plus display name rather than a Nominatim id. Reverse results return 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 place id |
osm_id / osm_type | Never set | As with Photon |
licence | Substituted | Data © Who's On First, Overture Maps, OpenAddresses, US Census TIGER — the sources these answers come from |
annotations | Addition | The OpenCage-style block from step 5 |
/lookup | 501 | Not implemented |
/reverse without a 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 | null | See the prerequisites |
libpostal: /parse and /expand
| ParameterparameterA 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. or field | Verdict | What that means here |
|---|---|---|
query, address | Honored | On /parse, either name works, over GET or POST. /expand takes address |
| Component 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. | Mapped | Mailwoman's tags project onto libpostallibpostalAn open-source C address parser used by Pelias. Mailwoman's rule-based v0 and neural classifier supersede it.'s names — street to road, locality to city, region to state, dependent_locality and neighbourhood both to suburb, and so on through twenty entries. A tag with no entry passes through under its own name |
/expand output | Deduplicated set | The input, its normalized form and its abbreviation-expanded form, with duplicates dropped — one to three strings rather than a hypothesis set. See step 6 |
| Language options | Not read | One weights bundlemodel weightsThe learned parameters of the neural classifier, shipped as ONNX files in the @mailwoman/neural-weights-* packages. Weights are locale-specific bundles that include the model, tokenizer, and a model-card.json metadata file. (en-us) is loaded at startup, and there is no per-request language parameterparameterA 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. |
8. Stop them
Press Ctrl-C in each server's terminal. The servers write no files to the data root, so a restart
continues from the same state.
What you have now
You have three compatible endpoints on your own hardware. They read one 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. and accept the request formats your existing callers already build. You also have a record of which parametersparameterA 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. each one reads, so if a swap changes an answer, you can find the reason in a table.
Next
- Run the API server — Mailwoman's own
/v1API, with the fuller result object and a generated OpenAPI document. As a rule, point an existing integration at a drop-in and a new one at/v1. - Improve geocode precision — the per-state download that moves these answers from a city centroidlocality centroidThe representative center point of a city or locality, used as a coarse coordinate when no exact address point is available — the coarsest tier of the geocode cascade. to a 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..
- Parse in the browser — the same 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.' with no server at all.