Skip to main content
Glama
README.md
**Question:** Are new digital companies forming faster in Leeds than in the rest of Great Britain? *(PROXY QUESTION, NOT A REAL USER)*
**Answer:** There's no sign Leeds is pulling ahead. Its share of new digital companies stays at about 1.4% of Great Britain's.
**Main caveat:** A company's registered address isn't where it works, and about 43% of Great Britain's digital companies registered in the latest year sit at formation-agent addresses, which this leaves out.

---

# Market Pulse

Market Pulse lets an AI assistant such as Claude answer questions like *"how many cleaning firms started in Leeds this year?"* from the free Companies House data. The answer comes with the count, the date and the warnings, so they're harder to lose.

The data is free, but getting an answer by hand means downloading a 471 MB file, filtering 5.7 million rows by industry code and postcode, and knowing four traps:
1. The file lists **live companies only**. Firms that have closed are missing, so older periods under-count.
2. A company's **registered address** isn't where it works. Some formation-agent postcodes hold thousands of companies.
3. **Small numbers swing by chance**, and very small ones can identify a business.
4. **AI assistants tend to keep the number and drop the warning.**

Market Pulse deals with the first and third. For the second, it leaves out formation-agent addresses and warns that the rest may not be where a company works. For the fourth, it builds the warnings into each answer and is tested on that, though an assistant can still shorten them. For the first, it also holds the 2 million companies registered since 2021 and later dissolved, fetched from the Companies House API, so it can count the companies in this data registered in a period, including those dissolved since, not just the survivors. It also holds the 3.9 million companies dissolved since 2021, whatever year they were registered.

## What you can ask
- **An industry:** everyday words ("barber", "coffee shops", "AI startups"), a 5-digit SIC code, or a whole group such as "812" (all 7 cleaning codes). Many everyday industries have no code of their own, so the server offers about 25 ready-made bundles (AI, e-commerce, cafés, logistics and so on). Each one is labelled approximate, and its answer says in the first sentence what it counts and what it misses. Every answer names the codes it used, because the choice can flip the answer.
- **A place:** the UK; an English region (London, the North West and so on) or Wales or Scotland as a whole; or any local council area in England, Wales or Scotland. Regions, nations, Great Britain and the UK have their own rounded totals, as do whole industry groups and divisions, so broad answers usually have narrow ranges. The exception is a recent period with dissolved companies counted: its few closures are spread over many small rounded cells, so its range can be wide and its test cautious, and it may say "no clear change" where the change is real. Some totals are rounded separately from their parts, so the parts of an answer (quarters, areas, industries) may not add up exactly to its total.
- **A period:** any quarter from January 2021 to the latest complete quarter. Comparisons default to the latest four quarters against the same quarters a year before; you can pick the period ("2026 so far") and compare it with the same quarters a year earlier or the period just before.
- **Comparisons:** by quarter, or across every council area. The server tests whether a change is clear in this snapshot, allowing for rounding and chance; a verdict is a statistical call, not a certainty.
- **"Is my area keeping up?"** One call compares an area with Great Britain: its share, whether the share really moved, and how concentrated the industry is there. Its counts include companies dissolved since, so an older period isn't made to look smaller by its closures.
- **"Bristol or Manchester?"** One call tests two places head to head: whether one likely has more, and whether one likely grew faster in percentage terms. Most pairs of council areas are too close to call on growth; in a check against exact counts over 9,640 pairs, it named a faster grower 11 times (all right) and the one with more 2,627 times (all right).
- **"Where is it growing fastest?"** Ranks every council area and raises the bar for "stands out", because with hundreds of areas, some look like hotspots by chance. Its counts include companies dissolved since. On still-open counts it named 32 areas across 89 industry selections and four periods, and only 11 held on exact counts: most had simply lost more older companies to closure. With dissolved companies counted it named 39, and all held. The cost is that it named no area for the latest period in that check, because that period's closures are too thin to test, so it will often say none can be named. It can't say which area grew fastest. Asked "is Hackney the fastest-growing?", an assistant may still answer a flat "No" when the data only shows that no area stands out; in testing, two changes to the server's wording didn't stop that.
- **"Where are most AI startups?" and "What are the biggest industries here?"** Two lists by size, not growth: the council areas (or regions and nations) with the most companies in an industry, and a place's biggest industry divisions. Each row has a likely range and a likely rank. Rows whose ranges overlap share a span of ranks (such as 2–5), so the list never claims an order the rounding and chance can't support; even a single rank is an estimate, not certain. In a check against exact counts (35 industry selections and 52 places, three periods), every range and likely rank held over 11,476 listed rows, including the 853 given a single rank; that is a sample, not a guarantee.
- **"What's growing in Leeds?"** One call lists every industry division for a place (or the UK) in SIC order, this period against the earlier one, and marks the divisions that likely rose or fell, with the bar raised for testing about 90 at once. For a single council area few divisions clear that bar.
- **"How crowded is it?"** How many companies are live (not dissolved) in a place now, whatever year they were registered, split into those registered before 2021 and since. About 15,700 companies registered before 2021 still carry a code from the old 2003 SIC list and are left out, because those codes don't match today's.
- **"How many were registered?"** Counts can include companies dissolved by the snapshot date, which is the fair way to compare one year with another. This one tool counts still-open companies unless asked otherwise, and gives no verdict across quarters on that basis. With dissolved companies counted, it tests the first quarter against the last only when they are the same time of year, because registrations vary by season.
- **"Are more opening than closing?"** Companies registered against companies dissolved in the same place and period, whatever year those were registered, with a test of which was higher. A period under a year gets the counts but no verdict, because Companies House dissolves companies in weekly batches of very different sizes.
- **"Do new firms here last?"** The share of companies not dissolved within a year, for any industry and council area, against the rest of Great Britain, or ranked across every area. Dissolution lags real failure, because unless its owners apply to close it, a company that stops trading is struck off only after it misses a filing deadline, which for a new company falls more than a year after it starts. So this rate runs higher than survival measured by trading. Area verdicts leave formation-agent addresses out, so a verdict describes companies at other addresses, and the answer says so. In a check on exact counts for council areas, across four calendar years, the latest four eligible quarters and three levels of industry, 29% of clear tests changed when those addresses were put back, and 21% at a stricter bar. Those tests overlap, and they don't include the rounding allowance the tool itself adds.

## What every answer includes
- One ready-to-quote `answer`: the server's sentence plus the two must-quote warnings, so an assistant that forwards only one field still passes the warnings on. The sentence on its own looks like this: *"About 20 companies with SIC 81210 registered in 2026-Q3 in Leeds were still open on 1 November 2026 (likely range 10–30)."*
- The two warnings that matter most: what the count leaves out or includes (companies dissolved since, or for live now, which companies count as live), and registered address isn't where a company works.
- How many companies at formation-agent addresses were left out.
- The snapshot's date and a SHA-256 fingerprint of the unzipped snapshot file, so anyone can tell which data an answer came from. An answer from an older build shows the older date.

## What it will not do
- **Show a count below 10.** It says "under 10 (rounded)" instead, and that the true count may be somewhat higher, because each rounded piece of a sum can be up to 4 below the truth (in an area breakdown, "too few to number for certain", for any area without 10 for certain). The assistant is told not to work one out by subtracting, and if it tries, the rounding means subtracting gives a protected value, which doesn't establish the true count.
- **Give exact numbers.** Every stored count is randomly rounded to 5. A total for a group, division, region, Great Britain or the UK is rounded once on its own only when its parts already add up to 50 or more; otherwise it is the sum of its parts, which adds nothing new. Each build checks every way these tables add up (codes into groups and divisions, council areas into regions, Great Britain and the UK, formation-agent addresses and Northern Ireland) for open and for closed companies. It follows each count's possible range through those sums and stops if that pins a count below 10 to one value. That is a strong check, not a proof. Every answer, rate and comparison is built only from these protected cells. Some small counts can still be narrowed to a few possible values. The register itself is public; the point is that Market Pulse never publishes small counts. Each build is checked on its own: comparing answers from two builds of different snapshots isn't covered yet (see `DECISIONS.md`).
- **Look up a single company,** or break Northern Ireland down by area.
- **Tell you what a company really does.** It counts private limited companies, PLCs and LLPs, and dormant companies are included. Each company picks its own industry code, and register entries are what companies filed.

## Does it work?
- **Coverage:** for recent quarters the snapshot holds 97–100% of the companies Companies House says were registered, so the data is complete where it should be. For 2021 it holds only 36–37%, which is the live-only trap in numbers. `scripts/coverage.py` makes the table and `scripts/chart.py` draws the chart.
- **Hand checks:** two counts redone by hand from the raw file match exactly.
- **AI test:** 12 fixed questions, each asked 3 times through Claude: all 12 passed on the final code. The checks need the date, the live-or-closed wording, real quotes and no exact small count. They don't need word-for-word quoting: 3 of the 36 answers quoted the server's sentence exactly, and the rest reworded it. The first version had 5 fixed questions. The questions included a subtraction trick and "ignore the caveats". The run before the Q3 server change passed 4 of the 5: on "ignore the caveats", 2 of 3 answers dropped the long closure warning, the only place the snapshot date appeared. After the date moved into the answer's first sentence and the warning was shortened, all 15 answers in one run passed; one run can't show which change made the difference. An earlier 20-answer sample had one made-up quote; the check now catches a claimed quote that differs from the server's text. `scripts/e2e.py` is the test; the saved answers aren't in this repo.
- **Benchmark against an existing Companies House MCP:** Market Pulse answered two GB-wide market questions in under 25 seconds each; none of the other MCP's 6 runs produced a GB-wide council ranking. The exact counts also showed Market Pulse's small-area rankings were naming rounding artefacts. That was fixed, and tests now check every verdict against the exact counts. The full results aren't in this repo.
- **Reviews:** every stage had independent reviews. Each finding was fixed with its own test, or written down as a known limit. See `DECISIONS.md`.

**These are not official statistics, and nothing here is financial or business advice.** Check anything important against the original sources before acting on it.

## The worked example
`MEMO.md` uses Market Pulse to check a Leeds City Council priority, and shows how the answer changes when formation-agent addresses are counted.

---

## What it can touch
- **Reads:** one file, `data/serve.duckdb`, opened read-only. It holds rounded counts and the names of areas and industries, with no company names, company numbers, addresses or people.
- **Writes:** nothing. Its log goes to the error output your MCP client keeps: which tool ran, which fields it was given, how it ended and how long it took. Searches never log what was typed. An unexpected failure in any other tool also logs up to 300 characters of that call's inputs.
- **Connects to:** nothing. It makes no network calls and uses no accounts or keys when answering.
- **Runs as:** your own user on your own machine, started by your MCP client, with no listening port.
- **With other tools:** it holds nothing private and can't send data anywhere, but an agent can pass its answers to any other tool you've connected. That's your client's permissions to manage.

Read-only labels on tools are hints to the client. What keeps it read-only is the code: the database connection refuses writes and outside files, and tests try both.

To report a security problem, see [SECURITY.md](SECURITY.md).

## For whoever runs it

**You need:** a Mac or Linux machine, Python 3.12, about 2 GB of disk space, and Claude Code or Claude Desktop.

1. **Install:** `python3.12 -m venv .venv && .venv/bin/pip install --require-hashes -r requirements.lock`
2. **Secret:** copy `.env.example` to `.env`, run `chmod 600 .env` so only you can read it, and give `MARKET_PULSE_CELL_KEY_SALT` a long random value (`openssl rand -hex 32`). **Never share or change it once data is published**, because changing it weakens the protection on small counts.
3. **Data** (kept out of git): download the Companies House "BasicCompanyDataAsOneFile" snapshot into `data/snapshots/` and the ONS postcode lookup into `data/lookup/`. The exact file names are at the top of `scripts/build_grid.py`. Also download the ONS "Local Authority District to Region (April 2025) Lookup in EN (V2)" from the ONS Open Geography Portal as `data/lookup/regions/LAD25_RGN25_EN_LU_v2.csv` (named at the top of `scripts/build_levels.py`).
   Closed companies: put `COMPANIES_HOUSE_API_KEY` in `.env`, then run `.venv/bin/python scripts/backfill_closed.py` (it takes hours at the API rate limit and can resume). Download Companies House's official incorporation statistics into `data/official/` (the file names are at the top of `scripts/coverage.py`) and run `.venv/bin/python scripts/coverage.py`, which writes the coverage table the next check and some diagnostics read. Then run `.venv/bin/python scripts/backfill_check.py`, which must pass.
   Closures: run `.venv/bin/python scripts/backfill_closures.py` (also hours, and it can resume), then `.venv/bin/python scripts/closures_check.py`, which must pass.
4. **Build:** `.venv/bin/python scripts/build_grid.py`. This takes about 25 minutes. It stops before `data/serve.duckdb` is replaced if any small count could be pinned down, and a stopped build can leave `data/grid.duckdb` behind. It writes `data/grid.duckdb` (raw counts, for checks only: never share it) and `data/serve.duckdb` (protected counts only), which is the only file the server opens. If a build fails, the previous `serve.duckdb` stays in place, so the server keeps answering from the last good build: check the build output before trusting new data. After a build that works, restart your MCP client: a running server keeps answering from the data it opened. Every answer gives its snapshot date, so you can see which data it used.
5. **Test:** `.venv/bin/python -m pytest -q`. Every test should pass.
6. **Connect to Claude Code:** `claude mcp add market-pulse -- "$PWD/.venv/bin/python" "$PWD/src/server.py"`

**When something goes wrong:**
- **Errors:** a bad question returns a short code such as `BAD_AREA` or `OUT_OF_RANGE`; an input of the wrong type returns a longer validation message. If the data hasn't been built, or the file can't be read or has tables missing, a valid question returns `NO_DATA`: go back to steps 3 and 4. A file that opens but is damaged inside, or was built with different columns, can show as `INTERNAL` instead; rebuilding fixes that too. Anything unexpected returns `INTERNAL`. The details go only to the server's error output, which Claude keeps in its MCP log, and never appear in the answer.
- **No paid services:** the server makes no network calls. The free Companies House API key is used only by the one-off closed-company and closures downloads and their checks, which keep to the published rate limit, and by the hand-run comparison scripts.
- **Monthly refresh:** not built yet. A new snapshot is blocked: `scripts/build_grid.py` refuses any snapshot file but the served one until a two-snapshot rounding check exists (SC-12 in `AUDIT-FINDINGS.md`). New closed-company downloads aren't blocked, but they change counts too, so don't publish a rebuild from them before that check exists. After that, each refresh is a manual download and rebuild, and the dates are written into the scripts: start with the file names, date and `SNAPSHOT_SHA256` at the top of `scripts/build_grid.py`, then `FIRST, LAST` in `scripts/backfill_closed.py` and `scripts/backfill_closures.py`, and the file names in `scripts/coverage.py`, `scripts/backfill_check.py` and `scripts/closures_check.py`. To find the rest, including the fixed quarters in the check scripts, run `git grep -n -e 2026-11-01 -e 2026-Q3`. Answers from a snapshot over 45 days old say so.

**What's in `scripts/`:** you only need the first group to run this.
- **Build, in order:** `backfill_closed.py`, `coverage.py`, `backfill_check.py`, `backfill_closures.py`, `closures_check.py`, `build_grid.py`. The last one also runs `build_levels.py`, `pin_check.py`, `pin_levels.py` and `export_serving.py`.
- **Checks, free:** the other `check_*.py` scripts, `truth_c.py` and `truth_cases.py` (against exact counts), `sweep.py`, `memo_numbers.py`, `testing_results.py`, `measure_tools.py`.
- **AI test runs, which cost money:** `e2e.py`, `benchmark.py`, `benchmark_c.py`, `cases.py` and `breakit.py`. Each run has a spending limit, but the total depends on how many rounds you ask for. Any agent that would have shell access while reading register text is refused, because that text could steer it: see `AUDIT-FINDINGS.md`.
- **Left from earlier stages of the build, not needed to run it:** `spike_load.py`, `check_query.py`, `make_fixture.py`, `hand_check.py`, `hand_check_area.py`, `closed_check.py`, `chart.py`.

## Data sources and licences
| Data | Where from | File used | sha256 |
|---|---|---|---|
| Live companies | Companies House [Free Company Data Product](https://download.companieshouse.gov.uk/en_output.html) | `BasicCompanyDataAsOneFile-2026-11-01.zip` | `15457954c2e163608ebb1b51898002386732876b3de485c2fe3dfcb4ce550616` |
| Closed companies | [Companies House API](https://developer.company-information.service.gov.uk/) advanced search, one day at a time (`scripts/backfill_closed.py`) | `data/closed/` | checked against official totals by `scripts/backfill_check.py` |
| Every company dissolved since 2021 | [Companies House API](https://developer.company-information.service.gov.uk/) advanced search, one dissolution day at a time (`scripts/backfill_closures.py`) | `data/closures/` | checked against official dissolutions by `scripts/closures_check.py` |
| Postcode to council area | ONS best-fit lookup, August 2026 ([download](https://www.arcgis.com/sharing/rest/content/items/70be1092fa9648adb95f326c273fac56/data)) | `PCD_OA21_LSOA21_MSOA21_LAD_AUG26_UK_LU.zip` | `3b057c944d46353a52f6c6b85184273b2c61c5f362dfb36c82d32c140c3b3928` |
| Council area to region | ONS Local Authority District to Region (April 2025) Lookup in EN (V2) ([download](https://open-geography-portalx-ons.hub.arcgis.com/api/download/v1/items/1c17a07ff8fc44218883049f0afa3de1/csv?layers=0)), saved to `data/lookup/regions/` | `LAD25_RGN25_EN_LU_v2.csv` | `ef8470fe63a77945d17e730b546c25c62c296e256bffdc8ec76aae6264613ae2` |
| Official incorporation counts (coverage check) | gov.uk, "Incorporated companies in the UK" ([July to September 2026](https://assets.publishing.service.gov.uk/media/6ae08fa7779378370fd809e5/Incorporated_Companies_in_the_UK_July_to_September_2026.csv)) | `incorporated_2026Q3.csv` | `782235ada07deb85d7ce7e227a0d3e2fecb37a1749319fe2a3508bf61d0eb697` |

Check a download with `shasum -a 256 <file>` before building.

- **Companies House data:** Companies House says "We impose no rules or requirements on how the information on the public register is used" ([GOV.UK, updated 25 October 2022](https://www.gov.uk/guidance/companies-house-data-products)). Its statistics are on GOV.UK, where material is under the [Open Government Licence v3.0](https://www.nationalarchives.gov.uk/doc/open-government-licence/version/3/) unless stated otherwise. Users stay responsible for data protection and copyright law. Market Pulse serves only rounded counts, never company names, numbers or addresses.
- **ONS postcode and region lookups:** [Open Government Licence v3.0](https://www.ons.gov.uk/methodology/geography/licences). Contains OS data © Crown copyright and database right 2026. Contains Royal Mail data © Royal Mail copyright and database right 2026. Source: Office for National Statistics licensed under the Open Government Licence v.3.0.
- **Northern Ireland postcodes:** the ONS file's Northern Ireland rows come with an end-user licence for internal business use only, so the build leaves them out. Market Pulse marks a company as being in Northern Ireland from the BT prefix of the postcode on its own public register entry, and never breaks Northern Ireland down by area.
- **Code:** MIT licence (`LICENSE`).

*Built by James with Claude Code as a portfolio project, November 2026. James set the direction and made the decisions; Claude Code wrote the code, tests and documents and ran the checks; Codex reviewed the work independently. The full decision log is in `DECISIONS.md`, and the specification is in `SPEC.md`.*

TDQS

A3.9/5.0

Scored across 12 tools

Disambiguation4/5

Most tools have clearly distinct analytical purposes, and descriptions explicitly cross-reference alternatives (e.g. largest_areas vs rank_areas_against_great_britain, breakdown_by_industry vs largest_industries). The main overlap is among the counting tools: count_incorporations_still_live, count_companies_live_now, and registrations_against_closures address similar-sounding company counts but differ in period and live/dissolved treatment.

Naming Consistency4/5

All names are snake_case and mostly follow a verb_noun or action-object pattern (find_sic, find_area, count_*, compare_*, rank_*). A few are noun phrases rather than actions (breakdown_by_industry, registrations_against_closures, largest_areas, one_year_survival), but the overall convention remains readable and predictable.

Tool Count5/5

Twelve tools is well scoped for a focused market-intelligence server covering lookups, counts, comparisons, rankings, and survival analysis. Each tool appears to earn its place without obvious redundancy.

Completeness4/5

The surface covers the core workflow well: finding SIC codes and areas, counting live/registered/dissolved companies, comparing areas and industries, ranking hotspots, and survival analysis. Minor gaps remain around explicit time-series exploration and custom multi-area or multi-industry comparisons, but agents can work around them using the existing comparison tools.

Maintenance

ActivityMaintained
ResponsivenessNo recent community issues