<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd" xmlns:googleplay="http://www.google.com/schemas/play-podcasts/1.0"><channel><title><![CDATA[Zero One Labs]]></title><description><![CDATA[We build tools that multiply human skill and leverage per unit of time - giving people freedom from repetitive work and time for what matters.]]></description><link>https://blog.01.inc</link><image><url>https://substackcdn.com/image/fetch/$s_!ebA-!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4d506132-9fc1-45f5-a7e0-e0a38527d6de_512x512.png</url><title>Zero One Labs</title><link>https://blog.01.inc</link></image><generator>Substack</generator><lastBuildDate>Sat, 18 Jul 2026 22:08:40 GMT</lastBuildDate><atom:link href="https://blog.01.inc/feed" rel="self" type="application/rss+xml"/><copyright><![CDATA[Zero One Labs LLC]]></copyright><language><![CDATA[en]]></language><webMaster><![CDATA[alf@01.inc]]></webMaster><itunes:owner><itunes:email><![CDATA[alf@01.inc]]></itunes:email><itunes:name><![CDATA[Alf Viktor Williamsen]]></itunes:name></itunes:owner><itunes:author><![CDATA[Alf Viktor Williamsen]]></itunes:author><googleplay:owner><![CDATA[alf@01.inc]]></googleplay:owner><googleplay:email><![CDATA[alf@01.inc]]></googleplay:email><googleplay:author><![CDATA[Alf Viktor Williamsen]]></googleplay:author><itunes:block><![CDATA[Yes]]></itunes:block><item><title><![CDATA[Your app should have an email address, not just a login page]]></title><description><![CDATA[Think about how a traditional SaaS app works.]]></description><link>https://blog.01.inc/p/your-app-should-have-an-email-address</link><guid isPermaLink="false">https://blog.01.inc/p/your-app-should-have-an-email-address</guid><dc:creator><![CDATA[Alf Viktor Williamsen]]></dc:creator><pubDate>Sun, 15 Mar 2026 15:52:50 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!F8d6!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1c892b45-b9d8-42e7-a732-61e4146ea395_3840x2560.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Think about how a traditional SaaS app works. You log in. You click around. You upload files. <em>You spend time inside the app.</em> You are operating it.</p><p>What if the app operated on your behalf instead?</p><p>For a long time, a simple idea has been forming in my mind. What if the application has <em>its own email address</em>, and you can just forward it files, messages, and instructions for whatever you need done? This is entirely possible with standard tools that are easy to set up and consistently reliable.</p><h2>The simplest version of an agent is an email</h2><p>The word &#8220;agent&#8221; has accumulated a lot of noise. Strip it back to first principles and an agent is just a system that receives <em>intent</em>, <em>decides</em> what to do, and <em>acts</em>. Email fits that definition perfectly. You express intent (the message), attach context (the files), and the system does the rest.</p><p>Give your application its own email address. Then users can forward files, attach instructions, and send requests to that address. The system receives, authenticates, processes, and completes the work in the background. The user never logs in.</p><p>I built this for a commission management platform that insurance firms use. Every month, firms receive new commission data files from their providers. These files carry inherent parsing complexity: new agents, changed rates, structural inconsistencies between providers. Historically, a user would log in, upload the file, wait for parsing, review errors, and manually resolve each one. The entire workflow required the user to sit inside the app.</p><p>Now they forward the file to an email address and move on with their day.</p><p>The system parses the files through production Python parsers, validates the data against existing records, flags anomalies, and stores everything. If the agent needs clarification (an ambiguous agent name, a rate that doesn&#8217;t match any known structure) it replies to the email thread and asks. The user responds when they have a moment. The loop continues until the work is complete.</p><p>The entire interaction model is: send email, receive confirmation or follow-up question, done. This is identical in shape to how you work with a human colleague. The difference is that this colleague is perpetually available, never forgets context, and processes files in minutes rather than hours.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!F8d6!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1c892b45-b9d8-42e7-a732-61e4146ea395_3840x2560.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!F8d6!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1c892b45-b9d8-42e7-a732-61e4146ea395_3840x2560.png 424w, https://substackcdn.com/image/fetch/$s_!F8d6!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1c892b45-b9d8-42e7-a732-61e4146ea395_3840x2560.png 848w, https://substackcdn.com/image/fetch/$s_!F8d6!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1c892b45-b9d8-42e7-a732-61e4146ea395_3840x2560.png 1272w, https://substackcdn.com/image/fetch/$s_!F8d6!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1c892b45-b9d8-42e7-a732-61e4146ea395_3840x2560.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!F8d6!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1c892b45-b9d8-42e7-a732-61e4146ea395_3840x2560.png" width="1456" height="971" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/1c892b45-b9d8-42e7-a732-61e4146ea395_3840x2560.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:971,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:118575,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://blog.01.inc/i/191030005?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1c892b45-b9d8-42e7-a732-61e4146ea395_3840x2560.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!F8d6!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1c892b45-b9d8-42e7-a732-61e4146ea395_3840x2560.png 424w, https://substackcdn.com/image/fetch/$s_!F8d6!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1c892b45-b9d8-42e7-a732-61e4146ea395_3840x2560.png 848w, https://substackcdn.com/image/fetch/$s_!F8d6!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1c892b45-b9d8-42e7-a732-61e4146ea395_3840x2560.png 1272w, https://substackcdn.com/image/fetch/$s_!F8d6!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1c892b45-b9d8-42e7-a732-61e4146ea395_3840x2560.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption"><strong>Diagram 1 (UX loop):</strong> Three steps, two require your attention. You send the email and check the response. Everything between is the system working without you.</figcaption></figure></div><h2>The architecture is four ordinary components</h2><p>The infrastructure behind this is deliberately boring. Nothing here is novel. That is the point: the value is in the design pattern, not the technology.</p><p>First, an email domain. This can be your app&#8217;s existing domain or a simple subdomain. It receives inbound messages and routes them to a worker for processing.</p><p>Second, a worker. This is the first thing that touches an inbound email. It authenticates the sender against an allowed-senders table (one row per authorized address, with metadata for audit trails). If the sender is not recognized, the email is dropped. No ambiguity. If authenticated, the worker extracts attachments, parses the message body for instructions, and routes everything to the correct storage and processing pipeline.</p><p>Third, a backend API. This runs deterministic processing: the production parsers that handle commission files, validation logic, data storage. No LLM in this layer. These are the same parsers that would run if the user uploaded the file through the app&#8217;s front end. The trigger is different; the processing is identical.</p><p>Fourth, a sandboxed agent environment. Once deterministic processing completes, the API triggers an LLM agent in a sandboxed environment. This agent handles anything requiring judgment: interpreting what changed in this month&#8217;s file compared to last month, configuring new rates for a new period, responding to freeform instructions the user included in their email. The sandbox is synchronous with the API call, meaning the output is streamed back and verified before anything is committed. The timeout is generous (thirteen minutes) because rigor matters more than speed here.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!cJLv!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F17b43bfa-ab01-47f2-a709-49b18454634f_3840x2560.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!cJLv!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F17b43bfa-ab01-47f2-a709-49b18454634f_3840x2560.png 424w, https://substackcdn.com/image/fetch/$s_!cJLv!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F17b43bfa-ab01-47f2-a709-49b18454634f_3840x2560.png 848w, https://substackcdn.com/image/fetch/$s_!cJLv!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F17b43bfa-ab01-47f2-a709-49b18454634f_3840x2560.png 1272w, https://substackcdn.com/image/fetch/$s_!cJLv!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F17b43bfa-ab01-47f2-a709-49b18454634f_3840x2560.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!cJLv!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F17b43bfa-ab01-47f2-a709-49b18454634f_3840x2560.png" width="1456" height="971" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/17b43bfa-ab01-47f2-a709-49b18454634f_3840x2560.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:971,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:77552,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://blog.01.inc/i/191030005?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F17b43bfa-ab01-47f2-a709-49b18454634f_3840x2560.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!cJLv!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F17b43bfa-ab01-47f2-a709-49b18454634f_3840x2560.png 424w, https://substackcdn.com/image/fetch/$s_!cJLv!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F17b43bfa-ab01-47f2-a709-49b18454634f_3840x2560.png 848w, https://substackcdn.com/image/fetch/$s_!cJLv!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F17b43bfa-ab01-47f2-a709-49b18454634f_3840x2560.png 1272w, https://substackcdn.com/image/fetch/$s_!cJLv!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F17b43bfa-ab01-47f2-a709-49b18454634f_3840x2560.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption"><strong>Diagram 2 (System):</strong> Four components, one return path. Deterministic parsers handle the files before the agent touches them. The agent replies through the same email thread when it needs clarification.</figcaption></figure></div><p>The agent can send follow-up questions back through the email thread. This creates a genuinely asynchronous collaboration loop. The user is not waiting on a loading spinner. They sent an email, and they will get a response when the work is done or when a question needs answering. Just like working with a person.</p><h2>Reason from first principles about where your interface lives</h2><p>Every app has one central function. One reason someone uses it, the core value proposition of your tool. The question worth asking before you build any interface: does that function require a custom screen, or could it travel through a channel the user already inhabits?</p><p>This is where most software gets it wrong by default. We build login pages, dashboards, navigation bars, settings screens. We build these because that is what apps look like. But &#8220;what apps look like&#8221; is convention, not principle. The presentation layer should be derived from the nature of the core function and the habits of the user, not from what other apps happen to do.</p><p>Two valid design paths exist.</p><p>The first: your tool is delivered through a bespoke interface that genuinely increases the quality of the experience. A design tool needs a canvas. A code editor needs syntax highlighting and a file tree. A mapping application needs a map. In these cases, the interface is inseparable from the value. The custom UI is not overhead; it is central to the product.</p><p>The second: you conform as closely as possible to the user&#8217;s existing workflows. If the core function reduces to &#8220;receive input, process, return output,&#8221; then the interface is a delivery mechanism, not a product. Here, the highest-leverage move is to meet the user where they already are.</p><p>Both are correct. The nature of your core function decides which path is natural. But most apps default to the first path without ever seriously considering the second. They build a full interface because that is what you do when you build an app. The result is that users must learn and operate a custom tool for a function that could have been an email.</p><p>The test is straightforward. Does your user prefer giving text instructions over clicking buttons? Do they already communicate the relevant information through email or messaging? Is the core value in the processing, not in the interaction with a screen? If the answer to any of these is yes, wrapping your core function behind an email address is not a limitation. It is a higher-leverage interface than anything you would build custom.</p><h2>The real value is background processing</h2><p>The deeper point is not about email as a protocol. It is about when work happens relative to the user&#8217;s attention.</p><p>In a traditional app, processing is synchronous with the user&#8217;s session. You upload, you wait, you review, you fix, you upload again. Your attention is locked to the app for the duration of the work. The app cannot do anything without you present.</p><p>With an email-triggered system (or any async system), the entire processing pipeline runs in the background before the user ever considers opening the app. For commission files with inherent parsing complexity, this matters enormously. The validation, anomaly detection, and initial resolution all happen between the moment the user hits send and the moment they next check their inbox. By the time they look, the work is either done or a specific question is waiting for them.</p><p>This is the difference between operating a tool and delegating to a teammate. You do not sit next to a colleague and watch them process a spreadsheet. You hand it to them, explain what you need, and check back later. The email-based agent design creates exactly this dynamic.</p><h2>This generalizes beyond commission files</h2><p>The pattern is simple enough to apply anywhere the core function is receive, process, return.</p><p>Consider a research assistant. You forward an email with a topic and constraints. The system runs deep research: searching, reading, synthesizing. Hours later, a finished report arrives in your inbox as a PDF or a link to a hosted page. You never opened an app. You sent an email and received a deliverable.</p><p>Consider an accounting tool. You forward receipts throughout the month, one email at a time or batched. At month end, you send a message: close the books for March. The system categorizes, reconciles, and produces a summary. The entire interaction happened inside your inbox.</p><p>Consider a document review system. You forward a contract. The agent reads it against your standard terms, flags deviations, and replies with a structured summary of what needs attention. You respond with approvals or questions. The negotiation prep happens through a channel you check thirty times a day anyway.</p><p>In each case, the same structure holds. The email is the trigger. The backend does the work. The inbox is the interface. The user never has to learn a new tool, navigate a new layout, or remember a new login.</p><h2>Email is the most underexploited interface in software</h2><p>Email is a powerful and completely generalizable channel that every professional already uses. Instead of fragmenting services into custom interfaces, consider whether your core value could travel through a channel your users already live in.</p><p>The strongest argument for this design is not technical. It is behavioral. You are not asking users to change how they work. You are not asking them to adopt a new tool, learn a new interface, or build a new habit. You are inserting your service into a workflow that already runs every single day. The friction drops to near zero because the interaction model is one the user has practiced for decades.</p><p>This is what making a tool feel like a teammate actually means. Not a chatbot inside your app. Not a sidebar with a language model. A system that receives work through the same channel you use to communicate with every other person in your professional life, and delivers results the same way.</p><p>Always reason from first principles when you build a user interface. Too many of the interfaces you and I encounter are conventional without being thoughtful. The presentation is what makes or breaks the experience. If your app&#8217;s core function can travel through email, give it an email address.</p>]]></content:encoded></item><item><title><![CDATA[Giving an LLM Full Database Access Is the Right Call, and Here’s the Specific Design That Makes It Safe]]></title><description><![CDATA[One of the most exciting applications of LLMs I&#8217;ve worked with is giving an agent full access to run commands on a database.]]></description><link>https://blog.01.inc/p/giving-an-llm-full-database-access</link><guid isPermaLink="false">https://blog.01.inc/p/giving-an-llm-full-database-access</guid><dc:creator><![CDATA[Alf Viktor Williamsen]]></dc:creator><pubDate>Fri, 06 Mar 2026 18:18:54 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!nJEI!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe750ce45-828a-4686-846c-e20d43332b25_3840x2560.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>One of the most exciting applications of LLMs I&#8217;ve worked with is giving an agent full access to run commands on a database. It allows the assistant to see the full picture: our data, settings, configurations, specifics. It fundamentally alters how the application functions and how good the outputs are.</p><p>But letting an agent have a full connection to your database is dangerous for obvious reasons. Agents can accidentally alter data without permission. So the challenge is: how do you give an LLM the full read picture while air-gapping it from accidental writes?</p><p>The answer is two connection strings.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!nJEI!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe750ce45-828a-4686-846c-e20d43332b25_3840x2560.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!nJEI!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe750ce45-828a-4686-846c-e20d43332b25_3840x2560.png 424w, https://substackcdn.com/image/fetch/$s_!nJEI!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe750ce45-828a-4686-846c-e20d43332b25_3840x2560.png 848w, https://substackcdn.com/image/fetch/$s_!nJEI!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe750ce45-828a-4686-846c-e20d43332b25_3840x2560.png 1272w, https://substackcdn.com/image/fetch/$s_!nJEI!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe750ce45-828a-4686-846c-e20d43332b25_3840x2560.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!nJEI!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe750ce45-828a-4686-846c-e20d43332b25_3840x2560.png" width="1456" height="971" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/e750ce45-828a-4686-846c-e20d43332b25_3840x2560.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:971,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:190867,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://blog.01.inc/i/189974130?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe750ce45-828a-4686-846c-e20d43332b25_3840x2560.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!nJEI!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe750ce45-828a-4686-846c-e20d43332b25_3840x2560.png 424w, https://substackcdn.com/image/fetch/$s_!nJEI!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe750ce45-828a-4686-846c-e20d43332b25_3840x2560.png 848w, https://substackcdn.com/image/fetch/$s_!nJEI!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe750ce45-828a-4686-846c-e20d43332b25_3840x2560.png 1272w, https://substackcdn.com/image/fetch/$s_!nJEI!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe750ce45-828a-4686-846c-e20d43332b25_3840x2560.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption"><strong>Diagram 1 (Architecture)</strong> Two connection strings, one database. The read-only replica gives the agent full visibility. The standard connection only fires on human approval.</figcaption></figure></div><h3>All Commission Data Through One Agent</h3><p>I built a platform for managing commission distribution at insurance firms. Sales, employees, agents, products, all in one Postgres database. Users manage commission flows from carrier to sales agent. The platform handles a dense stream of data: commission rates, agent information, performance analytics.</p><p>Users can navigate the UI manually. But the full capacity unlocks when an LLM agent works on behalf of the user. A task like migrating a commission rate across every configured agent, painful in a spreadsheet, trivial for the agent.</p><p>The system needs three foundational pieces to make this work.</p><h3>Schema, Strings, and a Map</h3><p>First, a schema that fits the application. Different apps need different schemas. An ecommerce store is fundamentally different from a commission distribution system, so the way you schematize your database is a contained problem for your specific app.</p><p>Second, two connection strings. The first is a read-only replica. This is the string the LLM uses for all queries that are not approved edits. The second is a standard connection string with write access, gated behind explicit human approval. This separation is the core of the design. It guarantees the agent can never run edits without approval, no matter what it generates.</p><p>Third, a continuously updated plain-text artifact of the schema, a markdown document describing every table, column, and relationship. This is what allows the LLM to instantly understand your specific database and write correct SQL against it. Without it, the LLM makes dumb errors.</p><h3>Query Without Risk</h3><p>Here&#8217;s how a query flows through the system. The user asks a question in a chat interface:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!-3q2!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdf95d504-765d-44db-9cc8-6faca38570b2_3840x2560.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!-3q2!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdf95d504-765d-44db-9cc8-6faca38570b2_3840x2560.png 424w, https://substackcdn.com/image/fetch/$s_!-3q2!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdf95d504-765d-44db-9cc8-6faca38570b2_3840x2560.png 848w, https://substackcdn.com/image/fetch/$s_!-3q2!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdf95d504-765d-44db-9cc8-6faca38570b2_3840x2560.png 1272w, https://substackcdn.com/image/fetch/$s_!-3q2!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdf95d504-765d-44db-9cc8-6faca38570b2_3840x2560.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!-3q2!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdf95d504-765d-44db-9cc8-6faca38570b2_3840x2560.png" width="1456" height="971" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/df95d504-765d-44db-9cc8-6faca38570b2_3840x2560.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:971,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:120722,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://blog.01.inc/i/189974130?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdf95d504-765d-44db-9cc8-6faca38570b2_3840x2560.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!-3q2!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdf95d504-765d-44db-9cc8-6faca38570b2_3840x2560.png 424w, https://substackcdn.com/image/fetch/$s_!-3q2!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdf95d504-765d-44db-9cc8-6faca38570b2_3840x2560.png 848w, https://substackcdn.com/image/fetch/$s_!-3q2!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdf95d504-765d-44db-9cc8-6faca38570b2_3840x2560.png 1272w, https://substackcdn.com/image/fetch/$s_!-3q2!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdf95d504-765d-44db-9cc8-6faca38570b2_3840x2560.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption"><strong>Diagram 2 (Read Path)</strong> Question in, answer out. The agent writes SQL against the read-only replica and returns a plain-language response in under ten seconds.</figcaption></figure></div><blockquote><p>&#8220;What does sales amount to in January?&#8221;</p></blockquote><p>The agent receives the question, references the schema artifact, and writes a SQL command:</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;sql&quot;,&quot;nodeId&quot;:&quot;be299b37-3c08-4817-98cb-d339a30dd1cd&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-sql">psql "$SANDBOX_DB_URL" -c "SELECT SUM(amount) FROM sales WHERE date &gt;= '2024-01-01' AND date &lt; '2024-02-01';"</code></pre></div><p>The agent executes that command against the read-only connection. The database returns:</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;sql&quot;,&quot;nodeId&quot;:&quot;2709a723-a01c-4385-b316-fa96bff55dd4&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-sql">    sum    
-----------
 452839.50
(1 row)</code></pre></div><p>The agent then writes the response in plain language:</p><blockquote><p>&#8220;Sales in January totaled $452,839.50.&#8221;</p></blockquote><p>The full loop (receive question, write SQL, execute, return answer) takes roughly ten seconds. Each step is one LLM call. The agent receives the user question and writes the SQL. The database result triggers a second call, now containing the returned data. The agent then decides: retry with a different query, or write the final reply.</p><h3>Writes Only on Approval</h3><p>Now for the dangerous part: edits.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!oas3!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F75cc3ca8-6cc1-4656-b1dd-9d2986a8114f_3840x2560.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!oas3!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F75cc3ca8-6cc1-4656-b1dd-9d2986a8114f_3840x2560.png 424w, https://substackcdn.com/image/fetch/$s_!oas3!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F75cc3ca8-6cc1-4656-b1dd-9d2986a8114f_3840x2560.png 848w, https://substackcdn.com/image/fetch/$s_!oas3!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F75cc3ca8-6cc1-4656-b1dd-9d2986a8114f_3840x2560.png 1272w, https://substackcdn.com/image/fetch/$s_!oas3!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F75cc3ca8-6cc1-4656-b1dd-9d2986a8114f_3840x2560.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!oas3!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F75cc3ca8-6cc1-4656-b1dd-9d2986a8114f_3840x2560.png" width="1456" height="971" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/75cc3ca8-6cc1-4656-b1dd-9d2986a8114f_3840x2560.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:971,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:134397,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://blog.01.inc/i/189974130?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F75cc3ca8-6cc1-4656-b1dd-9d2986a8114f_3840x2560.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!oas3!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F75cc3ca8-6cc1-4656-b1dd-9d2986a8114f_3840x2560.png 424w, https://substackcdn.com/image/fetch/$s_!oas3!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F75cc3ca8-6cc1-4656-b1dd-9d2986a8114f_3840x2560.png 848w, https://substackcdn.com/image/fetch/$s_!oas3!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F75cc3ca8-6cc1-4656-b1dd-9d2986a8114f_3840x2560.png 1272w, https://substackcdn.com/image/fetch/$s_!oas3!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F75cc3ca8-6cc1-4656-b1dd-9d2986a8114f_3840x2560.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption"><strong>Diagram 3 (Write Path)</strong> The same loop, one structural difference. Write operations are blocked, surfaced in the UI, and executed only on human approval through the standard connection.</figcaption></figure></div><p>When a user asks for an action that requires modifying data, the agent runs through the same loop but against the read-only string. The system identifies when the generated SQL contains a write operation (<code>INSERT</code>, <code>UPDATE</code>, <code>DELETE</code>), blocks it from executing, and surfaces the proposed SQL in the user interface for explicit approval.</p><p>Only on human approval does the system switch to the standard connection string and execute the write.</p><p>This is a simple design, but it&#8217;s the most effective one I&#8217;ve found. The read-only replica makes it physically impossible for the agent to alter data during its reasoning and exploration. The approval gate on the write string means edits only happen with informed human consent. Two connection strings, one architectural guarantee: the agent cannot break what it hasn&#8217;t been allowed to touch.</p><h3>Restriction Makes Agents Dumb</h3><p>LLMs are probabilistic machines. They can generate completely random, potentially harmful SQL. The instinct is to restrict their access: limit what tables they can see, constrain what queries they can write. But restriction makes the agent dumber. It loses context. It can&#8217;t answer questions about data it can&#8217;t see.</p><p>The better path is full read access with an air-gapped write path. Let the agent see everything. Let it explore, join, aggregate, analyze. Then gate the single dangerous action, writing, behind a human checkpoint. You get the full intelligence of the agent without the risk.</p>]]></content:encoded></item><item><title><![CDATA[Data That Answers When You Ask]]></title><description><![CDATA[Businesses collect data perpetually: product types, customer profiles, refund rates, currencies, sales identifiers, personnel records.]]></description><link>https://blog.01.inc/p/data-that-answers-when-you-ask</link><guid isPermaLink="false">https://blog.01.inc/p/data-that-answers-when-you-ask</guid><dc:creator><![CDATA[Alf Viktor Williamsen]]></dc:creator><pubDate>Tue, 03 Mar 2026 11:58:15 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!Bw8A!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F83dc86e4-0c8c-4ee6-96be-a623e3d03f64_3840x2560.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Businesses collect data perpetually: product types, customer profiles, refund rates, currencies, sales identifiers, personnel records. The combinations are infinite, and the more specific your business, the more novel the data types available for collection. But collection is not the hard part. The hard part is making the data useful: getting it out of scattered spreadsheets or systems, and into a structured store where it can help you answer questions and improve decisions.</p><p>In this article, I walk through a specific data flow from the insurance distribution business to present a framework for thinking about how data becomes useful. The goal is to make the example concrete enough that you can infer the key concepts and apply them to your own work.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Bw8A!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F83dc86e4-0c8c-4ee6-96be-a623e3d03f64_3840x2560.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Bw8A!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F83dc86e4-0c8c-4ee6-96be-a623e3d03f64_3840x2560.png 424w, https://substackcdn.com/image/fetch/$s_!Bw8A!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F83dc86e4-0c8c-4ee6-96be-a623e3d03f64_3840x2560.png 848w, https://substackcdn.com/image/fetch/$s_!Bw8A!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F83dc86e4-0c8c-4ee6-96be-a623e3d03f64_3840x2560.png 1272w, https://substackcdn.com/image/fetch/$s_!Bw8A!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F83dc86e4-0c8c-4ee6-96be-a623e3d03f64_3840x2560.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Bw8A!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F83dc86e4-0c8c-4ee6-96be-a623e3d03f64_3840x2560.png" width="1456" height="971" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/83dc86e4-0c8c-4ee6-96be-a623e3d03f64_3840x2560.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:971,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:76106,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://blog.01.inc/i/189747540?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F83dc86e4-0c8c-4ee6-96be-a623e3d03f64_3840x2560.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!Bw8A!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F83dc86e4-0c8c-4ee6-96be-a623e3d03f64_3840x2560.png 424w, https://substackcdn.com/image/fetch/$s_!Bw8A!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F83dc86e4-0c8c-4ee6-96be-a623e3d03f64_3840x2560.png 848w, https://substackcdn.com/image/fetch/$s_!Bw8A!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F83dc86e4-0c8c-4ee6-96be-a623e3d03f64_3840x2560.png 1272w, https://substackcdn.com/image/fetch/$s_!Bw8A!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F83dc86e4-0c8c-4ee6-96be-a623e3d03f64_3840x2560.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption"><strong>Diagram 1 (Pipeline):</strong> Raw data becomes a decision through four stages. Most businesses stop at collection, this framework carries data all the way to the user.</figcaption></figure></div><h3>Data Stuck in Spreadsheets</h3><p>Inside the insurance distribution business, there is a vast information flow where sales, products, and commissions are transported through multiple steps. This data is communicated and shared inside spreadsheets, which are inherently difficult to work with in bulk.</p><p>The problem, stated simply: get the data out of the spreadsheets, clean up the structure, and funnel the data into a structured, queryable database like Postgres. What we end up with is a database that gets hydrated with new data at each period interval &#8212; data we can then work with downstream. Finding out who sells the most, what is selling the best, what products have a bad clawback rate, and more.</p><p>The goal of cleaning the data into a database is to create a single source of data truth. All data conforms to the same structure, allowing us to use the data stream inside our models to get insights.</p><p>An analogy: imagine buying a bag of M&amp;Ms. You expect every piece of candy to conform to a specific shape, weight, and taste. But each piece has a different color. Now apply this to transforming spreadsheets into our database format. We build a transformer that reformats the data into our desired shape and form, but we retain the key value of each data point. We keep its colors intact. When we scale this across tens to hundreds of spreadsheets, this becomes critical. If even one source has been parsed incorrectly, our models lose accuracy. Uniform shape lets us compare the colors.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!k-EP!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F288eae04-2f32-4f8c-ba30-899c30112e2c_3840x2560.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!k-EP!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F288eae04-2f32-4f8c-ba30-899c30112e2c_3840x2560.png 424w, https://substackcdn.com/image/fetch/$s_!k-EP!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F288eae04-2f32-4f8c-ba30-899c30112e2c_3840x2560.png 848w, https://substackcdn.com/image/fetch/$s_!k-EP!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F288eae04-2f32-4f8c-ba30-899c30112e2c_3840x2560.png 1272w, https://substackcdn.com/image/fetch/$s_!k-EP!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F288eae04-2f32-4f8c-ba30-899c30112e2c_3840x2560.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!k-EP!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F288eae04-2f32-4f8c-ba30-899c30112e2c_3840x2560.png" width="1456" height="971" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/288eae04-2f32-4f8c-ba30-899c30112e2c_3840x2560.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:971,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:128240,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://blog.01.inc/i/189747540?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F288eae04-2f32-4f8c-ba30-899c30112e2c_3840x2560.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!k-EP!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F288eae04-2f32-4f8c-ba30-899c30112e2c_3840x2560.png 424w, https://substackcdn.com/image/fetch/$s_!k-EP!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F288eae04-2f32-4f8c-ba30-899c30112e2c_3840x2560.png 848w, https://substackcdn.com/image/fetch/$s_!k-EP!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F288eae04-2f32-4f8c-ba30-899c30112e2c_3840x2560.png 1272w, https://substackcdn.com/image/fetch/$s_!k-EP!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F288eae04-2f32-4f8c-ba30-899c30112e2c_3840x2560.png 1456w" sizes="100vw"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption"><strong>Diagram 2 (Schema):</strong> Three carriers, three different formats, transformed into one uniform schema. The colors stay, the shape becomes interchangeable.</figcaption></figure></div><h3>One Schema for All Sources</h3><p>For our insurance data flow, I am working with commission spreadsheets. Each spreadsheet has a different structure because each source is a different insurance carrier, each with different data systems. The most important task is to retain high resolution from each data source while transforming it to conform to our uniform schema for commission data.</p><p>The transformation is done with a Python backend written specifically for each commission type, which transforms the source to fit our uniform schema. For maximizing convenience, I have built the entire backend in the cloud: when users have new files, they simply forward an email to a custom address (with the spreadsheet files), which triggers the system to validate, transform, and store the data into the database. From there, the next chunk of work can be initiated immediately.</p><p>My goal as a systems engineer is to make purely necessary steps &#8212; like the data transformation &#8212; blend into the background. Make them as unnoticeable as possible so the app experience does not feel like another spreadsheet.</p><p>It is helpful to revisit and iterate in circles: how we transform the data, what models we want, what interfaces will be used. Continuously go around again, modifying the way we transform data so that we have the necessary inputs downstream. Some data sources will not meet all requirements for our schema. This is fine. We build dedicated models into the transformation phase to either enrich the data with additional metadata, or create ways of grouping temporal data to conform to our schema.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!tnzL!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb5027822-d4cd-454b-8e7d-777a1b0b2e77_3840x2560.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!tnzL!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb5027822-d4cd-454b-8e7d-777a1b0b2e77_3840x2560.png 424w, https://substackcdn.com/image/fetch/$s_!tnzL!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb5027822-d4cd-454b-8e7d-777a1b0b2e77_3840x2560.png 848w, https://substackcdn.com/image/fetch/$s_!tnzL!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb5027822-d4cd-454b-8e7d-777a1b0b2e77_3840x2560.png 1272w, https://substackcdn.com/image/fetch/$s_!tnzL!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb5027822-d4cd-454b-8e7d-777a1b0b2e77_3840x2560.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!tnzL!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb5027822-d4cd-454b-8e7d-777a1b0b2e77_3840x2560.png" width="1456" height="971" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/b5027822-d4cd-454b-8e7d-777a1b0b2e77_3840x2560.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:971,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:123981,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://blog.01.inc/i/189747540?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb5027822-d4cd-454b-8e7d-777a1b0b2e77_3840x2560.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!tnzL!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb5027822-d4cd-454b-8e7d-777a1b0b2e77_3840x2560.png 424w, https://substackcdn.com/image/fetch/$s_!tnzL!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb5027822-d4cd-454b-8e7d-777a1b0b2e77_3840x2560.png 848w, https://substackcdn.com/image/fetch/$s_!tnzL!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb5027822-d4cd-454b-8e7d-777a1b0b2e77_3840x2560.png 1272w, https://substackcdn.com/image/fetch/$s_!tnzL!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb5027822-d4cd-454b-8e7d-777a1b0b2e77_3840x2560.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption"><strong>Diagram 3 (Loop):</strong> What the interface needs changes how we transform. What we transform changes what we can model.</figcaption></figure></div><h3>Inference from Clean Data</h3><p>Once the data has been transformed and stored, the creative part begins.</p><p>A model is how you take stored data from the database and infer something from it. The word infer &#8212; to deduce or conclude information from evidence and reasoning rather than from explicit statements &#8212; closely aligns with the overarching goal of working with data. We should spend time making sure we have a solid model, so that from there we can infer valuable information.</p><p>Each model should tailor to a specific desired output. For the commission data flow, we want to understand the different products that are selling, and quantify them over different temporal spans. Breaking this into a pseudo-spec: I need the product rows, some way of identifying different product types, and temporal metadata about the time interval each record belongs to.</p><h3>The Interface Layer</h3><p>The second category is the interface: where our model is presented to the user so it makes sense to them, meeting them where they are so they can understand and make decisions with the data.</p><p>An interface is a point where two things meet and interact. The overarching purpose is to be the portal for the user into accessing all of their data maximally. Maximally means the models should be customizable, interactive, and not static. </p><blockquote><p>If the user gets an idea of how they would like to query the data, the interface must meet that demand.</p></blockquote><p>I believe there are currently two key forms of interfaces: natural language, and user-configurable modules. The example interface uses a combination of the two &#8212; leveraging the strengths of the modular configurable interface, and enhancing it with the simplicity of natural language. Language is used to orchestrate what you want. The modular interface is used to display it.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!vAnQ!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbb1988f1-3bd6-4c6e-9f3a-f4020a117110_3600x2260.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!vAnQ!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbb1988f1-3bd6-4c6e-9f3a-f4020a117110_3600x2260.png 424w, https://substackcdn.com/image/fetch/$s_!vAnQ!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbb1988f1-3bd6-4c6e-9f3a-f4020a117110_3600x2260.png 848w, https://substackcdn.com/image/fetch/$s_!vAnQ!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbb1988f1-3bd6-4c6e-9f3a-f4020a117110_3600x2260.png 1272w, https://substackcdn.com/image/fetch/$s_!vAnQ!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbb1988f1-3bd6-4c6e-9f3a-f4020a117110_3600x2260.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!vAnQ!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbb1988f1-3bd6-4c6e-9f3a-f4020a117110_3600x2260.png" width="1456" height="914" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/bb1988f1-3bd6-4c6e-9f3a-f4020a117110_3600x2260.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:914,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:733088,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://blog.01.inc/i/189747540?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbb1988f1-3bd6-4c6e-9f3a-f4020a117110_3600x2260.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!vAnQ!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbb1988f1-3bd6-4c6e-9f3a-f4020a117110_3600x2260.png 424w, https://substackcdn.com/image/fetch/$s_!vAnQ!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbb1988f1-3bd6-4c6e-9f3a-f4020a117110_3600x2260.png 848w, https://substackcdn.com/image/fetch/$s_!vAnQ!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbb1988f1-3bd6-4c6e-9f3a-f4020a117110_3600x2260.png 1272w, https://substackcdn.com/image/fetch/$s_!vAnQ!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbb1988f1-3bd6-4c6e-9f3a-f4020a117110_3600x2260.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption"><strong>Diagram 4 (App screenshot):</strong> The user writes one sentence. The system returns a structured view across thousands of rows.</figcaption></figure></div><h4>Tables That Breathe</h4><p>The interface is built with a hybrid of the accessible table-like design where content is displayed in a familiar spreadsheet way. Taller row heights and spacious column layouts are conscious decisions to make the spreadsheet visual a friendlier interface compared to a high-density spreadsheet. The overarching goal is to replicate the user&#8217;s familiarity with a table while reducing the energy needed for comprehension. A natural next step would be visual representations of the underlying model, perhaps clear visuals comparing and differentiating the data as graphs.</p><h4>Natural Language Interaction</h4><p>This is where the power comes in. Instead of the traditional model of a spreadsheet with columns, rows, sorting, and filters, natural language introduces higher resolution of intent. The user explains their desired outcome in their preferred language, rather than conforming to the rules of a spreadsheet.</p><p>Speed follows from this. Instead of the human manually configuring filters and rules, the underlying system can figure out user intent and build a model of the desired output at the speed of a hundred words per second. The difference in time spent compared to building the same view in Excel or Google Sheets is stark.</p><p>An example: a user might want to see all car insurance products from March to August with commission to agent under $100. Imagine the work of doing this across thirty-plus Excel files. But from the exact line of text &#8212; &#8220;all car insurance products from March to August with commission to agent under $100&#8221; &#8212; here, there is plenty of signal inferable for an intelligent system. Our example interface creates the view within seconds from synthesizing the user intent into a model. The user does not need to know any code, only a language.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!ZYg6!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa8c6d6a5-31e2-43d4-baee-f4dddf4ae46a_2876x1744.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!ZYg6!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa8c6d6a5-31e2-43d4-baee-f4dddf4ae46a_2876x1744.png 424w, https://substackcdn.com/image/fetch/$s_!ZYg6!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa8c6d6a5-31e2-43d4-baee-f4dddf4ae46a_2876x1744.png 848w, https://substackcdn.com/image/fetch/$s_!ZYg6!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa8c6d6a5-31e2-43d4-baee-f4dddf4ae46a_2876x1744.png 1272w, https://substackcdn.com/image/fetch/$s_!ZYg6!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa8c6d6a5-31e2-43d4-baee-f4dddf4ae46a_2876x1744.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!ZYg6!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa8c6d6a5-31e2-43d4-baee-f4dddf4ae46a_2876x1744.png" width="1456" height="883" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/a8c6d6a5-31e2-43d4-baee-f4dddf4ae46a_2876x1744.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:883,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:327395,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://blog.01.inc/i/189747540?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa8c6d6a5-31e2-43d4-baee-f4dddf4ae46a_2876x1744.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!ZYg6!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa8c6d6a5-31e2-43d4-baee-f4dddf4ae46a_2876x1744.png 424w, https://substackcdn.com/image/fetch/$s_!ZYg6!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa8c6d6a5-31e2-43d4-baee-f4dddf4ae46a_2876x1744.png 848w, https://substackcdn.com/image/fetch/$s_!ZYg6!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa8c6d6a5-31e2-43d4-baee-f4dddf4ae46a_2876x1744.png 1272w, https://substackcdn.com/image/fetch/$s_!ZYg6!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa8c6d6a5-31e2-43d4-baee-f4dddf4ae46a_2876x1744.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption"><strong>Diagram 5 (App screenshot):</strong> Interpreting a user&#8217;s filter request, exploring the database, and building the query in real time. The input field accepts plain language in any language.</figcaption></figure></div><p>For practical use, the users can download their view into an exported file PDF or Excel. This allows them to take the data further, into whatever work they are doing. Familiar formats win here because they make the data portable and easily sharable.</p><h4>How It Works: SQL Under Natural Language</h4><p>The LLM is the interpretation layer that receives the user intent, reasons over it, then begins an iterative process where it creates &#8212; through trial and error &#8212; the data model that satisfies the request. The interpreter returns the final data model back to the user interface for instant preview. A complete iteration takes less than thirty seconds.</p><blockquote><p>An <strong>LLM</strong> most commonly refers to a Large Language Model, a type of Artificial Intelligence (AI) trained on massive amounts of data to understand, generate, and process human language.</p></blockquote><p>Because of our heavy work upstream on clean and structured data, we have a perfectly predictable data source structure, as a result of our transformation, at this point in the pipeline. No matter the number of rows, the system iterates in seconds because of how the architecture is built.</p><p>The power here is the power of Postgres and SQL. Our LLM interpreter reads the user intent and writes SQL queries that shape our data model. Think of SQL like a language for prescribing data recipes: you write explicitly how to make a specific data dish. A recipe for making pizza scales no matter how many pizzas you make. SQL follows the same principle: no matter how much data you have, the recipe scales.</p><blockquote><p><strong>PostgreSQL</strong> (often shortened to Postgres) is a free, open-source object-relational database management system (ORDBMS). It is widely regarded as one of the most advanced and reliable database systems available.</p><p><strong>SQL</strong> (Structured Query Language) is the standard programming language used to manage, query, and manipulate data within relational databases. It organizes data into structured tables with rows and columns, functioning as a sophisticated system for handling large volumes of information far beyond the capacity of traditional spreadsheets.</p></blockquote><h3>Beyond Commissions</h3><p>The fundamentally interesting value of this interface is that it enables complete accessibility for any non-technical user to explore vast amounts of data. A few examples:</p><ul><li><p>Teachers with data about students and grades</p></li><li><p>Accountants searching for specific receipts</p></li><li><p>Researchers reviewing data quality</p></li><li><p>Library inventory databases</p></li><li><p>SaaS revenue analytics</p></li><li><p>Investor modelling for capital allocation</p></li></ul><p>Most data tools today assume a level of user expertise. I wanted to challenge that assumption. Instead of expecting the user to configure the system, why not let an AI do it? I believe this is the correct vision. The LLM becomes the configurator and the interpreter interface between raw human intent and structured data operations.</p><p>This interface is still in its infancy. There are many ways to improve the models, the interface design, and most importantly the accuracy of the LLM agent. At the boundary of any new technology, there is always a wide range of work to be done before the full value can be harvested. That is what makes it worth building.</p>]]></content:encoded></item><item><title><![CDATA[Production PDF Parsing for High-Stakes Financial Systems]]></title><description><![CDATA[Reading PDFs is a vital function of any application dealing with documents.]]></description><link>https://blog.01.inc/p/production-pdf-parsing-for-high-stakes</link><guid isPermaLink="false">https://blog.01.inc/p/production-pdf-parsing-for-high-stakes</guid><dc:creator><![CDATA[Alf Viktor Williamsen]]></dc:creator><pubDate>Sun, 22 Feb 2026 19:48:17 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!QAMs!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9747a3f1-4cc2-48c8-baf5-e002ba38e7f6_3840x2560.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!QAMs!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9747a3f1-4cc2-48c8-baf5-e002ba38e7f6_3840x2560.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!QAMs!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9747a3f1-4cc2-48c8-baf5-e002ba38e7f6_3840x2560.png 424w, https://substackcdn.com/image/fetch/$s_!QAMs!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9747a3f1-4cc2-48c8-baf5-e002ba38e7f6_3840x2560.png 848w, https://substackcdn.com/image/fetch/$s_!QAMs!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9747a3f1-4cc2-48c8-baf5-e002ba38e7f6_3840x2560.png 1272w, https://substackcdn.com/image/fetch/$s_!QAMs!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9747a3f1-4cc2-48c8-baf5-e002ba38e7f6_3840x2560.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!QAMs!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9747a3f1-4cc2-48c8-baf5-e002ba38e7f6_3840x2560.png" width="1456" height="971" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/9747a3f1-4cc2-48c8-baf5-e002ba38e7f6_3840x2560.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:971,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:156122,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://blog.01.inc/i/188825698?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9747a3f1-4cc2-48c8-baf5-e002ba38e7f6_3840x2560.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!QAMs!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9747a3f1-4cc2-48c8-baf5-e002ba38e7f6_3840x2560.png 424w, https://substackcdn.com/image/fetch/$s_!QAMs!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9747a3f1-4cc2-48c8-baf5-e002ba38e7f6_3840x2560.png 848w, https://substackcdn.com/image/fetch/$s_!QAMs!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9747a3f1-4cc2-48c8-baf5-e002ba38e7f6_3840x2560.png 1272w, https://substackcdn.com/image/fetch/$s_!QAMs!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9747a3f1-4cc2-48c8-baf5-e002ba38e7f6_3840x2560.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption"><strong>One file in, three parsers, one validated output.</strong></figcaption></figure></div><p>Reading PDFs is a vital function of any application dealing with documents. Financial documents are commonly stored as PDFs (portable document format) because of the format&#8217;s permanent nature and simple storage. PDF is a great format for humans. It has a natural print layout and an easy-to-digest way of structuring text content.</p><p>But one of the bottlenecks of PDFs is their difficulty of utilization by computers or intelligent systems such as LLMs. PDFs are best when &#8220;looked at&#8221;, not when they are parsed by a machine. The analogy is clear: the PDF is for humans, not for computers.</p><p>Reality has it so that for more than a decade, PDFs have been the de facto standard for storing key information such as reports, accounting ledger summaries, information transfers, and more. This poses a challenge to anyone building a system that leverages PDF ingestion as part of its components.</p><p>In this article, I propose a three-step process for dealing with PDF files, and parsing key information from them, in a high-stakes financial system.</p><h2>Setting the Scene</h2><p>I have worked for over a year on a component of a system that deals with financial matters like thousand-plus row files for commission records. A common file size is 107+/- page PDF documents. The requirement is perfect extraction quality of key financial data points, which then get ingested into a downstream calculation component of the overall system.</p><p>Through trials and evaluations of parsing techniques, I have landed on a solution which I have complete trust in. Today, I will be sharing this system in depth.</p><h2>Defining the Inputs and Outputs</h2><p>In any system, defining the interfaces for each component makes data flow between components a smooth matter. Starting with the parsing requirements for the PDF parsing component is one of the most important decisions you make. Clearly defining the input and output requirements helps you reduce the inherent noise of data. Knowing exactly what you need from a file is the first step.</p><p>For this system, the PDF parsing component is required to output the following key data points:</p><ul><li><p><strong>Agent number</strong> -- The identification of the sales agent from whom the parsed sales row is linked to</p></li><li><p><strong>Sales id</strong> -- Sales row identifier, for example, Sales #12345abc</p></li><li><p><strong>Product id</strong> -- &#8220;Car insurance, #999&#8221;</p></li><li><p><strong>Commission base</strong> -- The base amount, from which commission downstream gets computed with Python</p></li><li><p><strong>Commission amount</strong> -- Occasionally, the commission is pre-computed in the source file</p></li><li><p><strong>Period id</strong> -- Crucial identifier required in order to accept a sales row</p></li><li><p><strong>Commission rate</strong> -- Occasionally the rate is explicit in the source file</p></li></ul><p>Having defined the exact data I need from a PDF, I can go about the business of building the parsing. Knowing exactly what I am after allows me to build a schema into the system that can be validated for each output of the parsing component. This prevents bad data from ever reaching the downstream components. Additionally, I can reject files up-front: if the files are not compatible with the required output (i.e., if the PDF is a news article or something unexpected), the parsing cancels immediately instead of initializing a full &#8220;dead&#8221; run.</p><p>Once I know clearly what I expect from this component, I can progress into designing the rest of the system.</p><h2>Parsing Signal from Noise</h2><p>Parsing PDF files is one of the most delightful problems in software systems. Inherently, the task of getting information from a PDF is all about extracting a clean signal (a specific data point) from the random and high-entropy nature of PDFs (unlimited formatting variations possible).</p><p>I favour three different parsing methods and services. Let&#8217;s walk through each one, keeping in mind our schema and output requirements.</p><h3>Mistral OCR API</h3><p>The Mistral OCR API is a fast and reliable OCR machine learning model service where a user can ingest a PDF file of any form and sort, and get a structured output in markdown (plain text format without any formatting or styling) or JSON (JavaScript Object Notation). Both of these output formats are easy to parse and read by a computer, because both get rid of any unnecessary styling, metadata, and formatting, leaving you with only the words, text, and numbers.</p><p>The Mistral OCR API is a favourite of mine because of how fast you can go from zero to working system. The service allows large batch uploads and completion within seconds.</p><p>Thinking about how the Mistral OCR service fits into the system: the API allows you to parse any PDF, extract tables, get images, and extract the entire PDF contents into the two much cleaner formats mentioned.</p><p>From here, the clean and simple output is ready for the next step in the system, which I will talk more about below.</p><h3>Mathpix</h3><p>I believe in redundancy as a key property of any system, deeply integrated into the design from the very first initialization. This is why I choose to have an additional OCR-based service in utilization -- not just as a fallback for Mistral failures, but in synergy with Mistral. Mathpix is fundamentally different from Mistral in that it leans more heavily towards maths and tables. This is perfect for a financial system that requires complete accuracy. And, doing the maths on the probability of system failure, adding a second OCR tool exponentially reduces the probability of complete failure.</p><p>Mathpix is similar to Mistral in that you can upload a PDF and receive a structured, plain-text version of the PDF contents.</p><p>Getting specific: inside the Mathpix API there is a rather &#8220;hidden&#8221; boolean you can enable: <code>enable_tables_fallback=true</code>. This option enables what Mathpix calls &#8220;an advanced table processing algorithm that supports very large and complex tables.&#8221; Thinking back to what our schema requirements are, and the types of files our PDF parsing component handles, enabling this option is a no-brainer for our 100+ page table-heavy files.</p><h3>PDF to PNGs</h3><p>To further bulletproof the system, I leverage the tool <code>pdftoppm</code> -- a CLI (command line interface) tool that runs locally to convert a PDF file into one PNG image screenshot per page. This is a very high-leverage tool in this system. The two previous parsing services allow us to rapidly extract the text and image content of the input files, but <code>pdftoppm</code> allows us to do further and more rigorous analysis of each page and its original structure.</p><p>From the command below, I get one PNG image per page, from where the system can easily review the specifics of each page:</p><p><code>pdftoppm -png -scale-to 1800 input.pdf output</code></p><p><code>-scale-to 1800</code> constrains the output image resolution to maximally 1800px on the tallest side, useful for consistency and for downstream API ingestion limitations which we will get to.</p><h2>Putting It All Together</h2><p>So far, I have talked about how to get information from a PDF file into a &#8220;friendly&#8221; format, more simply readable and understood by a computer. Once these parsers have done their job, we have the following pieces to work with:</p><ul><li><p><strong>Mistral</strong>: cleaned markdown or JSON including extracted images</p></li><li><p><strong>Mathpix</strong>: clean markdown with additional &#8220;advanced&#8221; table extraction for edge cases and superior coverage for table-heavy files</p></li><li><p><strong>pdftoppm</strong>: one PNG screenshot per PDF page for deeper visual analysis of the original page structure</p></li></ul><h3>Orchestrating the Parsers</h3><p>With these three parsed versions in hand, we can now orchestrate agents to do the inference of data from the PDF source file. We leverage a visual and text-based LLM model inside a sandbox running in the cloud to do this work, using the two current best tools for the job:</p><ul><li><p><strong>Claude Agent SDK in Python</strong></p></li><li><p><strong>E2B sandbox pre-built templates</strong></p></li></ul><p>Claude Agent SDK is a very powerful tool for processing data and getting a specific output. Once installed, the Claude Agent SDK bundles Claude Code&#8217;s <code>claude</code> tool, which is the current best coding and computer agent available. Additionally, using Claude, you instantly get access to the best LLM models on the market.</p><p>E2B is a service for spawning ephemeral small virtual machines in the cloud. A virtual machine is like your desktop computer, but on a smaller scale and for a different use case. When using an E2B sandbox, we can allow the Claude Agent to do virtually anything to &#8220;its sandbox&#8221;, because the only thing that matters is not what the agent does inside the sandbox, only what it produces and outputs from the work done inside of it.</p><p>Think of the sandbox as the &#8220;workshop&#8221; where the LLM has a range of tools (such as the three parsers we have talked about, and Python) and where it can break things, run experiments, and do virtually anything, without ever touching our application production code.</p><h3>Instructing the Agent</h3><p>Now that we have laid the foundation of the environment, we can begin instructing the Claude Agent on what we desire it to do. Here, we revisit the schema we defined earlier -- agent number, sales id, product id, commission base, commission amount, period id, and commission rate. These are the exact fields we need from any given PDF file, and they form the foundation of the instructions we give to the Claude Agent in the form of a formal document inside the sandbox -- the agent&#8217;s &#8220;work requirements.&#8221; This formal markdown (.md) document is similar to a document you hand to a co-worker when you need them to do a particular thing. The fewer questions the Agent might have about your document, the better the document is.</p><p>Think of this as the specific instructions covering:</p><ol><li><p><strong>How the agent will work.</strong> Exactly what steps it should take.</p></li><li><p><strong>How the agent will create the output.</strong> Exactly how the desired output should look (use the schema rigorously).</p></li><li><p><strong>What are common issues and things to know?</strong> How does the agent deal with failure? (i.e., if the file is not a financial document, or if a part of the system breaks)</p></li></ol><p>These three points form the basis of a document which will be iterated on countless times through tests until the Claude Agent produces deterministically quality outputs. The Claude Agent is an LLM AI model, which means that the more specific and helpful you as the creator can be through the instructions, the more flawlessly the Agent can do the work for you.</p><p>Let me now outline how the Agent will do the work. I will not bore you with the full instructions, as these get long and specific for the system design requirements. By nature, your system will be of differing design, requiring a different set of instructions. But the following outline creates a high-quality, predictable set of examples you can build on.</p><div><hr></div><p><strong>Introduce how the component (the agent + sandbox) fits into the system:</strong></p><ul><li><p>&#8220;You are reading a pre-parsed PDF file containing financial information.&#8221;</p></li><li><p>&#8220;You are a component part of a larger system processing commission sales records using Python for calculation.&#8221;</p></li><li><p>&#8220;Your task is to produce high-quality JSON extractions of a PDF file.&#8221;</p></li><li><p>&#8220;The JSON file you write is used downstream inside the next system component to store and do Python calculations on. Doing any calculation with the data is NOT your task.&#8221;</p></li></ul><div><hr></div><p><strong>Introduce the system environment:</strong></p><ul><li><p>&#8220;You have three directories, each containing different parsing versions from the same file.&#8221;</p></li><li><p>&#8220;Use all three directories to produce the final JSON parsing of the sales rows containing complete verbatim-JSON-transformed extractions from the source file.&#8221;</p></li><li><p>&#8220;Use all three parsing versions in order to cross-verify the parsing of the file by processing each page in logical, self-determined chunks. Using all three parsing versions gives you a completely verifiable way of working, which is perfectly necessary for the complex financial data you are working with.&#8221;</p></li></ul><div><hr></div><p><strong>Define the expected output requirements and where it should be produced:</strong></p><ul><li><p>&#8220;You will be validated using programmatic JSON validation that the final JSON file you write is valid. Therefore, follow the assigned JSON schema rigorously.&#8221;</p></li><li><p>&#8220;If you realize that the PDF source file will not be compatible with the assigned JSON schema, you simply escape and fail instantly. Failure is accepted if the file is clearly incompatible -- in fact, failure is desirable in such a scenario.&#8221;</p></li><li><p>&#8220;All final JSON outputs must be written to a file called <code>output.json</code> inside the output directory in your file environment.&#8221;</p></li></ul><div><hr></div><p><strong>Explain how to work and the minimum amount of verification until confidence can be produced:</strong></p><ul><li><p>&#8220;Given the three versions of parsing, you should use all three versions iteratively to verify your inference of the data. This allows you to keep the data quality high.&#8221;</p></li></ul><div><hr></div><p><strong>How to deal with large samples:</strong></p><ul><li><p>&#8220;By running the tool <code>estimate_tokens.py</code> you can instantly get a recommendation as to how you can work with the assigned files. If the tool output is over the red line, you must spawn a team of agents and assign work specifically, with perfect overlap, and create rigorous validation for the final end product written to the output directory.&#8221;</p></li><li><p>&#8220;Each agent writes their own JSON files, from where you do the merging once ALL data has been processed. If a part of the data fails, or you get stuck somewhere, you must fail quickly instead of trying to fix a massive run.&#8221;</p></li></ul><div><hr></div><p><strong>How to deal with failure gracefully:</strong></p><ul><li><p>&#8220;Simple failures are tolerated and should simply be ignored. For example, a tool use failure or similar -- if this happens, simply write your own tools on demand.&#8221;</p></li><li><p>&#8220;Be flexible with the approach, but rigid in the output.&#8221;</p></li></ul><div><hr></div><p><strong>Specific first steps:</strong></p><ul><li><p>&#8220;Start first with checking the size of the assigned work. This will inform whether you can do the work alone, or if you need to spawn an agent team.&#8221;</p></li><li><p>&#8220;Always prefer creating an agent team, versus using sub-agents, when it comes to specifically dealing with writing outputs and processing files.&#8221;</p></li></ul><div><hr></div><h2>Making It Work</h2><p>The above system is a result of trying and experimenting with countless approaches to the problem of dealing with PDFs. I believe this system produces a predictable and satisfactory solution.</p><p>In integrating this into the overall system, I have had success processing high-risk financial information like commission data with accuracy. Dealing with, and handling the risks of, inaccurate or false data extraction is my worst nightmare. Hence, this system design aims to eliminate such risks through cross-verification, frontier LLM models, and validations.</p><p>Because of the nature of PDFs, it is impossible to create a perfectly deterministic solution when one does not know what the PDFs will look like. The system above is designed specifically to solve the requirement of being able to read and process any incoming PDF containing financial data. Once tested to a sufficient degree, and error-corrected through iterative design as per your system requirements, this system delivers a satisfactory result.</p>]]></content:encoded></item></channel></rss>