Every address on this site, as links

Everything below is a file you can fetch. No login, no rate limit, no JavaScript required. If you are a program, lunenburgbudgetproject.org/llms.txt explains what each one holds and how the figures are derived — but read the warning first.

Before computing anything.

The archive holds both what the town BUDGETED and what it SPENT. They differ by up to 59% on some lines, and a rate measured from one to the other is partly growth and partly the gap between them. Never mix them in one calculation. A budget line is also NET of grants, fees and state aid — it is not what a thing costs.

What you can ask, and the file that answers it

The meeting archive, one file per board

12,155 agendas and sets of minutes across 51 town boards, 2009-01-05 to 2026-11-17. Each file is every document that board published, concatenated, so it can be searched in one fetch. You cannot grep a website; you can read one file. The per-document copies, for citing, are under /docs/minutes/text/<board>/.

Finding a word in the minutes

Do not start with a bundle — the two largest are around a megabyte, more than many callers can read at once. Look the word up and fetch only the documents it names: three small requests instead of one large one. Everything needed to answer a question about this town is on this site; nothing here requires a repository, an account or a tool.

Every published data file

The same list lunenburgbudgetproject.org/llms.txt carries, with the same descriptions — both are generated from scripts/build_agent_endpoints.py, so neither can describe a file the other does not.

  • lunenburgbudgetproject.org/data/sped-lines.csvEvery budget line this project counts as special education, and which of the two rules caught it. They sum to the amount the projection starts from. Published because the state has no account code for special education, so the total is our classification rather than a figure anybody published. (0.0 MB)
  • lunenburgbudgetproject.org/data/sped-teacher-history.csvSpecial education teachers as budgeted, FY20 to FY27, by school. Eight budgets growing 2.67% a year against a 3.5% contract — below it, because headcount here has drifted down. (0.0 MB)
  • lunenburgbudgetproject.org/data/sped-para-history.csvSpecial education paraprofessionals as budgeted, FY18 to FY27, by school. Ten budgets growing 12.8% a year with an R-squared of 0.89 — which is why this line is escalated at what it has done rather than at the 2.0% its contract gives. (0.0 MB)
  • lunenburgbudgetproject.org/data/sped-transport-history.csvSpecial education transportation as budgeted, FY19 to FY27. Nine budgets, 5.7% a year, R-squared 0.33 — a weak trend, used because the vendor contract publishes no escalator. (0.0 MB)
  • lunenburgbudgetproject.org/data/ood-tuition-history.csvOut-of-district special education tuition as budgeted, FY17 to FY27, extracted from the district’s own budget documents with the budget stage held constant. Eleven budgets ranging 2.6x with no trend — which is why the model holds this line flat rather than escalating it. (0.0 MB)
  • lunenburgbudgetproject.org/data/model.jsonEvery figure the site computes: the FY27 base by bucket, the growth assumptions, the projection, the program catalogue, the conclusions, and the citations. (0.4 MB)
  • lunenburgbudgetproject.org/data/sources.jsonThe document archive: every source, its group, its size, and the URL it is served from. (3.9 MB)
  • lunenburgbudgetproject.org/data/budget-lines.csvThe district budget, 351 line items, one column per fiscal year and scenario. The tidy form of the workbook everything else is derived from. (0.1 MB)
  • lunenburgbudgetproject.org/data/district-page-index.csvThe 87 documents mirrored from the district budget page: label, our copy, the extracted text, the district’s original URL, and a sha256. (0.4 MB)
  • lunenburgbudgetproject.org/data/staff-roster-entries.csvEvery name and position the town printed in its per-school staff rosters, FY2011 to FY2025 — 3,815 rows across 51 roster blocks, with the school, the page it came from and the heading it sat under. Published because it is the only published quantity that bears on whether budgeted positions were filled. At 435KB this file is more than some callers can fetch in one piece; https://lunenburgbudgetproject.org/api/staff_roster_entries is the same rows as one file per fiscal year, about 60KB each. It is NOT a staffing level: there is no FTE, so a 0.4 music teacher and a full-timer are one row each; there is no funding source, which is the question that actually matters; and it is a point in time, undated within the year. POSITION IS OUR CLASSIFICATION AND IT FAILS IN SOME YEARS. It is mapped from the printed job title, and the print changes: FY2012 says "Tutor", FY2013 "Aide", FY2014 "Paraprofessional" — and once "Paraprotessional", an OCR typo that drops that person from the count. FY2015 printed the page in two columns, which the extractor collapsed, leaving five people with no title at all. So a series counting paraprofessionals in the Kindergarten section reads 0, 5, 4, 4, 0 for FY2011–FY2015 across roughly the same five people. THE ZEROS ARE EXTRACTION FAILURES, NOT STAFFING. Found by an assistant reading the rows, not by any check here. Use `role_raw`, which is what the report actually printed, before trusting `position`. (0.4 MB)
  • lunenburgbudgetproject.org/data/staff-roster-counts.csvThe same rosters counted by year, school and position — 699 rows. Use this rather than counting the entries yourself, and read the caveats on staff-roster-entries.csv before treating any of it as headcount. (0.0 MB)
  • lunenburgbudgetproject.org/data/placement-counts.csvOut-of-district special education placements by year, FY2013 to FY2025, split into collaborative, day and residential. From the Special Services report inside each annual town report, sourced to SIMS Report 7 and measured on 1 March. Two checks come with it: the parts sum to the total, and each year states the previous year’s figure. It is a count of children placed and says nothing about which fund paid or what a placement cost. (0.0 MB)
  • lunenburgbudgetproject.org/data/archive-manifest.csvEvery file in the archive — 3,876 of them — with its size, its sha256, and the publisher’s own URL where one is recorded. The documents themselves are no longer in the repository: they are in a public, locked R2 bucket and are served under the /docs/<path> URLs they have always had, so this is the index that makes a download checkable and the list a fresh clone works from. The bucket holds no copy of this file, deliberately — an object there cannot be updated once written, so a manifest inside it would be permanently out of date about its own contents. (9.4 MB)
  • lunenburgbudgetproject.org/data/free-cash-proof.csvThe Division of Local Services free cash proof for Lunenburg and eight comparable towns, 2021-2025, line by line. Free cash is what a town may appropriate without raising taxes. NOTE: these are absolute dollars with no denominator anywhere in the source, so they do not compare between towns of different size. The composition does compare, because a share has no size. (0.1 MB)
  • lunenburgbudgetproject.org/data/rate-register.csvEvery rate this project knows about — athletic and bus fees, collective bargaining raises, facilities — each carrying the fiscal year it applies to, the document that set it and the date. 62 rates. It exists because FY26 athletic fees were modelled on FY25’s schedule for months: a right number from the wrong year, taken from a fee page that states its rates and never states which year they cover. It deliberately includes the rates the model does NOT use and the ones we cannot state at all, because a fee the town charges and does not publish is a finding rather than a blank. (0.0 MB)
  • lunenburgbudgetproject.org/data/athletic-fee-schedule.csvAthletic user fees by fiscal year and tier, FY24 to FY27, per student per sport per season. 27 of 31 figures verified against a spreadsheet cell or a direct quotation from the School Committee vote that set them. (0.0 MB)
  • lunenburgbudgetproject.org/data/model/index.jsonEvery figure the site computes, one section per file. An index; each section is its own file, sized. (0.0 MB)
  • lunenburgbudgetproject.org/data/sources/index.jsonThe document archive: every source, its group, its size and its URL. An index; each section is its own file, sized. (0.0 MB)
  • lunenburgbudgetproject.org/data/minutes-index.csvEvery agenda and set of minutes the town publishes: board, date, kind, the town’s own URL, has_text and searchable. 12,198 rows, of which 12,147 have an extracted text file and only 11,011 hold any text a search can match — the rest are image scans. Check SEARCHABLE, not has_text, before concluding that something was never discussed: a document nothing can read and a subject nobody raised are different facts and produce the same empty result. (2.1 MB)
  • lunenburgbudgetproject.org/data/lunenburg.dbthe SQLite database everything on this site is derived from. Its sha256 is stated in /api/index, so you can check you got the bytes we published.

Everything else

What changed

Version 15 — updated September 20, 2026