尚未检测到更新。GitHub 发布版本后会显示在这里。
个人 GitHub 账号下公开仓库的所有者可以登录并验证所有权,自行管理介绍,无需管理员批准。
登录并生成验证文件,在 30 分钟内将其提交到此仓库的默认分支。其他分支或分叉仓库中的文件无效。然后在下方检查文件,即可无需管理员批准直接管理项目。请保留文件以维持管理权限。
如需登录,将前往登录页面。登录后请回到此处,再次点击所选的验证按钮。
在项目文件夹中运行 /nomorevibe verify,即可验证所有权并自行管理介绍。
一分钟完成验证Find new suppliers, including the ones that are not online, and compare them by real order cost, fair ratings and trust. 23 countries, 4 languages, optional Claude agent.
翻译准备中
取自仓库 README
正在加载完整 README。
查看完整 README ↗Find suppliers of goods and services, including the ones that are not online, by typing what you need in your own words. Live map search · real order cost · fair ratings · trust from referrals · human review · optional Claude agent.
▶ Live demo · How it works · Cómo funciona (español) · 🇪🇸 Resumen en español · Playbook: suppliers that are not online · Countries and languages
Finding a new supplier usually means a web search, a spreadsheet and a few phone calls. Three things go wrong:
The full walkthrough, from the live map search to how the ranking decides, is in How it works (español).
This is the core of the project. The full guide is in the playbook.
| Channel | How Supplier Scout helps |
|---|---|
| Referrals from current suppliers and colleagues | Drafts the "who do you buy this from?" message; records who recommended whom; counts only independent referrals toward trust |
| Public registries (procurement, chambers of commerce) | SECOP II connector for Colombia; an OCDS connector for every government that publishes open contracting data; any Socrata open-data portal; CSV import for any other registry. The app lists each country's procurement portal and business registry |
| Community maps | Live OpenStreetMap search in the web app and a connector in the CLI, for any country, reporting how many results have no website; a one-click Google Maps search for the businesses OSM does not have |
| Trade districts and fairs | CSV import that recognises columns by name in Spanish, English, Portuguese and French |
| Business cards, flyers, WhatsApp | Rule-based parser: name, tax ID with check digit, phones, emails, handles, address, prices, pack size, minimum order, lead time, payment terms |
| Verification | Tax-ID check digits, verification levels (contacted → formal → visited → bought from), human review queue |
| Factor | What it measures | When data is missing |
|---|---|---|
| Price | Quoted unit price with tax relative to the cheapest option; in the Quotes tab, the total cost of an order (packs, minimum, tax, shipping, currency, payment term) | Neutral + "ask for a quote" |
| Rating | Bayesian blend: a neutral prior worth 5 reviews, online reviews (capped at 100), team reviews ×3 | Neutral |
| Distance | Inside your radius; suppliers that deliver keep a floor | Neutral |
| Trust | Verification level + independent referrals (self and same-group referrals ignored, mutual ones count half) | Lowest level |
| Speed | Lead time; a hard warning if it misses your deadline | Neutral |
Weights are presets (balanced, cheapest, most reliable, nearest, urgent) or sliders.
Built in Colombia, meant for Latin America, usable anywhere. The full table is in docs/countries.md.
src/core is plain JavaScript with no dependencies. The browser demo, the CLI and the agent run the same code, and the tests cover it.agent/ uses the Claude API (official @anthropic-ai/sdk, model claude-opus-5-5 by default) with seven read-only tools: find_coordinates, search_my_database, search_map, search_public_registry (Colombia), search_google_places (only if you set a key), rank_candidates and draft_messages.
medium, prompt caching, and token usage printed at the end.fallbacks: "default").--dry-run runs the same tools in a fixed order without AI or a key, to try it or compare.--lang es|en|pt|fr; by default, the language of the country (--country BR answers in Portuguese).| Risk | Mitigation |
|---|---|
| AI invents suppliers, prices or reviews | Candidates come only from tool results; the loop is tested with a scripted model that tries to invent one |
| Prompt injection through third-party data (names, notes) | Tools are read-only; no send or write tools; the system prompt marks tool output as data; a person sends every message |
| Personal data sent to the AI provider | Tool results strip phones and emails (tested) |
| API keys leaking | Keys only in environment variables (.env is git-ignored, .env.example is empty); the Places key goes in a header, never the URL (tested) |
| Query injection (Overpass QL, SoQL) | User text is reduced to letters and digits before building map queries; SoQL string literals are escaped (tested) |
Malicious import file (XSS, javascript: links, huge files) | One sanitising gate for all external data (also applied to what the browser saved, since storage is shared by every page on the same GitHub Pages domain); http(s) links only; 2 MB limit; the page renders with textContent only |
| Huge or hostile inputs (availability) | Capture text capped at 5,000 characters and tested against regex backtracking; imports capped at 2,000 suppliers; duplicate search and ranking tested to stay fast at those limits; connector responses capped at 5 MB while streaming |
| Spreadsheet formula injection in the CSV export | Cells starting with =, +, -, @ are exported as text (tested) |
| Demo page | Strict CSP: scripts, styles and fonts (IBM Plex, self-hosted, SIL Open Font License) come from the site itself; connect-src allows only Nominatim, Overpass and the OSRM routing server, used only when you press Search the map, and img-src only OpenStreetMap's tiles (tested). Marker colours are set through the CSSOM because inline style attributes are blocked. No cookies or trackers. Map results go through the same sanitising gate as any import; the shortlist and recent places read back from storage are checked the same way |
| Personal data of sole traders (Colombia: Law 1581 of 2012; LGPD in Brazil and similar laws across the region) | Consent checkbox on capture that names the selected country's law, warning in the ranking when consent was refused, never sent to the AI agent when refused, data stays in the browser unless exported. The OCDS connector imports the business, never the contact person's name (tested) |
flowchart LR
subgraph S[Where suppliers come from]
MAP[OpenStreetMap]
REG[Public registries<br/>SECOP · OCDS · Socrata portals]
GP[Google Places<br/>optional key]
CSV[CSV<br/>fairs · chambers · sheets]
CARD[Cards · flyers · WhatsApp]
REF[Referrals]
end
MAP --> CON[Connectors · Node]
REG --> CON
GP --> CON
CSV --> CON
CARD --> PAR[Capture parser<br/>rules · offline]
REF --> PAR
CON --> GATE[(Common format<br/>sanitised)]
PAR --> REV{Human review}
GATE --> DUP{Duplicates<br/>confidence tiers}
DUP -->|exact · high · medium| DB[(Supplier list)]
DUP -->|low · conflict| REV
REV --> DB
DB --> RANK[Ranking<br/>order cost · fair rating<br/>distance · trust · speed]
RANK --> WEB[Web app]
RANK --> AG[Claude agent]
AG -.->|drafts only| YOU[You send quote<br/>and referral requests]
src/core/ shared logic, no dependencies (browser + Node)
services.js what the buyer typed -> trades, categories, map tags and name words (rules, ES/EN/PT/FR)
osm.js OpenStreetMap query and parsing, place disambiguation and search radius, Google Maps search link
shortlist.js the buyer's shortlist: statuses, three-quote progress, comparison table (CSV)
countries.js 23 country profiles: currency, tax, tax-ID check digits, phone habits, registries
capture.js business card / flyer / WhatsApp text -> draft supplier
quotes.js units, packs, minimum order, tax, shipping, FX, payment terms
reviews.js Bayesian rating blend
trust.js verification levels and referral counting
dedupe.js duplicate detection with confidence tiers, merging
score.js explainable ranking
csv.js · schema.js import/export and the sanitising gate
messages.js explanations (ES / EN / PT / FR) · outreach.js quote & referral drafts
src/connectors/ OpenStreetMap, Socrata/SECOP, OCDS, Google Places, Nominatim (Node)
src/data/ fictional demo data (Bogotá, Mexico City and São Paulo)
cli/scout.js connectors, CSV import, merge and rank from the terminal (args.js: shared parser)
agent/ Claude agent: tools, loop, system prompt, CLI
demo/ the web app (GitHub Pages): app.js, live.js (the only file that uses the network), map.js (OSM tiles + markers,
no library), i18n.js (ES/EN/PT/FR texts), self-hosted IBM Plex fonts
tests/ 179 tests: core, regional formats, connectors against API-shaped fixtures,
CLI, agent loop with a scripted model, demo security guards
docs/ how it works (ES/EN), screenshots, the offline playbook and the country coverage table
Requires Node 22+.
npm test # the whole suite, no network and no API key needed
Web app: open the live demo, or serve the repository locally (for example npx http-server .) and open /demo/.
Connectors (no AI): each command writes a JSON file you import in the web app (tab Data).
npm install
npm run scout -- osm --category packaging --lat 4.6782 --lng -74.1411 --radius 3000 --out data/map.json
npm run scout -- registry --preset secop-co --describe # show the dataset's columns and how they were mapped
npm run scout -- registry --preset secop-co --q "carton corrugado" --city Bogota --out data/secop.json
npm run scout -- registry --domain https://data.example.gov --dataset abcd-1234 --country XX --q "..." # any Socrata portal
npm run scout -- ocds --file releases.json --country PY --q "carton" --out data/ocds.json # any OCDS publisher (or --url https://...)
npm run scout -- csv --file exhibitors.csv --country CO --out data/fair.json
npm run scout -- merge data/map.json data/secop.json data/fair.json --out data/all.json
npm run scout -- rank --db data/all.json --category packaging --qty 500 --lat 4.6782 --lng -74.1411 --radius 12 --days 7
Agent:
cp .env.example .env # put your ANTHROPIC_API_KEY in .env (never in code)
node --env-file=.env agent/cli.js "Necesito 500 cajas de cartón corrugado cerca de Fontibón, Bogotá, en 7 días" \
--db data/all.json --out data/result.json
# Without AI or a key: the same tools in a fixed order
npm run agent -- --dry-run --db data/all.json --category packaging --qty 500 --lat 4.6782 --lng -74.1411 --days 7
data/ is git-ignored so your real supplier lists never end up in the repository.
Being explicit, because this matters more than the feature list:
live-check.yml) runs the web app's own search code against the real Nominatim, Overpass and OSRM for 12 buyer searches in Colombia, Peru, Mexico and Brazil, checks every listed business on the OpenStreetMap API, and uses the page in Chromium. Results: 67 of 67 businesses checked in three runs exist with the same name; searches with good map coverage found 16-37 real businesses (hardware stores in Barranquilla and Coyoacán, stationers in Chapinero, garages in Pinheiros); the map tiles, driving times, shortlist and quote request worked in the real browser with no console or security-policy error. The check also found real problems, now fixed: the public Overpass server took about 30 s to answer from GitHub's servers (hence the Nominatim fallback), searches took 13-20 s (now 3-13 s), place labels were long, and municipalities came back as "county".Built by Sergio García, an International Business graduate (diploma pending) based in Bogotá who likes turning repetitive work into automated systems. I don't come from engineering: I learn by building, using generative AI as a pair programmer. Supplier Scout is an independent project built with Claude Code; the design choices (neutral scoring for missing data, human review, drafts instead of automatic messages) come from what I saw of how purchasing actually works.
Companion project: Supplier Radar keeps track of the suppliers you already have; Supplier Scout finds new ones.
Portfolio · LinkedIn · [email protected]
Supplier Scout sirve para encontrar proveedores nuevos de productos y servicios, incluidos los que no aparecen en internet, escribiendo lo que necesitas con tus palabras.
Los datos de ejemplo de la demo son ficticios (dominios .example, teléfonos en rangos sin asignar, IDs tributarios generados); los de la búsqueda en el mapa son reales. Honestidad: la búsqueda en el mapa, los conectores y el agente están probados con respuestas simuladas; todavía no se han ejecutado contra los servicios reales porque el entorno de desarrollo no tenía acceso a internet. Ver la demo en vivo · Cómo funciona · Guía para encontrar proveedores fuera de internet.
| Leaking real data from this public repo | All data is fictional: .example domains, phones in unassigned ranges (Colombia 999, Mexico 55 0000, Brazil (11) 0000, or ranges reserved for fiction), tax IDs generated with a correct check digit. Tests enforce it |
| CI supply chain | Read-only permissions, no persisted credentials, every GitHub Action pinned to a commit SHA (tested; Dependabot updates the pins), npm ci --ignore-scripts, one runtime dependency (the official SDK, used only by the agent), Dependabot for security updates |
| Script injection through map data | Trusted Types enforced by the CSP (require-trusted-types-for 'script'), no HTML-string sinks anywhere in the web app (tested), every value rendered with textContent |
| Abuse of free services and location privacy | Nominatim and OSRM calls queued to at most one per second across searches (tested); the browser location is rounded to about 100 m before it is sent |
| Wrong but real results | Map tags checked against the OpenStreetMap wiki; name words that caught unrelated businesses (kindergartens, banks, universities) narrowed, with tests |
| Terms of the data sources | OSM and Nominatim: attribution, one geocoding call per search (a second one a second later only when the place is not in the chosen country), no search-as-you-type, a 10 km radius cap and the button disabled while a search runs (the CLI also sends an identifying User-Agent); OSM tiles: attribution on the map, a Referer on every tile request (the page otherwise sends none), only the tiles in view; OSRM demo server: one table request per search, at most 100 places, non-commercial use, credited; Overpass: one retry after 3 s when busy, no unverified mirrors (some serve stale data silently); Google Maps: only an official search link, nothing is copied and no Google data is shown on the OSM map (against Google's terms); Google Places (CLI, your own key): records are flagged for refresh or deletion per Google's terms |
<meta>