A locally-run research aid that finds companies worth a cold email — and refuses to tell you anything it can't cite. This page documents how it was built, what broke, and what's still honestly unsolved, using the same evidence discipline the tool itself is built around.
Exhibit A — what it actually outputs
Not a mockup. This is a live finding from a real run against itnetworks.com.au, discovered during this session's own testing — reproduced here exactly as the tool wrote it, because a case study about an evidence-only tool should open with evidence, not a claim about one.
“CTO” found on this page, near the text: “...About IT Networks. Meet the leadership team behind IT Networks’ managed IT support...”
That specific result didn't exist until this session fixed a false positive that pointed at a blog post about installing Microsoft Teams instead. See Case 01.
Brief
While there are many official and unofficial job boards out there, or else automation agents to make the job hunt easier, it focuses more on the 20% jobs posted seen rather than the 80% hidden job market through word of mouth, or the bold chance to reach out for them.
The idea stemmed with a piece of advice called 'why not search for the company, find the CTO / HR etc and then reach out via cold email? Find what you can solve for them, write it out and get that conversation'. Rather than job boards with the usual resume and cover letter fed to the ATS and 99% leading nowhere, why not that type of appeal?
The problem for me is finding those companies, especially 'small to mid-sized' companies more likely to hire junior / entry level candidates with international immigrant status even for just a bit and pay the bills than big companies that everyone covets. So, I reached out to spec this project, casting a net over the location for those companies, even non-tech as long as they have a tech team, and take my chances.
Given a location and a technical interest, Prospect Scout finds publicly visible companies that are plausible prospects, collects verifiable case-study and hiring signals from their own sites, and writes a local report for a human to review before reaching out. It is deliberately not a lead-generation guarantee — a search can return zero eligible companies when public evidence doesn't support one, and that's treated as a correct answer, not a failure.
The one rule everything else follows from: it must never invent a company, a case study, a problem, or a contact. Every finding ships with a source URL, an excerpt, and a confidence level the human is meant to actually distrust a little.
Log
Search widening, ranking, and a results page worth reading
OSM discovery widened to libraries and research institutes alongside offices; scout/research.py gained bounded concurrency so a 250-candidate run finishes in minutes instead of tens of minutes; scout/ranking.py shipped — eligible before needs-review, then location and evidence strength, reasons shown per company instead of an opaque score. Role matching switched from substring to whole-word after a real false positive: “software engineer” was matching inside “software engineering,” a degree name, not a role.
Baseline: fetcher, discovery, evidence pipeline, reporting
The polite fetcher (scout/fetcher.py) — honours robots.txt, identifies itself honestly, skips login-gated content. Sitemap-first page discovery, sector classification, location verification, and local Markdown/JSON reporting. First documented baseline; the web app and CLI both usable end to end.
Profile-aware discovery and a named contact, only when the site actually publishes one
OSM's single fixed office=* query became a per-profile tag set — the technology profile now asks for office=it/research/engineer, not everything. Team/leadership-page contact extraction shipped, deliberately scoped to a company's own published team page — no third-party enrichment, no guessed emails. Caught two real bugs in testing before shipping: naive matching once flagged “Sales Director” as a “CTO” hit (both words contain the substring “cto”), and a name-extraction heuristic once grabbed “Our Head” instead of the real name sitting two words later.
Live-testing the live tool, and fixing what it found
This session. Ran real searches, read every result by hand, and didn't like some of them — see the three cases below. Shipped from that: a word-boundary fix for a false-positive contact page, a minimum-evidence floor before the tool will assert a sector, contact-aware and MSP-language-aware wording on its weakest finding type, and a full redesign of outreach guidance — from a composed, sendable draft to personalized talking points, after a first attempt over-corrected into being generic.
Exhibits B–D
None of these came from a code review. They came from running real searches against real companies and refusing to accept a result just because it didn't crash.
Team-contact discovery matched pages by keyword: "team" among them. It flagged /blog/how-to-install-microsoft-teams/ as a leadership page — because "team" is a literal substring of "teams," the software product, not the org-chart concept. The extracted "contact" was Business Needs, pulled from the headline “Why Your Small Business Needs a CIO.”
Fixed with a word-boundary match, deliberately scoped to team-page keywords only — the case-study keyword list keeps its existing substring behaviour on purpose, since one of its terms ("success-stor") is an intentional truncation to catch both "story" and "stories." Re-ran the exact same company afterward: it found the real about page, and a real name.
Sector inference counts keyword hits per category and reports the winner, no matter how thin the margin. A local council library's homepage scored two hits under fashion/retail: "collection" and "clothing." A library collection isn't a clothing collection — but the word is identical either way.
Added a floor: a sector needs at least two independent keyword hits before it gets reported as anything but unknown. Re-ran the library afterward, expecting it fixed.
Prompted by a real story: someone found a tech role at a mining company through a networking event, not a search. Checked directly whether OpenStreetMap even had the data — it did. BHP's Melbourne HQ is a real, recently-verified OSM node, tagged office=company, with a live website tag pointing at bhp.com.
The technology profile's OSM query only asks for office=it/research/engineer — not office=company, the tag every generic corporate HQ gets. BHP was findable and invisible to this profile at the same time. Filed as evidence for a real, separately-scoped question: tech work increasingly lives inside companies that don't look like tech companies at all — not something to patch into this session's fixes by accident.
Contract
Not a style guide — an enforced shape. A finding missing any of these isn't a weaker finding, it's not a finding.
| Field | Requirement |
|---|---|
| source_url | Canonical URL after redirects — always the company's own site. |
| evidence | Short observed text, actually present on the fetched page. Never paraphrased into a claim. |
| confidence | High, medium, or low — a name match with no name nearby is low, always. |
| suggestion | A specific next action tied to that evidence, framed as a hypothesis, never a certainty. |
| status | eligible / needs_review / rejected. Only eligible companies get recommended — no evidence, no recommendation. |
Open ledger
Recorded on purpose, not discovered by a reader. A tool that only admits its limits when asked isn't actually being evidence-based about itself.
OpenStreetMap doesn't have every company mapped
Confirmed real misses, including a large multinational. This is the ceiling on discovery today, not a bug — the fix is a second, name-verification-only source, not a bigger query.
A tagged site can outlive the business it was tagged for
One confirmed case: an OSM record pointed at a domain since hijacked for SEO spam in another language. Nothing today tells "the fetch succeeded" apart from "this is still who OSM says it is."
Keyword matching can't tell intent from coincidence
A university's own career-services page can contain the exact phrase you searched for as a degree name, not a hiring signal. Word-boundary matching fixed the false certainty; it can't fix the ambiguity itself — that's left to the human review step on purpose.
A real, currently-open role can still be invisible
If a company only lists a vacancy on a third-party job board and nowhere on its own site, this tool won't find it — job-board scraping is explicitly out of scope, not an oversight.
Under the hood
Language — Python 3
Web app — FastAPI + Uvicorn
Fetching — httpx, robots.txt-honouring, self-identifying user agent
Parsing — BeautifulSoup, hand-rolled sitemap XML discovery
Discovery — OpenStreetMap (Nominatim geocoding + Overpass queries)
Tests — stdlib unittest, fixture & fake-based, zero live network calls
Reports — local Markdown + JSON, nothing leaves the machine