<?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: Colin J</title>
    <description>The latest articles on DEV Community by Colin J (@colinje01).</description>
    <link>https://dev.to/colinje01</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%2F4182450%2Fb7a344f7-36df-402d-9008-8c8a1bf0144f.png</url>
      <title>DEV Community: Colin J</title>
      <link>https://dev.to/colinje01</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/colinje01"/>
    <language>en</language>
    <item>
      <title>I built a tutor that circles your math mistake in red pen</title>
      <dc:creator>Colin J</dc:creator>
      <pubDate>Tue, 13 Oct 2026 20:31:41 +0000</pubDate>
      <link>https://dev.to/colinje01/i-built-a-tutor-that-circles-your-math-mistake-in-red-pen-3ffi</link>
      <guid>https://dev.to/colinje01/i-built-a-tutor-that-circles-your-math-mistake-in-red-pen-3ffi</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.to/mlh-hackathon"&gt;MLH x DEV Writing Challenge&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What I Built
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Somo&lt;/strong&gt; (Swahili for "lesson") is a math tutor you use by taking a photo. You snap a problem along with your handwritten working. Somo finds the exact line where the working goes wrong, circles it in red pen the way a teacher would, and then teaches the idea in English, Swahili or Spanish.&lt;/p&gt;

&lt;h3&gt;
  
  
  What inspired it
&lt;/h3&gt;

&lt;p&gt;I grew up in Tanzania. Primary school is taught in Swahili. Secondary school switches every subject to English, and you sit the NECTA national exams in a language you're still learning. Plenty of students understand the math and get stuck on the words. I see the same thing with English learners in New York.&lt;/p&gt;

&lt;p&gt;Most AI tools will solve the problem for you. I wanted to explore something different: could an AI tell a student &lt;em&gt;why they&lt;/em&gt; went wrong, in the language they think in? I built Somo in one day to find out.&lt;/p&gt;

&lt;h3&gt;
  
  
  How it works
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Snap.&lt;/strong&gt; Photograph the problem and your working.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Diagnose.&lt;/strong&gt; Gemini reads the handwriting and returns structured JSON with the transcription, the concept, the first wrong line, and why it's wrong. The UI circles that line in red.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Confirm.&lt;/strong&gt; Somo shows "Here's what I read," and you confirm it or correct it before any teaching happens.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Teach.&lt;/strong&gt; A short lesson streams in. It covers the idea, where it went wrong, an everyday analogy (a market scale, a subway fare), a worked example with &lt;em&gt;different&lt;/em&gt; numbers so the answer isn't given away, and the English exam terms you'll need.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Check.&lt;/strong&gt; You answer one question. Get it wrong and you get a simpler re-explanation with a new analogy. Get it right and you can &lt;strong&gt;practice on a real past exam question&lt;/strong&gt; found live on the web.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F9a0zrhyu1nky3d0whywe.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F9a0zrhyu1nky3d0whywe.png" alt="Somo circling the wrong line in red pen" width="800" height="1223"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  What I learned
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Reliability is most of AI engineering.&lt;/strong&gt; The prompts were the easy part. The work went into everything around them:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Self-verification.&lt;/strong&gt; A second, independent model call solves the problem &lt;em&gt;without seeing the diagnosis&lt;/em&gt;. If the two answers disagree, the student sees "I'm not fully sure I read this right."&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Verification can't catch reading mistakes.&lt;/strong&gt; One of my test photos was a printed question that had lost its formatting. Both model calls read it the same wrong way, and they agreed with each other. That's why the human-in-the-loop confirm step exists: the student can see the paper, and the model can't always.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Failover is a feature.&lt;/strong&gt; Gemini's free quota ran out mid-build. I routed every call through one function: try Gemini, retry once on a 503/429, then fall back to Claude, with a &lt;strong&gt;circuit breaker&lt;/strong&gt; that skips Gemini for 60 seconds after a quota error. Diagnosis went from &lt;strong&gt;~116 seconds&lt;/strong&gt; (waiting on an overloaded model) to &lt;strong&gt;~10 seconds&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Honest labels.&lt;/strong&gt; My pipeline once showed a UK worksheet as a "real past exam" question. Now every question is labeled &lt;em&gt;past exam paper&lt;/em&gt;, &lt;em&gt;practice question from the web&lt;/em&gt;, or &lt;em&gt;written by Somo&lt;/em&gt;, and off-topic questions are rejected.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In testing, Somo found the exact wrong line on all three of my handwritten test problems: a halving error (2B = 8 → B = 3), a dropped minus sign when rearranging, and multiplying the two sides of an equation by different numbers. No students have used it; every test problem was written by me.&lt;/p&gt;

&lt;h2&gt;
  
  
  Demo
&lt;/h2&gt;

&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/aAlYzSg1QhU" width="710" height="399"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fhd2lum60o9k8gj3tyalh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fhd2lum60o9k8gj3tyalh.png" alt="A streamed lesson in Swahili with bilingual key terms" width="800" height="1188"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The stack is a FastAPI backend with Server-Sent Events for streaming, plus a single-file mobile interface styled like a school exercise book: grid paper, a red margin line, and a handwriting font for the teacher's notes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Partner Technologies
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Google Gemini (and Gemma 4)
&lt;/h3&gt;

&lt;p&gt;Gemini (&lt;code&gt;gemini-flash-latest&lt;/code&gt; through the &lt;code&gt;google-genai&lt;/code&gt; SDK) does the hard multimodal work. The key was &lt;strong&gt;structured output&lt;/strong&gt;. Instead of parsing free text, the diagnosis is validated against a Pydantic schema:&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;response&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="n"&gt;models&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;generate_content&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;gemini-flash-latest&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;contents&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;photo&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;DIAGNOSE_PROMPT&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;types&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;GenerateContentConfig&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;response_mime_type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;application/json&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;response_schema&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;Diagnosis&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="c1"&gt;# transcription, concept, error_step, final_answer...
&lt;/span&gt;    &lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;diagnosis&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;parsed&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Because &lt;code&gt;error_step&lt;/code&gt; is a real field, the UI knows exactly which line to circle. Gemini also streams the lessons and writes the check questions.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Gemma 4&lt;/strong&gt; (&lt;code&gt;gemma-4-26b-a4b-it&lt;/code&gt;, served through the same Gemini API) handles the frequent, low-stakes work: grading answers and deciding whether two answers are equivalent ("x = 4" vs "4"). It's fast and cheap, so it's a good fit for checks that run on every answer.&lt;/p&gt;

&lt;h3&gt;
  
  
  Nimble
&lt;/h3&gt;

&lt;p&gt;Nimble turned "practice more" into "practice the real exam." When a lesson starts, a background job asks Nimble to search the live web for past papers on the student's concept, starting with official sites:&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;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;nimble&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;search&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;NECTA CSEE Basic Mathematics past paper &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;concept&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;max_results&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;search_depth&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;standard&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;full_content&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;include_domains&lt;/span&gt;&lt;span class="o"&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;necta.go.tz&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;maktaba.tetea.org&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;US students get NY Regents question banks (&lt;code&gt;jmap.org&lt;/code&gt;, &lt;code&gt;nysedregents.org&lt;/code&gt;) instead, and if the official sites return nothing, Somo searches the open web.&lt;/p&gt;

&lt;p&gt;Nimble found the right documents: official NECTA (Tanzania's National Examinations Board) Basic Mathematics papers and examiner reports from 2017 to 2023. But for PDFs, search results came back as ~300–700 character summaries, with no questions in them. The fix was to treat Nimble as the &lt;strong&gt;finder&lt;/strong&gt;: when a result is a short PDF, Somo downloads it, extracts up to 20,000 characters with &lt;code&gt;pypdf&lt;/code&gt; (five papers in parallel), and Gemini picks one question that appears word for word and tests the same concept. NECTA's &lt;em&gt;Candidates' Item Response Analysis&lt;/em&gt; reports turned out to be gold, because they quote every exam question verbatim.&lt;/p&gt;

&lt;p&gt;The first real result was a matrix word problem from the &lt;strong&gt;NECTA CSEE 2023&lt;/strong&gt; Basic Mathematics paper, which gets shown with an exam stamp and a link to the source. Results are cached to disk with fuzzy topic matching, so each topic is searched only once.&lt;/p&gt;

&lt;h3&gt;
  
  
  Sentry
&lt;/h3&gt;

&lt;p&gt;Somo makes a lot of calls to several providers, so I wanted to see what it was actually doing. Every Gemini, Gemma, Claude and Nimble call is a Sentry span, and background jobs (verification, question prep, past-paper search) are their own transactions:&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="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;sentry_sdk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;start_span&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;gen_ai.chat&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;gemini &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;label&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;span&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;span&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set_data&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;model&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;gemini_call&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Every Gemini → Claude failover also raises a warning issue, so the issues list became a timeline of when and why the app switched providers.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Then Sentry found a real bug.&lt;/strong&gt; The trace waterfall for one past-paper search showed a single NECTA server taking &lt;strong&gt;3.6 minutes&lt;/strong&gt; to send one PDF. I had a 12-second timeout, but httpx applies it &lt;em&gt;per chunk&lt;/em&gt;, so a server trickling data never trips it. The fix was a hard deadline on the whole download:&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;deadline&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;time&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;12&lt;/span&gt;
&lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;httpx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stream&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;GET&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;timeout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;12&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;r&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;chunk&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;iter_bytes&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
        &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;extend&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;chunk&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;time&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;deadline&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;TimeoutError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;download took over 12s&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;The worst case dropped from about 4 minutes to about 30 seconds. I wouldn't have found that one from logs. No student photos or prompt text are sent to Sentry (&lt;code&gt;send_default_pii=False&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F5liifna9ar1ew883m0qw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F5liifna9ar1ew883m0qw.png" alt="Sentry Trace" width="800" height="438"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Hackathon Experience
&lt;/h2&gt;

&lt;p&gt;I attended the &lt;strong&gt;AI Engineer NYC Hackathon&lt;/strong&gt;, a one-day MLH event on October 11, 2026. I came in without a team and without an idea, so the morning was brainstorming. I narrowed it down to education because of my own background, then spent most of the day building.&lt;/p&gt;

&lt;p&gt;What I'll remember most:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Building alongside coding agents.&lt;/strong&gt; I started with Gemini CLI, which hit its usage limit partway through, so I switched to working with Claude. It changed how I worked: I spent my time on design decisions and testing with real handwritten problems, and less on typing boilerplate.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The sponsor talks paid off.&lt;/strong&gt; I hadn't planned to use Nimble until the sponsor presentation. It ended up being the feature I'm proudest of.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Real-world friction.&lt;/strong&gt; The venue wifi wouldn't let my phone reach my laptop, my Gemini quota ran out, and a government server was very slow. Each one forced a better design.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The 5 PM deadline was tight. I froze features at 3:45, then wrote the README, recorded a demo, and submitted with minutes to spare.&lt;/p&gt;

&lt;p&gt;Thanks to MLH and the sponsors for a great day of building.&lt;/p&gt;

</description>
      <category>mlhacks</category>
      <category>devchallenge</category>
      <category>hackathon</category>
      <category>ai</category>
    </item>
  </channel>
</rss>
