<?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: Ekong Ikpe</title>
    <description>The latest articles on DEV Community by Ekong Ikpe (@edmundsparrow).</description>
    <link>https://dev.to/edmundsparrow</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3576994%2F5cc16c73-7e27-48bf-a2e1-9dab93f3cf7a.png</url>
      <title>DEV Community: Ekong Ikpe</title>
      <link>https://dev.to/edmundsparrow</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/edmundsparrow"/>
    <language>en</language>
    <item>
      <title>Every Generation Thinks the Next One Has It Easy 💃💃 💃</title>
      <dc:creator>Ekong Ikpe</dc:creator>
      <pubDate>Sat, 01 Aug 2026 19:31:03 +0000</pubDate>
      <link>https://dev.to/edmundsparrow/every-generation-thinks-the-next-one-has-it-easy-42ke</link>
      <guid>https://dev.to/edmundsparrow/every-generation-thinks-the-next-one-has-it-easy-42ke</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fz9tkw5wtrvc43zyrzl2s.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fz9tkw5wtrvc43zyrzl2s.png" alt="vibes2" width="480" height="262"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Is It Wrong to Watch Movies, Cartoons, or Sci-Fi? 🤔
&lt;/h2&gt;

&lt;p&gt;Of course not.&lt;/p&gt;

&lt;p&gt;We enjoy movies even though they're fictional. We appreciate cartoons&lt;br&gt;
even though the characters aren't real. We watch science fiction knowing&lt;br&gt;
today's imagination often becomes tomorrow's technology.&lt;/p&gt;

&lt;p&gt;That made me think about another question:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why is AI-assisted development treated so differently?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I'm fond of reading to keep abreast of what's happening in software and&lt;br&gt;
technology.&lt;/p&gt;

&lt;p&gt;Lately, I came across a discussion that made me realize I needed to&lt;br&gt;
write a sequel to a post I published back in April, &lt;strong&gt;&lt;a href="https://dev.to/edmundsparrow/defending-vibe-coding-why-syntax-might-not-be-the-bottleneck-anymore-53lp"&gt;Defending Vibe&lt;br&gt;
Coding: Why Syntax Might Not Be the Bottleneck&lt;br&gt;
Anymore&lt;/a&gt;&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;In that article, I argued that AI is shifting the bottleneck away from&lt;br&gt;
syntax and toward system design, validation, and execution clarity.&lt;/p&gt;

&lt;p&gt;This time, I'd like to look at &lt;em&gt;why&lt;/em&gt; that idea still meets so much&lt;br&gt;
resistance.&lt;/p&gt;

&lt;p&gt;That discussion also helped me understand some of the reactions I&lt;br&gt;
receive whenever I post or share my projects.&lt;/p&gt;

&lt;p&gt;Nevertheless, I'm still on my vibes. 🙃&lt;/p&gt;

&lt;p&gt;So, let's talk about it.&lt;/p&gt;

&lt;p&gt;Every generation of engineers believes the next generation's tools make&lt;br&gt;
the craft too easy.&lt;/p&gt;

&lt;p&gt;When automatic transmissions became common, no one insisted every driver&lt;br&gt;
master a manual gearbox first.&lt;/p&gt;

&lt;p&gt;When voice-to-text arrived, we didn't demand that everyone become an&lt;br&gt;
expert speller before speaking into their phones.&lt;/p&gt;

&lt;p&gt;Most programmers today have never written a compiler, an operating&lt;br&gt;
system, or a network stack from scratch. Yet we don't question whether&lt;br&gt;
they're programmers.&lt;/p&gt;

&lt;p&gt;So why is AI-assisted development treated differently?&lt;/p&gt;

&lt;p&gt;The point isn't that fundamentals are worthless. Far from it. The point&lt;br&gt;
is that the definition of a "fundamental" evolves as technology evolves.&lt;/p&gt;

&lt;p&gt;Programming has never been about typing the greatest number of&lt;br&gt;
characters. It has always been about solving problems.&lt;/p&gt;

&lt;p&gt;Today, programming is shifting from writing every instruction manually&lt;br&gt;
to designing systems, evaluating solutions, testing assumptions, and&lt;br&gt;
taking responsibility for the final product.&lt;/p&gt;

&lt;p&gt;The keyboard is becoming less important than judgment.&lt;/p&gt;

&lt;p&gt;AI doesn't remove accountability. If an AI introduces a bug, the&lt;br&gt;
responsibility is still mine. If I can't explain my architecture, defend&lt;br&gt;
my decisions, or verify my software, then I haven't done my job as an&lt;br&gt;
engineer.&lt;/p&gt;

&lt;p&gt;But if I understand the system, direct its design, validate its&lt;br&gt;
behavior, and stand behind every release, then whether some of the&lt;br&gt;
implementation came from AI becomes a secondary question.&lt;/p&gt;

&lt;p&gt;Every technological shift has been uncomfortable. The challenge isn't to&lt;br&gt;
reject new tools or forget the old lessons. It's to carry forward the&lt;br&gt;
discipline, curiosity, and responsibility that define good engineering&lt;br&gt;
while embracing new capabilities.&lt;/p&gt;

&lt;p&gt;The future won't belong to developers who refuse AI, nor to those who&lt;br&gt;
blindly trust it.&lt;/p&gt;

&lt;p&gt;It will belong to those who know how to think.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>discuss</category>
      <category>vibecoding</category>
    </item>
    <item>
      <title>Who Owns the Thinking When You Vibe Code? 🧐</title>
      <dc:creator>Ekong Ikpe</dc:creator>
      <pubDate>Thu, 30 Jul 2026 11:45:47 +0000</pubDate>
      <link>https://dev.to/edmundsparrow/who-owns-the-thinking-when-you-vibe-code-3l4p</link>
      <guid>https://dev.to/edmundsparrow/who-owns-the-thinking-when-you-vibe-code-3l4p</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fejwszaqc16d8o9mzyk4u.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fejwszaqc16d8o9mzyk4u.png" alt="vibes" width="320" height="481"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I’ve been thinking about the phrase “vibe coding.”&lt;/p&gt;

&lt;p&gt;Andrej Karpathy used it to describe a way of working where you mostly let the AI write the code and you stop worrying too much about the details.&lt;/p&gt;

&lt;p&gt;That’s a real way of working.&lt;/p&gt;

&lt;p&gt;But I think we’ve started using the same phrase for two very different habits.&lt;/p&gt;

&lt;h2&gt;
  
  
  Two Different Ways of “Vibe Coding”
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Type&lt;/th&gt;
&lt;th&gt;What actually happens&lt;/th&gt;
&lt;th&gt;Who’s doing the thinking?&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Passive&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;AI writes it. You mostly just accept it.&lt;/td&gt;
&lt;td&gt;Mostly the AI.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Active&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;You explore ideas with the AI, push back, change direction, and shape the final result.&lt;/td&gt;
&lt;td&gt;You — with the AI as a partner.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The first one is what most people complain about.&lt;/p&gt;

&lt;p&gt;The second one is something good builders have been doing long before AI showed up.&lt;/p&gt;

&lt;p&gt;When an experienced person says, “This doesn’t feel right,” nobody calls it magic. We call it judgment.&lt;/p&gt;

&lt;p&gt;That judgment isn’t random.&lt;/p&gt;

&lt;p&gt;It comes from years of building things, breaking them, fixing them, and coming back to them later. Your brain starts noticing patterns before you can even explain them in words.&lt;/p&gt;

&lt;p&gt;That’s why some ideas suddenly feel obvious.&lt;/p&gt;

&lt;p&gt;They weren’t sudden. They were quietly forming for a long time.&lt;/p&gt;

&lt;p&gt;AI just changes what happens next.&lt;/p&gt;

&lt;p&gt;Sometimes the first idea is yours.&lt;br&gt;&lt;br&gt;
Sometimes the AI asks a question that shows a weak spot in your thinking.&lt;br&gt;&lt;br&gt;
Sometimes it offers a direction you hadn’t seen.&lt;br&gt;&lt;br&gt;
Sometimes it’s confidently wrong.&lt;/p&gt;

&lt;p&gt;And this is where I think we also need to appreciate something else: our strengths are diverse, and recognizing those differences matters.&lt;/p&gt;

&lt;p&gt;When I interact with an AI assistant, my engagement is often more like having a research assistant or an improved “2010 Google search” 🙃. The difference is that today’s assistants can interact with us in ways that can create an illusion of literacy and understanding.&lt;/p&gt;

&lt;p&gt;That doesn't mean we should treat every assistant as the same tool.&lt;/p&gt;

&lt;p&gt;A junior developer quickly learns that the choice of tool matters. The same way a sledgehammer is better suited to breaking concrete than a nail hammer, different AI assistants may simply be better suited to different tasks.&lt;/p&gt;

&lt;p&gt;Gemini may be better at one thing than ChatGPT. Alexa may be better at another than Grok. And none of that should be surprising. Different tools, different strengths, different purposes.&lt;/p&gt;

&lt;p&gt;The more properly we learn how to use these tools, the healthier our development process can become — with or without AI.&lt;/p&gt;

&lt;p&gt;And there is another part of this that I think we sometimes overlook: people are part of the toolchain too.&lt;/p&gt;

&lt;p&gt;Seniors eventually move on, wear out, change roles, or retire. Juniors eventually have to take over. That means appreciating the process matters. What we learn today shouldn't only help us finish today's task; it should help someone else understand, maintain, and improve what comes next.&lt;/p&gt;

&lt;p&gt;No matter how careful we are, humans are explorers by nature. We will always discover something new, question something old, and find another direction to try. Nothing stays perfect enough to satisfy that curiosity forever.&lt;/p&gt;

&lt;p&gt;But one thing is worth carrying forward: the willingness to relearn.&lt;/p&gt;

&lt;p&gt;We can adopt better tools without throwing away the values that shaped us. We can let AI change how we work without forgetting why we learned to build, debug, question, and understand things in the first place.&lt;/p&gt;

&lt;p&gt;Who spoke first doesn’t matter much.&lt;/p&gt;

&lt;p&gt;What matters is who made the final call.&lt;/p&gt;

&lt;p&gt;Understanding something is a bit like walking without a map. You may not know every step ahead, but you know where you’re trying to go well enough to notice when you’ve started drifting off course.&lt;/p&gt;

&lt;p&gt;Ideas don’t always belong to one mind anymore.&lt;/p&gt;

&lt;p&gt;Sometimes the spark comes from you.&lt;br&gt;&lt;br&gt;
The next step comes from the AI.&lt;br&gt;&lt;br&gt;
The final result grows out of the conversation between both.&lt;/p&gt;

&lt;p&gt;That isn’t passive vibe coding.&lt;/p&gt;

&lt;p&gt;That’s still engineering.&lt;/p&gt;

&lt;p&gt;The real danger isn’t AI.&lt;/p&gt;

&lt;p&gt;The danger is reaching the point where you stop asking “why” and only ask “what’s next.”&lt;/p&gt;

&lt;p&gt;There’s a big difference between using AI so you don’t have to think… and using AI so you can think better.&lt;/p&gt;

&lt;p&gt;The first one takes over your judgment.&lt;br&gt;&lt;br&gt;
The second one strengthens it.&lt;/p&gt;

&lt;p&gt;So maybe we’ve been arguing about the wrong phrase all along.&lt;/p&gt;

&lt;p&gt;The real question isn’t whether something was “vibe coded.”&lt;/p&gt;

&lt;p&gt;The question is:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Who owned the thinking?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;And when the AI is gone, who still understands what was built?&lt;/p&gt;

</description>
      <category>ai</category>
      <category>programming</category>
      <category>discuss</category>
      <category>productivity</category>
    </item>
    <item>
      <title>PWAs Cache Resources. Spirit Installs an Application.</title>
      <dc:creator>Ekong Ikpe</dc:creator>
      <pubDate>Sun, 26 Jul 2026 10:09:54 +0000</pubDate>
      <link>https://dev.to/edmundsparrow/pwas-cache-resources-spirit-installs-an-application-4hmf</link>
      <guid>https://dev.to/edmundsparrow/pwas-cache-resources-spirit-installs-an-application-4hmf</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ff28ckzbu0to4otmq3f2d.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ff28ckzbu0to4otmq3f2d.png" alt="PWA reimagined" width="799" height="436"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Before we go into this post I earlier planned for a different topic however in the course of my vibe experience something else came up.&lt;/p&gt;

&lt;p&gt;There is a question nobody asks when they set up a service worker:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Who owns the application lifecycle?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;With a conventional PWA, the browser primarily orchestrates installation, caching, and the service worker lifecycle. The application participates in those decisions, but the browser ultimately controls when service workers are activated, how storage is managed, and what "installed" means on a given platform.&lt;/p&gt;

&lt;p&gt;Spirit gives a different answer. The application owns installation, storage, and updates. The browser simply provides the runtime.&lt;/p&gt;

&lt;p&gt;That is not a small distinction. It starts with one reframe:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;spirit-sw.js&lt;/code&gt; is firmware, not middleware.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Every conventional PWA uses the service worker as a proxy — it intercepts requests and decides whether to serve from cache or go to the network. Spirit uses the service worker differently. It never serves your application files. It never touches Cache Storage. It serves a single hardcoded bootstrap string that knows how to resurrect the application from IndexedDB. The service worker is a bootloader. It boots the same way every time.&lt;/p&gt;

&lt;p&gt;Everything else follows from that.&lt;/p&gt;




&lt;h2&gt;
  
  
  What Spirit is
&lt;/h2&gt;

&lt;p&gt;Spirit is an IDB-native installation and boot system. Four moving parts:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;spirit-grave.js&lt;/strong&gt; — the storage layer. Pure IndexedDB, no DOM, no network. Buries a file as a Blob, exhumes it later. Nothing else.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;spirit-reg.js&lt;/strong&gt; — the installer. Runs once, on the first real online visit. Reads &lt;code&gt;spirit-manifest.json&lt;/code&gt;, fetches every listed file, buries each one in IndexedDB under &lt;code&gt;gnoke:spirit/files&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;spirit-sw.js&lt;/strong&gt; — the bootloader. Intercepts every navigation request and responds immediately with a hardcoded HTML string baked into the worker itself. That string contains an inline IDB reader — no separate fetch. It reconstructs the application from the grave: CSS injected as &lt;code&gt;&amp;lt;style&amp;gt;&lt;/code&gt;, images converted to blob URLs, JS executed as classic scripts in manifest order. Zero network requests on boot.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;spirit-revive.js&lt;/strong&gt; — the updater. Exposes &lt;code&gt;Spirit.reviveFromNetwork()&lt;/code&gt;. Call it from a button inside the running application. It re-fetches the manifest, re-buries changed files, and reloads only if something actually changed. Nothing runs in the background automatically.&lt;/p&gt;




&lt;h2&gt;
  
  
  The lifecycle comparison
&lt;/h2&gt;

&lt;p&gt;With a conventional PWA:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Browser requests URL
→ SW intercepts, checks cache
→ serves cached or fetches fresh
→ background SW update check runs independently
→ new SW waits for all tabs to close (or skipWaiting forces it)
→ user may receive updated code mid-session without requesting it
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With Spirit:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Browser requests URL
→ SW responds immediately with hardcoded bootstrap
→ bootstrap opens IndexedDB, reconstructs app from buried files
→ app runs — no network involved
→ update only happens when Spirit.reviveFromNetwork() is called
→ app controls when to prompt, when to reload
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The update is part of the application's lifecycle, not the browser's.&lt;/p&gt;




&lt;h2&gt;
  
  
  What this makes possible
&lt;/h2&gt;

&lt;p&gt;Given a valid installation, startup is deterministic. The same boot sequence runs every time — online or offline, first launch or hundredth. There is no cache miss, no conditional fetch, no race between a new service worker and open tabs.&lt;/p&gt;

&lt;p&gt;Spirit is designed so updates replace the installed application as a single managed operation, avoiding the mixed-version states that can occur when independently cached assets drift. One call, one operation, one reload decision.&lt;/p&gt;

&lt;p&gt;The bootloader is stable. &lt;code&gt;spirit-sw.js&lt;/code&gt; is the only file that triggers the browser's own SW update cycle — and it is designed to change rarely, like actual firmware. The application underneath it can update as often as it needs to without touching the bootloader.&lt;/p&gt;




&lt;h2&gt;
  
  
  Where this matters and where it does not
&lt;/h2&gt;

&lt;p&gt;Spirit is not a general improvement over Cache Storage. For a news site, a marketing page, a content application — the browser's built-in model is exactly right. HTTP caching, ETags, Cache Storage, and the SW update cycle were designed for that world and they work well in it.&lt;/p&gt;

&lt;p&gt;Spirit makes sense for a different category: software that happens to be delivered via the web.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Offline-first tools where network access is intermittent or absent&lt;/li&gt;
&lt;li&gt;Browser OS environments where the app manages its own disk&lt;/li&gt;
&lt;li&gt;Industrial or embedded browser runtimes where update timing must be controlled&lt;/li&gt;
&lt;li&gt;Editors and development tools that need to own their own boot sequence&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Spirit was built for GnokeStation — a browser-native OS where IndexedDB is the disk, a SharedWorker is the kernel, and tabs are processes. In that context, the conventional PWA model has a fundamental mismatch. Spirit fits the architecture instead of fighting it.&lt;/p&gt;




&lt;h2&gt;
  
  
  The honest trade-offs
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;What you give up:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Browser DevTools understand Cache Storage natively. An IDB-backed virtual filesystem is more opaque to debug.&lt;/li&gt;
&lt;li&gt;HTTP-level caching is bypassed entirely. Spirit's current change detection compares blob sizes — a content hash would be more robust and is worth adding.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;reviveFromNetwork()&lt;/code&gt; buries files sequentially. A tab closed mid-update leaves a partially updated grave. A staged swap — write new files first, then commit — would make updates truly atomic.&lt;/li&gt;
&lt;li&gt;The first visit still requires a real online session. Unavoidable.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;navigator.storage.persist()&lt;/code&gt; lowers eviction risk but does not eliminate it.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;What you gain:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The web delivers the application once. After that it runs from local storage entirely.&lt;/li&gt;
&lt;li&gt;No dependency on Cache Storage eviction policies.&lt;/li&gt;
&lt;li&gt;The application decides when it updates and what the user sees when it does.&lt;/li&gt;
&lt;li&gt;The bootloader is stable across application versions.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  The deeper idea
&lt;/h2&gt;

&lt;p&gt;Spirit doesn't try to replace the PWA model. It explores a different one: treating the browser as a runtime capable of hosting installed software, rather than a document viewer that happens to cache files.&lt;/p&gt;

&lt;p&gt;The web is used once to install the application. From then on, the browser hosts a locally managed runtime whose lifecycle is controlled by the application — not by HTTP caching semantics, not by the SW activation queue, not by storage eviction policy.&lt;/p&gt;

&lt;p&gt;Whether that trade-off is right depends entirely on the kind of application you are building.&lt;/p&gt;

&lt;p&gt;Spirit is built for the second kind.&lt;/p&gt;

&lt;p&gt;And for the records my semantics for file names are my way of expressing myself, what matters to me is that the aim is achieved not the name of the file 🤓&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Spirit is part of GnokeStation v2 — a browser-native OS built on SharedWorker as kernel, IndexedDB as disk, and tabs as processes. Built by edmundsparrow.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>architecture</category>
      <category>javascript</category>
      <category>softwaredevelopment</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Stop Believing "Convert PDF to Original Format" Is Magic</title>
      <dc:creator>Ekong Ikpe</dc:creator>
      <pubDate>Wed, 22 Jul 2026 18:56:38 +0000</pubDate>
      <link>https://dev.to/edmundsparrow/stop-believing-convert-pdf-to-original-format-is-magic-51n5</link>
      <guid>https://dev.to/edmundsparrow/stop-believing-convert-pdf-to-original-format-is-magic-51n5</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F3aib8poo09izetwfx9ta.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F3aib8poo09izetwfx9ta.png" alt="pdfs" width="800" height="533"&gt;&lt;/a&gt;&lt;br&gt;
💡 A recent article by &lt;a href="https://dev.to/dannwaneri/substacks-new-ai-detector-has-the-same-blind-spot-devtos-did-103j"&gt;@dannwaneri&lt;/a&gt; on AI detection motivated this thought.&lt;/p&gt;

&lt;p&gt;People often assume that if you have the final product, you can always reconstruct how it was made.&lt;/p&gt;

&lt;p&gt;You can't.&lt;/p&gt;

&lt;p&gt;Take PDF as an example.&lt;/p&gt;

&lt;p&gt;We've all seen advertisements promising:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;"Convert any PDF back to Word."&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That sounds impressive until you ask one simple question.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How do you know the PDF originally came from Microsoft Word?&lt;/strong&gt; 🤔&lt;/p&gt;

&lt;p&gt;What if it came from Photoshop?&lt;/p&gt;

&lt;p&gt;What if it came from Illustrator?&lt;/p&gt;

&lt;p&gt;What if it was generated by CAD software?&lt;/p&gt;

&lt;p&gt;What if it was exported from LaTeX?&lt;/p&gt;

&lt;p&gt;Or better still...&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What if it was a handwritten note with hand-drawn diagrams that someone scanned into a PDF?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Now ask yourself:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How is any converter supposed to regenerate the original handwritten notebook?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;It can't.&lt;/p&gt;

&lt;p&gt;Not because the software is bad.&lt;/p&gt;

&lt;p&gt;Because the software does &lt;strong&gt;not explicitly know the format or medium in which the document was originally created.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Without knowing whether the source was Word, Photoshop, a scanner, a notebook, or something else entirely, claiming to recreate the &lt;em&gt;original&lt;/em&gt; is creating a false reality.&lt;/p&gt;

&lt;p&gt;The converter can only produce the &lt;strong&gt;best approximation&lt;/strong&gt; in a format it understands.&lt;/p&gt;

&lt;p&gt;That's why "convert PDF to its original format" is usually marketing—not magic.&lt;/p&gt;

&lt;p&gt;A PDF is a destination format.&lt;/p&gt;

&lt;p&gt;Many completely different tools—and even pen and paper—can produce one.&lt;/p&gt;

&lt;p&gt;This is why that discussion on AI detectors resonated with me.&lt;/p&gt;

&lt;p&gt;AI detectors examine the final text and attempt to infer the process that created it.&lt;/p&gt;

&lt;p&gt;Likewise, people expect PDF converters to examine the final document and somehow infer the software—or even the physical medium—that produced it.&lt;/p&gt;

&lt;p&gt;In both cases, we expect certainty from an artifact that does not necessarily reveal its own history. 📄&lt;/p&gt;

&lt;p&gt;Computers are excellent at transforming data.&lt;/p&gt;

&lt;p&gt;They are not magical historians.&lt;/p&gt;

&lt;p&gt;Sometimes the most honest answer isn't:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"This is the original."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It's:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"This is the closest reconstruction possible with the information available."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;👍 &lt;strong&gt;Never confuse an artifact with the process that created it.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The output tells part of the story.&lt;/p&gt;

&lt;p&gt;It rarely tells the whole story.&lt;/p&gt;

&lt;p&gt;And perhaps that's the bigger lesson—not just for PDF converters or AI detectors, but for technology as a whole.&lt;/p&gt;

&lt;p&gt;We spend so much time expecting tools to perform magic that we sometimes forget to understand what they were actually designed to do.&lt;/p&gt;

&lt;p&gt;Every tool has capabilities.&lt;/p&gt;

&lt;p&gt;Every tool has limits.&lt;/p&gt;

&lt;p&gt;Knowing the difference is part of becoming a better engineer.&lt;/p&gt;

&lt;p&gt;🔥 In my next piece, I'll share why learning &lt;strong&gt;how&lt;/strong&gt; to use a tool is often more valuable than simply knowing &lt;strong&gt;that&lt;/strong&gt; the tool exists.&lt;/p&gt;

</description>
      <category>tutorial</category>
      <category>discuss</category>
      <category>productivity</category>
      <category>programming</category>
    </item>
    <item>
      <title>Browser OS Redefined: The Desktop Metaphor Doesn't Quite Fit a 5" Screen Browser</title>
      <dc:creator>Ekong Ikpe</dc:creator>
      <pubDate>Sun, 19 Jul 2026 13:34:01 +0000</pubDate>
      <link>https://dev.to/edmundsparrow/browser-os-redefined-the-desktop-metaphor-doesnt-quite-fit-a-5-screen-browser-4hg1</link>
      <guid>https://dev.to/edmundsparrow/browser-os-redefined-the-desktop-metaphor-doesnt-quite-fit-a-5-screen-browser-4hg1</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F9r4zp8r2sgk2ae1n417o.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F9r4zp8r2sgk2ae1n417o.png" alt="A new modus operandi" width="800" height="533"&gt;&lt;/a&gt;&lt;br&gt;
GnokeStation is a browser OS: it boots its own environment inside the browser, the same way a traditional OS boots hardware. Tabs are processes. IndexedDB is disk. A SharedWorker is the kernel coordinating all of it. It doesn't need to touch your device's hardware to earn the name — the browser is the platform, and GS2 runs it like one.&lt;/p&gt;

&lt;p&gt;I had to stop pretending a phone is just a tiny PC and give these apps their own world.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Gnokestation (GS1)*
&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Faycmvbgq7qryupvz7ivq.jpg" alt="GSv1" width="720" height="1640"&gt;
&lt;/li&gt;
&lt;li&gt;Since I'm always on my phone instead of a PC, treating my tabs as full-blown apps just makes perfect sense for my workflow.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The honest answer for why I moved from GnokeStation to GnokeStation 2 isn't "GS1 was broken." It's that I was trying to run a desktop-shaped UI on a 5" screen, and no amount of polish fixes that mismatch.&lt;/p&gt;

&lt;h2&gt;
  
  
  GS1 worked. That was never the problem.
&lt;/h2&gt;

&lt;p&gt;GnokeStation did what it set out to do — a browser-native OS, SharedWorker kernel, apps as windows on a shared desktop canvas. It ran. It held state. It felt like an OS.&lt;/p&gt;

&lt;p&gt;But try running Windows 10 or 11 on a 5" screen — even if every pixel renders correctly, it's not usable. That's what GS1 felt like on my phone. The desktop metaphor — shared canvas, floating windows, window chrome — assumes screen real estate I didn't have. The code wasn't the issue. The paradigm was.&lt;/p&gt;

&lt;h2&gt;
  
  
  GS2: The realization - tabs don't need a desktop under them
&lt;/h2&gt;

&lt;p&gt;The fix wasn't a redesign. It was dropping an assumption.&lt;/p&gt;

&lt;p&gt;If each tab is its own process — not a window &lt;em&gt;on&lt;/em&gt; a desktop, but a full-screen app that owns its own canvas — there's no shared desktop to shrink. Screen size stops being a single constraint you're fighting across every app, and becomes a per-app concern each tab handles on its own.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Gnoke-station2 (GS2)*
&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F8ue0udpchq4fntnq8bjd.jpg" alt="GS2" width="720" height="1640"&gt;
That's GS2: tabs as processes. Each one gets the whole screen when it's active. No window management overhead, no chrome eating into 5 inches of usable space, no cramming.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Every app in GS2 is built independently, styled on its own terms. But there's a deliberate pecking order to how styles load — the shell always gets the last word. No matter what an individual app tries to do visually, it can't accidentally break the look of the bar, the icons, or the chrome around it. Independence for each app, but the whole still holds together.&lt;/p&gt;

&lt;h2&gt;
  
  
  Rehydration: the part that makes it not feel like "just tabs"
&lt;/h2&gt;

&lt;p&gt;Multi-tab browsing on mobile has a known problem: the OS kills backgrounded tabs for memory constantly. Normally that means losing your place — reload, re-navigate, re-enter data.&lt;/p&gt;

&lt;p&gt;GS2's &lt;code&gt;gnoke-spirit&lt;/code&gt; layer persists tab state to IndexedDB continuously, so when the browser reclaims a tab's memory and you reopen it, it rehydrates — not a fresh load, a resume. That's the difference between "a tab that died" and "an app that was suspended," and it's what makes 50 tabs in GS2 feel closer to 10 native app instances than 10 browser tabs.&lt;/p&gt;

&lt;p&gt;I don't need the cloud to keep my world running. My phone holds the truth, and the network is just an option.&lt;/p&gt;

&lt;h2&gt;
  
  
  So why would anyone leave a Play Store app for this?
&lt;/h2&gt;

&lt;p&gt;Fair question, and I don't think the honest answer is "GS2 is better at everything." It isn't. If you need something to just be great at one thing, a native app that's built and tuned for exactly that thing will usually win.&lt;/p&gt;

&lt;p&gt;Where GS2 makes a different tradeoff:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;No one installs Adobe Premiere Pro on a machine with 512MB of RAM&lt;/strong&gt; — and nobody should have to install ten separate native apps just to get ten small utilities on a low-end device either. GS2's apps are small, share one runtime, and don't each carry their own bundled webview/engine overhead.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;20 tabs in GS2 vs. 10 tabs in Chrome on the same low-end phone&lt;/strong&gt; — GS2 reuses one browser webview across every app instead of each one spinning up its own runtime. Roughly double the tabs for the same memory footprint, because the overhead isn't being duplicated per app.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Offline-first by default.&lt;/strong&gt; Not "works offline if you toggle a setting" — the storage layer (GnokeStore, unified over IndexedDB) is the source of truth, network is optional.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No ads, no accounts, no server dependency.&lt;/strong&gt; It's not a business model that needs your attention or your data. It just runs.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A URL is already an app.&lt;/strong&gt; No store listing, no install screen, no permissions dialog, no waiting on a review queue for updates. Tap "Add to Home Screen" and you're done — the next time you open it, whatever changed is already there. Installing a native app is a process. Installing GS2 is a tap.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That's not a pitch that GS2 replaces your Play Store apps generally. It's a pitch that if you're on a low-end device juggling a dozen small tools, running them as lightweight tabs sharing one kernel is a genuinely better use of your hardware than a dozen separate native installs each paying their own memory tax.&lt;/p&gt;

&lt;h2&gt;
  
  
  The takeaway
&lt;/h2&gt;

&lt;p&gt;GS1 proved the architecture works. GS2 made more sense knowing the architecture only fits once I stopped assuming a desktop has to sit underneath it. Same kernel philosophy, different canvas model — and on a phone, it finally feels like the architecture matches the device.&lt;/p&gt;

&lt;p&gt;It's not finished. But it already does the one thing it needed to prove: a browser OS can be a realistic idea on the smallest screen you own.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://gnokestation.netlify.app" rel="noopener noreferrer"&gt;GSv1&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://gnoke-station2.netlify.app" rel="noopener noreferrer"&gt;GS2&lt;/a&gt;&lt;/p&gt;

</description>
      <category>showdev</category>
      <category>webdev</category>
      <category>programming</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Disconnected: A 24-Hour Stress Test for Humanity 🥸</title>
      <dc:creator>Ekong Ikpe</dc:creator>
      <pubDate>Tue, 14 Jul 2026 15:27:11 +0000</pubDate>
      <link>https://dev.to/edmundsparrow/disconnected-a-24-hour-stress-test-for-humanity-mg2</link>
      <guid>https://dev.to/edmundsparrow/disconnected-a-24-hour-stress-test-for-humanity-mg2</guid>
      <description>&lt;h2&gt;
  
  
  &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F9xu2yplabfeguco6k8oy.png" alt="soliloquizing" width="800" height="533"&gt;
&lt;/h2&gt;

&lt;h2&gt;
  
  
  This isn't a wish for the internet to stop — just a moment to imagine what it'd mean to breathe without it.
&lt;/h2&gt;

&lt;p&gt;Not everyone, but a huge percentage of the world now relies heavily on the internet.&lt;/p&gt;

&lt;p&gt;What if it were unavoidably shut down for just 24 hours? How long would those hours actually feel — and how much would they reshape our daily routines?&lt;/p&gt;

&lt;p&gt;I see the irony everywhere already. The moment a page hangs, I instinctively dial a USSD code to check my data balance. I know someone who pings &lt;code&gt;google.com&lt;/code&gt; just to see if he's still connected — using the internet to check whether the internet is still there.&lt;/p&gt;

&lt;p&gt;The first hour would probably be spent staring at the network icon, refreshing pages, waiting for life to resume. That's when we'd notice how much of the day quietly depends on the cloud: deliveries stall, payments freeze, navigation disappears, businesses pause. Millions would discover just how many invisible gears keep everyday life moving.&lt;/p&gt;

&lt;p&gt;Then the smaller shifts. Looking at the sky to guess the weather instead of opening an app. Realizing the only people who "exist" are the ones actually in front of you. Sitting in a room where the loudest sound is the silence of the feed.&lt;/p&gt;

&lt;p&gt;Maybe one day, staying offline will be a skill of its own.&lt;/p&gt;

&lt;p&gt;Have we gotten so used to consulting the network before taking a step that we've stopped trusting our own judgment?&lt;/p&gt;

&lt;p&gt;Perhaps 24 hours of silence wouldn't just be an outage. It would be a reminder — that before the cloud, there was memory. Before search engines, there was curiosity. Before notifications, there was presence. And before constant connection, we still knew how to walk on our own.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;If you asked me, What cloud or internet service would you miss most for a day?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;For me, I don't remember the last time I went 48 hours without Gemini. &lt;/p&gt;

</description>
      <category>discuss</category>
      <category>webdev</category>
      <category>reviews</category>
      <category>learning</category>
    </item>
    <item>
      <title>Owning Compute vs Renting Intelligence ✍️</title>
      <dc:creator>Ekong Ikpe</dc:creator>
      <pubDate>Sat, 27 Jun 2026 09:52:41 +0000</pubDate>
      <link>https://dev.to/edmundsparrow/owning-compute-vs-renting-intelligence-2j35</link>
      <guid>https://dev.to/edmundsparrow/owning-compute-vs-renting-intelligence-2j35</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fcz17mhwg7okyqnwwkvuh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fcz17mhwg7okyqnwwkvuh.png" alt="cloud or " width="800" height="640"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;About two weeks ago, the U.S. government directed Anthropic to suspend access to its latest frontier models. This week, OpenAI was required to limit the rollout of GPT-5.6 over cybersecurity concerns.&lt;/p&gt;

&lt;p&gt;Whether you agree with those decisions or not isn't the point.&lt;/p&gt;

&lt;p&gt;The point is that they highlighted something many of us have quietly ignored for years.&lt;/p&gt;

&lt;p&gt;If your software depends entirely on somebody else's API, then part of your software is no longer under your control.&lt;/p&gt;

&lt;p&gt;Your application can be rate-limited. Features can disappear overnight. Pricing can change. Access can be restricted by policy, regulation, geography, or business decisions you have no say in.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;That's not ownership. That's renting intelligence.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;For years, local-first development was treated like a niche philosophy. People associated it with privacy enthusiasts, hobbyists, or developers who simply didn't want to manage servers.&lt;/p&gt;

&lt;p&gt;Today it feels less like nostalgia and more like common sense.&lt;/p&gt;

&lt;p&gt;The conversation is no longer just about privacy.&lt;/p&gt;

&lt;p&gt;It's about availability.&lt;/p&gt;

&lt;p&gt;It's about resilience.&lt;/p&gt;

&lt;p&gt;It's about building software that continues to work even when the internet, an API, or a provider decides otherwise.&lt;/p&gt;

&lt;p&gt;This doesn't mean cloud computing is dead. Far from it.&lt;/p&gt;

&lt;p&gt;The cloud will remain an important part of our industry.&lt;/p&gt;

&lt;p&gt;But we've reached the point where depending on it for everything is becoming an architectural risk, not just a technical decision.&lt;/p&gt;

&lt;p&gt;I don't think we're witnessing the end of the cloud.&lt;/p&gt;

&lt;p&gt;I think we're being reminded of the value of a parallel ecosystem.&lt;/p&gt;

&lt;p&gt;One where intelligence isn't rented—it runs locally.&lt;/p&gt;

&lt;p&gt;One where software doesn't ask permission to keep working.&lt;/p&gt;

&lt;p&gt;One where the browser is treated as a capable computing platform, not just a window into someone else's server.&lt;/p&gt;

&lt;p&gt;No recurring API bills.&lt;/p&gt;

&lt;p&gt;No mandatory internet connection.&lt;/p&gt;

&lt;p&gt;No unnecessary data leaving the device.&lt;/p&gt;

&lt;p&gt;We don't need billion-dollar server farms to solve every problem.&lt;/p&gt;

&lt;p&gt;Sometimes a browser tab, local compute, and well-designed software are enough. &lt;/p&gt;

&lt;p&gt;For the past year, that's the direction I've been exploring: treating the browser less like a document viewer and more like a sovereign operating system capable of running meaningful software entirely on the client.&lt;/p&gt;

&lt;p&gt;Maybe the future isn't cloud-first.&lt;/p&gt;

&lt;p&gt;Maybe it's cloud-optional.&lt;/p&gt;

&lt;p&gt;Because if recent events have shown us anything, it's this:&lt;/p&gt;

&lt;p&gt;The more your software depends on someone else's infrastructure, the less independent it really is.&lt;/p&gt;

&lt;p&gt;There's nothing as soothing as having software that works whether there's an internet connection or not. 😎&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>discuss</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Kitana: Beyond Token Prediction: Building AI with Human Cognitive Structure</title>
      <dc:creator>Ekong Ikpe</dc:creator>
      <pubDate>Sun, 21 Jun 2026 06:10:24 +0000</pubDate>
      <link>https://dev.to/edmundsparrow/kitana-why-im-replacing-token-prediction-with-dictionary-traversal-5266</link>
      <guid>https://dev.to/edmundsparrow/kitana-why-im-replacing-token-prediction-with-dictionary-traversal-5266</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fj0gm67m76cezaua1zdjl.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fj0gm67m76cezaua1zdjl.jpg" alt="tank map" width="800" height="537"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What If Language Understanding Starts With a Dictionary Instead of a Model?
&lt;/h2&gt;

&lt;p&gt;LLM → pattern matching → guessing → hallucination.&lt;/p&gt;

&lt;p&gt;That’s the standard pipeline we accept today.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;What if understanding language doesn’t start with prediction… but with structure?&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  🧠 The thing everyone skips
&lt;/h2&gt;

&lt;p&gt;Every modern AI system eventually scales into:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;more parameters
&lt;/li&gt;
&lt;li&gt;more data
&lt;/li&gt;
&lt;li&gt;more compute
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And yet the same problem keeps showing up:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Meaning is still unstable.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Not compute. Not storage.&lt;/p&gt;

&lt;p&gt;Meaning.&lt;/p&gt;




&lt;h2&gt;
  
  
  📚 The overlooked system already exists
&lt;/h2&gt;

&lt;p&gt;A dictionary already contains something interesting:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A–Z defined
&lt;/li&gt;
&lt;li&gt;0–9 defined
&lt;/li&gt;
&lt;li&gt;symbols defined
&lt;/li&gt;
&lt;li&gt;every word has meaning
&lt;/li&gt;
&lt;li&gt;every word connects to other words
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It’s not random text.&lt;/p&gt;

&lt;p&gt;It’s a structured semantic network.&lt;/p&gt;

&lt;p&gt;Not perfect.&lt;/p&gt;

&lt;p&gt;But structured.&lt;/p&gt;




&lt;h2&gt;
  
  
  ✍️ The simple realization
&lt;/h2&gt;

&lt;p&gt;No human knows every word in a dictionary.&lt;/p&gt;

&lt;p&gt;But humans still learn language.&lt;/p&gt;

&lt;p&gt;So the question becomes:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;What if understanding is not stored… but constructed?&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  🧩 The direction I started exploring
&lt;/h2&gt;

&lt;p&gt;Instead of building a model that predicts language, I started exploring something else:&lt;/p&gt;

&lt;p&gt;A system that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;starts from basic symbols (A–Z, 0–9, characters)
&lt;/li&gt;
&lt;li&gt;builds into spelling → words → grammar → meaning
&lt;/li&gt;
&lt;li&gt;uses a dictionary as the grounding layer
&lt;/li&gt;
&lt;li&gt;connects meaning through structured relationships
&lt;/li&gt;
&lt;li&gt;learns progressively like a curriculum
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Not guessing.&lt;/p&gt;

&lt;p&gt;Tracing meaning step by step.&lt;/p&gt;




&lt;h2&gt;
  
  
  🌊 The core idea (Kitana)
&lt;/h2&gt;

&lt;p&gt;Kitana is not a traditional language model.&lt;/p&gt;

&lt;p&gt;It is a cognitive system where:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;knowledge is structured (dictionary grounding layer)
&lt;/li&gt;
&lt;li&gt;learning is progressive (like schooling)
&lt;/li&gt;
&lt;li&gt;meaning is connected (graph / “tank” structure)
&lt;/li&gt;
&lt;li&gt;understanding is dynamic, not stored facts
&lt;/li&gt;
&lt;li&gt;reasoning comes from relationships, not prediction
&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  ⚠️ Still early
&lt;/h2&gt;

&lt;p&gt;Right now it’s unstable.&lt;/p&gt;

&lt;p&gt;Language is messy:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;slang
&lt;/li&gt;
&lt;li&gt;ambiguity
&lt;/li&gt;
&lt;li&gt;contradictions
&lt;/li&gt;
&lt;li&gt;exceptions
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And I’m still testing how far structure can go before it breaks.&lt;/p&gt;

&lt;p&gt;But one pattern keeps repeating:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The system keeps returning to definitions instead of guesses.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  🔥 Final thought
&lt;/h2&gt;

&lt;p&gt;Maybe language understanding doesn’t start with intelligence.&lt;/p&gt;

&lt;p&gt;Maybe it starts with:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;structure strong enough to make intelligence emerge.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ffs4rguu0iigwtu56mqx4.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ffs4rguu0iigwtu56mqx4.jpg" alt="kitana AI" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>machinelearning</category>
      <category>weekendchallenge</category>
      <category>cognitivescience</category>
    </item>
    <item>
      <title>How we curb hallucination</title>
      <dc:creator>Ekong Ikpe</dc:creator>
      <pubDate>Tue, 16 Jun 2026 14:03:48 +0000</pubDate>
      <link>https://dev.to/edmundsparrow/how-we-curb-hallucination-4m2i</link>
      <guid>https://dev.to/edmundsparrow/how-we-curb-hallucination-4m2i</guid>
      <description>&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%2Fzdtafctx72p2yi8mvghl.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%2Fzdtafctx72p2yi8mvghl.png" alt="reality or hallucination" width="800" height="533"&gt;&lt;/a&gt;&lt;br&gt;
&lt;strong&gt;Artificial intelligence&lt;/strong&gt; is often blamed for hallucinations as though they emerge from nowhere. In reality, most hallucinations are the result of misalignment—between the system, the task, and the expectations placed upon it.&lt;/p&gt;

&lt;p&gt;Reducing hallucination is less about chasing perfection and more about understanding the environment in which intelligence operates.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. The Core Persona. 😎
&lt;/h2&gt;

&lt;p&gt;Like a skilled artisan using the proper chisel, an AI requires conscious direction. Before any model is deployed, developers must establish its distinct boundaries and operational capabilities, ensuring the technology aligns with human intent from the start.&lt;/p&gt;

&lt;p&gt;An undefined system is an unpredictable system. The clearer the purpose, the lower the probability of deviation.&lt;/p&gt;




&lt;h2&gt;
  
  
  2. The Mismatch Problem.  🤦
&lt;/h2&gt;

&lt;p&gt;We often encounter a conceptual error, much like attempting to use a basic text editor for complex graphic design.&lt;/p&gt;

&lt;p&gt;Consumers frequently overrate these systems, forgetting that an AI lacks true situational consciousness. It does not understand the unspoken objective behind a request. It acts upon available information, patterns, and constraints.&lt;/p&gt;

&lt;p&gt;When expectations exceed the architecture's intended purpose, friction becomes inevitable. The hallucination is often not the cause of the mismatch—it is the symptom.&lt;/p&gt;




&lt;h2&gt;
  
  
  3. The Logical Selection.  🧘
&lt;/h2&gt;

&lt;p&gt;Effective workflow relies on choosing the right apparatus for the job rather than expecting a single tool to perform every function flawlessly.&lt;/p&gt;

&lt;p&gt;You do not place images inside Notepad documents simply because a particular developer insists their version can handle them. A DocX file or a dedicated word processor was designed for that environment. Notes are for text.&lt;/p&gt;

&lt;p&gt;The distinction is not capability alone; it is native capability versus forced execution.&lt;/p&gt;

&lt;p&gt;A highly skilled designer may push CorelDraw to perform deep Photoshop-level raster manipulation. The result may even be impressive. Yet the effort itself reveals the mismatch. The designer is working against the environment rather than with it. Meanwhile, a less experienced Photoshop user can often achieve the same outcome with significantly less friction because the tool was architected for that purpose from the beginning.&lt;/p&gt;

&lt;p&gt;The same principle applies to artificial intelligence. Expecting a basic or mismatched system to imitate the behavior of a specialized architecture is a conceptual error. Reliability emerges not from forcing one instrument to perform every task, but from selecting the instrument whose natural design already aligns with the objective.&lt;/p&gt;

&lt;p&gt;Familiarity and precision should guide our choices, ensuring the digital environment matches the complexity of the task at hand.&lt;/p&gt;




&lt;h2&gt;
  
  
  4. The Builder's Responsibility.  👌
&lt;/h2&gt;

&lt;p&gt;A tool should be presented as what it is, not what marketing wishes it to become.&lt;/p&gt;

&lt;p&gt;Much of the confusion surrounding artificial intelligence does not originate from the user. It originates from unclear boundaries, exaggerated claims, and the failure to communicate limitations honestly.&lt;/p&gt;

&lt;p&gt;A smart calculator does not become intelligent because someone labels it AI. A pattern-matching system does not become conscious because it produces convincing language. Renaming a capability does not expand it.&lt;/p&gt;

&lt;p&gt;The responsibility therefore extends beyond the consumer. Builders, developers, and organizations must clearly communicate what their systems can do, what they cannot do, and where their reliability begins to decline.&lt;/p&gt;

&lt;p&gt;Honest representation creates appropriate expectations. Appropriate expectations create appropriate usage. Appropriate usage reduces friction.&lt;/p&gt;

&lt;p&gt;When a tool is accurately described, users naturally place it in the correct environment. When a tool is misrepresented, disappointment becomes inevitable because the promise and the architecture no longer align.&lt;/p&gt;

&lt;p&gt;The objective is not to make every system appear more intelligent than it is. The objective is to ensure that capability, description, and expectation remain synchronized.&lt;/p&gt;

&lt;p&gt;Truthful boundaries are not a weakness of a product. They are evidence of confidence in its actual purpose.&lt;/p&gt;




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

&lt;p&gt;Hallucination is rarely an isolated defect. More often, it is the visible consequence of a deeper misalignment between purpose, architecture, and expectation.&lt;/p&gt;

&lt;p&gt;Define the system.&lt;/p&gt;

&lt;p&gt;Understand its boundaries.&lt;/p&gt;

&lt;p&gt;Select the appropriate environment.&lt;/p&gt;

&lt;p&gt;Communicate it honestly.&lt;/p&gt;

&lt;p&gt;Refine through feedback.&lt;/p&gt;

&lt;p&gt;The objective is not to eliminate uncertainty entirely. The objective is to reduce unnecessary friction between human intent and machine execution.&lt;/p&gt;

&lt;p&gt;When that alignment is achieved, hallucination becomes less of a mystery and more of a manageable engineering problem.&lt;/p&gt;

&lt;p&gt;Photo credits = chatgpt 🙏&lt;br&gt;
Post credits = Gemini  🤝&lt;/p&gt;

&lt;p&gt;Need a more powerful AI, find out about kitana&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%2Fjxgrklbyhj9u953lpfhw.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%2Fjxgrklbyhj9u953lpfhw.jpg" alt="clean path" width="800" height="437"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>programming</category>
      <category>tutorial</category>
      <category>learning</category>
    </item>
    <item>
      <title>Gnoke AI Was the Plan. Then Kitana Happened. 🤔</title>
      <dc:creator>Ekong Ikpe</dc:creator>
      <pubDate>Mon, 15 Jun 2026 14:08:20 +0000</pubDate>
      <link>https://dev.to/edmundsparrow/gnoke-ai-was-the-plan-then-kitana-happened-2h78</link>
      <guid>https://dev.to/edmundsparrow/gnoke-ai-was-the-plan-then-kitana-happened-2h78</guid>
      <description>&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%2F1m9krhk257gtjzf19e2b.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%2F1m9krhk257gtjzf19e2b.png" alt="kitana my kitana" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  LLM — pattern matching — guessing — hallucination.
&lt;/h2&gt;

&lt;p&gt;The holy trinity of modern AI "intelligence." Throw enough parameters at it and after enough guesses it usually lands on something useful. Not wrong, exactly… just started way too heavy. 🤧&lt;/p&gt;

&lt;p&gt;Don't get it twisted I ain't trying to solve hallucination - the best intelligence will garbage out the worst inference, just feed it with the right input with wrong intent 😂 &lt;/p&gt;

&lt;p&gt;Gnoke AI (browser-based sLM) was the original plan.&lt;/p&gt;

&lt;p&gt;That was the target.&lt;/p&gt;

&lt;p&gt;A small language model that could run inside the browser. Lightweight. Practical. Built for Gnoke-Station 2.&lt;/p&gt;

&lt;p&gt;Nothing dramatic. Just engineering constraints and a clear goal.&lt;/p&gt;

&lt;p&gt;But the more I worked on it, the more the same problem kept showing up.&lt;/p&gt;

&lt;p&gt;Not compute.&lt;/p&gt;

&lt;p&gt;Not storage.&lt;/p&gt;

&lt;p&gt;Not architecture.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Meaning.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;How do you make a system understand language without turning it into something massive?&lt;/p&gt;




&lt;h2&gt;
  
  
  The thing I kept ignoring
&lt;/h2&gt;

&lt;p&gt;Every direction I explored eventually bent back to the same place.&lt;/p&gt;

&lt;p&gt;More data.&lt;/p&gt;

&lt;p&gt;More parameters.&lt;/p&gt;

&lt;p&gt;More complexity.&lt;/p&gt;

&lt;p&gt;And I kept thinking:&lt;/p&gt;

&lt;p&gt;There has to be a simpler layer under all of this.&lt;/p&gt;

&lt;p&gt;Something closer to how humans actually deal with language.&lt;/p&gt;

&lt;p&gt;Not how we predict words.&lt;/p&gt;

&lt;p&gt;But how we understand them.&lt;/p&gt;




&lt;h2&gt;
  
  
  The cheat book — An Oxford or Webster dictionary 👌
&lt;/h2&gt;

&lt;p&gt;At some point, I stopped and looked at something too obvious to notice.&lt;/p&gt;

&lt;p&gt;A dictionary.&lt;/p&gt;

&lt;p&gt;English already contains a structured system where:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A–Z is defined&lt;/li&gt;
&lt;li&gt;0–9 is defined&lt;/li&gt;
&lt;li&gt;Special characters are defined&lt;/li&gt;
&lt;li&gt;Every word has meaning&lt;/li&gt;
&lt;li&gt;Every word has usage examples&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It's already a complete semantic handbook.&lt;/p&gt;

&lt;p&gt;Not perfect. Not complete.&lt;/p&gt;

&lt;p&gt;But structured.&lt;/p&gt;

&lt;p&gt;Then another thought hit me:&lt;/p&gt;

&lt;p&gt;No human knows every English dictionary word…&lt;/p&gt;

&lt;p&gt;but we still know how to learn 🤷&lt;/p&gt;

&lt;p&gt;That's the part that matters. Not an AIO but super intelligent enough to know when to use a medical dictionary or physics textbook verified by the and trusted.&lt;/p&gt;




&lt;h2&gt;
  
  
  Kitana wasn't planned
&lt;/h2&gt;

&lt;p&gt;I set out to build a small language &lt;strong&gt;model&lt;/strong&gt;. What emerged was something closer to a language &lt;strong&gt;engine&lt;/strong&gt; — one that treats the dictionary not as training data, but as the operating system.&lt;/p&gt;

&lt;p&gt;Gnoke AI was trying to generate language.&lt;/p&gt;

&lt;p&gt;Kitana started leaning toward something else:&lt;/p&gt;

&lt;p&gt;Understanding language through structure, not prediction.&lt;/p&gt;

&lt;p&gt;Not guessing what comes next.&lt;/p&gt;

&lt;p&gt;But tracing what something means.&lt;/p&gt;

&lt;p&gt;Step by step.&lt;/p&gt;

&lt;p&gt;Definition by definition.&lt;/p&gt;




&lt;h2&gt;
  
  
  I don't think this is finished
&lt;/h2&gt;

&lt;p&gt;Right now, Kitana is still unstable.&lt;/p&gt;

&lt;p&gt;Still being tested against ambiguity, slang, exceptions, and all the messy parts of human language.&lt;/p&gt;

&lt;p&gt;And honestly, I don't know where it fully lands yet.&lt;/p&gt;

&lt;p&gt;But one pattern keeps repeating:&lt;/p&gt;

&lt;p&gt;Every time I try to move it toward a standard AI approach…&lt;/p&gt;

&lt;p&gt;It moves back toward definitions.&lt;/p&gt;




&lt;p&gt;The smallest dictionary is capable.&lt;/p&gt;

&lt;p&gt;Once inference, comprehension, and understanding exist — evolution is unstoppable. Out of the box.&lt;/p&gt;




&lt;p&gt;I need to stop here 😂&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%2Fqgsvd9hmxvecgn9ui3y1.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%2Fqgsvd9hmxvecgn9ui3y1.png" alt="worlds programming book" width="799" height="436"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>programming</category>
      <category>webdev</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>I think I just made PWAs obsolete. Or maybe I upgraded them. I genuinely can't tell. 🤔</title>
      <dc:creator>Ekong Ikpe</dc:creator>
      <pubDate>Mon, 08 Jun 2026 11:38:07 +0000</pubDate>
      <link>https://dev.to/edmundsparrow/i-think-i-just-made-pwas-obsolete-or-maybe-i-upgraded-them-i-genuinely-cant-tell-53hk</link>
      <guid>https://dev.to/edmundsparrow/i-think-i-just-made-pwas-obsolete-or-maybe-i-upgraded-them-i-genuinely-cant-tell-53hk</guid>
      <description>&lt;h2&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%2F2vayvpqp5c2h2ing720l.png" alt="1 signal"&gt;
&lt;/h2&gt;

&lt;p&gt;I watched a movie yesterday (Signal One, 2026) — just when I needed a sci-fi break.&lt;/p&gt;

&lt;p&gt;Okay 🤦 I'm obsessed with the browser but don't think all I do is Gnoke. 😉&lt;/p&gt;




&lt;h2&gt;
  
  
  Why This Post Matters
&lt;/h2&gt;

&lt;p&gt;PWAs have a Service Worker. A manifest. Maybe some IndexedDB if you're disciplined.&lt;/p&gt;

&lt;p&gt;And when Android kills your tab — because Android kills everything, eventually — you come back to a blank page. Or the home screen. Or whatever the browser decides to show you.&lt;/p&gt;

&lt;p&gt;The app is still "installed." The data is still there. But the &lt;em&gt;session&lt;/em&gt; is gone. Where you were. What you were doing. That context that made the app feel like yours.&lt;/p&gt;

&lt;p&gt;We just accept this. We've always accepted this.&lt;/p&gt;

&lt;p&gt;I don't accept it in Gnoke Station 2 — my browser OS where tabs are apps. Shopping list. Council. Notes. They're supposed to feel &lt;em&gt;real&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Real apps don't forget you.&lt;/p&gt;




&lt;h2&gt;
  
  
  What PWAs actually give you (and what they don't)
&lt;/h2&gt;

&lt;p&gt;Service Worker caches your assets. Cold boot works offline. Good.&lt;/p&gt;

&lt;p&gt;Manifest tells the OS your name and icon. Install prompt appears. Good.&lt;/p&gt;

&lt;p&gt;Neither of them knows where you &lt;em&gt;were&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;That's the gap. PWAs solved the &lt;em&gt;delivery&lt;/em&gt; problem. Nobody solved the &lt;em&gt;session&lt;/em&gt; problem.&lt;/p&gt;

&lt;p&gt;Every PWA on your phone has the same quiet flaw: open it after Android clears it from memory, and you start over.&lt;/p&gt;




&lt;h2&gt;
  
  
  Gnoke-Spirit as a solution
&lt;/h2&gt;

&lt;p&gt;Before the tab dies — on &lt;code&gt;pagehide&lt;/code&gt; — snapshot everything. Where the user was. What they typed. The URL hash. Scroll position. Every form field that isn't a password.&lt;/p&gt;

&lt;p&gt;Write it to IndexedDB. Not localStorage — IndexedDB survives process kills.&lt;/p&gt;

&lt;p&gt;On the next boot, before the app renders anything, read it back. Restore it. Fire an event.&lt;/p&gt;

&lt;p&gt;The app wakes up exactly where the user left it. Not approximately. &lt;em&gt;Exactly.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;I called it resurrection.&lt;/p&gt;

&lt;p&gt;It's best-effort — &lt;code&gt;pagehide&lt;/code&gt; as the primary trigger, &lt;code&gt;visibilitychange&lt;/code&gt; as backup, plus debounced input saves. Abrupt kills may lose the last few seconds. Still vastly better than starting from scratch.&lt;/p&gt;




&lt;h2&gt;
  
  
  The part I didn't expect
&lt;/h2&gt;

&lt;p&gt;Once spirit was working I looked at the other pieces sitting around it.&lt;/p&gt;

&lt;p&gt;Service Worker. Already running. Knows whether the page was served from cache or the network.&lt;/p&gt;

&lt;p&gt;Manifest. Already declared. Handles the OS install layer.&lt;/p&gt;

&lt;p&gt;Spirit. Knows the full session state.&lt;/p&gt;

&lt;p&gt;Three things. Three completely separate browser concerns. Not one of them talks to the others.&lt;/p&gt;

&lt;p&gt;But I had &lt;code&gt;boot.js&lt;/code&gt; — a single file every Gnoke app loads first. I thought: what if boot.js just asked all three before firing?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;source&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;cache&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;        &lt;span class="c1"&gt;// SW told boot.js this&lt;/span&gt;
  &lt;span class="nx"&gt;resurrecting&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;     &lt;span class="c1"&gt;// spirit found a snapshot&lt;/span&gt;
  &lt;span class="nx"&gt;snapshot&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;hash&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#list:abc123&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;scroll&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;x&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;y&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;340&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="nx"&gt;forms&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[...]&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;One event. One decision point. Full context. No manual wiring.&lt;/p&gt;

&lt;p&gt;Instead of this — per app, every time:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;load&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;saved&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;localStorage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;last-page&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;saved&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nf"&gt;navigateTo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;saved&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nb"&gt;navigator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;serviceWorker&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ready&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;reg&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;fromCache&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;reg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;active&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;activated&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;fromCache&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nf"&gt;skipLoadingScreen&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You get this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;gnoke:boot&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;detail&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;detail&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;resurrecting&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nf"&gt;navigateTo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;detail&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;snapshot&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;hash&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;detail&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;source&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;cache&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nf"&gt;skipLoadingScreen&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The apps get smarter for free. The coordinator does the work once, centrally.&lt;/p&gt;




&lt;h2&gt;
  
  
  Against native apps
&lt;/h2&gt;

&lt;p&gt;Android kills your native app. Android kills your browser tab. Same question either way: &lt;em&gt;how do we get the user back to where they were?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Native platforms have lifecycle APIs, Bundles, ViewModels, Room, CoreData — a decade of patterns built around surviving process death.&lt;/p&gt;

&lt;p&gt;The web has mostly been pretending the problem doesn't exist.&lt;/p&gt;

&lt;p&gt;Spirit isn't doing something native apps can't. It's bringing the same lifecycle resilience to the browser with a tiny amount of vanilla JavaScript.&lt;/p&gt;

&lt;p&gt;Spirit treats browser state as the source of truth — the URL, the hash, scroll position, focused field, form values. Those things already exist. Spirit snapshots them. The restore isn't a replay. It's a read.&lt;/p&gt;

&lt;p&gt;Spirit doesn't know what a shopping list is. It doesn't need to. If the list encodes its state as &lt;code&gt;#list:abc123&lt;/code&gt; — Spirit captures it automatically.&lt;/p&gt;

&lt;p&gt;The hash is the state. Spirit snapshots it. Boot restores it.&lt;/p&gt;




&lt;h2&gt;
  
  
  The diagram
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[ Service Worker ] ---&amp;gt; (Network Layer)  \
[ Web Manifest   ] ---&amp;gt; (OS Layer)        +---&amp;gt; [ boot.js ] ---&amp;gt; Event: `gnoke:boot`
[ Gnoke Spirit   ] ---&amp;gt; (Session Layer)  /
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Service Worker owns the network layer.&lt;br&gt;
Manifest owns the OS layer.&lt;br&gt;
Spirit owns the session layer.&lt;/p&gt;

&lt;p&gt;Boot.js sits at the intersection. Making it conscious of all three costs almost nothing.&lt;/p&gt;




&lt;h2&gt;
  
  
  What I'm actually claiming
&lt;/h2&gt;

&lt;p&gt;The delivery problem was solved by Service Workers.&lt;br&gt;
The install problem was solved by manifests.&lt;br&gt;
What was missing was a lifecycle.&lt;/p&gt;

&lt;p&gt;Not storage. Not caching. Not installation. Continuity.&lt;/p&gt;

&lt;p&gt;Service Worker gave PWAs a body.&lt;br&gt;
The manifest gave them an identity.&lt;br&gt;
Spirit gives them a memory.&lt;/p&gt;

&lt;p&gt;That feels less like a webpage. And a lot more like an application.&lt;/p&gt;




&lt;p&gt;The coordinator pattern is part of Gnoke Station — open source, MIT.&lt;/p&gt;

&lt;p&gt;If you're a senior dev who works close to the browser — primitives, lifecycle, platform APIs — I'd genuinely welcome your eyes on the architecture. 🤷&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;References&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://dev.to/edmundsparrow/tabs-are-apps-the-os-just-never-told-the-browser-3k72"&gt;gnoke-spirit — Tabs as processes. IndexedDB as memory.&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/edmundsparrow/gnoke-station-the-browser-as-a-sovereign-operating-system-a-response-to-google-io-2026-12fb"&gt;Gnoke Station 2 — A Response to Google I/O 2026&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/edmundsparrow/gnoke-spirit" rel="noopener noreferrer"&gt;Source: github.com/edmundsparrow/gnoke-spirit&lt;/a&gt; — MIT&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;— Edmund Sparrow, Gnoke Suite&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>webdev</category>
      <category>pwa</category>
      <category>architecture</category>
    </item>
    <item>
      <title>Gnoke Skins: Every Device Already Has a Face. It Just Hasn't Rendered Yet.</title>
      <dc:creator>Ekong Ikpe</dc:creator>
      <pubDate>Wed, 03 Jun 2026 11:28:25 +0000</pubDate>
      <link>https://dev.to/edmundsparrow/gnoke-skins-every-device-already-has-a-face-it-just-hasnt-rendered-yet-1n2b</link>
      <guid>https://dev.to/edmundsparrow/gnoke-skins-every-device-already-has-a-face-it-just-hasnt-rendered-yet-1n2b</guid>
      <description>&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%2Fcij4eiwxj6i3p2b6rvvo.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%2Fcij4eiwxj6i3p2b6rvvo.png" alt="Gnoke Skins"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;There is a gap between what a device &lt;em&gt;knows&lt;/em&gt; and what it &lt;em&gt;shows&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Your MiFi router knows signal strength, battery level, how many people are connected, how much data is left. Your AC unit knows the room temperature, the mode, the timer. Your PWM controller knows the duty cycle, the frequency, the load. A signal tower on a factory floor knows whether the line is running, warning, or stopped.&lt;/p&gt;

&lt;p&gt;They all know. Most of them just never figured out how to &lt;em&gt;tell you&lt;/em&gt; in a way that felt human.&lt;/p&gt;

&lt;p&gt;That is not a hardware problem. That is a skin problem.&lt;/p&gt;




&lt;h2&gt;
  
  
  The $15,000 lesson
&lt;/h2&gt;

&lt;p&gt;A while back I built &lt;a href="https://dev.to/edmundsparrow/replacing-5000-of-industrial-equipment-with-a-browser-tab-3jc6"&gt;SignalTower&lt;/a&gt; — an Andon-style stack light controller that runs in a browser tab. The point was simple: a standard industrial HMI panel setup costs $15,000 once you add the proprietary OS, the vendor lock-in, the license fees. The browser already ships with Web Serial, WebUSB, Web Bluetooth. The hardware APIs are free. The screen you already have.&lt;/p&gt;

&lt;p&gt;SignalTower was one proof. But the skin was never meant to be device-specific. Any hardware that speaks JSON deserves a face.&lt;/p&gt;

&lt;p&gt;What if any device that speaks JSON could get a face — designed for humans, not firmware teams under deadline?&lt;/p&gt;




&lt;h2&gt;
  
  
  Gnoke-Skins
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Device (JSON) → config.js → Gnoke skin → Browser
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Three pieces. That is the entire architecture.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The device&lt;/strong&gt; — any hardware that exposes a JSON endpoint. ESP32. Arduino. Raspberry Pi. STM32. A MiFi router. An AC unit. A PWM controller. A generator. A signal tower. Anything.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;config.js&lt;/strong&gt; — one file. You declare the host, map the keys, define presets. Nothing else. This is the only file that changes per deployment.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The skin&lt;/strong&gt; — a single &lt;code&gt;index.html&lt;/code&gt;. Pure display logic. Zero firmware dependency. Swap skins freely. The device never changes.&lt;/p&gt;

&lt;p&gt;The firmware bridge is the only device-specific work. Everything else is reusable. One integration per hardware model — after that, every future UI is a skin change, not a firmware project. For manufacturers, that means the frontend never blocks a product launch again.&lt;/p&gt;




&lt;h2&gt;
  
  
  Three worlds, same idea
&lt;/h2&gt;

&lt;p&gt;I built three skins so far. Each one is a different proof of the same philosophy.&lt;/p&gt;

&lt;h3&gt;
  
  
  MiFi — &lt;a href="https://gnoke-skins.netlify.app/mifi" rel="noopener noreferrer"&gt;live demo&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;Most MiFi users never change their factory default SSID. Not because they don't want to — because 192.168.1.1 gets in the way.&lt;/p&gt;

&lt;p&gt;The skin puts configuration directly on the device screen: SSID, password, connected users, data usage. Navigated with three physical buttons on the device body. T9 keyboard for field editing. 5-second hold-to-reset. Full boot sequence.&lt;/p&gt;

&lt;p&gt;No phone. No laptop. No IP address typed into a browser at midnight while your internet is down.&lt;/p&gt;

&lt;p&gt;A device that ships with this skin means the customer never sees 192.168.1.1. They see an interface that was &lt;em&gt;designed for them&lt;/em&gt;. The telco that ships this first owns that experience.&lt;/p&gt;

&lt;h3&gt;
  
  
  PWM Controller — &lt;a href="https://gnoke-skins.netlify.app/pwm1" rel="noopener noreferrer"&gt;live demo&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;Industrial dark. Large touch targets. Segmented duty cycle bars. Preset buttons: Lathe, Pump, Drill, Boost.&lt;/p&gt;

&lt;p&gt;The kind of interface a workshop operator can read from across a room, with gloves on, under bad lighting. Not because it is pretty — because it is &lt;em&gt;right for its context&lt;/em&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  AC Remote — &lt;a href="https://gnoke-skins.netlify.app/ac-remote" rel="noopener noreferrer"&gt;live demo&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;Retro LCD aesthetic. Tactile button feel. Mode, fan speed, sleep, timer, swing.&lt;/p&gt;

&lt;p&gt;Works as a phone remote &lt;em&gt;or&lt;/em&gt; as an on-device touchscreen. Same skin, two deployment contexts. The device does not change. The surface does.&lt;/p&gt;




&lt;h2&gt;
  
  
  The deeper thing
&lt;/h2&gt;

&lt;p&gt;A device without a screen is not a limitation. Your phone fills in. Point a browser at the JSON endpoint — the skin renders. The device gains a face it never had from the factory.&lt;/p&gt;

&lt;p&gt;A device with a screen but terrible UI is not stuck. The screen runs a browser. The skin loads. The firmware team never has to touch the frontend again.&lt;/p&gt;

&lt;p&gt;A device that does not exist yet — that you are sketching on paper right now — can have its UI built before the hardware ships. The skin is decoupled. The bridge connects later.&lt;/p&gt;

&lt;p&gt;This is what I mean when I say the face is already there.&lt;/p&gt;

&lt;p&gt;The hardware is already broadcasting. The JSON is already flowing. The state is already known. The only missing piece was a layer that catches all of it and renders it as something worth looking at — something a real person can read, navigate, and trust.&lt;/p&gt;

&lt;p&gt;Gnoke-Skins is that layer.&lt;/p&gt;




&lt;p&gt;The repo is MIT BSL licensed. If you build hardware and you have ever thought &lt;em&gt;"my users deserve better than this"&lt;/em&gt; — this is what that looks like before a framework arrives to complicate it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://gnoke-skins.netlify.app" rel="noopener noreferrer"&gt;gnoke-skins.netlify.app&lt;/a&gt;&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;&lt;a href="https://github.com/edmundsparrow/gnoke-skins" rel="noopener noreferrer"&gt;github.com/edmundsparrow/gnoke-skins&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Built on an Infinix phone. Deployed to Netlify. Zero dependencies. Because the constraint is part of the philosophy.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>iot</category>
      <category>javascript</category>
      <category>showdev</category>
    </item>
  </channel>
</rss>
