Skip to content
FS Fábio Silva
← All work

Developer & designer (solo)

Vouchline

A research tool for SEC filings where every sentence of an AI answer links to the exact line it came from, and "the filings don't say" is a real answer. Search, figures, diffs and alerts are deterministic code. The language model only turns retrieved passages into prose, and the code checks its work before you see it.

Vouchline in action: ask a plain question about public companies, get an answer where every sentence is cited, and open any citation at the highlighted line of the SEC filing.

AI research has a trust problem, not a feature problem

Analysts, investor-relations teams and competitive-intelligence people live inside SEC filings. A single 10-K often runs past a hundred pages, and a watchlist of twenty companies produces dozens of filings every quarter. AI research tools promise to read them for you.

But these people have to defend every number they quote, to a manager, a client or an investment committee. An answer that sounds right isn’t enough, so they open the filing and check. If they check every AI answer anyway, the AI hasn’t saved them a step. It has added one.

The bottleneck was never writing. Language models summarise documents well. The bottleneck is verification.

So Vouchline is built around one promise. Every sentence of an answer can be checked in one click, and when the filings don’t say something, Vouchline tells you instead of guessing.

The model writes. The code checks.

Here is what happens when you ask “What does NVIDIA say about export controls?”

1. Retrieve. Postgres full-text search runs over about 7,800 passages from 77 filings: the latest 10-K, two 10-Qs and the latest earnings release for 20 large US companies. Each passage is scored by how rare its matching keywords are across the whole corpus, so common words can’t carry a weak passage. Two rules came from reading real results:

  • Safe-harbour boilerplate lists every topic a company touches and says nothing about any of them. It is weighted to a fifth.
  • An earnings release opens with its headline figures, so that passage counts half as much again.

2. Write. An LLM receives the passages numbered and wrapped as quoted data, with instructions to ignore anything inside them that looks like a command. Every factual sentence must end with the number of the passage it came from. The model also has a defined way out. If the passages don’t answer the question, it must reply with a single NO_ANSWER token. If they answer only part of it, it must name the missing part on a line of its own.

3. Check. Then the code takes over, and it does not trust the model to audit itself:

  • A citation that points at a passage the model wasn’t given is deleted.
  • Only passages the answer actually used are cited.
  • Each sentence is split out and checked on its own. Any sentence without a source is flagged No source in the interface, not hidden.
  • Each answer gets a coverage note, for example “5 of 6 statements cite a filing”, along with the parts of the question the filings didn’t cover.
  • Citations are written by the server, never by the client. The database has no insert rule that would let a user create one.

Click a citation and the filing opens with that passage highlighted.

There are smaller details too. While the answer streams, the first few characters are held back until the code knows they aren’t the start of NO_ANSWER, so you never see a half-written refusal. And if there is no API key, or the model call fails, Ask returns the cited passages themselves. The product still works without the model, which shows the model is one layer of the product, not the product.

The model is asked to behave. The code makes sure it did.

Most of this app never calls a model

All of the AI in Vouchline lives in one 110-line file. Everything else is deterministic, and that is a deliberate choice:

JobHow it’s doneModel?
SearchA query parser (AND, OR, NOT, NEAR/n, phrases, prefixes) compiled to Postgres full-text queries. A plain question is reduced to its keywords, and the query that ran is shown on screenNo
Financial statementsRead from EDGAR’s XBRL company facts. Q4 is worked out as the full year minus three quartersNo
What changedA Myers diff of this year’s filing against last year’s, sentence by sentence, then word by word inside edited sentencesNo
TablesRebuilt from the filing’s HTML, with stray $ and ) cells folded back into their figuresNo
AlertsOne email per window, grouped by company. Sending is idempotent, so a filing is never sent twiceNo
Earnings datesEstimated from the company’s own reporting history and always labelled as an estimateNo
Answers, grid cells, research plans, company overviews, follow-up questionsAn LLM, from retrieved passages onlyYes

Financial data shows why this matters. NVIDIA changed the XBRL concept it uses to report capital expenditure. For some periods, the figure EDGAR puts first comes from a proxy statement, rounded to millions. A model would blur both cases. The code handles them directly: for each period it takes the first concept that has a value, and it uses the 10-K or 10-Q figure instead of the proxy statement’s rounded one. I checked the numbers by hand against the published reports.

What it does

  • Ask, and Ask in Doc. Cited answers across the whole library or inside a single filing, with three suggested follow-up questions.
  • Search that explains itself. Type a plain question, or Boolean syntax if you know it. Vouchline shows the query it ran, and each result shows the sentence that matched.
  • Grid. Filings in rows and questions in columns, for example “How does each company describe pricing pressure?” across twenty 10-Ks. Every cell is cited or reads “This filing doesn’t say”. Cells fill four at a time in the background, and an answer to a question you have since edited is thrown away. Exports to CSV.
  • Deep research. The LLM splits a broad question into three to five sections. Each section is searched and written separately, citing only its own passages, and the progress is saved section by section, so the report keeps going if you leave the page.
  • Agents. A saved question with variables, such as “What did {Company} say about {Topic}?”, run on demand or on a daily or weekly schedule. Each run produces a cited answer, delivered by email.
  • Copy quote with source. Select any words and copy them as “the words” — company, form, date, page and SEC link. The text always comes from the stored passage, never from the browser.
  • Quiet alerts. Saved searches become digests that never repeat a filing, with an “own filings only” option and a “Too noisy?” button that tightens an alert in one click.
  • Financials, tables and what changed. Three statements with charts and CSV export, the tables of every filing, and a word-level diff against the previous year’s filing.
  • Share, export and upload. Read-only links for people without an account, sharing with colleagues, Markdown and Word export with numbered sources, earnings dates as an .ics calendar file, and private uploads (PDF, Word, HTML, Markdown) that are searched and cited like filings.

Trust is enforced in the database

Showing citations in the interface isn’t enough. The data access underneath has to be trustworthy too.

Every query runs as the signed-in user, and Postgres row-level security decides what comes back. Even a scheduled alert runs its search as the alert’s owner. A share link’s token is shown once and only its hash is stored. A shared page shows only passages from public filings, checked each time the page is read. That way, an answer that later draws on a private upload can’t leak through an old link. Passwords are hashed with scrypt, sign-in attempts are rate-limited, and unsubscribe links are signed.

Architecture

Vouchline runs on a single laptop with no cloud infrastructure. The database is PGlite, which is Postgres 17 compiled to WebAssembly, and emails go to a local mailbox. Filings come from SEC EDGAR’s official endpoints, at about six requests a second to stay inside the SEC’s fair-access limit. Background jobs (alerts every 15 minutes, new filings every six hours) run inside the server process. Every job is retried with backoff and logged.

LayerTechnologies
FrontendNext.js 16 (App Router) · React 19 · Tailwind 4 · Radix · design tokens with every colour pair checked for WCAG AA, Light and Dark
DataPostgreSQL 17 via PGlite · full-text search · row-level security · SEC EDGAR filings and XBRL company facts
AIAn LLM through the provider-agnostic Vercel AI SDK: cited answers, grid cells, research plans, company overviews and follow-up questions only
Quality131 Playwright end-to-end tests on desktop and at 390px, with an axe accessibility scan on every screen · 55 unit tests · 44 bugs logged and tracked to a fix

The broader point

Language models write fluent summaries of documents. That part is solved. What was missing was the ability to trust the summary without redoing the work.

Vouchline spends its effort on that gap. Citations are checked by code, gaps are named, figures come from the source, and the model is allowed to say it doesn’t know. Every feature starts from what an analyst has to do with an answer — check it, quote it, share it — not from what the model happens to be able to do.

The model has one job: turning passages into prose. It’s useful because everything around it was built to be checked.