Property Lead Pipeline: GIS Lookups on Code-Enforcement & Lien Notices
City of Ocala and Marion County, Florida. Feasibility assessment and automation master plan.
Executive Summary
Goal: an automated pipeline that finds Ocala + Marion County properties carrying overgrown-lot / weed / nuisance code-enforcement notices or recorded liens, joins each to GIS parcel data (owner name, mailing address, situs, geometry), and emits a deduped, map-ready lead list.
Verdict: FEASIBLE
The GIS join is the easy part. Clean, public parcel and owner data is confirmed live and queryable. The friction sits on the code-enforcement and lien side, where there is no single clean API, so it takes targeted scraping plus fuzzy address-to-parcel matching. A county-only MVP ships in about a day; the full two-jurisdiction system in three to four.
Confirmed Data Sources
Status reflects live probes run during the assessment (2026-06-09). “Needs check” means the endpoint exists but timed out from the dev sandbox. That is almost certainly a geo or firewall block, so re-verify from the Contabo production host.
| Source | Endpoint | Status | Role |
|---|---|---|---|
| FL Statewide Cadastral (FDOR 2025) |
services9.arcgis.com/Gh9awoU677aKree0/…/Florida_Statewide_Cadastral/FeatureServer/0 |
Verified | Join backbone. Public, no token, queryable, 2,000 rec/req. Fields: OWN_NAME, OWN_ADDR1/2, OWN_CITY/STATE/ZIP, PHY_ADDR1/2 (situs), S_LEGAL, PARCEL_ID, CO_NO. Filter CO_NO=42 for Marion. |
| County parcels (self-host) | gis.marionfl.org/public/rest/services/General/Parcels/MapServer |
Needs check | Richer geometry fallback. Exists; timed out from dev sandbox. Run from Contabo. |
| County code-enf lien search | bcc.marionfl.org/billing/paycode-demo.aspx |
Needs check | Violation and lien lookup. Scrape target. Exists; timed out. |
| Marion Clerk official records | marioncountyclerk.org records search |
Needs check | Recorded liens by document type (municipal / code-enforcement lien). |
| Ocala code enforcement | ocala.granicus.com + ocala.legistar.com board agendas |
Needs check | Case notices live in board agendas / minutes (PDF + HTML). Primary Ocala path. |
| Ocala iWorQ portal (guessed) | ocalafl.portal.iworq.net |
Blocked | 404, does not exist. Discard. (An Ollama-suggested lead that failed the live check.) |
| Marion Property Appraiser (AGOL) | services3.arcgis.com/hrGHbYKdjpN9Dagg/…/Parcels |
Blocked | Token required (private). Discard; use FL Cadastral instead. |
Ollama Pro Research Test
I ran deepseek-v4-pro at the endpoint-discovery question. It knew the territory, naming Granicus, the Clerk records system, and the Geocortex GIS pattern. Better still, it returned UNKNOWN rather than hallucinate exact endpoints. But the one lead it gave with confidence, the Ocala iWorQ URL, 404'd on the live check.
Conclusion: Ollama Pro is an inference engine with no live web access. It is the wrong tool for discovery, and the right tool for the normalize / fuzzy-match / extract layer (free, flat-fee). Discovery must use live fetch tools. This split matches the house economic rule: the subscription model does the bulk work, live tools verify.
Architecture
Seven stages. Live tools own discovery; Ollama Pro owns text normalization; plain Python owns the GIS join and output.
- Discovery (live tools, monthly re-verify)WebFetch, curl, and chrome-devtools confirm endpoints, then capture iWorQ and Granicus URLs into
endpoints.json. - Fetch (Python cron)Ocala Granicus/Legistar agendas, County
bcc.marionfl.orglien search, Clerk official records. - Normalize (Ollama Pro)Extract address, case number, and fine from messy text; clean and standardize address strings.
- Parcel join (Python)Query FL Cadastral
CO_NO=42by parcel or address for owner, mailing address, geometry. - Geocode fallback (free)Census and Nominatim fill any unmatched situs addresses.
- Dedupe (ledger)14-day cooldown ledger emits new-only leads.
- OutputCSV + GeoJSON map + email digest.
The Two Hard Parts
- Ocala has no clean case API. Notices live in Code Enforcement Board agendas and minutes (Granicus plus Legistar). That means PDF and HTML parsing, which is inherently brittle. This is exactly where Ollama Pro earns its keep: pulling structured cases out of agenda text.
- Address-to-parcel matching is fuzzy. Code-enforcement situs addresses are abbreviated or typo'd; cadastral
PHY_ADDR1is formatted differently. Ollama normalization plus a geocode fallback closes most of the gap. Expect roughly 85-90% auto-match, with the rest flagged for manual review.
agent-os Build Plan
| Stage | Tool | Output |
|---|---|---|
| 0. Discover (monthly) | WebFetch / curl | endpoints.json, verified live URLs |
| 1. Pull Ocala | Python + Granicus/Legistar scrape | Raw cases (address, case #, fine, date) |
| 2. Pull County | Python scrape bcc.marionfl.org + Clerk | Raw violations + recorded liens |
| 3. Normalize | Ollama Pro (deepseek_pro / kimi) | Clean address + structured fields |
| 4. Parcel join | Python → FL Cadastral CO_NO=42 | + OWN_NAME, mailing address, geometry |
| 5. Geocode fallback | Census / Nominatim (free) | Fill unmatched |
| 6. Dedupe | Ledger /var/lib/agent-os/weed-liens/ | New-only, 14-day cooldown |
| 7. Output | Python | CSV + GeoJSON + Leaflet map + email |
Pattern: pure-Python drainer mirroring index-submit-drainer.py; weekly cron on Contabo 194; reuses the existing agent-os email-zip + ledger plumbing.
MVP Cut
County-only path, skipping Ocala Granicus (the hardest piece): bcc.marionfl.org lien search → Ollama normalize → FL Cadastral join → CSV. That alone gives you Marion County overgrown-lot and lien parcels with owner names and mailing addresses, a usable lead list on day one. Ocala agendas and Clerk recorded-liens come in phase 2.
Effort & Phasing
- Phase 1, MVP (county only): about 1 day
- Phase 2, Full (Ocala agendas + Clerk + map + weekly cron): about 3-4 days, most of it absorbed by Ocala PDF brittleness
Legal / Compliance Note
All sources are public records. Respect each portal's robots.txt and Terms of Service; throttle scrapes and cache aggressively. Clerk bulk data may require a paid subscription at volume. The resulting lead list is for lawful outreach only.