<?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: Brian Myers</title>
    <description>The latest articles on DEV Community by Brian Myers (@brian_myers_asi).</description>
    <link>https://dev.to/brian_myers_asi</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%2F4099294%2Fe902c878-f28c-4fc9-9403-41c63fcf91d7.jpg</url>
      <title>DEV Community: Brian Myers</title>
      <link>https://dev.to/brian_myers_asi</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/brian_myers_asi"/>
    <language>en</language>
    <item>
      <title>I built an agent that reads SEC filings so I don't have to</title>
      <dc:creator>Brian Myers</dc:creator>
      <pubDate>Fri, 28 Aug 2026 16:57:15 +0000</pubDate>
      <link>https://dev.to/brian_myers_asi/i-built-an-agent-that-reads-sec-filings-so-i-dont-have-to-kn3</link>
      <guid>https://dev.to/brian_myers_asi/i-built-an-agent-that-reads-sec-filings-so-i-dont-have-to-kn3</guid>
      <description>&lt;p&gt;Every public company's story is hiding in plain sight — in 10-Ks and 10-Qs that&lt;br&gt;
almost nobody reads end-to-end. The good stuff is specific: a gross margin&lt;br&gt;
inflecting, risk-factor language that wasn't there last quarter, a going-concern&lt;br&gt;
sentence buried on page 60. I wanted that surfaced to me every morning without&lt;br&gt;
me doing the reading.&lt;/p&gt;

&lt;p&gt;So for the &lt;strong&gt;All Things Agentic Hackathon&lt;/strong&gt; I built &lt;strong&gt;EDGAR Sentinel&lt;/strong&gt;: an&lt;br&gt;
autonomous agent on Google Cloud that wakes up at 6:30 every morning, scans SEC&lt;br&gt;
EDGAR for new filings across a 30-company watchlist, reads them with a&lt;br&gt;
two-model pipeline, remembers every prior filing, and emails me what changed —&lt;br&gt;
with a public dashboard for everything it knows.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Demo video (4 min):&lt;/strong&gt; &lt;a href="https://youtu.be/jJYZ74b0gUs" rel="noopener noreferrer"&gt;https://youtu.be/jJYZ74b0gUs&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Live dashboard:&lt;/strong&gt; &lt;a href="https://edgar-sentinel-dashboard-69101307007.us-central1.run.app" rel="noopener noreferrer"&gt;https://edgar-sentinel-dashboard-69101307007.us-central1.run.app&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Code:&lt;/strong&gt; &lt;a href="https://github.com/brianmyers-ctrl/edgar-sentinel" rel="noopener noreferrer"&gt;https://github.com/brianmyers-ctrl/edgar-sentinel&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The architecture in one breath
&lt;/h2&gt;

&lt;p&gt;Cloud Scheduler → Cloud Run Job → an &lt;strong&gt;ADK orchestrator agent&lt;/strong&gt; (Gemini 3.5)&lt;br&gt;
whose tools are the pipeline stages → SEC EDGAR (politely: declared User-Agent,&lt;br&gt;
throttled) → raw filings archived to Cloud Storage → a section parser →&lt;br&gt;
&lt;strong&gt;Gemma&lt;/strong&gt; (on its own Cloud Run service, via Ollama) writes triage notes →&lt;br&gt;
&lt;strong&gt;Gemini 3.5 on Vertex AI&lt;/strong&gt; scores the filing against a five-pillar "Filing&lt;br&gt;
Health Score" with schema-enforced JSON → Firestore stores it → a &lt;strong&gt;delta&lt;br&gt;
engine&lt;/strong&gt; compares against the company's prior filing and fires deterministic&lt;br&gt;
alerts → SendGrid emails the digest.&lt;/p&gt;

&lt;p&gt;One design rule shaped everything: &lt;strong&gt;agentic control flow, deterministic&lt;br&gt;
execution&lt;/strong&gt;. The LLM decides &lt;em&gt;what runs&lt;/em&gt; and writes the run report. Tested&lt;br&gt;
Python decides &lt;em&gt;what is true&lt;/em&gt; — section slicing, score weighting, the alert&lt;br&gt;
rule, state transitions. When a judge (or I) ask "why did this alert fire?",&lt;br&gt;
the answer is a rule you can read, not a vibe.&lt;/p&gt;

&lt;h2&gt;
  
  
  Two models, two jobs
&lt;/h2&gt;

&lt;p&gt;Gemini 3.5 Flash does the deep reading: five pillar scores with cited&lt;br&gt;
rationale, extracted metrics, three decision-relevant highlights. Temperature&lt;br&gt;
zero, pydantic schema enforced, composite recomputed in code so config — not&lt;br&gt;
the model's arithmetic — is authoritative.&lt;/p&gt;

&lt;p&gt;Gemma's job is deliberately smaller: read the risk-factors section and produce&lt;br&gt;
a dozen terse triage bullets — red flags, notable changes, tone — that ride&lt;br&gt;
along to Gemini as a second opinion. It runs scale-to-zero on CPU. My first&lt;br&gt;
design had Gemma &lt;em&gt;rewriting&lt;/em&gt; filing text; that was wrong in an instructive way&lt;br&gt;
(below).&lt;/p&gt;

&lt;h2&gt;
  
  
  What actually broke (the fun part)
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Gemma 4 is a thinking model.&lt;/strong&gt; My triage calls returned empty strings
with &lt;code&gt;done_reason: length&lt;/code&gt; — the model spent its whole output budget on
hidden reasoning and never wrote the answer. One &lt;code&gt;think: false&lt;/code&gt; later,
33-second useful triage notes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ollama's default context window silently truncates.&lt;/strong&gt; My "cleaned" MD&amp;amp;A
came back 12× smaller — not cleaning, truncation. That failure convinced me
to change Gemma's job from rewriting text to writing &lt;em&gt;notes about&lt;/em&gt; text.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Inline-XBRL splits words across spans.&lt;/strong&gt; Microsoft's 10-K renders "RISK
FACTORS" as &lt;code&gt;RIS K FACTORS&lt;/code&gt;, and repeats "Item 1A" as a page header through
the whole section — my "take the last heading match" heuristic found
nothing. Fix: match headings with optional intra-word whitespace and take
the match with the &lt;em&gt;longest following body&lt;/em&gt;. Microsoft's risk section went
from 0 to 80,000 characters.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A use-after-free in Python.&lt;/strong&gt; Creating the google-genai client inline
(&lt;code&gt;make_client().models.generate_content(...)&lt;/code&gt;) let the client get
garbage-collected mid-request; its finalizer closed the HTTP pool:
&lt;code&gt;Cannot send a request, as the client has been closed.&lt;/code&gt; Cached singleton.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Org policies bite.&lt;/strong&gt; Our org restricts Vertex models
(&lt;code&gt;constraints/vertexai.allowedModels&lt;/code&gt;) and strips default service-account
grants — both showed up as cryptic 400s/403s. Both fixed with scoped,
least-privilege IAM rather than hammer-sized grants.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Every one of these would have detonated during a live demo. Finding them on day&lt;br&gt;
one and day four instead is most of what "production-minded" means.&lt;/p&gt;

&lt;h2&gt;
  
  
  Does it actually notice things?
&lt;/h2&gt;

&lt;p&gt;The delta engine is the feature I'd defend in a knife fight. Because every&lt;br&gt;
analysis persists in Firestore, each new filing is compared with the company's&lt;br&gt;
prior one — pillar by pillar — and a deterministic rule (≥10-point move, band&lt;br&gt;
change, or risk-pillar collapse) decides whether to alert. On the full&lt;br&gt;
backfill it flagged, among others: Plug Power sliding &lt;strong&gt;Caution → Distress&lt;/strong&gt;&lt;br&gt;
(cash down to $161.9M), Salesforce and Meta dropping out of Strong, and&lt;br&gt;
Coinbase and AMC genuinely recovering. It also caught Apple's management going&lt;br&gt;
cautious on component costs a quarter before it showed up anywhere else in the&lt;br&gt;
filing — a 10-point management-signal drop while the composite barely moved.&lt;/p&gt;

&lt;h2&gt;
  
  
  The numbers
&lt;/h2&gt;

&lt;p&gt;30 companies · 58 filings analyzed · 8 live alerts · running unattended every&lt;br&gt;
morning since August 14 · ~1 minute per filing · 20 unit tests · roughly a&lt;br&gt;
dollar a day in cloud costs while idle-scaling to zero.&lt;/p&gt;

&lt;p&gt;One last production note: even the demo video is Google AI — narration by&lt;br&gt;
Cloud Text-to-Speech (Chirp3-HD), soundtrack generated with Lyria 2 on&lt;br&gt;
Vertex AI, and the screen captured while the real daily job ran live on&lt;br&gt;
Cloud Run.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;I created this piece of content for the purposes of entering the All Things&lt;br&gt;
Agentic Hackathon.&lt;/em&gt; EDGAR Sentinel produces automated research summaries&lt;br&gt;
derived from SEC filings — not investment advice.&lt;/p&gt;

</description>
      <category>googlecloud</category>
      <category>ai</category>
      <category>agents</category>
      <category>hackathon</category>
    </item>
  </channel>
</rss>
