Build specs / Territory runner
Raw markdown for AI agents →

Build spec: territory runner

A tool that turns "every roofer in Texas" into a plan, runs it within a budget the user sets, and reports honestly on what was and was not covered.

Build this when the user needs market coverage, not a sample.

Before you build: ask. See https://lyreleads.com/build for the four rules that apply to every build on this API.


The problem it solves

A single Google Maps search returns far fewer businesses than exist. Measured on one metro category in July 2026: one search reached under 4% of at least 1,605 findable businesses. Eight deep-paginated searches reached 69%.

Coverage does not come from more pages. It comes from more searches: more keyword variants, more places, smaller places.

Doing that by hand is tedious and easy to do badly, which is exactly why it should be a program.


What it does

  1. User states a target: a business type, a region, a token budget.
  2. The tool expands that into a plan: a grid of (keyword × place) searches.
  3. Shows the plan and the worst-case cost before anything runs.
  4. Executes it, resumably, respecting the budget.
  5. Reports coverage honestly, including what it did not reach.

Plan expansion

This is the part with the actual intelligence in it, and it is where you earn your keep.

Keyword variants

Google matches against the business's own listed category, and businesses in one trade do not all pick the same category. One word is one slice.

Generate 4–8 variants per trade. For roofing: roofer, roofing contractor, roofing company, roof repair, roof replacement, commercial roofing. Include the generic and the specific, and the noun and the agent form.

You are a language model. Generating these is the easiest thing you will do all day, and it roughly multiplies coverage. Do not skip it because one word "seems fine".

Show the user the list and let them edit it. They know their trade better than you do.

Places

Bigger places are not better. A search is centred on a point, so one search on a large metro misses its edges entirely. Ten searches on ten suburbs beat one on the metro.

Expand a region into its cities and large towns. For a metro, expand into named districts and adjacent municipalities. Let the user paste their own list, because they often have one.

The grid

keywords × places searches. Warn the user if the grid is enormous before you show a cost, because the number tends to surprise people.


Budget, shown before anything runs

The one screen that must be right.

Plan: 6 keywords × 24 places = 144 searches
Pages per search: 2
Worst case: 144 × 40 = 5,760 tokens
Your balance: 5,000 tokens

Duplicates are free, and overlap between keyword variants
is heavy, so the real cost is usually well below worst case.
Actual spend is reported as it runs.

Never start a run that could exceed the balance without saying so. Let them cap it: "stop at 2,000 tokens" is a reasonable and common request.

GET /api/v1/balance for the current balance. It is free.


Execution

POST /api/v1/search   { query, city, country, pages }

Sequential, not parallel. This is a shared rate limit and a token budget; hammering it gets you 429s and helps nobody.

Between calls, track cumulative tokens_used from each response. Stop when the budget is hit and say so clearly.

Make it resumable. Persist the plan with a status per cell (pending, done, failed, skipped) before you start. A 144-search run will be interrupted — a laptop sleeps, a network drops. Resuming should be obvious and safe, and re-running a completed cell should be free anyway because duplicates are not charged.

Show live progress: which cell, how many businesses so far, tokens spent, tokens left.


Coverage reporting

Be honest here. This is the difference between a useful tool and a false sense of completeness.

After a run, report:

A good signal for the user: if the last few searches were still returning new businesses, coverage is not complete. If they were returning almost entirely duplicates, you are close to what Maps will give you.


After the run

Coverage is step one. The businesses are saved but only partly enriched.

Show the count breakdown before each of these. The user has just spent a lot of tokens on discovery and should decide deliberately about the next spend.


Traps specific to this build

Running the grid in parallel. Rate limits, and no faster in practice.

Not persisting the plan before starting. An interrupted run with no state is a lost run.

Treating overlap as waste. Heavy overlap between keyword variants is expected and free. It is evidence the coverage is converging, not evidence of a bug.

Claiming completeness. You cannot know the denominator. Never imply you do.

Expanding a region into places with no listings. Filter obviously-empty results out of the report rather than presenting a wall of zeros; but keep them in the plan record so a rerun does not retry them.

Ignoring 429. Exponential backoff, resume where you stopped.

Lyre Leads · Home · Agent guide · Build specs · API docs · Data dictionary