You can already find this data. What costs you a week is putting it together. This is that week, in about twenty seconds, with every claim resolving to a record.
Seven open-source data connectors · Free · MIT licensed · Every figure dated and sourced
Do not explain the domain to this room. They know the Council's discretionary funding documents better than you do and have FOILed for worse. The pitch is never "here is discretionary funding" — it is "here is discretionary funding, queryable in seconds, by an agent that cites its source and refuses to guess."
Expect to be interrupted with hard questions about provenance and coverage. That is the good outcome. Every slide has notes written so you can answer them.
Runs ~21 minutes. If short on time cut Act 4 (slide 8), never Act 5 (slides 9–11).
If you have the contract ID, open Checkbook. A browser tab beats a query every time. Do not let a tool add a step.
A FOIL request, a filing, a number going in front of a judge. Go to the source document. This is a research accelerator, not a system of record.
Campaign finance to legislative district. 18.3 million rows, refreshed daily, attributable to a district on 0.16% of them. No tool fixes a missing key.
What is left is the part that actually costs you: assembling something nobody has assembled yet, across systems that were never designed to be joined.
Open by conceding, and mean it. This room has watched a decade of civic tech oversell. The fastest way to lose them is to claim the tool is good at everything.
The third card is the strongest and it is our own finding — Crosswalk F in the repo. 18.3M campaign finance rows, district-attributable on 0.16%. An honest "this join does not exist" buys more here than any capability claim.
Then pivot on the last line. Assembly is the thing they actually pay for in staff hours.
Individual designations run $5,000 to $280,000. The tool reports the total over every matching row, whatever the display limit.
Organization is the Association of Community Employment Programs for the Homeless (EIN 13-3846431). Verified 2026-10-19 with search_disclosure_awards(ein="133846431", fiscal_year=2026): 71 rows, $7,399,527, all Cleared, none Pending. Press R to replay.
Precision on the sponsors: 41 named council members, plus the Speaker, the Brooklyn and Queens delegations, and one $153,277 BID Containerization line (via DSNY) with no member printed. Do not say "44 council members."
This is the Council's discretionary funding disclosure, its own award-level list. It is a later snapshot than the adopted budget's Schedule C, so it includes designations made after adoption, each marked Cleared or Pending. In July this slide read 54 awards and $6,455,750 from the adopted-budget extract; the difference is the snapshot, not an error.
Left panel is "by hand," not a web search. This room can already find the workbook. What they lack is the assembly, so that is what the comparison has to be about.
32 payment records · $1,040,448.79 across DYCD, DOE, SBS, DOT and Small Business Services.
Three checks under budget code 3625 (TAX LEVY ELECTED OFFICIALS):
$107,244.16, $33,000.00, $2,560.00.
"Check Checkbook for FY2026 spending paid to CLOTH."
Run this query
The allocation side shows CLOTH receiving $40,000 from Council Member De La Rosa. The disbursement side shows $142,804.16 under Tax Levy Elected Officials.
Those do not match, and that is not an error. The disclosure also lists CLOTH funding from
the Speaker, Council Member Abreu and the Manhattan Delegation — $353,986 in all. Code 3625
does not say whose allocation a check discharges.
So the join is real — allocation in one system, an actual check in another. And getting from there to whose allocation that check discharges is a further step the budget code does not give you. Published, current, and still not joinable to the unit governance actually uses.
🚩 Do not say $107,244.16 is De La Rosa's money arriving. Her FY2026 designations to CLOTH are $30,000 (NYC Cleanup) and $10,000 (Community Safety and Victim Services). It is not, and this room will catch it. Say the gap out loud before anyone asks.
The interesting output of this pattern is the mismatch, not the match — allocations with no matching spending, or spending exceeding allocation. Just be precise about which mismatches are findings and which are artifacts of a coarse budget code.
Checkbook figures re-verified live 2026-10-19 (search_spending, 32 records, $1,040,448.79, no error). Allocation figures from search_disclosure_awards(legal_name="Community League of the Heights", fiscal_year=2026), 2026-10-19: 9 rows, $353,986, all Cleared.
Two independent catalog searches return six CTE report datasets spanning 2015–16 through 2019–2020. Most recent published 2021-09-22. Nothing newer.
"LL174 requires an annual CTE report. What is the most recent on the portal?"
Run this query
What we established is that the dataset is not on the portal. That is not the same as the report was never produced.
It may well have gone to the Council as a PDF and never been published as open data. Different findings, different remedies — and the second one has a named owner: § 23-507 puts an open data coordinator at every agency.
This is a method, not a finding. Any reporting mandate in the Administrative Code can be checked against the portal the same way. That is a survey your team could run.
Do not skip the right-hand card. "The law says annual, the portal's most recent is 2019–2020, it is 2026" is the line that lands — and the bounded negative immediately after is what makes it survive scrutiny.
Second live example if you want one: NYC's Broadband Adoption by State Senate District dataset (9bjg-n96a) has 26 rows covering SD 10–34 plus 36, all created 2020-06-19. It does not contain District 59 — the file predates current district lines. A digital-equity dataset that cannot answer for a third of the city's senate districts.
This is the act to cut if you are short on time, but it is also the most reusable one for their own staff.
FY2009 and FY2011–FY2027, award by award. FY2010 is not loaded: the Council's own workbook for it is incomplete. FY2009 and FY2013 are early snapshots, so their Cleared totals are not headline figures. Nothing before FY2009.
FY2015–FY2017 and FY2019–FY2027. FY2018 is missing from every source found. Exact by budget line only: the Council's project IDs do not link to OMB or Checkbook projects. Join on budget line, not on project ID.
council_member matches as a substring — "Powers" returns
Brooks-Powers and Keith Powers. The tool now names both and splits the totals; read that note.
One tax ID can cover many programs: EIN 13-2612524, the Fund for the City of New York,
carries dozens of them.
get_voting_record returns real positions, but defaults to the 50 newest rows
with no total, and carries each matter's introduction date, not the vote date. Ask for a large
limit, dedupe by file number, and use vote_breakdown for dates.
Stating a coverage gap before you are asked buys more credibility with this room than any figure could.
Do not read the grid. Pick the two that match what they asked about.
The council_member substring match used to merge two members silently. Budget MCP 2.0.0 now names every person matched with their own totals; use council_member_id for exactly one. Background: budget repo issue #38.
The votes card is the live example of a quiet default: 50 rows, newest first, no total. A July script reported "46 matters" for a member who had 459 by October.
Search nysenate.gov one session at a time. Every year is a separate search.
Match on title, because print numbers change every session:
A8139 becomes A6323 becomes A5485.
Then notice it moved between three sponsors over fourteen years. Nothing upstream links a bill to its own past lives.
A8139-2011 Hanna · A6323-2013 Nojay ·
A5485-2015 Nojay · A5768-2017 Errigo
Same title, same summary. Four sessions, three sponsors, none became law. In 2016 someone struck the enacting clause.
"Trace this bill across every session it was introduced in."
Run this query
Every one of those bills is public. The pattern is indexed nowhere. "How many times has this been introduced and killed" is a days-long research task in Albany and a ten-second question here.
Keep this to two minutes. It exists because of their name — Reinvent Albany tracks which reforms die repeatedly, and this is the only act in the deck built for one organization.
The line to land: "Same bill, same summary, four sessions, three different sponsors, fourteen years. In 2016 someone struck the enacting clause. None of it became law, and no single page anywhere tells you that."
⚠️ Do not say A3140-2025 "died." Linda Rosenthal's FOIL and Open Meetings review bill (A7933-2023 → A3140-2025) was re-referred to Governmental Operations on 2026-01-07 and is live this session. The dead lineage is the real-property-tax one. Getting that backwards in front of this room would be bad.
⚠️ Statuses move. This is bills in committee; one can be reported out between now and the meeting. Re-verify.
⚠️ Coverage gaps, volunteer them. The local corpus holds 231,194 bills and 1,992 members — but floor transcripts and hearing transcripts are both 0 rows, and NYS law sections number only 137. The transcript tools reach the live API but have no local corpus. Do not demo transcript search. Verified against corpus.db 2026-07-27.
Read the refusal aloud if it comes up. Passing query= instead of term= returns: "Unrecognized parameters are rejected rather than ignored, because silently dropping a filter returns real data that answers a different question." That sentence is the entire thesis of the meeting, written by the tool.
Returns live notices with agency, PIN/EPIN, selection method, hour-precise due date, and a named contact with a phone number.
"What NYC procurement solicitations are currently open, and which agencies posted them?"
Run this query
Without reading the daily PDF.
This act is only worth running live. The whole point is that the notices are current, and reading out a solicitation that closed last week undercuts it entirely.
⏳ The three examples in the July 21 script have expired. FDNY 05726B0010 closed 2026-07-21 14:00. Do not quote them. Run the prompt fresh and read whatever comes back.
This is the act to cut if you are short on time. Never cut Act 5.
If it runs long: get_open_solicitations is very verbose — City Record notices embed raw HTML. Always bound the query.
Checkbook's documented API starts returning 403 to us. The site loads fine in a browser.
A letter to the Comptroller's office. Three asks. No header spoofing, no working around the block.
Two days. A real technical response, their CIO looped in, and an offer of a call.
Access working. The residual block was ours — we were exceeding a rate limit.
We were making roughly forty requests against their origin for every one logical API call, because our client followed redirects. Their fix had already worked. What we were still measuring was our own client getting itself blocked. Fixed on our side in v1.6.0: rate pacing, backoff, no redirect following.
🚫 Do not run part one as a live query. The July 21 version of this act demoed the 403. Access was restored 2026-07-28 and re-verified 2026-07-30 — the query now simply works.
Why this is the right material for this room: they spend their working lives being told a data problem is somebody else's fault. An organization that says "we asked, they fixed it, and the rest was us" establishes that its findings are worth trusting when they do point outward. The correction is the credential.
If the room is technical, tell the near-miss: on 2026-07-27 we nearly reported "your fix did not work" to a CIO who had just done real work for us. The test had egressed through a VPN on a datacenter IP, not the office address they investigated. Chrome from the same address loaded fine, which caught it. One address, two clients, minutes apart: browser 200, command line 403.
Our 2026-07-09 audit made two claims about public data we could not reach. The office answered both, and corrected us on one.
We reported that a prime-expense registration date was not available as a filter or a response column.
It is. The field was there and we missed it.
Not exposed in the API or on the open data portal.
Confirmed by the office. They said they will consider it.
That correction is on this slide for a reason. It is the same standard we are asking you to hold every other number in this deck to, applied to us, by someone else, in public.
Say "the field was there and we missed it" in exactly those words. This is the slide that pays for the whole deck with this audience.
⚠️ Scope, per the 2026-07-27 decision. This slide reports on our error. It does not critique the Comptroller's dashboard — that critique was deliberately removed and is not reinstated by our now having more information. Do not evaluate another office's product in front of a third party.
Also confirmed by the office, if asked: the Checkbook 2.0 migration dropped no documented API fields or domains, and external applications can keep using the API without going through the web interface. They also fixed two drifted NYC Open Data catalog entries we had flagged.
This is the worked example of the rule in our own good-government README: an absence you searched for is weaker evidence than a presence you found. We published an absence and it did not hold.
1 request per second. 20,000 records per call.
Neither appears on the API landing page, in the global parameters table, or on any domain page. We learned both by violating one, getting blocked, and being well-connected enough to get someone on the phone. The office says other users are hitting the same wall for the same reason.
The landing page says 20,000 records per call; every domain parameter table says fewer than 1,000 and caps the field at four characters, which cannot express 20000. We tested — 20,000 is correct and the tables are stale.
The landing page says records_from. The parameter tables say record_from.
That is the part worth knowing. Not that the limits exist — they are reasonable limits. It is that the only way we learned them was to violate one and get blocked. A researcher hitting the same wall just experiences an outage and concludes the data is unreliable.
We have passed all of it back to them. That is where it sits.
⚠️ This slide carries NO ask, per the 2026-07-27 scope decision. Report the finding and stop. Do not invite the room to co-sign anything and do not suggest their name would carry it further. That framing was removed deliberately and is not coming back. If someone volunteers to weigh in, that is their initiative and a fine outcome — you do not solicit it.
Get the letter's status right. Sent 2026-07-22, answered 2026-07-24. Do not describe it as pending, unsent, or unanswered. Richard Lundy (Assistant Comptroller, IT Operations/CIO) is the technical route, Matt Rubin (Chief of Staff) is the relationship owner.
We replied 2026-07-29 confirming access works, owning the rate-limit fault, and asking whether the limit is scoped per IP or per client. That question is outstanding — and it is ours to pursue.
We checked the portal's contents and nothing else. "Not on the portal" is the whole claim. It may have gone to the Council as a PDF.
We checked the landing page, the global parameters table, and every domain page, and the office confirmed verbally it is undocumented. That is our search plus their word, not proof.
This slide is not a disclaimer, it is the product demonstrating what it is for. An audience that does oversight for a living will notice the difference between "this dataset is not on the portal" and "the city stopped producing this report" immediately.
Overstating once costs more than the finding was worth. Say that out loud if it helps.
NYC Council Legistar · the Comptroller's Checkbook NYC · The City Record · the City Charter, Administrative Code and Rules · NYC Open Data · NYS Senate OpenLegislation · NYC 311.
All public. None of it ours.
An assistant queries these connectors and reads back what they return. It does not extract the budget data — that is deterministic PDF parsing, reconciled against printed totals, because reconciling public money has to be reproducible.
The AI is the interface, not the arithmetic.
BetaNYC received $25,000 in FY2026 Council discretionary funding under the Digital Inclusion and Literacy Initiative, via the Fund for the City of New York.
You can verify that in fifteen seconds, with no account.
Every bug described in Act 5 is a public issue with our name on it, including the one where we were the problem.
The third card is the strongest one in the deck and it costs nothing. A deck that teaches people to query discretionary funding should disclose its own award and invite them to check it.
If asked about the AI-use position: it matches the statements carried in the public repos. Vagueness here would be self-defeating in a deck about grounding.
The connectors are public repos, the guides are CC BY-SA, and most of it needs no API key at all. We would rather you check it than take our word for any of it.
If there is a query your team runs constantly by hand, that is exactly the user journey we want to add.
The ask is the last line. Get one concrete recurring query out of the room before you leave. That is worth more than any follow-up meeting.
Leave-behind: the published script for this meeting is at guides/good-government/reinvent-albany.md in the repo, with every figure's provenance in the presenter notes at the bottom.