Docs
/

Business Finder

@leumas/business-finder

Leumas Prospecting: find local businesses with weak/missing web presence (OpenStreetMap discovery + website analysis + deep-scan), score the Imperium opportunity (esp. a site shipping no schema.org...

Business Finder (@leumas/business-finder)

Leumas Prospecting: find local businesses with weak/missing web presence (OpenStreetMap discovery + website analysis + deep-scan), score the Imperium opportunity (esp. a site shipping no schema.org JSON-LD), and draft each lead a starter Imperium site. Migrated from the legacy leumas-business-site-finder tool; the node-safe SDK powers the adapter + router, the React app powers the Studio/desktop/Web dashboard.

How agents call it

SurfaceHow
CLI (headless, no server/auth)node ops/tools/run-tool/run-tool.mjs business-finder <op> '<jsonArgs>'
MCP client / chatbot / Leviathanadapter business-finder → tool/functioncall (discover, analyzeSite, scoreLead, deepScan, assembleImperiumConfig)
Automation rule / grid celladapter ops as cells + action business-finder.draft-imperium-site (lead → drafted config)
HTTP/api/business-finder/* (JSON, requireAuth)
StudioProspecting domain (/admin/prospecting)
CoderunSearchPipeline, scoreLead, assembleImperiumConfig … from @leumas/business-finder/sdk

Run it from the CLI

node ops/tools/run-tool/run-tool.mjs business-finder discover '{"query":"plumber","city":"Chicago","state":"IL","maxResults":8}'

discover hits OpenStreetMap live — set OSM_CONTACT_EMAIL for the polite Nominatim email. Ops: discover (area → ranked leads, best = weakest site), analyzeSite ({url} → status/score + missing-schema signal), scoreLead ({lead} → Imperium-opportunity score), deepScan ({url|lead} → services/USPs/credentials for a starter brief), assembleImperiumConfig ({lead,mode}{mode,data,seo} draft). See --describe business-finder.

/api/business-finder routes

Stateful orchestration + persistence over the SDK. Runs persist in the dynamic bf_runs collection, per-user settings in bf_settings; everything is owner-scoped (doc.owner === req.user.id || admin).

  • POST /search — discover + analyze + score, persist a run. GET /runs, GET /runs/:id.
  • POST /analyze/run/:id — re-analyze every lead in a run.
  • GET /leads/:id, PATCH /leads/:id (manual review), POST /leads/:id/deep-scan.
  • POST /leads/:id/draft-sitedraft (never publish) a starter Imperium config and store it on

the lead. GET/PATCH /settings. POST /export/:runId (csv|json). GET /health.

draft-imperium-site (the flagship flow)

POST /leads/:id/draft-site (and the identical shared action business-finder.draft-imperium-site, so it's a chainable grid cell) composes existing adapters through the registry — no cross-pack static import:

  • landing-copy → AI hero / benefits / CTA copy blocks.
  • seojsonLd (schema.org Organization) — the structured data the current site lacked.
  • assembleImperiumConfig (pure) stitches them into { id, appName, mode, data, seo, source }.

Publishing stays a manual step in the Hosting domain; this only drafts. Each adapter call is try/caught, so a missing LLM degrades to a deterministic draft rather than failing.

Studio Prospecting domain

/admin/prospectingProspectingSurface mounts @leumas/business-finder/app (nav id prospecting, icon [target], surface ProspectingSurface). Same React app runs on the leumas-os desktop and the Web library.

DRY reuse (do NOT duplicate)

  • Discovery = OpenStreetMap (Nominatim + Overpass) in the SDK provider registry — no paid places

API, no key. mock provider for offline demos.

  • Scraping/SSRF = the shared _shared/net.js guard (same one scraping + url-screenshot use);

URL-fetching ops refuse private/localhost. analyzeSite/deepScan fetch with cheerio, not a browser.

  • AI copy = the landing-copy adapter; structured data = the seo adapter — both via the

injected registry, never a raw provider fetch.

  • Persistence = the dynamic CRUD connector (api.db), not bespoke storage.
  • Render/publish = @leumas/ui DynamicPage + @leumas/hosting — the finder only produces the

config.

Gating

Adapter ops are free/ungated (registry-projected). The router is requireAuth on everything; PassNode feature:business-finder.run meters the network/LLM lanes (search / analyze / deep-scan / draft-site) — a no-op until a passnode_rules doc for that resource id exists. run-tool bypasses auth (no HTTP layer). No membership tier is required.

Source shared/services/knowledge/build-knowledge/business-finder.md (no-git)markdownjson
Generated from the Leumas repository. Every page cites the file it came from.leumas.techllms.txt