<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Dominique Church</title>
    <description>The latest articles on DEV Community by Dominique Church (@dominique_church_a9abd890).</description>
    <link>https://dev.to/dominique_church_a9abd890</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4096426%2Faffb5ca2-b8ff-46a5-8d01-5de0fac27984.png</url>
      <title>DEV Community: Dominique Church</title>
      <link>https://dev.to/dominique_church_a9abd890</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/dominique_church_a9abd890"/>
    <language>en</language>
    <item>
      <title>I built an API that checks whether SEC financial data adds up</title>
      <dc:creator>Dominique Church</dc:creator>
      <pubDate>Mon, 28 Sep 2026 18:54:46 +0000</pubDate>
      <link>https://dev.to/dominique_church_a9abd890/i-built-an-api-that-checks-whether-sec-financial-data-adds-up-kjn</link>
      <guid>https://dev.to/dominique_church_a9abd890/i-built-an-api-that-checks-whether-sec-financial-data-adds-up-kjn</guid>
      <description>&lt;p&gt;I'm a solo developer in Canada, and I built BalanceProof: an API for SEC EDGAR fundamentals on 6,000+ US public companies, where every balance sheet, income statement and cash flow is checked against its own totals before you get it.&lt;/p&gt;

&lt;p&gt;The video above is the 33-second version. This post is the longer one: what it does, why I bothered, and how to try it for free.&lt;/p&gt;

&lt;h2&gt;
  
  
  The problem
&lt;/h2&gt;

&lt;p&gt;If you have ever pulled fundamentals out of SEC filings yourself, you know the numbers are not as tidy as the filings look on paper. XBRL is flexible, which is great for filers and painful for anyone reading it in bulk. The same concept can be tagged several ways. Segment figures sit next to consolidated ones. Later filings recast earlier periods. A pipeline that grabs "the" total assets for a company can quietly grab the wrong one.&lt;/p&gt;

&lt;p&gt;Most data sources hand you a number either way. You find out it was wrong when a ratio looks strange, or you never find out.&lt;/p&gt;

&lt;p&gt;I hit every one of these while building the data load:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;An early load dropped 37 companies because of a CIK-to-ticker mapping bug.&lt;/li&gt;
&lt;li&gt;8-K recast filings once made Stryker's Q4 and full-year figures collide. The fix was to read only periodic reports (10-K and 10-Q) and purge 81,397 rows that came from non-periodic filings.&lt;/li&gt;
&lt;li&gt;JPMorgan tags "Total assets" in 23 different ways in one filing.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;None of those show up as an error. The request succeeds, the numbers look plausible, and they are quietly wrong or missing. That is what pushed me to test the data against itself.&lt;/p&gt;

&lt;h2&gt;
  
  
  The three checks
&lt;/h2&gt;

&lt;p&gt;So that became the product. Every period is tested against accounting identities that must hold if the figures are right:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Balance sheet:&lt;/strong&gt; assets = liabilities + equity&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Income statement:&lt;/strong&gt; revenue - cost of revenue = gross profit&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cash flow:&lt;/strong&gt; operating + investing + financing + FX = change in cash&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;A filing that does not add up is not passed through silently. It is flagged, with the reason. Figures are as filed, not smoothed over.&lt;/p&gt;

&lt;p&gt;For a concrete example, Apple's 10-Q for the quarter ended 27 Jun 2026 (filed 31 Jul 2026) reports total assets of $383.27B, liabilities of $275.75B and shareholders' equity of $107.52B. 275.75 + 107.52 = 383.27, so it passes. Microsoft's 10-K for the year ended 30 Jun 2026: assets $758.38B, liabilities $315.99B, equity $442.39B. Also passes.&lt;/p&gt;

&lt;p&gt;(Company numbers here are examples of data checks, not investment advice.)&lt;/p&gt;

&lt;h2&gt;
  
  
  Python quickstart (free tier)
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pip &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="s2"&gt;"balanceproof[pandas]"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Grab a free key at &lt;a href="https://balanceproof.dev/dashboard" rel="noopener noreferrer"&gt;https://balanceproof.dev/dashboard&lt;/a&gt; (no card), then:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;balanceproof&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;bp&lt;/span&gt;
&lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Client&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;YOUR_KEY&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;# or set BALANCEPROOF_API_KEY
&lt;/span&gt;&lt;span class="n"&gt;sheet&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;balance_sheet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;AAPL&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;stmts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;statements&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;AAPL&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;period&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;quarterly&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;stmts&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;periods&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;][:&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;period_end&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="p"&gt;[(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;check&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;status&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;checks&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]])&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;balance_sheet&lt;/code&gt; returns the latest filed balance sheet, with assets, liabilities and equity line items and a list of any data quality issues. &lt;code&gt;statements&lt;/code&gt; returns one entry per period with the income statement, the cash flow, the filing date, a &lt;code&gt;derived&lt;/code&gt; list, and a &lt;code&gt;checks&lt;/code&gt; list. Each check has a name, the rule it tested, and a status of &lt;code&gt;passed&lt;/code&gt;, &lt;code&gt;failed&lt;/code&gt; or &lt;code&gt;not_testable&lt;/code&gt; (the last one names the missing figures).&lt;/p&gt;

&lt;p&gt;If you forget the key, the client raises &lt;code&gt;balanceproof.BalanceProofError&lt;/code&gt; with a 401 that tells you where to get a free one.&lt;/p&gt;

&lt;p&gt;If you prefer pandas:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;df&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;panel&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;AAPL&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;MSFT&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;KO&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;revenue&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;net_income&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;operating_cash_flow&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
                  &lt;span class="n"&gt;period&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;quarterly&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;clean&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;checks_failed&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;  &lt;span class="c1"&gt;# drop periods that failed a check
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;panel&lt;/code&gt; gives you one row per (ticker, period), with &lt;code&gt;filing_date&lt;/code&gt;, &lt;code&gt;fiscal_period&lt;/code&gt;, &lt;code&gt;checks_failed&lt;/code&gt; and &lt;code&gt;derived&lt;/code&gt; columns next to the metrics. &lt;code&gt;derived&lt;/code&gt; lists figures that were computed rather than filed, such as Q4 as the year minus nine months.&lt;/p&gt;

&lt;h2&gt;
  
  
  Use it from Claude, ChatGPT or Cursor (MCP)
&lt;/h2&gt;

&lt;p&gt;There is an MCP server at:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;https://balanceproof.dev/mcp
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add it as a remote MCP server in Claude, ChatGPT or Cursor. The tools it exposes are &lt;code&gt;search_companies&lt;/code&gt;, &lt;code&gt;get_balance_sheet&lt;/code&gt;, &lt;code&gt;check_balance_sheet&lt;/code&gt;, &lt;code&gt;get_balance_sheet_history&lt;/code&gt;, &lt;code&gt;get_balance_sheet_changes&lt;/code&gt;, &lt;code&gt;get_financial_statements&lt;/code&gt;, &lt;code&gt;get_exceptions&lt;/code&gt; and &lt;code&gt;get_api_key&lt;/code&gt;. The most useful one is probably &lt;code&gt;check_balance_sheet&lt;/code&gt;: ask "does this company's latest balance sheet add up?" and you get an answer with the reason, instead of a number the model has to trust.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is free and what is paid
&lt;/h2&gt;

&lt;p&gt;I would rather be clear about this up front.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Free:&lt;/strong&gt; 1,000 API calls a month, no card. Balance sheets and statements (with their checks) are included.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Starter, $19/mo CAD:&lt;/strong&gt; adds &lt;code&gt;changes()&lt;/code&gt;, which shows what moved since the previous period and what was restated.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pro, $49/mo CAD:&lt;/strong&gt; 10,000 calls, plus &lt;code&gt;as_of&lt;/code&gt; point-in-time queries (only what had been filed by a given date, for backtests), the &lt;code&gt;exceptions()&lt;/code&gt; feed of failed checks and restatements across all companies (last 90 days), and &lt;code&gt;verify()&lt;/code&gt; for 50 tickers at once.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Business:&lt;/strong&gt; full exceptions history and &lt;code&gt;verify()&lt;/code&gt; for 500 tickers.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you call something your plan does not include, the client raises &lt;code&gt;balanceproof.PlanRequired&lt;/code&gt;, and its &lt;code&gt;.required_plan&lt;/code&gt; tells you which plan you would need. No silent empty results.&lt;/p&gt;

&lt;p&gt;There is also a public restatements tracker at &lt;a href="https://balanceproof.dev/restatements" rel="noopener noreferrer"&gt;https://balanceproof.dev/restatements&lt;/a&gt; if you just want to see which companies revised figures recently.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I would love feedback on
&lt;/h2&gt;

&lt;p&gt;I would genuinely like to hear:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Does the check-first framing make sense, or would you rather just get the numbers?&lt;/li&gt;
&lt;li&gt;Which checks are missing for your use case?&lt;/li&gt;
&lt;li&gt;Anything in the Python client that feels awkward? The method list is short on purpose.&lt;/li&gt;
&lt;li&gt;If you try the MCP server, did the tools do what you expected from their names?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Comments here are great. So is trying to break it: find a filing where you think the check is wrong and tell me.&lt;/p&gt;

&lt;p&gt;It is live at &lt;a href="https://balanceproof.dev" rel="noopener noreferrer"&gt;https://balanceproof.dev&lt;/a&gt;. Thanks for reading.&lt;/p&gt;

</description>
      <category>python</category>
      <category>api</category>
      <category>fintech</category>
      <category>showdev</category>
    </item>
    <item>
      <title>How I engineered a multi-agent coding terminal with a 3D Three.js Office Floor UI published</title>
      <dc:creator>Dominique Church</dc:creator>
      <pubDate>Thu, 27 Aug 2026 00:54:19 +0000</pubDate>
      <link>https://dev.to/dominique_church_a9abd890/how-i-engineered-a-multi-agent-coding-terminal-with-a-3d-threejs-office-floor-uipublished-52bf</link>
      <guid>https://dev.to/dominique_church_a9abd890/how-i-engineered-a-multi-agent-coding-terminal-with-a-3d-threejs-office-floor-uipublished-52bf</guid>
      <description>&lt;h1&gt;
  
  
  Building Gnosis: A Multi-Agent Terminal with a 3D Office UI
&lt;/h1&gt;

&lt;p&gt;I spent my summer building &lt;strong&gt;Gnosis&lt;/strong&gt;, a local-first, open-source terminal coding agent designed around one idea: make multi-agent work easier to see and understand.&lt;/p&gt;

&lt;p&gt;Instead of an endless stream of terminal output, Gnosis puts agents inside an interactive &lt;strong&gt;Three.js office&lt;/strong&gt;, where their location reflects what they are actually doing.&lt;/p&gt;

&lt;h2&gt;
  
  
  Architecture
&lt;/h2&gt;

&lt;p&gt;Gnosis uses a TypeScript backend for agent execution, tools, processes, and session state, with React + Three.js rendering everything in real time.&lt;/p&gt;

&lt;h3&gt;
  
  
  Model Hot-Swapping
&lt;/h3&gt;

&lt;p&gt;The conversation state is separated from the model provider, so you can switch between &lt;strong&gt;any OpenRouter model mid-session&lt;/strong&gt; without losing context or tool state.&lt;/p&gt;

&lt;h3&gt;
  
  
  Prompt Caching
&lt;/h3&gt;

&lt;p&gt;Context is structured to maximize provider prompt caching.&lt;/p&gt;

&lt;p&gt;One measured request dropped from &lt;strong&gt;$0.0252 to $0.0021 — a 12× reduction&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  The 3D Office
&lt;/h2&gt;

&lt;p&gt;Agents move between five zones:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Coordinator&lt;/strong&gt; — main session&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Planning&lt;/strong&gt; — task breakdown&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Coding&lt;/strong&gt; — file changes&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Application&lt;/strong&gt; — testing and verification&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Sub-Agents&lt;/strong&gt; — parallel work&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The office updates as agents work, and clicking an agent opens its session.&lt;/p&gt;

&lt;h2&gt;
  
  
  Other Systems
&lt;/h2&gt;

&lt;p&gt;Gnosis also includes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Tree-sitter code indexing&lt;/li&gt;
&lt;li&gt;Scoped sub-agents with context and tool limits&lt;/li&gt;
&lt;li&gt;Local PTY terminal streaming&lt;/li&gt;
&lt;li&gt;Obsidian persistent memory&lt;/li&gt;
&lt;li&gt;Computer use&lt;/li&gt;
&lt;li&gt;MCP support for Context7, Playwright, and Chrome DevTools&lt;/li&gt;
&lt;li&gt;File browser and diff viewer&lt;/li&gt;
&lt;li&gt;Webhook inspector&lt;/li&gt;
&lt;li&gt;Mobile and LAN control&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The project has &lt;strong&gt;104 automated test suites running on Windows CI&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Gnosis is &lt;strong&gt;MIT licensed, local-first, and BYOK&lt;/strong&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-g&lt;/span&gt; @dominquechurch/gnosis
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;GitHub:&lt;/strong&gt; &lt;a href="https://github.com/DOMCHURCH/Gnosis" rel="noopener noreferrer"&gt;https://github.com/DOMCHURCH/Gnosis&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>vibecoding</category>
      <category>typescript</category>
      <category>opensource</category>
    </item>
  </channel>
</rss>
