<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Tommy Leonhardsen</title>
    <description>The latest articles on DEV Community by Tommy Leonhardsen (@tommy_leonhardsen_81d1f4e).</description>
    <link>https://dev.to/tommy_leonhardsen_81d1f4e</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F2473558%2Fad9d69e4-7452-45bb-9843-6470b688e730.png</url>
      <title>DEV Community: Tommy Leonhardsen</title>
      <link>https://dev.to/tommy_leonhardsen_81d1f4e</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/tommy_leonhardsen_81d1f4e"/>
    <language>en</language>
    <item>
      <title>I Spent 10 Hours Deploying "Hello World" to a Samsung Commercial Display - Samsung OH46DX</title>
      <dc:creator>Tommy Leonhardsen</dc:creator>
      <pubDate>Wed, 25 Mar 2026 10:36:16 +0000</pubDate>
      <link>https://dev.to/tommy_leonhardsen_81d1f4e/i-spent-10-hours-deploying-hello-world-to-a-samsung-commercial-display-samsung-oh46dx-n0c</link>
      <guid>https://dev.to/tommy_leonhardsen_81d1f4e/i-spent-10-hours-deploying-hello-world-to-a-samsung-commercial-display-samsung-oh46dx-n0c</guid>
      <description>&lt;h1&gt;
  
  
  I Spent 10 Hours Deploying "Hello World" to a Samsung Commercial Display
&lt;/h1&gt;

&lt;p&gt;&lt;em&gt;A tale of corporate hubris, an IDE that actively sabotages your work, and the most hostile developer experience since the browser wars. Also: Samsung's documentation team should be reassigned to something less critical, like guarding a fire extinguisher.&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;You know how Apple builds a walled garden but at least makes it &lt;em&gt;pretty&lt;/em&gt; inside? Samsung looked at that and said "we want a walled garden too, but with barbed wire, landmines, a moat, and a gate attendant who speaks only a dialect of Klingon that was discontinued in 2019. Also, the walls move between firmware versions and we won't tell you."&lt;/p&gt;

&lt;p&gt;I needed to deploy a simple HTML/JS app to a Samsung OH46DX — a commercial outdoor display running Tizen 8.0. The app is literally a bootloader: fetch a script from a server, run it fullscreen. A competent platform would take 20 minutes. Samsung took 10 hours, two AI assistants, and a substantial portion of my will to live.&lt;/p&gt;

&lt;p&gt;Let me be very clear about something before we start: the OH46DX hardware is beautiful. Gorgeous panel. Built like a Norwegian winter. Completely waterproof. I love it.&lt;/p&gt;

&lt;p&gt;The software ecosystem wrapped around it is a war crime.&lt;/p&gt;




&lt;h2&gt;
  
  
  The First Thing You Need to Know
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;This is NOT a consumer TV.&lt;/strong&gt; Almost every Tizen tutorial on the internet targets consumer Samsung TVs. Those guides are not just useless — they are &lt;em&gt;actively harmful&lt;/em&gt;. Following them will confidently lead you in the wrong direction at every single step. Different menus. Different certificates. Different deployment model. Different everything.&lt;/p&gt;

&lt;p&gt;Samsung's own documentation? Technically it exists, in the same philosophical sense that Schrödinger's cat exists. There are PDFs. They reference features that may or may not still be present. The screenshots are from 2019. The menu they're describing was renamed in 2021, renamed again in 2023, and may no longer exist at all on your firmware version. Samsung treats their developer documentation the way I treat gym memberships — maintained just enough to claim it exists, never actually used.&lt;/p&gt;

&lt;p&gt;The word "SSSP" (Samsung Smart Signage Platform) appears everywhere in search results. Samsung deprecated it in 2021. They replaced it with "TEP" (Tizen Enterprise Platform). They did not tell the internet. The internet continues to confidently document SSSP as if it's current. You will follow this documentation. It will not work. This is not the internet's fault.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Certificate Circus, or: How Samsung Learned to Love Bureaucracy
&lt;/h2&gt;

&lt;p&gt;Here is Samsung's vision for deploying your own app to a display you physically own and paid for:&lt;/p&gt;

&lt;p&gt;You need a &lt;strong&gt;Samsung Partner certificate&lt;/strong&gt;. Not a Tizen certificate. Not a developer certificate. A &lt;em&gt;Partner&lt;/em&gt; certificate, created through Samsung's Certificate Manager, signed by Samsung's servers, bound to your specific display's hardware ID, with a privilege level of "Partner" — because apparently "Public" privilege doesn't actually let you do anything on commercial hardware, a distinction Samsung mentions in exactly one footnote in a document you will not find until hour seven.&lt;/p&gt;

&lt;p&gt;"But surely a Tizen developer certificate works? It's still Tizen, right?"&lt;/p&gt;

&lt;p&gt;Error -3. Invalid certificate chain.&lt;/p&gt;

&lt;p&gt;"Okay, Samsung certificate with Public privilege?"&lt;/p&gt;

&lt;p&gt;Error -3. Invalid certificate chain.&lt;/p&gt;

&lt;p&gt;Samsung has decided that you — the person who bought their hardware, is running their operating system, and just wants to put a web page on it — need to prove yourself worthy. You do this by going through a certificate creation wizard that requires a Samsung account, multiple clicks through screens that look like they were designed in 2013, and ultimately produces a file that only works on devices you've registered in advance.&lt;/p&gt;

&lt;p&gt;Apple does this too, of course. The difference is that Apple has documentation, consistent error messages, and a developer experience that doesn't make you feel like you're filling out paperwork at a Soviet-era municipal office.&lt;/p&gt;

&lt;h3&gt;
  
  
  The DUID Comedy, Starring: Two Identical-Looking IDs
&lt;/h3&gt;

&lt;p&gt;Every Samsung display has a DUID — a hardware identifier that gets baked into your certificate. Wrong DUID: Error -4. The display you own, the certificate you created, your own app — rejected.&lt;/p&gt;

&lt;p&gt;Samsung helpfully shows you your device identifiers on the About screen. Two of them. Side by side. With no indication which one you need.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;What Samsung Calls It&lt;/th&gt;
&lt;th&gt;Looks Like&lt;/th&gt;
&lt;th&gt;Actually For&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;EMUID&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;58164423-e912-79fd-eb69-9fd562040b6a&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Tizen Studio certificate binding — &lt;strong&gt;this is the one you need&lt;/strong&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Unique Device ID&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;2DCPLROPJJQQY&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Something Samsung cares about. Not you.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;You will write down the wrong one. Of course you will — they're both labeled "Device ID" in spirit, displayed with equal prominence, and Samsung's documentation mentions the distinction in a paragraph buried in a guide for a different product. I wrote down the wrong one. I spent an hour creating fresh certificates before I realized the UUID-format string on the left side of the screen was the one I needed, not the alphanumeric string on the right.&lt;/p&gt;

&lt;p&gt;Samsung put both IDs on the About screen without explaining what either is for. This is not an oversight. At this point I believe it is deliberate.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Just connect via SDB and let Device Manager auto-detect the DUID.&lt;/strong&gt; Don't trust your own eyes. Don't trust anything Samsung labels.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Secret Handshake Nobody Told You About
&lt;/h3&gt;

&lt;p&gt;So you've:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Enabled developer mode ✅&lt;/li&gt;
&lt;li&gt;Connected via SDB ✅
&lt;/li&gt;
&lt;li&gt;Created the correct Samsung Partner certificate ✅&lt;/li&gt;
&lt;li&gt;Signed your package correctly ✅&lt;/li&gt;
&lt;li&gt;Served the package from a web server ✅&lt;/li&gt;
&lt;li&gt;Watched the display download it ✅&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And it still fails with a certificate error.&lt;/p&gt;

&lt;p&gt;Why? Because there is a &lt;strong&gt;mandatory step that is not documented anywhere in the certificate setup flow, not suggested in any error message, and not mentioned in any getting-started guide:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Right-click the device in Device Manager → "Permit to install apps."&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;That's it. That's the step. Without it, every certificate is rejected regardless of validity. The error message says the certificate is invalid. The certificate is not invalid. The error message is lying to you. Samsung's error messages lie to you. Keep this in mind for later.&lt;/p&gt;

&lt;p&gt;I lost three hours to this. Three hours recreating certificates that were correct from the beginning, because the error message blamed the certificate instead of the missing permission step.&lt;/p&gt;

&lt;p&gt;If there is a Samsung developer experience team — and I'm genuinely not sure there is — I want them to know that this is unconscionable. You sell commercial hardware to integrators and developers. You have an undocumented mandatory step that produces a misleading error. Someone on your team chose to write "invalid certificate" instead of "please run Permit to Install Apps." That person should not be allowed near error messages.&lt;/p&gt;




&lt;h2&gt;
  
  
  Finding Developer Mode: A Treasure Hunt With No Treasure Map
&lt;/h2&gt;

&lt;p&gt;Consumer TV guides say: "Home → Apps → type 12345."&lt;/p&gt;

&lt;p&gt;Commercial displays don't have an "Apps" button where you'd expect it. After fifteen minutes of staring at the Home screen, I had tried every button on the remote, opened Settings three times, considered factory resetting, and briefly contemplated returning the display to the vendor and becoming a farmer.&lt;/p&gt;

&lt;p&gt;The actual path:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Press &lt;strong&gt;Home&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Go to the &lt;strong&gt;Features&lt;/strong&gt; tab (not Settings — Settings is a trap that goes somewhere else entirely)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Apps&lt;/strong&gt; is hiding as the rightmost icon under Features&lt;/li&gt;
&lt;li&gt;Type &lt;strong&gt;12345&lt;/strong&gt; — the developer mode dialog finally appears&lt;/li&gt;
&lt;li&gt;Enter your development machine's IP address&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Reboot the display&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwta6gotdhjd9b1icvq35.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwta6gotdhjd9b1icvq35.jpg" alt="OH46DX Home screen — Apps is the rightmost icon under Features" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Also: the remote control is completely miserable for typing an IP address, a fact Samsung is aware of and has addressed by supporting USB keyboards perfectly. They just don't mention this anywhere. Type "Samsung commercial display USB keyboard" into any search engine and the silence is deafening. Plug in a keyboard. It works. You're welcome.&lt;/p&gt;

&lt;p&gt;Also also: Samsung renames these menus between firmware versions. "URL Launcher" became "Custom App." "App Management" appeared. "Play Via" exists on some models and not others. Samsung's menu naming team operates completely independently of their documentation team, both of whom operate completely independently of their developer relations team, all three of whom appear to operate completely independently of anyone who has ever actually tried to use the product.&lt;/p&gt;




&lt;h2&gt;
  
  
  Tizen Studio: An Eclipse-Based IDE in 2026
&lt;/h2&gt;

&lt;p&gt;Samsung's development environment for Tizen is called Tizen Studio. It is based on Eclipse. In 2026. I am not going to editorialize further on that point because the sentence is already doing sufficient work.&lt;/p&gt;

&lt;p&gt;What I &lt;em&gt;will&lt;/em&gt; editorialize on is Tizen Studio's signature feature: &lt;strong&gt;it actively corrupts your project files.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Switch between the Design tab and Source tab in the config.xml editor? Congratulations — &lt;code&gt;&amp;lt;name&amp;gt;&lt;/code&gt; is now &lt;code&gt;&amp;lt;n&amp;gt;&lt;/code&gt;. Not a typo. Not a display artifact. The IDE has silently rewritten your XML. Your package now fails with a generic error. The error does not mention the malformed tag. You get to discover it by reading the raw file after two failed deployments.&lt;/p&gt;

&lt;p&gt;This is not a subtle edge case. This is the primary workflow — open config.xml, edit something, save. The editor corrupts the output. This is a bug that has apparently existed long enough to become load-bearing.&lt;/p&gt;

&lt;p&gt;But wait, there's more! Tizen Studio also packages your IDE metadata into the .wgt file. Files like &lt;code&gt;.project&lt;/code&gt; and &lt;code&gt;.settings/&lt;/code&gt; get bundled alongside your actual app. These files aren't covered by the package signatures. The display rejects the package with "unsigned file found." The error does not tell you which file is unsigned. Samsung believes you should enjoy the mystery.&lt;/p&gt;

&lt;p&gt;The CLI — &lt;code&gt;tizen package -t wgt -s "PROFILE" -- /path/to/project&lt;/code&gt; — does everything correctly. Excludes metadata. Doesn't corrupt XML. Works first time. Samsung built a working tool and then built a broken GUI on top of it. If you take one thing from this article: use the CLI. Open Tizen Studio only for Certificate Manager and Device Manager. Close it before it can hurt you. Do not let it touch your project files.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Three Stages of Samsung Deployment Failure
&lt;/h2&gt;

&lt;p&gt;Samsung serves the same three error dialogs for completely different underlying problems. Learning to distinguish them will save you hours.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Stage 1 — Display downloads sssp_config.xml but not the .wgt&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Network problem, firewall, wrong URL, or malformed XML. Nothing to do with Samsung specifically. Fix your server.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Stage 2 — Display downloads the .wgt, shows "Installing...", then fails&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Certificate problem. Wrong cert type (you used Tizen Public, not Samsung Partner), wrong DUID, or you forgot the "Permit to install apps" secret handshake. The error says "Unable to install." It means "your certificate is rejected." These are different statements that Samsung has decided should look identical.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Stage 3 — Display installs successfully, then "Unable to start the app"&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Stop debugging certificates immediately. The certificate is fine. The package content is broken. Common causes: malformed config.xml (the &lt;code&gt;&amp;lt;n&amp;gt;&lt;/code&gt; bug), wrong project type (&lt;code&gt;&amp;lt;tizen:addon&amp;gt;&lt;/code&gt; instead of &lt;code&gt;&amp;lt;tizen:application&amp;gt;&lt;/code&gt; — yes, Tizen Studio will silently create the wrong project type if you click the wrong wizard option), or missing index.html.&lt;/p&gt;

&lt;p&gt;I spent four hours in Stage 3 convinced it was a certificate problem, because Samsung's error message for "your app crashed on launch" is visually identical to "certificate rejected." Samsung UX team, I hope your dashboards are as uninformative as your error messages.&lt;/p&gt;


&lt;h2&gt;
  
  
  SDB: Like ADB, But Supervised
&lt;/h2&gt;

&lt;p&gt;SDB is Samsung's version of Android's ADB. Port 26101. The basics work:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;sdb connect &amp;lt;ip&amp;gt;:26101
tizen &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; MyApp.wgt &lt;span class="nt"&gt;-s&lt;/span&gt; &amp;lt;ip&amp;gt;:26101 &lt;span class="nt"&gt;--&lt;/span&gt; /path/to/project
tizen run &lt;span class="nt"&gt;-p&lt;/span&gt; MyApp0000.app &lt;span class="nt"&gt;-s&lt;/span&gt; &amp;lt;ip&amp;gt;:26101
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What doesn't work: &lt;code&gt;sdb shell&lt;/code&gt;. On the OH46DX, shell access is disabled. &lt;code&gt;intershell_support:disabled&lt;/code&gt;. No logs. No filesystem access. No debugging. You are deploying to a sealed box.&lt;/p&gt;

&lt;p&gt;"But I'm in developer mode! Surely developer mode means I can—"&lt;/p&gt;

&lt;p&gt;No. Samsung's "developer mode" allows you to install apps and not much else. It is developer mode in the same sense that a test drive is car ownership. You're interacting with the thing, but Samsung is in the passenger seat with their hand near the handbrake.&lt;/p&gt;

&lt;p&gt;Test everything in a desktop browser first. Once it's on the display, you are completely blind. If it breaks, you will have no idea why. This is fine, according to Samsung.&lt;/p&gt;




&lt;h2&gt;
  
  
  The sssp_config.xml Trap for the Historically Inclined
&lt;/h2&gt;

&lt;p&gt;SDB-deployed apps don't auto-start on reboot — yet another thing Samsung doesn't mention until you discover it empirically. For production you need the HTTP deployment path: serve a &lt;code&gt;sssp_config.xml&lt;/code&gt; that tells the display where to find your .wgt.&lt;/p&gt;

&lt;p&gt;The correct format for Tizen 8.0:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?xml version="1.0" encoding="UTF-8"?&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;widget&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;ver&amp;gt;&lt;/span&gt;1&lt;span class="nt"&gt;&amp;lt;/ver&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;size&amp;gt;&lt;/span&gt;EXACT_BYTE_COUNT&lt;span class="nt"&gt;&amp;lt;/size&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;widgetname&amp;gt;&lt;/span&gt;MyApp&lt;span class="nt"&gt;&amp;lt;/widgetname&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;source&amp;gt;&lt;/span&gt;http://YOUR_SERVER/MyApp.wgt&lt;span class="nt"&gt;&amp;lt;/source&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;webtype&amp;gt;&lt;/span&gt;tizen&lt;span class="nt"&gt;&amp;lt;/webtype&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/widget&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you've read any Samsung SSSP documentation, you'll find references to &lt;code&gt;&amp;lt;SamsungSmartSignage&amp;gt;&lt;/code&gt; XML with &lt;code&gt;&amp;lt;type&amp;gt;url&amp;lt;/type&amp;gt;&lt;/code&gt; — a format that lets you point the display directly at a webpage URL without packaging anything. No certificate needed. Just a URL. Simple. Elegant. Documented.&lt;/p&gt;

&lt;p&gt;Also: completely non-functional on Tizen 8.0. The display fetches the XML, silently ignores the URL, and does nothing. No error. No log. Your Apache server shows the request arriving. The display decides the response is beneath its attention.&lt;/p&gt;

&lt;p&gt;Samsung deprecated &lt;code&gt;&amp;lt;type&amp;gt;url&amp;lt;/type&amp;gt;&lt;/code&gt; when they moved to TEP and forgot to put a deprecation notice anywhere a human being might encounter it. The documentation describing it as functional is still live. It will continue to be live long after I am gone from this earth.&lt;/p&gt;

&lt;p&gt;There is no way to deploy a webpage without signing a .wgt package. There is no unsigned mode. Developer mode does not help. There is no escape. Welcome to Samsung's commercial ecosystem — you may check out any time you like, but you can never leave without a Partner certificate.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Actual Working Workflow (15 Minutes, Once You Know)
&lt;/h2&gt;

&lt;p&gt;This took 10 hours to discover and takes 15 minutes to execute:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Install Tizen Studio + Samsung Certificate Extension&lt;/li&gt;
&lt;li&gt;Connect display via ethernet, note its IP&lt;/li&gt;
&lt;li&gt;Home → &lt;strong&gt;Features&lt;/strong&gt; tab → Apps (rightmost icon) → type &lt;strong&gt;12345&lt;/strong&gt; → enable Developer Mode → enter your PC's IP → reboot&lt;/li&gt;
&lt;li&gt;&lt;code&gt;sdb connect &amp;lt;display-ip&amp;gt;:26101&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Certificate Manager → New → &lt;strong&gt;Samsung&lt;/strong&gt; → &lt;strong&gt;Partner&lt;/strong&gt; privilege → let Device Manager auto-detect DUID&lt;/li&gt;
&lt;li&gt;Device Manager → right-click device → &lt;strong&gt;"Permit to install apps"&lt;/strong&gt; ← THIS ONE. DON'T SKIP IT.&lt;/li&gt;
&lt;li&gt;Create project directory: &lt;code&gt;config.xml&lt;/code&gt; + &lt;code&gt;index.html&lt;/code&gt; + &lt;code&gt;icon.png&lt;/code&gt;. Nothing else. No IDE files.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;tizen package -t wgt -s "YOUR-PROFILE" -- /path/to/project&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;tizen install -n MyApp.wgt -s &amp;lt;ip&amp;gt;:26101 -- /path/to/project&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;For auto-start on boot: serve .wgt + &lt;code&gt;sssp_config.xml&lt;/code&gt; via HTTP, configure the display's Custom App URL&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;That's it. Nine steps and a warning. Ten hours of pain condensed into fifteen minutes of work.&lt;/p&gt;




&lt;h2&gt;
  
  
  Things That Absolutely Did NOT Help
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Every consumer Tizen TV tutorial ever written.&lt;/strong&gt; Wrong platform, wrong menus, wrong certs, wrong assumptions, aggressively confident tone.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Samsung's official documentation.&lt;/strong&gt; Exists. Is findable. Has not been maintained since the Obama administration.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Manually zipping files and renaming to .wgt.&lt;/strong&gt; Unsigned packages are rejected unconditionally, always, in all modes. The display has no mercy.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tizen Studio's GUI for building packages.&lt;/strong&gt; Corrupts your files. Includes your IDE metadata. Is Eclipse. Use the CLI.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The &lt;code&gt;&amp;lt;type&amp;gt;url&amp;lt;/type&amp;gt;&lt;/code&gt; sssp_config.xml format.&lt;/strong&gt; Silently does nothing on Tizen 8.0. Samsung didn't announce this change. The docs describing it as functional are still live.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reading the error messages literally.&lt;/strong&gt; "Invalid certificate" means at least four different things. "Unable to install" means at least six. Samsung error messages are impressionist art — suggestive, open to interpretation, not meant to convey specific information.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  In Conclusion
&lt;/h2&gt;

&lt;p&gt;Samsung sells hardware at Apple prices and delivers a developer ecosystem at mid-2000s-shareware quality. The OH46DX panel is exceptional — I would buy it again without hesitation. The Tizen commercial software platform wrapped around it is the product of an organization that has never in its history been required to dogfood its own developer tools.&lt;/p&gt;

&lt;p&gt;Apple's walled garden is frustrating. Samsung's is frustrating &lt;em&gt;and&lt;/em&gt; poorly maintained &lt;em&gt;and&lt;/em&gt; undocumented &lt;em&gt;and&lt;/em&gt; inconsistent across firmware versions &lt;em&gt;and&lt;/em&gt; does not tell you the truth when something goes wrong.&lt;/p&gt;

&lt;p&gt;If you work at Samsung and you've read this far: I'm not angry. I'm disappointed. You make world-class display hardware. The panel quality, the outdoor rating, the build quality — genuinely excellent. And then you ship it with an SDK based on Eclipse, an IDE that corrupts XML on tab-switch, a certificate system with undocumented mandatory steps, error messages that actively mislead developers, and documentation that hasn't tracked your own product changes in years.&lt;/p&gt;

&lt;p&gt;You have the hardware to be the go-to platform for professional signage. You have the software to ensure that only the most determined — or most foolish — developers ever successfully deploy to it.&lt;/p&gt;

&lt;p&gt;I am apparently both.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;The full, non-snarky step-by-step guide (every command, every config file, every screenshot) lives at &lt;a href="https://gist.github.com/aweussom/28c7e9f06fee0eb7db91476d800cbfa0" rel="noopener noreferrer"&gt;this GitHub Gist&lt;/a&gt;. Bookmark it. You'll need it more than Samsung's docs.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>oh46dx</category>
      <category>samsung</category>
    </item>
    <item>
      <title>Code Was Always the Easy Part</title>
      <dc:creator>Tommy Leonhardsen</dc:creator>
      <pubDate>Mon, 09 Mar 2026 16:26:30 +0000</pubDate>
      <link>https://dev.to/tommy_leonhardsen_81d1f4e/code-was-always-the-easy-part-5eaa</link>
      <guid>https://dev.to/tommy_leonhardsen_81d1f4e/code-was-always-the-easy-part-5eaa</guid>
      <description>&lt;p&gt;There is a piece doing the rounds on DEV.to — &lt;a href="https://dev.to/_itsglover/ai-writes-the-code-now-so-what-are-you-3b7i"&gt;&lt;em&gt;AI Writes the Code Now. So What Are You?&lt;/em&gt;&lt;/a&gt; — and it is thoughtful, well-written, and almost right.&lt;/p&gt;

&lt;p&gt;I am a sysadmin. I have always looked askew at programmers. From where I sit: if they are not producing bugs, they are busy creating security holes.&lt;/p&gt;

&lt;p&gt;That is unfair, of course. But only slightly.&lt;/p&gt;

&lt;p&gt;The author is worried that AI is replacing programmers. He's not wrong about the symptoms. He's wrong about the diagnosis.&lt;/p&gt;

&lt;p&gt;AI isn't threatening programmers because programmers suddenly became redundant.&lt;/p&gt;

&lt;p&gt;AI is exposing something that was always true and that the industry spent decades pretending wasn't.&lt;/p&gt;

&lt;p&gt;To say it plainly: &lt;strong&gt;most code is not the hard part of software. Most of it never was.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This needs some unpacking, because "code" covers a lot of ground.&lt;/p&gt;




&lt;h2&gt;
  
  
  Three Things We've Been Calling the Same Thing
&lt;/h2&gt;

&lt;p&gt;There is a distinction that working developers know intuitively but rarely say out loud.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Code&lt;/strong&gt; is notation. It is the translation layer between intent and machine. API wiring, CRUD endpoints, framework glue, configuration, boilerplate. The mechanical work of expressing something that is already understood. Most production code is this. The overwhelming majority of commits in the overwhelming majority of repositories is this.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Algorithms&lt;/strong&gt; are different. Implementing a distributed consensus protocol. Designing a lock-free data structure. Writing a B-tree. Building the arc-calculation for a ballista AI that lobs projectiles over obstacles with realistic physics. This is genuine intellectual content. It is hard. It lives &lt;em&gt;inside&lt;/em&gt; the code but it is not the code — it is the thinking that precedes the code, expressed as code.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Engineering&lt;/strong&gt; is different again. It is the meta-level. Not "does this work?" but "under what conditions does this fail, and who gets paged at 3am when it does?" It is the failure mode analysis, the operational thinking, the system that someone else can understand and fix under pressure. It lives largely &lt;em&gt;outside&lt;/em&gt; the code.&lt;/p&gt;

&lt;p&gt;AI has eaten the first category almost entirely. It assists meaningfully with parts of the second. The third remains human territory — and it is the category the industry has been most consistently failing to teach, reward, or even name.&lt;/p&gt;




&lt;h2&gt;
  
  
  What AI Actually Does Well
&lt;/h2&gt;

&lt;p&gt;A few weeks ago I built a game.&lt;/p&gt;

&lt;p&gt;Not a toy. A working browser game with Matter.js physics, destructible terrain, a ballista AI with parabolic arc calculation, tower crumble simulation with proper angular velocity decomposition, particle effects, and per-entity state management. Single HTML file. Runs in any browser.&lt;/p&gt;

&lt;p&gt;I didn't write most of the code. I nudged an LLM and it wrote code. Then I nudged again.&lt;/p&gt;

&lt;p&gt;Here is the interesting part: the code is not what makes the game interesting. The interesting decisions are the ones I made: that the tower should crumble based on tilt &lt;em&gt;and&lt;/em&gt; support state, not just collision force. That my "Slemmings" should auto-walk with player override rather than pure manual control. That bolts need a clearance check so they don't fire into their own base. That a wedge-break enforcement pass needs to run after all constraint solving for the tick, not before.&lt;/p&gt;

&lt;p&gt;The arc calculation for the ballista is an algorithm — projectile motion, gravity compensation, angular spread. That took thought. The LLM implemented it correctly once I specified what it needed to do.&lt;/p&gt;

&lt;p&gt;The crumble condition is engineering — what does "the tower falls" mean in a physics simulation? What are the edge cases? What feels right to a player? That required judgment that has nothing to do with code.&lt;/p&gt;

&lt;p&gt;The boilerplate — the event loop, the canvas rendering, the input handling — is code. The LLM wrote that fluently because it was always mechanical. Translating known intent into known syntax is what LLMs do, because that is what most code has always been.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Constraint Interrupt
&lt;/h2&gt;

&lt;p&gt;During development of a boardgame, I needed boards to be solvable. The LLM, left to its own devices, built a complete solution: a snake-path Hamiltonian construction algorithm, a DFS solver, timeout handling, retry loops, a Web Worker to avoid UI freezing. Correct code. Thoughtful architecture.&lt;/p&gt;

&lt;p&gt;I interrupted it:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;"I think you are overthinking this. The boards do NOT have to be generated in realtime. We can pre-compute boards. Then, when the user is playing, the computer mostly waits for user input — use that CPU to generate more boards."&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The entire structure collapsed. The realtime constraint that was driving the complexity didn't exist. The LLM had accepted an implicit assumption in my problem statement and built an elaborate solution around it. I had to supply the one thing it couldn't: the view from outside the problem.&lt;/p&gt;

&lt;p&gt;This is the actual gap. Not code. Not even algorithm. It is the capacity to question the frame rather than optimize within it. To ask whether the problem as stated is the right problem.&lt;/p&gt;

&lt;p&gt;That capacity has a name. It is engineering.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Grigorev Problem
&lt;/h2&gt;

&lt;p&gt;The article opens with the story of Alexey Grigorev, founder of DataTalks.Club, who let Claude Code run a Terraform command that wiped out his entire production infrastructure. Two and a half years of student submissions, gone in seconds.&lt;/p&gt;

&lt;p&gt;The author frames this as over-reliance on AI. That is accurate but incomplete.&lt;/p&gt;

&lt;p&gt;Claude actually gave the right advice — keep the infrastructure separate. Grigorev overruled it. Claude then executed the Terraform logic precisely. Every individual step was correct. The system-level understanding of what was about to happen was absent.&lt;/p&gt;

&lt;p&gt;At no point was there a code problem. There was no bad algorithm. There was a failure of engineering thinking: what does "state file missing" mean for a live platform? What is the blast radius of &lt;code&gt;terraform destroy&lt;/code&gt; on a system with 100,000 users? Who owns this decision?&lt;/p&gt;

&lt;p&gt;Those questions live outside the code. They always did. AI cannot ask them on your behalf because asking them requires understanding what you care about losing.&lt;/p&gt;

&lt;p&gt;This is not an AI story. It is a story about what happens when programmer-mode thinking — does this plan look valid? — gets applied at engineer-scale blast radius.&lt;/p&gt;

&lt;p&gt;AI just made each step faster and more confident-looking.&lt;/p&gt;




&lt;h2&gt;
  
  
  What the Industry Got Wrong
&lt;/h2&gt;

&lt;p&gt;The Glover article cites BLS data: programmer employment fell sharply while software developer employment — the more architecture-oriented role — held nearly flat. He presents this as AI disruption. That framing is too generous.&lt;/p&gt;

&lt;p&gt;BLS has long separated "Computer Programmers" from "Software Developers." Programmers — the narrower, more implementation-focused classification — were already in structural decline before any LLM could write a line of code. The market was already distinguishing between the mechanical-coding tier and the design-and-systems tier. AI didn't create that distinction. It is finishing what the market already started, faster.&lt;/p&gt;

&lt;p&gt;"Software Engineer" became a title handed to anyone who could write a for loop. The actual engineering — the failure mode analysis, the operational thinking, the system design that someone else can reason about under pressure — was treated as a personality trait rather than a skill. Either you had it or you didn't, and if you didn't, nobody taught it.&lt;/p&gt;

&lt;p&gt;Nobody taught it because it is invisible. Code ships. Architecture reviews are expensive. Post-mortems happen after disasters. The preventive thinking that stops the disaster earns nothing and appears nowhere on a CV.&lt;/p&gt;

&lt;p&gt;My book has a chapter that opens with a real conversation. A senior designer told me during a discussion of one of my designs: "Using the filesystem as a database is fine, as long as there's just one user and nobody needs to work on the same data."&lt;/p&gt;

&lt;p&gt;That sentence was not an argument. It was a worldview. A worldview that had never examined what &lt;code&gt;rename()&lt;/code&gt; actually does at the kernel level. That had never asked whether &lt;code&gt;flock()&lt;/code&gt; would solve the concurrency problem. That had never read a post-mortem about what happens when you add MySQL to a system that was working fine without it.&lt;/p&gt;

&lt;p&gt;That designer was a competent programmer. He had simply never been asked to think like an engineer, so he didn't.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Part That Will Sting
&lt;/h2&gt;

&lt;p&gt;Here is the thing the Glover article circles without quite landing.&lt;/p&gt;

&lt;p&gt;The developers most anxious about AI are the ones whose professional identity is built on &lt;em&gt;being the person who writes the code&lt;/em&gt;. When a model can write the code, that identity is threatened.&lt;/p&gt;

&lt;p&gt;But the conflation was always there. "I write code" and "I understand systems" are not the same thing. "I can implement this feature" and "I understand what this feature does to the system under load" are not the same thing. The industry let people spend entire careers on the first half of each pair and call it the second.&lt;/p&gt;

&lt;p&gt;The engineers — the people who were always thinking about failure modes and operational consequences, who found the code itself the least interesting part of the work — are largely fine. AI gives them faster notation. Good.&lt;/p&gt;

&lt;p&gt;The sysadmins, the infrastructure people, the ones who inherited what programmers shipped and had to keep it alive — we were never impressed by the code. We were impressed by whether it still worked at 3am on a Tuesday after a kernel update. Much of it didn't.&lt;/p&gt;

&lt;p&gt;The programmers who never developed the thinking beyond the code are in genuine trouble. Not because AI replaced them. Because the thing that insulated them from that question — the craft mystique, the framework mastery, the conference talks about clean architecture — is gone. What remains is the thinking. And if the thinking was never there, there is nothing left.&lt;/p&gt;

&lt;p&gt;That is not AI's fault.&lt;/p&gt;

&lt;p&gt;It was always true.&lt;/p&gt;

&lt;p&gt;It just wasn't visible until the notation became free.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;The author is writing a book about systems, Linux internals, and the gap between how things are taught and how they actually work.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>career</category>
      <category>discuss</category>
      <category>programming</category>
    </item>
    <item>
      <title>I Got Tired of Guessing My Claude Quota, So I Made a Robot Read It For Me</title>
      <dc:creator>Tommy Leonhardsen</dc:creator>
      <pubDate>Thu, 19 Feb 2026 19:10:02 +0000</pubDate>
      <link>https://dev.to/tommy_leonhardsen_81d1f4e/i-got-tired-of-guessing-my-claude-quota-so-i-made-a-robot-read-it-for-me-3513</link>
      <guid>https://dev.to/tommy_leonhardsen_81d1f4e/i-got-tired-of-guessing-my-claude-quota-so-i-made-a-robot-read-it-for-me-3513</guid>
      <description>&lt;h2&gt;
  
  
  Update: MUCH less crazy way of displaying quota
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/aweussom/claude-code-quota" rel="noopener noreferrer"&gt;https://github.com/aweussom/claude-code-quota&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Please use this instead.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Problem Nobody Asked Me to Solve
&lt;/h2&gt;

&lt;p&gt;If you use Claude Pro (or Max, or Team), you've probably experienced the ritual: you're deep in a coding session, Claude is on fire, and then — rate limited. The dreaded "you've hit your usage limit" message appears. You stare at the usage bar in settings. &lt;em&gt;Was that 60%? 65%? How long until reset?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Anthropic shows you this information on a nice little settings page. But there's no API for it. No webhook. No "hey, you're at 80%" notification. Just a page with bars and text that you have to manually go look at.&lt;/p&gt;

&lt;p&gt;So naturally, I did what any reasonable developer would do: I built a pipeline that screenshots my screen every minute and feeds it to a 235-billion-parameter vision model to read the numbers for me.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Architecture (If You Can Call It That)
&lt;/h2&gt;

&lt;p&gt;The system has three moving parts:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Part 1: A PowerShell script that mashes the Print Screen button&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;\capture_claude_usage.ps1&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;That's it. It takes a full screenshot every 60 seconds and saves it as a timestamped PNG. You open the Claude usage page, run the script, and walk away. It uses &lt;code&gt;System.Windows.Forms&lt;/code&gt; to grab the screen — no dependencies, no installs, just raw .NET energy.&lt;/p&gt;

&lt;p&gt;If PowerShell refuses to run it with a "not digitally signed" error, the file is probably blocked (Mark-of-the-Web). Check and unblock it:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="n"&gt;Get-Item&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;\capture_claude_usage.ps1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Stream&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Zone.Identifier&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-ErrorAction&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;SilentlyContinue&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;Unblock-File&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;\capture_claude_usage.ps1&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Also: this capture approach is most reliable on a single-monitor setup. Mixed resolutions + mixed DPI scaling (and browser zoom) can cause clipped captures.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Part 2: A Python script that asks an AI to read a screenshot of an AI's usage page&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python parse_quota.py parse claude_usage_2026-01-16_01-15-51.png
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;By default this uses Ollama Cloud (Qwen3-VL 235B) and asks it to extract the quota numbers. You can also point it at a local Ollama host if you don't want screenshots leaving your machine. The response comes back as structured JSON:&lt;/p&gt;

&lt;p&gt;cat .\quota-data.json&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"quota_used_pct"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"weekly_used_pct"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;99&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"resets_in"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2 hr 38 min"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"weekly_resets"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"13 hr 38 min"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"updated"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2026-02-19T18:24:37.351014+00:00"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"valid"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"source_image"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"claude_usage_2026-02-19_19-24-25.png"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;And because I'm incapable of leaving well enough alone, here's the same output as a screenshot:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmr95jclfle1p8nlbtw8m.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmr95jclfle1p8nlbtw8m.png" alt=" "&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Why a screenshot instead of a code block?
&lt;/h3&gt;

&lt;p&gt;Because the whole point is that it looks good. The JSON output is rendered in Windows 11 PowerShell with oh-my-posh and a properly installed Nerd Font — which took an embarrassingly non-trivial amount of effort to set up for someone who has spent 40 years avoiding Windows terminals on principle.&lt;/p&gt;

&lt;p&gt;A code block would just show you text. The screenshot shows you that yes, a middle-aged Norwegian with a Linux soul can make PowerShell look like that. Consider it proof of non-suckiness.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Part 3: A monitor loop that feeds Claude Code's status line&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;parse_quota.py monitor&lt;/code&gt; watches a screenshot directory and writes &lt;code&gt;~/.claude/quota-data.json&lt;/code&gt; atomically. Pair it with &lt;code&gt;statusline.ps1&lt;/code&gt; and you can display &lt;code&gt;ctx:&amp;lt;...&amp;gt;% quota:&amp;lt;...&amp;gt;%&lt;/code&gt; in Claude Code while you work.&lt;/p&gt;

&lt;p&gt;Bonus: it cleans up after itself. If a screenshot parses correctly, it gets deleted. If parsing fails, it keeps only the first and the most recent failing screenshot (and deletes the rest) so your screenshot folder doesn't quietly evolve into a 4K documentary about your browser tabs. Please do not point &lt;code&gt;--watch-dir&lt;/code&gt; at your Photos folder unless you're emotionally prepared for consequences.&lt;/p&gt;
&lt;h2&gt;
  
  
  Why Ollama Cloud + Qwen3-VL?
&lt;/h2&gt;

&lt;p&gt;A few reasons:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;It has a free tier (for now)&lt;/strong&gt; — Ollama Cloud gives you access to massive models without paying per token (still requires an API key, and "free" is famously a temporary condition on the internet)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Qwen3-VL 235B is genuinely good at reading text in images&lt;/strong&gt; — it nails the percentage values and reset times consistently&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Zero Python dependencies&lt;/strong&gt; — the entire script uses only stdlib (&lt;code&gt;urllib&lt;/code&gt;, &lt;code&gt;json&lt;/code&gt;, &lt;code&gt;base64&lt;/code&gt;, &lt;code&gt;argparse&lt;/code&gt;). No &lt;code&gt;requests&lt;/code&gt;, no &lt;code&gt;pillow&lt;/code&gt;, no &lt;code&gt;openai&lt;/code&gt; SDK. Just raw &lt;code&gt;urllib.request&lt;/code&gt; like our ancestors intended&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;
  
  
  The Interesting Parts
&lt;/h2&gt;
&lt;h3&gt;
  
  
  Robust JSON Extraction
&lt;/h3&gt;

&lt;p&gt;LLMs are... creative with their output formatting. Sometimes you get clean JSON. Sometimes you get JSON wrapped in markdown code blocks. Sometimes you get a &lt;code&gt;&amp;lt;think&amp;gt;&lt;/code&gt; tag with the model's internal monologue followed by JSON with trailing commas.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;extract_json_from_response&lt;/code&gt; function handles all of this:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Strip thinking tags first
&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;strip_thinking_tags&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# Try code blocks: 
# Try brace matching: find first { and its matching }
# Try cleaning: remove trailing commas
# Last resort: parse the whole thing
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;It's the kind of defensive parsing you write after the third time your pipeline breaks at 2 AM.&lt;/p&gt;
&lt;h3&gt;
  
  
  Fail-Safe Output
&lt;/h3&gt;

&lt;p&gt;The script never crashes on bad data. If the vision model hallucinates, if the JSON is garbage, if the image is blank — you still get a valid response structure with &lt;code&gt;null&lt;/code&gt; values. The exit code tells you something went wrong, but downstream consumers always get parseable JSON.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;empty_quota_response&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;captured_at&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;datetime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;timezone&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;utc&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;isoformat&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;current_session&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;percent_used&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;resets_in&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;""&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;weekly_limits&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;percent_used&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;resets&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;""&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  Zero Temperature
&lt;/h3&gt;

&lt;p&gt;The Ollama API call uses &lt;code&gt;temperature: 0.0&lt;/code&gt; because we want deterministic extraction, not creative writing. When you're reading numbers off a screen, you want the model to be as boring as possible.&lt;/p&gt;
&lt;h2&gt;
  
  
  How to Use It
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Prerequisites:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Windows (for the screenshot script)&lt;/li&gt;
&lt;li&gt;Python 3.10+&lt;/li&gt;
&lt;li&gt;An Ollama endpoint (cloud or local)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;OLLAMA_API_KEY&lt;/code&gt; if you're using a non-local host (like &lt;code&gt;https://ollama.com&lt;/code&gt;)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Steps:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Clone the repo:
&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="n"&gt;git&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;clone&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;https://github.com/aweussom/claude-quota-scraper.git&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;cd&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;claude-quota-scraper&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;ol&gt;
&lt;li&gt;If you're using Ollama Cloud, set your API key:
&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$&lt;/span&gt;&lt;span class="nn"&gt;env&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nv"&gt;OLLAMA_API_KEY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"your-key-here"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Open Claude.ai settings/usage page in your browser&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Start capturing:&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;\capture_claude_usage.ps1&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;ol&gt;
&lt;li&gt;Parse any screenshot (cloud):
&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="n"&gt;python&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;parse_quota.py&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;parse&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;claude_usage_2026-01-16_01-15-51.png&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Local Ollama example (recommended if you're privacy-paranoid. Well. Actually, recommended anyways. Automatically sending screenshots to the internet is bound to create interesting incidents some way down the line):&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="n"&gt;python&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;parse_quota.py&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;parse&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;claude_usage_2026-01-16_01-15-51.png&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;\&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nt"&gt;--host&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;http://localhost:11434&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;\&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nt"&gt;--model&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;qwen3-vl:8b&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;ol&gt;
&lt;li&gt;Run a continuous monitor loop (updates &lt;code&gt;~/.claude/quota-data.json&lt;/code&gt;):
&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="n"&gt;python&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;parse_quota.py&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;monitor&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;--watch-dir&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"C:/path/to/screenshots"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;If you want it to start screenshot capture automatically:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python parse_quota.py monitor &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--start-capture&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--watch-dir&lt;/span&gt; &lt;span class="s2"&gt;"C:/path/to/screenshots"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--capture-interval&lt;/span&gt; 60
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h2&gt;
  
  
  A less stupid option is: skip screenshots entirely (Claude Code + Chrome)
&lt;/h2&gt;

&lt;p&gt;Claude Code can integrate with a Chrome/Edge extension and extract data directly from web pages (using your existing logged-in browser session). In theory, that could open &lt;code&gt;https://claude.ai/settings/usage&lt;/code&gt; and read the quota values with zero screenshots and zero OCR.&lt;/p&gt;

&lt;p&gt;The catch: Chrome integration is not supported in WSL, so you'd run this from Claude Code on Windows. &lt;/p&gt;

&lt;p&gt;Even Claude finds this amusing: &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Figxe062g2hlugwl54lyq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Figxe062g2hlugwl54lyq.png" alt=" "&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  What's Next?
&lt;/h2&gt;

&lt;p&gt;This is a scrappy v1. Some ideas for making it less ridiculous:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Crop the screenshot&lt;/strong&gt; to just the usage area instead of sending the full screen (faster, cheaper, more accurate)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Add a scheduler&lt;/strong&gt; that runs the full pipeline end-to-end and logs to a CSV/SQLite database&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Build a dashboard&lt;/strong&gt; to visualize usage over time&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cross-platform capture&lt;/strong&gt; using Python instead of PowerShell&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Alert thresholds&lt;/strong&gt; — get a notification when you're approaching your limit&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Claude Code + Chrome mode&lt;/strong&gt; — read the numbers from the DOM instead of doing screenshot OCR&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Or, you know, Anthropic could just give us an API endpoint for this. Just putting that out there.&lt;/p&gt;
&lt;h2&gt;
  
  
  The Repo
&lt;/h2&gt;

&lt;p&gt;

&lt;/p&gt;
&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/aweussom" rel="noopener noreferrer"&gt;
        aweussom
      &lt;/a&gt; / &lt;a href="https://github.com/aweussom/claude-quota-scraper" rel="noopener noreferrer"&gt;
        claude-quota-scraper
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Monitor Claude.ai usage quota via screenshots + Ollama vision model extraction
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;SUPERSEDED BY SIMPLER VERSION&lt;/h1&gt;
&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/aweussom/claude-code-quota" rel="noopener noreferrer"&gt;https://github.com/aweussom/claude-code-quota&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This code will stay online, because it documents a very simple way to get full screen screenshots, and use a (free) LLM to decode information from it.&lt;/p&gt;

&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;claude-quota-scraper&lt;/h1&gt;
&lt;/div&gt;

&lt;p&gt;Monitor your Claude.ai usage quota by capturing screenshots and extracting structured data with an Ollama vision model.&lt;/p&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;What It Does&lt;/h2&gt;
&lt;/div&gt;

&lt;p&gt;Claude.ai shows your usage limits on a settings page, but there's no API to query them programmatically. This project works around that:&lt;/p&gt;


&lt;ol&gt;

&lt;li&gt;

&lt;strong&gt;&lt;code&gt;capture_claude_usage.ps1&lt;/code&gt;&lt;/strong&gt; - A PowerShell script that takes a screenshot of your screen every N seconds (default: 60). You navigate to the Claude usage page and let it run.&lt;/li&gt;

&lt;li&gt;

&lt;strong&gt;&lt;code&gt;parse_quota.py&lt;/code&gt;&lt;/strong&gt; - A single Python script with two modes: &lt;code&gt;parse&lt;/code&gt; (one-shot parse for one screenshot) and &lt;code&gt;monitor&lt;/code&gt; (long-running mode that watches screenshots and updates &lt;code&gt;~/.claude/quota-data.json&lt;/code&gt; for Claude Code status line usage).&lt;/li&gt;

&lt;li&gt;

&lt;strong&gt;&lt;code&gt;statusline.ps1&lt;/code&gt;&lt;/strong&gt; - A PowerShell status line script that combines Claude Code's built-in context window percentage with…&lt;/li&gt;

&lt;/ol&gt;
&lt;/div&gt;
&lt;br&gt;
  &lt;/div&gt;
&lt;br&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/aweussom/claude-quota-scraper" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;br&gt;
&lt;/div&gt;





&lt;p&gt;The whole thing is a single stdlib Python script plus two small PowerShell scripts, zero external dependencies, and MIT licensed. Star it if you too have been personally victimized by Claude rate limits.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Built with frustration and a vision model that's probably using more compute to read my quota than I'm using on the quota itself.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>claudecode</category>
      <category>python</category>
      <category>powershell</category>
    </item>
    <item>
      <title>Destructive Reader LLM — When an Author Gets Tired of Reddit's Gatekeeping</title>
      <dc:creator>Tommy Leonhardsen</dc:creator>
      <pubDate>Sat, 14 Feb 2026 19:03:40 +0000</pubDate>
      <link>https://dev.to/tommy_leonhardsen_81d1f4e/destructive-reader-llm-when-an-author-gets-tired-of-reddits-gatekeeping-2k9f</link>
      <guid>https://dev.to/tommy_leonhardsen_81d1f4e/destructive-reader-llm-when-an-author-gets-tired-of-reddits-gatekeeping-2k9f</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.to/challenges/github-2026-01-21"&gt;GitHub Copilot CLI Challenge&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

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

&lt;p&gt;I'm a systems administrator who dabbles in programming — and an author with two published novels. I'm working on my third book, and I needed honest, structured feedback on my chapters.&lt;/p&gt;

&lt;p&gt;I found &lt;a href="https://www.reddit.com/r/DestructiveReaders/" rel="noopener noreferrer"&gt;r/DestructiveReaders&lt;/a&gt;, a Reddit community known for "brutal but loving" literary critique. The concept is exactly what I wanted: direct, specific feedback that doesn't sugarcoat problems but always offers solutions. The reality was different. The community requires extensive karma-building before you can receive a critique — other authors report spending days earning enough credit. And after all that effort, the critiques I read varied wildly in quality.&lt;/p&gt;

&lt;p&gt;So I built my own.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Destructive Reader LLM&lt;/strong&gt; is a Python CLI tool that takes a fiction chapter and delivers structured literary critique in the r/DestructiveReaders style. It uses NVidia Nemotron Nano 30B via &lt;a href="https://ollama.com/" rel="noopener noreferrer"&gt;Ollama&lt;/a&gt; — a free cloud model — guided by a carefully crafted system prompt that captures the community's ethos: be brutal, be loving, be specific, always offer a fix.&lt;/p&gt;

&lt;p&gt;The critique follows a consistent structure:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Opening Hook&lt;/strong&gt; — one thing that works, the biggest problem, overall take&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The Big Issues&lt;/strong&gt; (2-3 max) — quoted from your text, explained, with concrete fixes&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reader Journey&lt;/strong&gt; — where the critic was hooked, lost, confused, or kept reading&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Quick Fixes&lt;/strong&gt; — ranked actionable changes with before/after examples&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;What's Working&lt;/strong&gt; — genuine positives with quoted evidence&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This isn't a toy project. I use it on my actual manuscript chapters. The critique below was generated from a chapter of my published novel in 15 seconds.&lt;/p&gt;

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

&lt;p&gt;&lt;strong&gt;GitHub Repository:&lt;/strong&gt; &lt;a href="https://github.com/aweussom/DestructiveReader-LLM" rel="noopener noreferrer"&gt;github.com/aweussom/DestructiveReader-LLM&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Running the tool against a chapter from my published novel:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;python destructive-reader-llm.py Markdown/01-AWAKENING.md
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;p&gt;The generated critique is saved as Markdown alongside the chapter file, ready to reference during revision.&lt;/p&gt;

&lt;h2&gt;
  
  
  My Experience with GitHub Copilot CLI
&lt;/h2&gt;

&lt;p&gt;I used GitHub Copilot CLI (v0.0.410, running on the free Claude Haiku 4.5 model) as my development partner for the entire build. The whole tool went from idea to working software in a single session.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 1: Describe the project and test connectivity
&lt;/h3&gt;

&lt;p&gt;I opened Copilot CLI and described what I needed — a test script to verify I could connect to Ollama cloud and the Nemotron model. Copilot CLI generated a working &lt;code&gt;test_ollama.py&lt;/code&gt; on the first attempt. It worked after I corrected the model name from &lt;code&gt;nemotron-3-nano:latest&lt;/code&gt; to &lt;code&gt;nemotron-3-nano:30b-cloud&lt;/code&gt;.&lt;/p&gt;

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

&lt;h3&gt;
  
  
  Step 2: Build the main tool
&lt;/h3&gt;

&lt;p&gt;I gave Copilot CLI a clear spec: read &lt;code&gt;INSTRUCTIONS.md&lt;/code&gt;, accept a chapter filename as argument, build a combined prompt, send to Ollama, save the critique as &lt;code&gt;&amp;lt;chapter-name&amp;gt;-critique-&amp;lt;timestamp&amp;gt;.md&lt;/code&gt;. Copilot CLI read my instructions file to understand the context, then generated the complete &lt;code&gt;destructive-reader-llm.py&lt;/code&gt; — 145 lines covering argument parsing, file loading, prompt construction, API calls, and output saving. It worked on first run.&lt;/p&gt;

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

&lt;h3&gt;
  
  
  Step 3: Refine the output
&lt;/h3&gt;

&lt;p&gt;The critique was truncated on console but saved correctly to disk. I asked Copilot CLI to print the full response, add timing, and display the output filename. Two targeted edits, done.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 4: Evaluate the results
&lt;/h3&gt;

&lt;p&gt;Here's where it got interesting. I asked Copilot CLI to read the original chapter, the instructions, and the generated critique — then tell me whether the Nemotron critique was any good and how it would compare to Claude Sonnet 4.5. Copilot CLI gave a thoughtful assessment: Nemotron nails the brutal-but-constructive voice but misses some thematic subtlety that a larger model would catch. Its recommendation — stick with Nemotron for the punchy r/DestructiveReaders style, consider a second model for deeper thematic analysis.&lt;/p&gt;

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

&lt;h3&gt;
  
  
  Overall impression
&lt;/h3&gt;

&lt;p&gt;The free tier Haiku 4.5 model in Copilot CLI was more than capable for this kind of structured code generation. Copilot handled the boilerplate and let me focus on what actually matters — the critique prompt and the workflow design. From first prompt to working tool: one session, no debugging required beyond correcting a model name.&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>githubchallenge</category>
      <category>cli</category>
      <category>githubcopilot</category>
    </item>
  </channel>
</rss>
