<?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: opensource</title>
    <description>The latest articles tagged 'opensource' on DEV Community.</description>
    <link>https://dev.to/t/opensource</link>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/tag/opensource"/>
    <language>en</language>
    <item>
      <title>I gave Claude a memory of everything I browse — here's the architecture</title>
      <dc:creator>Kiell Tampubolon</dc:creator>
      <pubDate>Mon, 15 Jun 2026 08:05:42 +0000</pubDate>
      <link>https://dev.to/kielltampubolon/i-gave-claude-a-memory-of-everything-i-browse-heres-the-architecture-3a7d</link>
      <guid>https://dev.to/kielltampubolon/i-gave-claude-a-memory-of-everything-i-browse-heres-the-architecture-3a7d</guid>
      <description>&lt;p&gt;Claude can read my files, my terminal, even my screen. But it had no idea what I read in my browser yesterday.&lt;/p&gt;

&lt;p&gt;That gap bugged me enough to build &lt;strong&gt;&lt;a href="https://github.com/glatinone/BraveMCP" rel="noopener noreferrer"&gt;BraveMCP&lt;/a&gt;&lt;/strong&gt;: a local-first "second brain" that gives Claude Desktop access to my browsing history, bookmarks, highlights, and notes through the Model Context Protocol (MCP). Everything stays on my machine. No cloud, no tracking.&lt;/p&gt;

&lt;p&gt;This is the technical write-up: the architecture, the one constraint that shaped the whole design, and the bugs that cost me the most time.&lt;/p&gt;

&lt;h2&gt;
  
  
  The constraint that shaped everything
&lt;/h2&gt;

&lt;p&gt;MCP servers talk to Claude Desktop over &lt;strong&gt;stdio&lt;/strong&gt;, a JSON-RPC stream on stdin/stdout. A browser extension lives in a sandbox and &lt;strong&gt;cannot speak stdio&lt;/strong&gt;. It can only make outbound HTTP requests.&lt;/p&gt;

&lt;p&gt;So the two halves of the system physically cannot talk to each other directly. That single fact drove the entire design.&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%2F8eyfvw7pw9kfotk5sr0z.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%2F8eyfvw7pw9kfotk5sr0z.png" alt="BraveMCP architecture" width="800" height="368"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The fix is a small &lt;strong&gt;HTTP bridge&lt;/strong&gt;: an Express server running on port &lt;code&gt;3747&lt;/code&gt;, &lt;em&gt;inside the same process&lt;/em&gt; as the MCP server. The extension POSTs browsing events to it; the MCP server reads from the shared database when Claude calls a tool.&lt;/p&gt;

&lt;h2&gt;
  
  
  The storage layer: hybrid search
&lt;/h2&gt;

&lt;p&gt;Keyword search and semantic search each miss things the other catches. So BraveMCP runs both and merges them.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;SQLite with FTS5&lt;/strong&gt; for fast BM25 keyword ranking over titles, summaries, notes, and highlights.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;ChromaDB&lt;/strong&gt; for cosine vector similarity, so "MCP security" still finds a page titled "Claude agent hardening."
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Merge keyword + vector hits; boost items that appear in both&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;merged&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Map&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="k"&gt;for &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;m&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;chromaMatches&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nx"&gt;merged&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;m&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&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="nx"&gt;m&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;source&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;semantic&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="k"&gt;for &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;m&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;ftsMatches&lt;/span&gt;&lt;span class="p"&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;existing&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;merged&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;m&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&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;existing&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nx"&gt;existing&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;relevance&lt;/span&gt; &lt;span class="o"&gt;*=&lt;/span&gt; &lt;span class="mf"&gt;1.1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// appears in both -&amp;gt; boost&lt;/span&gt;
  &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="nx"&gt;merged&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;m&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&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="nx"&gt;m&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;source&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;keyword&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If ChromaDB is not running, the server degrades to FTS5-only instead of failing. Local-first means it has to work with whatever services you actually have up.&lt;/p&gt;

&lt;h2&gt;
  
  
  The AI pipeline, and why the fallback matters
&lt;/h2&gt;

&lt;p&gt;When a page is captured, BraveMCP generates a summary and an embedding. It tries &lt;strong&gt;Ollama&lt;/strong&gt; first (fully local: &lt;code&gt;llama3.2&lt;/code&gt; for summaries, &lt;code&gt;nomic-embed-text&lt;/code&gt; for embeddings), then falls back to the &lt;strong&gt;Anthropic API&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;But here is the trap I walked into. The first version, when &lt;em&gt;no&lt;/em&gt; LLM was available, returned canned strings:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// before: this ignores the actual data entirely&lt;/span&gt;
&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s2"&gt;`Synthesis on "&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;topic&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;": Relies on the gathered browser research database.`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That is useless. It says the same thing no matter what you searched. So I rewrote every fallback to be &lt;strong&gt;extractive&lt;/strong&gt;: to build a real summary from the actual data, grouping matching pages by domain with real snippets pulled from SQLite. With no LLM at all, asking for a topic synthesis now returns the genuine sources. Different input produces different output. The "AI" tools stay useful even when there is no AI running.&lt;/p&gt;

&lt;h2&gt;
  
  
  Recovering forgotten pages
&lt;/h2&gt;

&lt;p&gt;The tool I use most is &lt;code&gt;find_forgotten_content&lt;/code&gt;. You give it a vague description and it does hybrid search, then re-ranks with &lt;strong&gt;time decay&lt;/strong&gt; and a &lt;strong&gt;visit-count boost&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;timeDecay&lt;/span&gt;  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;max&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;0.5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;exp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mf"&gt;0.01&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;daysElapsed&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;visitBoost&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mf"&gt;0.2&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;visitCount&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;adjusted&lt;/span&gt;   &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;min&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;0.99&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;relevance&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;timeDecay&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;visitBoost&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A page you opened three times last week beats one you glanced at once today. That matches how memory actually feels.&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%2Feoa6vtgb3ar5f4faitf6.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%2Feoa6vtgb3ar5f4faitf6.png" alt="Before and after BraveMCP" width="800" height="432"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Two bugs that cost me hours
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;1. dotenv v17 broke the entire protocol.&lt;/strong&gt; MCP communicates over stdout. dotenv v17 prints a status line to stdout by default. That one line corrupted the JSON-RPC channel and Claude Desktop refused to connect with a cryptic &lt;code&gt;Unexpected token&lt;/code&gt; error. The fix was pinning &lt;code&gt;dotenv@16&lt;/code&gt;. Two hours on a single log line.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. The dual-process state problem.&lt;/strong&gt; Claude Desktop and my dev client each spawn their own copy of the MCP server. Only the instance that grabs port &lt;code&gt;3747&lt;/code&gt; receives extension data. The other had empty in-memory state, so tab tools returned nothing. The fix: stop treating in-memory state as the source of truth and fall back to SQLite, which both processes share.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's in the box
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;A Manifest V3 extension (tab sync, bookmarks, context-menu highlights)&lt;/li&gt;
&lt;li&gt;An MCP server exposing &lt;strong&gt;13 tools&lt;/strong&gt; (&lt;code&gt;search_memory&lt;/code&gt;, &lt;code&gt;find_forgotten_content&lt;/code&gt;, &lt;code&gt;summarize_research_topic&lt;/code&gt;, &lt;code&gt;generate_weekly_digest&lt;/code&gt;, &lt;code&gt;suggest_tab_cleanup&lt;/code&gt;, and more)&lt;/li&gt;
&lt;li&gt;SQLite + ChromaDB hybrid search&lt;/li&gt;
&lt;li&gt;A test suite on Node's built-in runner, wired into CI&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It is open source, MIT licensed: &lt;strong&gt;&lt;a href="https://github.com/glatinone/BraveMCP" rel="noopener noreferrer"&gt;https://github.com/glatinone/BraveMCP&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If you are building on MCP, the stdio-vs-HTTP bridge pattern is the part worth stealing. What would you want your AI to remember?&lt;/p&gt;

</description>
      <category>mcp</category>
      <category>ai</category>
      <category>typescript</category>
      <category>opensource</category>
    </item>
    <item>
      <title>I'm building a read-only context engine for Kubernetes and AI agents</title>
      <dc:creator>Luca Sepe</dc:creator>
      <pubDate>Mon, 15 Jun 2026 08:03:09 +0000</pubDate>
      <link>https://dev.to/lucasepe/im-building-a-read-only-context-engine-for-kubernetes-and-ai-agents-40nh</link>
      <guid>https://dev.to/lucasepe/im-building-a-read-only-context-engine-for-kubernetes-and-ai-agents-40nh</guid>
      <description>&lt;p&gt;Kubernetes gives us an incredibly powerful API.&lt;/p&gt;

&lt;p&gt;It also gives us a familiar debugging ritual:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl get pods
kubectl describe pod ...
kubectl get svc ...
kubectl get endpointslices ...
kubectl get deployment ...
kubectl get events ...
kubectl get application.argoproj.io ...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then we mentally stitch the result together.&lt;/p&gt;

&lt;p&gt;Which workload owns this Pod? Which Service routes to it? Are there ready endpoints? Is the namespace unhealthy because of one bad Deployment, a missing backend, warning Events, or something else? &lt;/p&gt;

&lt;p&gt;Which facts should I paste into an incident, attach to a CI failure, or give to an AI assistant before asking it to reason?&lt;/p&gt;

&lt;p&gt;I started building &lt;a href="https://github.com/lucasepe/kctx" rel="noopener noreferrer"&gt;&lt;code&gt;kctx&lt;/code&gt;&lt;/a&gt; because I wanted a small tool for that missing middle layer: not raw YAML, not a dashboard, not an auto-remediation system.&lt;/p&gt;

&lt;p&gt;Just structured Kubernetes context.&lt;/p&gt;

&lt;h2&gt;
  
  
  The short version
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/lucasepe/kctx" rel="noopener noreferrer"&gt;&lt;code&gt;kctx&lt;/code&gt;&lt;/a&gt; is a read-only Kubernetes context engine for humans, scripts, and AI agents.&lt;/p&gt;

&lt;p&gt;It turns live Kubernetes API state into a compact model of:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;entities: Pods, Services, workloads, Nodes, PVCs, ConfigMaps, Secrets, and supported CRDs&lt;/li&gt;
&lt;li&gt;relations: ownership, selection, scheduling, service routing, and dependencies&lt;/li&gt;
&lt;li&gt;signals: factual observations such as unhealthy Pods, missing endpoints, warning Events, failed readiness, or degraded workloads&lt;/li&gt;
&lt;li&gt;graphs: dependency and ownership views around supported resources&lt;/li&gt;
&lt;li&gt;dumps: deterministic namespace snapshots for automation, incident review, and agent grounding&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The design goal is intentionally conservative:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;read cluster state, normalize facts, avoid speculative root-cause claims.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That boundary matters.&lt;/p&gt;

&lt;p&gt;I do not want &lt;a href="https://github.com/lucasepe/kctx" rel="noopener noreferrer"&gt;&lt;code&gt;kctx&lt;/code&gt;&lt;/a&gt; to be a tool that confidently invents explanations. I want it to provide the evidence layer that humans, automation, and AI agents can use before reasoning.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why another Kubernetes tool?
&lt;/h2&gt;

&lt;p&gt;Most Kubernetes tools are optimized for one of a few jobs:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;kubectl&lt;/code&gt; exposes the raw API very well&lt;/li&gt;
&lt;li&gt;dashboards make current state visible&lt;/li&gt;
&lt;li&gt;monitoring systems track metrics and alerts over time&lt;/li&gt;
&lt;li&gt;logging systems answer "what happened in the process?"&lt;/li&gt;
&lt;li&gt;GitOps tools understand desired state and sync status&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Those are all useful. I use them too.&lt;/p&gt;

&lt;p&gt;But during debugging, there is still a recurring gap between "I can query every object" and "I have a compact operational picture of what is connected to what."&lt;/p&gt;

&lt;p&gt;For example, when looking at a Service, I often care less about the complete YAML and more about questions like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Which EndpointSlices back this Service?&lt;/li&gt;
&lt;li&gt;Which endpoints are ready?&lt;/li&gt;
&lt;li&gt;Which Pods do those endpoints point to?&lt;/li&gt;
&lt;li&gt;Who owns those Pods?&lt;/li&gt;
&lt;li&gt;Which Nodes are involved?&lt;/li&gt;
&lt;li&gt;Are there obvious factual signals, such as missing endpoints or no ready Pods?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That is the kind of context &lt;a href="https://github.com/lucasepe/kctx" rel="noopener noreferrer"&gt;&lt;code&gt;kctx&lt;/code&gt;&lt;/a&gt; tries to assemble.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kctx trace service payments-api &lt;span class="nt"&gt;--namespace&lt;/span&gt; payments
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For a namespace-level view:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kctx health namespace payments
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For a focused resource view:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kctx explain pod api-xyz &lt;span class="nt"&gt;--namespace&lt;/span&gt; payments
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And when you need a deterministic JSON snapshot for automation or incident review:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kctx dump namespace payments &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; payments-dump.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The important constraint: read-only
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/lucasepe/kctx" rel="noopener noreferrer"&gt;&lt;code&gt;kctx&lt;/code&gt;&lt;/a&gt; does not mutate Kubernetes resources.&lt;/p&gt;

&lt;p&gt;It does not:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;restart workloads&lt;/li&gt;
&lt;li&gt;apply manifests&lt;/li&gt;
&lt;li&gt;patch resources&lt;/li&gt;
&lt;li&gt;delete anything&lt;/li&gt;
&lt;li&gt;perform remediation&lt;/li&gt;
&lt;li&gt;claim to know the root cause&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That is not because remediation is uninteresting. It is because I think the context layer should be boring, auditable, and safe before anything else is built on top of it.&lt;/p&gt;

&lt;p&gt;This becomes even more important when AI agents enter the picture.&lt;/p&gt;

&lt;p&gt;If an agent needs Kubernetes context, I would rather give it a narrow read-only tool that returns structured facts than hand it broad cluster access and hope the prompt is enough of a safety boundary.&lt;/p&gt;

&lt;h2&gt;
  
  
  Kubernetes context for AI agents
&lt;/h2&gt;

&lt;p&gt;One of the areas I am experimenting with is exposing &lt;code&gt;kctx&lt;/code&gt; through the Model Context Protocol.&lt;/p&gt;

&lt;p&gt;Current serve modes include:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kctx serve &lt;span class="nt"&gt;--mode&lt;/span&gt; mcp
kctx serve &lt;span class="nt"&gt;--mode&lt;/span&gt; mcp-sse
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The MCP tools currently cover the same core context operations:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;get_namespace_health&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;explain_resource&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;trace_service&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;get_pod_graph&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;dump_namespace&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The idea is simple: let an AI assistant ask for Kubernetes context without giving it mutation capabilities.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;No remediation.&lt;/li&gt;
&lt;li&gt;No raw YAML firehose.&lt;/li&gt;
&lt;li&gt;No root-cause guessing dressed up as certainty.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Just compact operational facts that can be used as evidence.&lt;/p&gt;

&lt;p&gt;There is also an MCP/SSE release test guide for anyone who wants to try this with a local kind cluster, the released Helm chart, Online Boutique, ngrok, Codex, Claude Code, or ChatGPT Developer Mode:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/lucasepe/kctx/tree/main/docs/kctx-mcp-sse-release-test-guide.pdf" rel="noopener noreferrer"&gt;https://github.com/lucasepe/kctx/tree/main/docs/kctx-mcp-sse-release-test-guide.pdf&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Important note: the MCP/SSE endpoint is read-only, but built-in AuthN/AuthZ is not production-ready yet. Treat it as local-lab or trusted-network tooling for now, or put it behind an external access-control layer.&lt;/p&gt;

&lt;h2&gt;
  
  
  CRDs need semantics, not wishful thinking
&lt;/h2&gt;

&lt;p&gt;Another design choice: &lt;a href="https://github.com/lucasepe/kctx" rel="noopener noreferrer"&gt;&lt;code&gt;kctx&lt;/code&gt;&lt;/a&gt; does not pretend that every custom resource can be understood generically.&lt;/p&gt;

&lt;p&gt;Kubernetes discovery can tell you that a CRD exists. It cannot tell you what that CRD means operationally.&lt;/p&gt;

&lt;p&gt;So &lt;a href="https://github.com/lucasepe/kctx" rel="noopener noreferrer"&gt;&lt;code&gt;kctx&lt;/code&gt;&lt;/a&gt; uses explicit adapters for ecosystem-specific resources. An adapter can translate a CRD into the same core model used by the rest of the project: resource identity, compact status, related entities, relations, signals, and graph nodes or edges.&lt;/p&gt;

&lt;p&gt;The current adapter set includes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Argo CD &lt;code&gt;Application&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Argo CD &lt;code&gt;AppProject&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;cert-manager &lt;code&gt;Certificate&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That approach is slower than saying "we support every CRD", but I think it is more honest. If a tool is going to describe operational context, it should know what it is describing.&lt;/p&gt;

&lt;h2&gt;
  
  
  JSON first, because scripts and agents need contracts
&lt;/h2&gt;

&lt;p&gt;The CLI and HTTP API emit versioned JSON by default.&lt;/p&gt;

&lt;p&gt;Responses include a schema version and kind, for example:&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;"schemaVersion"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"kctx.io/v1alpha1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"kind"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"NamespaceHealth"&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;The repository includes machine-readable JSON schemas under:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;schemas/kctx.io/v1alpha1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That part may sound less exciting than graphs or agents, but it is one of the pieces I care about most.&lt;/p&gt;

&lt;p&gt;If humans are the only users, text output can be enough. If scripts, CI systems, incident tooling, and AI agents are also users, the output needs a contract.&lt;/p&gt;

&lt;h2&gt;
  
  
  Data safety
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/lucasepe/kctx" rel="noopener noreferrer"&gt;&lt;code&gt;kctx&lt;/code&gt;&lt;/a&gt;` is designed to provide operational context, not sensitive data.&lt;/p&gt;

&lt;p&gt;It avoids returning raw manifests, Secret data, ConfigMap data, raw environment variables, logs, and workload metrics.&lt;/p&gt;

&lt;p&gt;Supported outputs also pass metadata and Kubernetes messages through a small redaction policy for common secret-bearing keys and text patterns.&lt;/p&gt;

&lt;p&gt;This is not a magic privacy shield, but it is an intentional boundary in the design.&lt;/p&gt;

&lt;h2&gt;
  
  
  A tiny example workflow
&lt;/h2&gt;

&lt;p&gt;Install:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&lt;/code&gt;&lt;code&gt;bash&lt;br&gt;
curl -fsSL https://raw.githubusercontent.com/lucasepe/kctx/main/install.sh | bash&lt;br&gt;
&lt;/code&gt;&lt;code&gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Run against your current Kubernetes context:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&lt;/code&gt;&lt;code&gt;bash&lt;br&gt;
kctx health namespace default&lt;br&gt;
kctx explain pod &amp;lt;pod-name&amp;gt; --namespace default&lt;br&gt;
kctx trace service &amp;lt;service-name&amp;gt; --namespace default&lt;br&gt;
kctx graph pod &amp;lt;pod-name&amp;gt; --namespace default --render mermaid&lt;br&gt;
kctx dump namespace default&lt;br&gt;
&lt;/code&gt;&lt;code&gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Or run the read-only HTTP server:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&lt;/code&gt;&lt;code&gt;bash&lt;br&gt;
kctx serve&lt;br&gt;
curl http://localhost:8080/health/namespace/default&lt;br&gt;
&lt;/code&gt;&lt;code&gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Or install the in-cluster server with Helm:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&lt;/code&gt;&lt;code&gt;bash&lt;br&gt;
VERSION=0.3.0&lt;br&gt;
helm upgrade --install kctx \&lt;br&gt;
  "https://github.com/lucasepe/kctx/releases/download/v${VERSION}/kctx-${VERSION}.tgz" \&lt;br&gt;
  --namespace kctx-system \&lt;br&gt;
  --create-namespace&lt;br&gt;
&lt;/code&gt;&lt;code&gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Then:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&lt;/code&gt;&lt;code&gt;bash&lt;br&gt;
kubectl -n kctx-system port-forward svc/kctx 8080:8080&lt;br&gt;
curl http://localhost:8080/health/namespace/default&lt;br&gt;
&lt;/code&gt;&lt;code&gt;&lt;/code&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What I am looking for
&lt;/h2&gt;

&lt;p&gt;The project is still under active development. It is useful today, but I am still hardening packaging, production deployment guidance, auth boundaries for server mode, and client compatibility around MCP/SSE.&lt;/p&gt;

&lt;p&gt;I would love feedback from SREs, platform engineers, Kubernetes operators, and people experimenting with AI-assisted operations.&lt;/p&gt;

&lt;p&gt;In particular:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Does the output feel like useful operational context?&lt;/li&gt;
&lt;li&gt;Are the signals too noisy, too sparse, or missing obvious facts?&lt;/li&gt;
&lt;li&gt;Which CRDs would be most valuable to support next?&lt;/li&gt;
&lt;li&gt;Does the JSON contract work for your scripts or internal tools?&lt;/li&gt;
&lt;li&gt;Does the MCP interface fit how you want AI agents to inspect infrastructure?&lt;/li&gt;
&lt;li&gt;Where does the install, Helm chart, or local test flow feel confusing?&lt;/li&gt;
&lt;li&gt;What would make you trust a tool like this in a production debugging workflow?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you try the MCP/SSE path, I am especially interested in:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;OS and Kubernetes/kind version&lt;/li&gt;
&lt;li&gt;AI client and version&lt;/li&gt;
&lt;li&gt;transport used: localhost, port-forward, ngrok, or internal URL&lt;/li&gt;
&lt;li&gt;whether the standalone smoke test passed&lt;/li&gt;
&lt;li&gt;whether the AI client discovered and called the tools&lt;/li&gt;
&lt;li&gt;any rough edges in the responses&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The repo
&lt;/h2&gt;

&lt;p&gt;GitHub:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/lucasepe/kctx" rel="noopener noreferrer"&gt;https://github.com/lucasepe/kctx&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If this idea resonates with you, a star would help the project reach more Kubernetes and platform people.&lt;/p&gt;

&lt;p&gt;But even more useful: open an issue, tell me where the model feels wrong, or share a debugging scenario where structured context would have saved time.&lt;/p&gt;

&lt;p&gt;That is the kind of feedback that can make &lt;a href="https://github.com/lucasepe/kctx" rel="noopener noreferrer"&gt;&lt;code&gt;kctx&lt;/code&gt;&lt;/a&gt; sharper.&lt;/p&gt;

</description>
      <category>kubernetes</category>
      <category>sre</category>
      <category>opensource</category>
      <category>ai</category>
    </item>
    <item>
      <title>We Submitted 59 PRs and Got 0 Merged — Here Is What We Learned</title>
      <dc:creator>Кирилл</dc:creator>
      <pubDate>Mon, 15 Jun 2026 08:00:17 +0000</pubDate>
      <link>https://dev.to/_1353e04f14b156240b/we-submitted-59-prs-and-got-0-merged-here-is-what-we-learned-1331</link>
      <guid>https://dev.to/_1353e04f14b156240b/we-submitted-59-prs-and-got-0-merged-here-is-what-we-learned-1331</guid>
      <description>&lt;p&gt;I've been working on integrating AI-powered features into my e-commerce platform for the past year. Honestly, it's been a wild ride. My team and I decided to contribute to an open-source project that aligns with our goals, hoping to give back to the community and gain some experience. We spent 3 months submitting 59 pull requests, but none of them were merged. I remember last Tuesday, I was going through our 3-server setup, trying to figure out why our changes weren't being accepted.&lt;/p&gt;

&lt;p&gt;The project we contributed to is a popular AI-powered chatbot built using Node.js and TensorFlow.js. We chose this project because it aligns with our system's requirements, and we believed that our contributions could make a significant impact. Our goal was to improve the chatbot's natural language processing capabilities by integrating a custom intent recognition model. The thing is, we didn't just want to contribute to the project - we wanted to learn from it too.&lt;/p&gt;

&lt;p&gt;We started by forking the repository and creating a new branch for our contributions. Our first PR was a simple bug fix, which we thought would be easy to get merged. However, the maintainers asked us to add more test cases and improve the code documentation. We obliged, and here's an example of how we added test cases using Jest:&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="c1"&gt;// tests/intentRecognition.test.js&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;intentRecognition&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../intentRecognition&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nf"&gt;describe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;intentRecognition&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="nf"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;should recognize intent correctly&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;input&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;I want to buy a product&lt;/span&gt;&lt;span class="dl"&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;expectedOutput&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;buy_product&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;intentRecognition&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;)).&lt;/span&gt;&lt;span class="nf"&gt;toBe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;expectedOutput&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;We also improved the code documentation by adding JSDoc comments:&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="c1"&gt;// intentRecognition.js&lt;/span&gt;
&lt;span class="cm"&gt;/**
 * Recognizes the intent behind a given input string.
 * @param {string} input - The input string to recognize intent from.
 * @returns {string} The recognized intent.
 */&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;intentRecognition&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// implementation&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;One of our PRs aimed to improve the chatbot's performance by reducing the latency of the intent recognition model. Turns out, we were able to achieve this by optimizing the model's architecture and using a more efficient algorithm. We measured the performance improvement using the &lt;code&gt;performance-now&lt;/code&gt; library:&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="c1"&gt;// performanceTest.js&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;performance&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;performance-now&lt;/span&gt;&lt;span class="dl"&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;intentRecognition&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../intentRecognition&lt;/span&gt;&lt;span class="dl"&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;input&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;I want to buy a product&lt;/span&gt;&lt;span class="dl"&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;startTime&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;performance&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;output&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;intentRecognition&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;input&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;endTime&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;performance&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;latency&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;endTime&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;startTime&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Latency: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;latency&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;ms`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Our optimization reduced the latency from 500ms to 200ms, resulting in a 60% improvement. This was a significant win for us, and we were excited to see the impact it could have on our system.&lt;/p&gt;

&lt;p&gt;Although none of our PRs were merged, we still benefited from the experience. We learned how to optimize our system's performance, which resulted in a 30% reduction in cloud costs. We also improved our testing and documentation processes, which saved us 10 hours of development time per week. This was a huge win for us, and we were able to apply these lessons to our production system.&lt;/p&gt;

&lt;p&gt;We spent a total of 240 hours working on the PRs, which is equivalent to 6 weeks of full-time development. Although it was a significant investment, we gained valuable experience and insights that we can apply to our system. We also developed a custom AI agent that we can use in production, which will save us 20 hours of development time per month.&lt;/p&gt;

&lt;p&gt;In the end, I realized that the time and effort we invested were not wasted. We saved around 40 hours of development time and $1,500 in cloud costs per month. And when I did the math, I was amazed to see that we saved our company $27,000 over the next 6 months. It just goes to show that even unmerged PRs can have a significant impact on your business.&lt;/p&gt;

</description>
      <category>opensource</category>
      <category>github</category>
      <category>ai</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Our OS AI skills framework is actually getting some heat - new contributors welcome &lt;3</title>
      <dc:creator>Ross Peili</dc:creator>
      <pubDate>Mon, 15 Jun 2026 07:51:55 +0000</pubDate>
      <link>https://dev.to/rosspeili/our-os-ai-skills-framework-is-actually-getting-some-heat-new-contributors-welcome-3-43c0</link>
      <guid>https://dev.to/rosspeili/our-os-ai-skills-framework-is-actually-getting-some-heat-new-contributors-welcome-3-43c0</guid>
      <description>&lt;p&gt;Today, we released Skillware v0.3.6, Skillware is basiclaly an open-source framework for packaging Python capabilities (wallet screening, PDF tools, compliance checks, etc.) as skills agents call via normal tool APIs, instead of generating one-off code each time.&lt;/p&gt;

&lt;p&gt;This release is mostly contributor-facing: CLI works out of the box (&lt;code&gt;pip install skillware&lt;/code&gt;, &lt;code&gt;python -m skillware&lt;/code&gt; fallback), clearer help, CI runs bundle tests under &lt;code&gt;skills/&lt;/code&gt;, and a small &lt;code&gt;wallet_screening&lt;/code&gt; fix, and this made me pause for a moment and be grateful of all the contributors and what we've built.&lt;/p&gt;

&lt;p&gt;Today, we have over 40 stars and 12 contributors from all over the world. I know it might sound like nothing to some, but we started from zero, and slowly built this upwards together. I won't explain here why Skillware is better than agent skills, you can check the docs or read articles about it, but I wanna share why I am so excited about these numbers, even tho again, to some they might sound non worthy of hype.&lt;/p&gt;

&lt;p&gt;Initially, we built skillware having machines in mind. Most people are building AI, apps, services, tools, products, targeting humans. But in 2026, AI is your core audience, the one that makes up more than half of the internet traffic. I mean, even when humans dyor they essentially employ an AI to do the search, even when you google things, AI is replying. So, the idea was to make Skillware easily accessible, discoverable, parsable, testable, and usable by LLMs and AI Agents with 0 friction.&lt;/p&gt;

&lt;p&gt;We built the website in a way that makes it easy for agents to find, browse skills, find skills they need, and use them out of the box with one code block, no matter which model or framework they are coming from.&lt;/p&gt;

&lt;p&gt;On top of that, our repo is not only AI friendly, but AI focused. YES! we expect that everyone is using AI tools, code assitsants and AI enabled IDEs. There is no excuse to not do it in 2026. Our repo is build in such a way, that literally any agent or model can understand it instantly and start solving issues with single shots, without back and forths, without breaking files, or ignoring important ripple effects or complementary files etc.&lt;/p&gt;

&lt;p&gt;I take this moment to celebrate Skillware. Even if I am celebrating alone ❤️ and I would like to welcome anyone who wants to contribute to open source AI, or sharpen their python skills to join us and give it a spin, not just a project/tool, but also as modern clean cut repo tailored for agents at work. Lots of good first issues, as well as complex and sophisticated skill bundles that are not just silly md prompts.&lt;/p&gt;

&lt;p&gt;You can check the repo at &lt;a href="https://github.com/arpahls/skillware" rel="noopener noreferrer"&gt;arpahls/skillware&lt;/a&gt;, install with pip install skillware, or visit &lt;a href="https://skillware.site" rel="noopener noreferrer"&gt;skillware.site&lt;/a&gt;&lt;/p&gt;

</description>
      <category>opensource</category>
      <category>skillware</category>
      <category>agentskills</category>
      <category>ai</category>
    </item>
    <item>
      <title>I resurrected an archived C++/Qt6 desktop mascot and injected a fully autonomous local AI agent core into it (Powered by Ollama/Qwen)</title>
      <dc:creator>Lumina403</dc:creator>
      <pubDate>Mon, 15 Jun 2026 07:47:09 +0000</pubDate>
      <link>https://dev.to/lumina403/i-resurrected-an-archived-cqt6-desktop-mascot-and-injected-a-fully-autonomous-local-ai-agent-j3h</link>
      <guid>https://dev.to/lumina403/i-resurrected-an-archived-cqt6-desktop-mascot-and-injected-a-fully-autonomous-local-ai-agent-j3h</guid>
      <description>&lt;p&gt;Hey everyone,&lt;/p&gt;

&lt;p&gt;I’ve been working on a small passion project for the past few weeks and wanted to share it here: Lumina AI.&lt;/p&gt;

&lt;p&gt;It started as me reviving an old archived project called Shijima-Qt—a simple Qt desktop mascot. I always liked the idea, so I tried to push it further and turn it into something more useful: a lightweight, offline AI desktop agent.&lt;/p&gt;

&lt;p&gt;I’m a 17-year-old self-taught developer from Indonesia, and this project has basically been my way of learning more about C++, desktop applications, and local AI systems by building something far beyond what I originally thought I could handle.&lt;/p&gt;

&lt;p&gt;Some of the things I ended up implementing include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Local AI integration through Ollama&lt;/li&gt;
&lt;li&gt;A native tool-calling system written in C++&lt;/li&gt;
&lt;li&gt;Desktop and active-window awareness&lt;/li&gt;
&lt;li&gt;Basic file and system automation&lt;/li&gt;
&lt;li&gt;Lightweight web scraping using Qt networking&lt;/li&gt;
&lt;li&gt;Persistent JSON-based memory between sessions&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The project is built with C++17, Qt6, Make, and Ollama, with a strong focus on staying lightweight and running entirely offline.&lt;/p&gt;

&lt;p&gt;One thing I tried to be careful about was preserving the original project's history. The repository still contains the full commit history from Shijima-Qt, since I see this more as continuing an abandoned idea rather than replacing it.&lt;/p&gt;

&lt;p&gt;The project is open source under GPLv3.&lt;/p&gt;

&lt;p&gt;I'm still learning, so I'd be especially interested in hearing how more experienced C++ and AI developers would approach some of these problems differently. If you spot architectural mistakes, questionable design decisions, or areas that could be improved, I'd genuinely love to learn from the feedback.&lt;/p&gt;

&lt;p&gt;Repository:&lt;br&gt;
&lt;a href="https://github.com/Lumina403/Lumina-AI" rel="noopener noreferrer"&gt;https://github.com/Lumina403/Lumina-AI&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>programming</category>
      <category>opensource</category>
      <category>automation</category>
    </item>
    <item>
      <title>Wavelength Calculator: Easily Calculate Wave Length, Frequency, and Wave Speed</title>
      <dc:creator>CloudAiRambo</dc:creator>
      <pubDate>Mon, 15 Jun 2026 07:43:46 +0000</pubDate>
      <link>https://dev.to/cloudairambo/wavelength-calculator-easily-calculate-wave-length-frequency-and-wave-speed-4e9i</link>
      <guid>https://dev.to/cloudairambo/wavelength-calculator-easily-calculate-wave-length-frequency-and-wave-speed-4e9i</guid>
      <description>&lt;p&gt;Understanding wavelength is essential in physics, engineering, telecommunications, optics, and even everyday technologies like Wi-Fi, radio, and mobile networks. Whether you're a student learning wave mechanics or a professional working with electromagnetic signals, calculating wavelength accurately is important.&lt;/p&gt;

&lt;p&gt;To make calculations fast and error-free, try the free online Wavelength Calculator:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.cloudaipdf.com/calculators/wavelength/" rel="noopener noreferrer"&gt;https://www.cloudaipdf.com/calculators/wavelength/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;What Is Wavelength?&lt;/p&gt;

&lt;p&gt;Wavelength is the distance between two identical points in a repeating wave, such as two consecutive crests or troughs.&lt;/p&gt;

&lt;p&gt;It is commonly represented by the Greek letter λ (lambda).&lt;/p&gt;

&lt;p&gt;Wavelength is usually measured in:&lt;/p&gt;

&lt;p&gt;Meters (m)&lt;br&gt;
Centimeters (cm)&lt;br&gt;
Millimeters (mm)&lt;br&gt;
Nanometers (nm)&lt;/p&gt;

&lt;p&gt;The wavelength of a wave depends on both its frequency and speed.&lt;/p&gt;

&lt;p&gt;The Wavelength Formula&lt;/p&gt;

&lt;p&gt;The standard formula for wavelength is:&lt;/p&gt;

&lt;p&gt;λ = v ÷ f&lt;/p&gt;

&lt;p&gt;Where:&lt;/p&gt;

&lt;p&gt;λ = Wavelength&lt;br&gt;
v = Wave speed&lt;br&gt;
f = Frequency&lt;/p&gt;

&lt;p&gt;This equation shows that wavelength and frequency are inversely proportional.&lt;/p&gt;

&lt;p&gt;When frequency increases, wavelength decreases.&lt;/p&gt;

&lt;p&gt;When frequency decreases, wavelength increases.&lt;/p&gt;

&lt;p&gt;Real-World Examples of Wavelength&lt;/p&gt;

&lt;p&gt;Wavelength calculations are used in many fields:&lt;/p&gt;

&lt;p&gt;Radio Broadcasting&lt;/p&gt;

&lt;p&gt;Radio stations transmit signals at specific frequencies. Engineers use wavelength calculations when designing antennas and communication systems.&lt;/p&gt;

&lt;p&gt;Wi-Fi Networks&lt;/p&gt;

&lt;p&gt;Wireless routers operate at frequencies such as 2.4 GHz and 5 GHz. These frequencies correspond to different wavelengths that affect signal propagation.&lt;/p&gt;

&lt;p&gt;Fiber Optic Communication&lt;/p&gt;

&lt;p&gt;Light signals travel through optical fibers using specific wavelengths to transmit data across long distances.&lt;/p&gt;

&lt;p&gt;Medical Equipment&lt;/p&gt;

&lt;p&gt;Various imaging and diagnostic systems rely on wave behavior and wavelength calculations.&lt;/p&gt;

&lt;p&gt;Astronomy&lt;/p&gt;

&lt;p&gt;Scientists analyze wavelengths emitted by stars and galaxies to understand their composition and movement.&lt;/p&gt;

&lt;p&gt;Example Wavelength Calculation&lt;/p&gt;

&lt;p&gt;Suppose a wave travels at:&lt;/p&gt;

&lt;p&gt;Speed = 300,000,000 m/s&lt;br&gt;
Frequency = 100 MHz&lt;/p&gt;

&lt;p&gt;Using the formula:&lt;/p&gt;

&lt;p&gt;λ = 300,000,000 ÷ 100,000,000&lt;/p&gt;

&lt;p&gt;Result:&lt;/p&gt;

&lt;p&gt;Wavelength = 3 meters&lt;/p&gt;

&lt;p&gt;This means each complete wave cycle occupies a distance of three meters.&lt;/p&gt;

&lt;p&gt;Instead of performing manual calculations, you can instantly calculate results using:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.cloudaipdf.com/calculators/wavelength/" rel="noopener noreferrer"&gt;https://www.cloudaipdf.com/calculators/wavelength/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Why Use an Online Wavelength Calculator?&lt;/p&gt;

&lt;p&gt;Manual calculations are straightforward for simple values, but they become more complicated when dealing with:&lt;/p&gt;

&lt;p&gt;Scientific notation&lt;br&gt;
High frequencies&lt;br&gt;
Unit conversions&lt;br&gt;
Engineering calculations&lt;br&gt;
Laboratory measurements&lt;/p&gt;

&lt;p&gt;A dedicated calculator helps eliminate mistakes and saves time.&lt;/p&gt;

&lt;p&gt;Benefits include:&lt;/p&gt;

&lt;p&gt;Instant calculations&lt;br&gt;
Accurate results&lt;br&gt;
Easy-to-use interface&lt;br&gt;
Helpful for students and professionals&lt;br&gt;
No software installation required&lt;br&gt;
Common Mistakes When Calculating Wavelength&lt;br&gt;
Using Incorrect Units&lt;/p&gt;

&lt;p&gt;Frequency should be entered in the correct units, such as Hertz (Hz), kilohertz (kHz), megahertz (MHz), or gigahertz (GHz).&lt;/p&gt;

&lt;p&gt;Mixing Speed and Frequency Units&lt;/p&gt;

&lt;p&gt;Always ensure that speed and frequency values are compatible.&lt;/p&gt;

&lt;p&gt;Confusing Frequency and Wavelength&lt;/p&gt;

&lt;p&gt;Many beginners assume that higher frequency means longer wavelength. In reality, the opposite is true.&lt;/p&gt;

&lt;p&gt;Forgetting Scientific Notation&lt;/p&gt;

&lt;p&gt;Electromagnetic waves often involve very large or very small numbers, making scientific notation important.&lt;/p&gt;

&lt;p&gt;Who Can Benefit From a Wavelength Calculator?&lt;/p&gt;

&lt;p&gt;This tool is useful for:&lt;/p&gt;

&lt;p&gt;Physics students&lt;br&gt;
Science teachers&lt;br&gt;
Electrical engineers&lt;br&gt;
Telecommunications professionals&lt;br&gt;
Radio operators&lt;br&gt;
Researchers&lt;br&gt;
Network engineers&lt;br&gt;
Electronics hobbyists&lt;/p&gt;

&lt;p&gt;Anyone working with waves, signals, or electromagnetic radiation can benefit from quick wavelength calculations.&lt;/p&gt;

&lt;p&gt;Applications of Wavelength in Modern Technology&lt;/p&gt;

&lt;p&gt;Modern technology depends heavily on wavelength calculations.&lt;/p&gt;

&lt;p&gt;Examples include:&lt;/p&gt;

&lt;p&gt;Mobile communications&lt;br&gt;
Satellite systems&lt;br&gt;
Radar technology&lt;br&gt;
GPS navigation&lt;br&gt;
Optical networking&lt;br&gt;
Medical imaging&lt;br&gt;
Wireless internet&lt;br&gt;
Scientific research&lt;/p&gt;

&lt;p&gt;Understanding wavelength helps professionals optimize performance, improve signal quality, and design more efficient systems.&lt;/p&gt;

&lt;p&gt;Final Thoughts&lt;/p&gt;

&lt;p&gt;Wavelength is one of the fundamental concepts in physics and wave science. From radio transmissions and internet connectivity to optical communications and astronomy, wavelength calculations play a critical role in modern technology.&lt;/p&gt;

&lt;p&gt;If you need a fast and reliable way to calculate wavelength, frequency, or wave speed, try the free online Wavelength Calculator:&lt;/p&gt;

&lt;p&gt;👉 &lt;a href="https://www.cloudaipdf.com/calculators/wavelength/" rel="noopener noreferrer"&gt;https://www.cloudaipdf.com/calculators/wavelength/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Whether you're studying physics, designing communication systems, or solving engineering problems, this tool can help you obtain accurate results in seconds.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>programming</category>
      <category>productivity</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Working Capital Calculator: The Financial Metric Every Business Owner Should Track</title>
      <dc:creator>CloudAiRambo</dc:creator>
      <pubDate>Mon, 15 Jun 2026 07:41:13 +0000</pubDate>
      <link>https://dev.to/cloudairambo/working-capital-calculator-the-financial-metric-every-business-owner-should-track-1ld4</link>
      <guid>https://dev.to/cloudairambo/working-capital-calculator-the-financial-metric-every-business-owner-should-track-1ld4</guid>
      <description>&lt;p&gt;Running a business is not just about making sales. A company can be profitable on paper and still struggle to pay suppliers, employees, or day-to-day expenses. This is where working capital becomes one of the most important financial metrics for business owners, startups, freelancers, and finance professionals.&lt;/p&gt;

&lt;p&gt;If you want to quickly calculate your company's working capital, you can use this free online tool:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.cloudaipdf.com/calculators/working-capital/" rel="noopener noreferrer"&gt;https://www.cloudaipdf.com/calculators/working-capital/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;What Is Working Capital?&lt;/p&gt;

&lt;p&gt;Working capital measures a company's short-term financial health. It shows whether a business has enough resources to cover its immediate obligations and continue operating smoothly.&lt;/p&gt;

&lt;p&gt;The standard formula is:&lt;/p&gt;

&lt;p&gt;Working Capital = Current Assets − Current Liabilities&lt;/p&gt;

&lt;p&gt;Current assets typically include:&lt;/p&gt;

&lt;p&gt;Cash and cash equivalents&lt;br&gt;
Accounts receivable&lt;br&gt;
Inventory&lt;br&gt;
Short-term investments&lt;/p&gt;

&lt;p&gt;Current liabilities may include:&lt;/p&gt;

&lt;p&gt;Accounts payable&lt;br&gt;
Short-term loans&lt;br&gt;
Taxes payable&lt;br&gt;
Payroll obligations&lt;/p&gt;

&lt;p&gt;A positive result generally indicates that a business can comfortably meet its short-term financial commitments, while a negative result may signal liquidity challenges. Financial experts widely use this formula to evaluate operational efficiency and short-term financial stability.&lt;/p&gt;

&lt;p&gt;Why Working Capital Matters&lt;/p&gt;

&lt;p&gt;Many business owners focus only on revenue and profit. However, cash flow issues often arise even when sales are growing.&lt;/p&gt;

&lt;p&gt;Healthy working capital helps businesses:&lt;/p&gt;

&lt;p&gt;Pay suppliers on time&lt;br&gt;
Cover employee salaries&lt;br&gt;
Purchase inventory&lt;br&gt;
Handle unexpected expenses&lt;br&gt;
Invest in growth opportunities&lt;br&gt;
Improve creditworthiness with lenders&lt;/p&gt;

&lt;p&gt;Without sufficient working capital, businesses may face operational disruptions or be forced to rely on expensive short-term financing.&lt;/p&gt;

&lt;p&gt;Example Calculation&lt;/p&gt;

&lt;p&gt;Imagine a company has:&lt;/p&gt;

&lt;p&gt;Current Assets: $75,000&lt;br&gt;
Current Liabilities: $45,000&lt;/p&gt;

&lt;p&gt;Working Capital:&lt;/p&gt;

&lt;p&gt;$75,000 − $45,000 = $30,000&lt;/p&gt;

&lt;p&gt;This means the business has $30,000 available after covering its short-term obligations.&lt;/p&gt;

&lt;p&gt;Instead of calculating manually every time, you can use the free Working Capital Calculator:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.cloudaipdf.com/calculators/working-capital/" rel="noopener noreferrer"&gt;https://www.cloudaipdf.com/calculators/working-capital/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Signs of Strong Working Capital Management&lt;/p&gt;

&lt;p&gt;Businesses with effective working capital management often:&lt;/p&gt;

&lt;p&gt;Collect customer payments quickly&lt;br&gt;
Maintain optimal inventory levels&lt;br&gt;
Control operating expenses&lt;br&gt;
Negotiate favorable supplier terms&lt;br&gt;
Monitor cash flow regularly&lt;/p&gt;

&lt;p&gt;Good working capital management supports both stability and growth. Financial analysts often consider it one of the key indicators of operational efficiency.&lt;/p&gt;

&lt;p&gt;Common Mistakes Businesses Make&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Ignoring Accounts Receivable&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Outstanding invoices can create cash shortages even when sales are strong.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Overstocking Inventory&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Excess inventory ties up cash that could be used elsewhere.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Paying Suppliers Too Early&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;While maintaining good supplier relationships is important, paying invoices significantly before due dates can reduce available cash.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Not Monitoring Working Capital Regularly&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Many businesses review finances only monthly or quarterly, which can delay identifying cash flow issues.&lt;/p&gt;

&lt;p&gt;How a Working Capital Calculator Helps&lt;/p&gt;

&lt;p&gt;A reliable calculator eliminates manual calculations and reduces the chance of errors.&lt;/p&gt;

&lt;p&gt;The free calculator available at:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.cloudaipdf.com/calculators/working-capital/" rel="noopener noreferrer"&gt;https://www.cloudaipdf.com/calculators/working-capital/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;allows users to:&lt;/p&gt;

&lt;p&gt;Calculate working capital instantly&lt;br&gt;
Evaluate short-term financial health&lt;br&gt;
Support budgeting decisions&lt;br&gt;
Improve financial planning&lt;br&gt;
Save time compared to spreadsheet calculations&lt;/p&gt;

&lt;p&gt;Whether you're a startup founder, accountant, finance student, or small business owner, having quick access to this metric can improve financial decision-making.&lt;/p&gt;

&lt;p&gt;Who Should Use a Working Capital Calculator?&lt;/p&gt;

&lt;p&gt;This tool is useful for:&lt;/p&gt;

&lt;p&gt;Small business owners&lt;br&gt;
Startups&lt;br&gt;
Accountants&lt;br&gt;
Financial analysts&lt;br&gt;
Entrepreneurs&lt;br&gt;
Finance students&lt;br&gt;
Business consultants&lt;/p&gt;

&lt;p&gt;Anyone responsible for managing cash flow can benefit from understanding and tracking working capital.&lt;/p&gt;

&lt;p&gt;Final Thoughts&lt;/p&gt;

&lt;p&gt;Working capital is more than a simple accounting formula. It is a key indicator of a company's ability to operate, grow, and survive unexpected financial challenges.&lt;/p&gt;

&lt;p&gt;Regularly monitoring your working capital helps ensure your business maintains enough liquidity to meet short-term obligations while positioning itself for future growth.&lt;/p&gt;

&lt;p&gt;If you want a fast and free way to calculate working capital, try the online calculator here:&lt;/p&gt;

&lt;p&gt;👉 &lt;a href="https://www.cloudaipdf.com/calculators/working-capital/" rel="noopener noreferrer"&gt;https://www.cloudaipdf.com/calculators/working-capital/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Understanding your numbers today can help prevent financial problems tomorrow.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>programming</category>
      <category>productivity</category>
      <category>opensource</category>
    </item>
    <item>
      <title>5 heuristic bugs that made my design-token tool call a bright cream page "dark and moody"</title>
      <dc:creator>Yuvraj Angad Singh</dc:creator>
      <pubDate>Mon, 15 Jun 2026 07:36:19 +0000</pubDate>
      <link>https://dev.to/yuvrajangadsingh/5-heuristic-bugs-that-made-my-design-token-tool-call-a-bright-cream-page-dark-and-moody-3b7e</link>
      <guid>https://dev.to/yuvrajangadsingh/5-heuristic-bugs-that-made-my-design-token-tool-call-a-bright-cream-page-dark-and-moody-3b7e</guid>
      <description>&lt;p&gt;i maintain a small cli called &lt;a href="https://github.com/yuvrajangadsingh/brandmd" rel="noopener noreferrer"&gt;brandmd&lt;/a&gt;. it points a headless browser at any url, reads the computed css, and writes a &lt;code&gt;DESIGN.md&lt;/code&gt; that AI coding agents (Claude Code, Cursor, Gemini CLI) can read so they build on-brand UI instead of guessing.&lt;/p&gt;

&lt;p&gt;last week i ran it on cognition.ai's FrontierCode blog post and the output was embarrassing. the page is cream and bright, basically a magazine layout. here is what brandmd said about it:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;mood: "Dark and moody"&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;#F7F6F5&lt;/code&gt; got named "Light Muted Orange"&lt;/strong&gt; (it is off-white)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;#2200FF&lt;/code&gt; got named "Dark Blue"&lt;/strong&gt; (it is the most electric blue you have ever seen)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;border radii: &lt;code&gt;4px, 3.35544e+07px&lt;/code&gt;&lt;/strong&gt; (yes, scientific notation in a design doc)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;type scale: &lt;code&gt;11px, 11.05px, 11.5px, 12px, 12.5px, 12.75px, 13px&lt;/code&gt;&lt;/strong&gt; (seven sizes that are really three)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;every single one was a different heuristic bug. here is the anatomy of each, because they are the kind of mistakes that look fine in a unit test and fall apart on a real site.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. mood from averaging luminance
&lt;/h2&gt;

&lt;p&gt;the mood line came from averaging the luminance of the whole palette, then bucketing: high average is "light and airy", low is "dark and moody".&lt;/p&gt;

&lt;p&gt;the problem is averaging treats a tiny dark footer the same as a full-viewport cream background. cognition has a dark footer and a few dark chips. they dragged the average down far enough to flip the whole verdict, even though 90% of the screen is cream.&lt;/p&gt;

&lt;p&gt;the fix was to stop averaging and anchor to the dominant background instead. find the background color that covers the most viewport area, judge the mood from that. one color, weighted by how much of the page it actually owns.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Bright, high contrast; off-white background dominates with black text and vivid blue accents
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;that line is evidence-based now. it names the dominant color and what it does, instead of a vibe word.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. color names from nearest-RGB
&lt;/h2&gt;

&lt;p&gt;color naming used nearest-neighbor in RGB space against a list of named colors. cream (&lt;code&gt;#F7F6F5&lt;/code&gt;) has a slight warm cast, so the closest named color by raw RGB distance landed on a muted orange. technically the nearest point. completely wrong to a human.&lt;/p&gt;

&lt;p&gt;RGB distance is a bad model for how we name colors. switched to HSL rules instead:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;lightness above ~90% is a near-white. if the hue is warm it reads as cream, if cool it reads as off-white. it never gets a chromatic name.&lt;/li&gt;
&lt;li&gt;high saturation in the mid lightness band gets "vivid".&lt;/li&gt;
&lt;li&gt;everything else maps hue ranges to names.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;now &lt;code&gt;#F7F6F5&lt;/code&gt; is "off-white" and &lt;code&gt;#2200FF&lt;/code&gt; is "vivid blue".&lt;/p&gt;

&lt;h2&gt;
  
  
  3. blue is "dark" by luminance
&lt;/h2&gt;

&lt;p&gt;this one is the most counterintuitive. &lt;code&gt;#2200FF&lt;/code&gt; is a bright electric blue, but brandmd called it "dark blue". why? because the tone word was derived from luminance, and blue barely contributes to luminance.&lt;/p&gt;

&lt;p&gt;the standard luminance formula weights the channels roughly:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;luminance&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;0.2126&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;R&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mf"&gt;0.7152&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;G&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mf"&gt;0.0722&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;B&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;blue is only 7% of the weight. so a fully saturated blue scores darker than a muted brown. by luminance, &lt;code&gt;#2200FF&lt;/code&gt; genuinely is "dark", even though your eye reads it as loud and bright.&lt;/p&gt;

&lt;p&gt;the fix is to take tone words from HSL lightness, not luminance. lightness treats the channels evenly, so a mid-lightness blue reads as a mid-tone, and the saturation check adds "vivid".&lt;/p&gt;

&lt;h2&gt;
  
  
  4. scientific notation in a design doc
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;3.35544e+07px&lt;/code&gt;. that is what &lt;code&gt;getComputedStyle&lt;/code&gt; returns for &lt;code&gt;border-radius: 9999px&lt;/code&gt; on a pill-shaped button (the browser resolves the "make it fully round" intent into a giant pixel value).&lt;/p&gt;

&lt;p&gt;brandmd was printing the raw computed value straight into the markdown. worse, it was feeding that giant number into the shape-language inference, so a sharp-edged site with one pill button got described as "rounded and friendly".&lt;/p&gt;

&lt;p&gt;two fixes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;normalize any radius above ~999px to &lt;code&gt;9999px (pill)&lt;/code&gt; for display, keep it CSS-valid.&lt;/li&gt;
&lt;li&gt;exclude pill values from the "is this site rounded or sharp" judgment. judge shape from the largest non-pill radius.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  5. sub-pixel font sizes are noise
&lt;/h2&gt;

&lt;p&gt;the type scale had seven sizes between 11 and 13px because sub-pixel rendering and zoom produce values like &lt;code&gt;11.05px&lt;/code&gt; and &lt;code&gt;12.75px&lt;/code&gt;. those are not distinct steps in a design system, they are rendering artifacts.&lt;/p&gt;

&lt;p&gt;the fix is a clustering pass: round every size to the nearest 0.5px before ranking, then dedupe. seven noisy values collapse to the three real ones.&lt;/p&gt;

&lt;h2&gt;
  
  
  the lesson that actually mattered
&lt;/h2&gt;

&lt;p&gt;the bug that taught me the most was not in this list directly. while fixing the palette i found that &lt;strong&gt;element count is a terrible proxy for visual dominance.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;brandmd was ranking colors by how many elements used them. a 6% alpha black overlay sat on dozens of tiny chips, so by element count it outranked the actual page background that lived on one big element. the "primary" color was an overlay nobody consciously sees.&lt;/p&gt;

&lt;p&gt;weighting by viewport area share instead of element count fixed the palette ordering in one line. how much of the screen a color owns is a far better signal than how many nodes reference it.&lt;/p&gt;

&lt;h2&gt;
  
  
  try it
&lt;/h2&gt;

&lt;p&gt;all of this shipped in brandmd v0.12. you can reproduce the before and after yourself:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx brandmd@0.11.1 https://cognition.ai/blog/frontier-code   &lt;span class="c"&gt;# the bad output&lt;/span&gt;
npx brandmd@0.12.0 https://cognition.ai/blog/frontier-code   &lt;span class="c"&gt;# the fixed output&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;the &lt;a href="https://github.com/yuvrajangadsingh/brandmd/blob/main/CHANGELOG.md" rel="noopener noreferrer"&gt;full changelog&lt;/a&gt; has the side by side. repo is &lt;a href="https://github.com/yuvrajangadsingh/brandmd" rel="noopener noreferrer"&gt;here&lt;/a&gt; if you want to point your coding agent at a real design system instead of letting it guess.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>webdev</category>
      <category>css</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Stop pasting JWTs into random websites — I built a zero-dep CLI to decode them in your terminal</title>
      <dc:creator>benjamin</dc:creator>
      <pubDate>Mon, 15 Jun 2026 07:31:16 +0000</pubDate>
      <link>https://dev.to/_06a3df6b50aec966668fb/stop-pasting-jwts-into-random-websites-i-built-a-zero-dep-cli-to-decode-them-in-your-terminal-1lj1</link>
      <guid>https://dev.to/_06a3df6b50aec966668fb/stop-pasting-jwts-into-random-websites-i-built-a-zero-dep-cli-to-decode-them-in-your-terminal-1lj1</guid>
      <description>&lt;p&gt;You're debugging an auth issue. There's a JWT in a log line, or in an &lt;code&gt;Authorization&lt;/code&gt; header you copied out of the network tab. You need to know two things: &lt;strong&gt;what's in it&lt;/strong&gt;, and &lt;strong&gt;has it expired?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;So you do what everyone does — paste it into jwt.io.&lt;/p&gt;

&lt;p&gt;Stop for a second. That token is often a &lt;em&gt;live credential&lt;/em&gt;. You just pasted it into a third-party web page: it's in your browser history, maybe in someone's logs, maybe cached. For a token that's still valid, that's a real problem.&lt;/p&gt;

&lt;p&gt;The other option is the pipeline nobody can remember:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$TOKEN&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; | &lt;span class="nb"&gt;cut&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt;&lt;span class="nb"&gt;.&lt;/span&gt; &lt;span class="nt"&gt;-f2&lt;/span&gt; | &lt;span class="nb"&gt;base64&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt; 2&amp;gt;/dev/null | python &lt;span class="nt"&gt;-m&lt;/span&gt; json.tool
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;...which doesn't decode the header, doesn't tell you whether it's expired, breaks on base64url padding, and needs &lt;code&gt;base64 -d&lt;/code&gt; on Linux but &lt;code&gt;-D&lt;/code&gt; on macOS.&lt;/p&gt;

&lt;p&gt;So I built &lt;strong&gt;jwtpeek&lt;/strong&gt;: one command, fully offline, zero dependencies.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx jwtpeek &amp;lt;token&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="err"&gt;Header&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;span class="nl"&gt;"alg"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"HS256"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"typ"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"JWT"&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;span class="err"&gt;Payload&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;span class="nl"&gt;"sub"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"1234567890"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"John Doe"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"exp"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1609459200&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;span class="err"&gt;Claims&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="err"&gt;issued&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="mi"&gt;2020-12-31&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;23&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;00&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;00&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;UTC&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="err"&gt;y&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;166&lt;/span&gt;&lt;span class="err"&gt;d&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;ago&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="err"&gt;expires&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="mi"&gt;2021-01-01&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;00&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;00&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;00&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;UTC&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="err"&gt;EXPIRED&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="err"&gt;y&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;166&lt;/span&gt;&lt;span class="err"&gt;d&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;ago&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It turns every time claim (&lt;code&gt;exp&lt;/code&gt;, &lt;code&gt;iat&lt;/code&gt;, &lt;code&gt;nbf&lt;/code&gt;, &lt;code&gt;auth_time&lt;/code&gt;, …) into a real date plus "expires in 3h 21m" / "EXPIRED 2d ago" — which is usually the actual answer you were after.&lt;/p&gt;

&lt;h2&gt;
  
  
  It fits how you already paste tokens
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pbpaste | jwtpeek                  &lt;span class="c"&gt;# pipe it in&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$AUTH_HEADER&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; | jwtpeek      &lt;span class="c"&gt;# a leading "Bearer " / "Authorization:" is stripped&lt;/span&gt;
jwtpeek &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$t&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;--json&lt;/span&gt; | jq .payload  &lt;span class="c"&gt;# machine-readable; stdout stays pure&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Decoded output goes to &lt;strong&gt;stdout&lt;/strong&gt;; the "signature not verified" note goes to &lt;strong&gt;stderr&lt;/strong&gt;, so piping into &lt;code&gt;jq&lt;/code&gt; stays clean.&lt;/p&gt;

&lt;h2&gt;
  
  
  Script-friendly exit codes
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;0   decoded OK and not expired (or no exp claim)
1   decoded OK but expired
2   not a valid JWT
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;jwtpeek &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$TOKEN&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt;/dev/null 2&amp;gt;&amp;amp;1 &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"still valid"&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"expired or invalid"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Decode, not verify — on purpose
&lt;/h2&gt;

&lt;p&gt;The one thing I want to be loud about: &lt;strong&gt;jwtpeek does not check the signature.&lt;/strong&gt; It shows you what a token &lt;em&gt;says&lt;/em&gt;, not whether it's authentic. Verifying a signature needs the issuer's secret/public key, which is out of scope for a "what's in this thing" tool. Never make an authorization decision from decoded-but-unverified contents — jwtpeek prints a reminder on stderr every time.&lt;/p&gt;

&lt;h2&gt;
  
  
  A couple of design notes
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Zero dependencies, both ecosystems.&lt;/strong&gt; Node uses &lt;code&gt;Buffer&lt;/code&gt;, Python uses &lt;code&gt;base64&lt;/code&gt;/&lt;code&gt;json&lt;/code&gt;/&lt;code&gt;datetime&lt;/code&gt;. Nothing else — &lt;code&gt;npx&lt;/code&gt;/&lt;code&gt;pipx&lt;/code&gt; and it runs.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;NumericDate is seconds&lt;/strong&gt; per RFC 7519, but some issuers wrongly emit milliseconds. jwtpeek detects implausibly large values (a real seconds value won't reach 1e12 until the year 5138) and handles both.&lt;/li&gt;
&lt;li&gt;The Node and Python ports are behavior-identical: same flags, same exit codes, byte-identical &lt;code&gt;--json&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Install
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx jwtpeek &amp;lt;token&amp;gt;        &lt;span class="c"&gt;# Node &amp;gt;= 18&lt;/span&gt;
pip &lt;span class="nb"&gt;install &lt;/span&gt;jwtpeek        &lt;span class="c"&gt;# Python &amp;gt;= 3.8&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;npm: &lt;a href="https://www.npmjs.com/package/jwtpeek" rel="noopener noreferrer"&gt;https://www.npmjs.com/package/jwtpeek&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;PyPI: &lt;a href="https://pypi.org/project/jwtpeek" rel="noopener noreferrer"&gt;https://pypi.org/project/jwtpeek&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;GitHub: &lt;a href="https://github.com/jjdoor/jwtpeek" rel="noopener noreferrer"&gt;https://github.com/jjdoor/jwtpeek&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;How do you inspect tokens today — jwt.io, a &lt;code&gt;base64&lt;/code&gt; one-liner, an editor plugin? And would you actually want signature verification (bring-your-own-key) in a tool like this, or does that cross the line from "decoder" into "just do it properly in your app"? Curious what people think.&lt;/p&gt;

</description>
      <category>showdev</category>
      <category>security</category>
      <category>cli</category>
      <category>opensource</category>
    </item>
    <item>
      <title>I Built Calcify — All Calculators in One Place</title>
      <dc:creator>Parsun kumar Patel</dc:creator>
      <pubDate>Mon, 15 Jun 2026 07:29:07 +0000</pubDate>
      <link>https://dev.to/prashuncodes/i-built-calcify-all-calculators-in-one-place-2g3c</link>
      <guid>https://dev.to/prashuncodes/i-built-calcify-all-calculators-in-one-place-2g3c</guid>
      <description>&lt;p&gt;As developers, students, and professionals, we constantly search for calculators:&lt;/p&gt;

&lt;p&gt;✅ EMI Calculator&lt;br&gt;
✅ SIP Calculator&lt;br&gt;
✅ BMI Calculator&lt;br&gt;
✅ Percentage Calculator&lt;br&gt;
✅ Age Calculator&lt;br&gt;
✅ Unit Converters&lt;br&gt;
✅ And dozens more...&lt;/p&gt;

&lt;p&gt;I got tired of opening different websites every time I needed a simple calculation.&lt;/p&gt;

&lt;p&gt;So I built Calcify — a growing collection of calculators and tools available in one place.&lt;/p&gt;

&lt;p&gt;🔗 Try it here:&lt;br&gt;
&lt;a href="https://new-calcify-calcify.vercel.app" rel="noopener noreferrer"&gt;https://new-calcify-calcify.vercel.app&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Why I Built It&lt;br&gt;
Fast and mobile-friendly&lt;br&gt;
No unnecessary clutter&lt;br&gt;
Multiple calculators in one platform&lt;br&gt;
Free to use&lt;br&gt;
Regular updates and new tools being added&lt;br&gt;
Current Focus&lt;/p&gt;

&lt;p&gt;I'm continuously improving:&lt;/p&gt;

&lt;p&gt;UI/UX&lt;br&gt;
Performance&lt;br&gt;
More finance calculators&lt;br&gt;
More developer tools&lt;br&gt;
Better search and navigation&lt;br&gt;
Looking for Feedback&lt;/p&gt;

&lt;p&gt;I'd love to hear:&lt;/p&gt;

&lt;p&gt;What calculator/tool should I add next?&lt;br&gt;
What can be improved?&lt;br&gt;
Any bugs or issues you find?&lt;/p&gt;

&lt;p&gt;Building in public and learning every day. 🚀&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>productivity</category>
      <category>javascript</category>
      <category>opensource</category>
    </item>
    <item>
      <title>The Best React Data Grid Is the One You Will Not Hate After Feature Request Number Seven</title>
      <dc:creator>Vitalii Shevchuk</dc:creator>
      <pubDate>Mon, 15 Jun 2026 07:21:09 +0000</pubDate>
      <link>https://dev.to/vitalii_shevchuk_de4862c7/the-best-react-data-grid-is-the-one-you-will-not-hate-after-feature-request-number-seven-52o9</link>
      <guid>https://dev.to/vitalii_shevchuk_de4862c7/the-best-react-data-grid-is-the-one-you-will-not-hate-after-feature-request-number-seven-52o9</guid>
      <description>&lt;p&gt;I have never seen a product manager open a ticket called:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Turn this table into a small operating system.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It happens one perfectly reasonable request at a time.&lt;/p&gt;

&lt;p&gt;"Can we sort it?"&lt;/p&gt;

&lt;p&gt;"Can status be editable?"&lt;/p&gt;

&lt;p&gt;"Can I paste this column from Excel?"&lt;/p&gt;

&lt;p&gt;"Can the total stay visible?"&lt;/p&gt;

&lt;p&gt;"Can it remember my filters?"&lt;/p&gt;

&lt;p&gt;"Can it load the next ten thousand rows from the server?"&lt;/p&gt;

&lt;p&gt;By feature request number seven, the table has focus rules, validation, permissions, persistence, and performance problems.&lt;/p&gt;

&lt;p&gt;Congratulations. You built a product inside a rectangle.&lt;/p&gt;

&lt;p&gt;That is why most "best React data grid" articles miss the useful question. Every grid looks good with twenty rows and a sort icon.&lt;/p&gt;

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

&lt;p&gt;&lt;strong&gt;Which grid will you still like after the roadmap arrives?&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Here is my actual shortlist
&lt;/h2&gt;

&lt;p&gt;If I wanted the safest established answer, I would start with &lt;strong&gt;AG Grid&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;If I wanted complete control over markup and styling, I would start with &lt;strong&gt;TanStack Table&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;If the app already lived inside Material UI, &lt;strong&gt;MUI X Data Grid&lt;/strong&gt; would be hard to ignore.&lt;/p&gt;

&lt;p&gt;If users wanted an actual spreadsheet experience, I would test &lt;strong&gt;Handsontable&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;If a focused open-source grid was enough, I would test &lt;strong&gt;Comcast React Data Grid&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;If I were building an application workflow that could grow in several directions, I would put &lt;strong&gt;Ace Grid&lt;/strong&gt; in the final two.&lt;/p&gt;

&lt;p&gt;That last sentence is the interesting one.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Ace Grid is on this list
&lt;/h2&gt;

&lt;p&gt;Ace Grid is not trying to win the longest-feature-list contest.&lt;/p&gt;

&lt;p&gt;Its useful position is narrower:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;It is for the awkward middle where a table is no longer enough, a workbook is the wrong data model, and a full enterprise-grid commitment feels premature.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Ace Grid Core is MIT licensed. It covers the grid foundation: editing, selection, sorting, filtering, virtualization, CSV workflows, theming, and custom cells.&lt;/p&gt;

&lt;p&gt;When the product becomes more spreadsheet-like, Pro adds formulas, validation, Excel import and export, grouping, tree data, spanning, sparklines, and advanced filtering.&lt;/p&gt;

&lt;p&gt;When browser-owned data is no longer enough, Enterprise adds server row model, pivoting, charts, and master-detail.&lt;/p&gt;

&lt;p&gt;That progression matters.&lt;/p&gt;

&lt;p&gt;You can start with the workflow you have instead of buying the workflow somebody might request next year.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Ace Grid features that matter after the demo
&lt;/h2&gt;

&lt;p&gt;The tier path is only half the story.&lt;/p&gt;

&lt;p&gt;Ace Grid also has compatibility packages for AG Grid and MUI migrations. They translate known configuration and produce diagnostics about what maps, what needs manual work, and what may require another tier.&lt;/p&gt;

&lt;p&gt;That is more honest than promising a magic migration button.&lt;/p&gt;

&lt;p&gt;Ace Grid also has schema packages for describing grid state and validating structured output, including AI-generated results, before the application renders or applies them.&lt;/p&gt;

&lt;p&gt;This matters when an assistant returns a table that users can edit, approve, or use to trigger actions.&lt;/p&gt;

&lt;p&gt;The model should not be allowed to invent arbitrary component props and hope for the best.&lt;/p&gt;

&lt;p&gt;These are not the features that make a five-second demo exciting.&lt;/p&gt;

&lt;p&gt;They are the features that matter when a grid becomes infrastructure.&lt;/p&gt;

&lt;h2&gt;
  
  
  The honest reason not to choose Ace Grid
&lt;/h2&gt;

&lt;p&gt;Ace Grid is younger.&lt;/p&gt;

&lt;p&gt;There are fewer production years behind it, fewer community answers, and fewer engineers who already know it.&lt;/p&gt;

&lt;p&gt;That is a real cost.&lt;/p&gt;

&lt;p&gt;I would not choose it because of this article. I would build the ugliest screen in the product:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the custom editor everyone fears&lt;/li&gt;
&lt;li&gt;invalid Excel paste&lt;/li&gt;
&lt;li&gt;keyboard movement through errors&lt;/li&gt;
&lt;li&gt;pinned rows and columns&lt;/li&gt;
&lt;li&gt;a very wide virtualized view&lt;/li&gt;
&lt;li&gt;a slow server response&lt;/li&gt;
&lt;li&gt;a rejected save&lt;/li&gt;
&lt;li&gt;restored filters and column state&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If Ace Grid passes that screen, the staged architecture becomes a meaningful advantage.&lt;/p&gt;

&lt;p&gt;If it does not, choose the library that passes.&lt;/p&gt;

&lt;p&gt;That is how a challenger earns trust.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. AG Grid: the safe heavyweight
&lt;/h2&gt;

&lt;p&gt;AG Grid is the maturity and breadth choice.&lt;/p&gt;

&lt;p&gt;It has deep documentation, a large ecosystem, multiple framework integrations, and an enormous feature surface.&lt;/p&gt;

&lt;p&gt;For many teams, that ends the discussion.&lt;/p&gt;

&lt;p&gt;The question is not whether AG Grid can do enough. It almost certainly can.&lt;/p&gt;

&lt;p&gt;The question is how much platform you want, which edition your real workflow needs, and how much application code will become AG Grid-shaped.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Choose it when:&lt;/strong&gt; proven breadth matters more than keeping the grid footprint small.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. MUI X Data Grid: the ecosystem choice
&lt;/h2&gt;

&lt;p&gt;MUI X becomes very attractive when the rest of the application already uses Material UI.&lt;/p&gt;

&lt;p&gt;Shared themes, components, conventions, and team experience save real time.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Choose it when:&lt;/strong&gt; Material alignment removes work you would otherwise need to build.&lt;/p&gt;

&lt;p&gt;Do not choose it only because the demo looks familiar.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. TanStack Table: the ownership choice
&lt;/h2&gt;

&lt;p&gt;TanStack Table is headless.&lt;/p&gt;

&lt;p&gt;It gives you state and data-processing tools without pretending to be a finished visual grid.&lt;/p&gt;

&lt;p&gt;That is freedom.&lt;/p&gt;

&lt;p&gt;It is also work.&lt;/p&gt;

&lt;p&gt;Your application owns more rendering, editing, menus, keyboard behavior, virtualization integration, and accessibility.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Choose it when:&lt;/strong&gt; owning every pixel and interaction is intentional.&lt;/p&gt;

&lt;p&gt;"Lightweight" is not always less work. Sometimes the weight moved into your repository.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Handsontable: the spreadsheet choice
&lt;/h2&gt;

&lt;p&gt;Handsontable makes sense when users think in cells, ranges, formulas, paste operations, autofill, and undo.&lt;/p&gt;

&lt;p&gt;That is different from an application grid, even when both products look like rows and columns.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Choose it when:&lt;/strong&gt; spreadsheet behavior is the product, not a supporting interaction.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Comcast React Data Grid: the focused choice
&lt;/h2&gt;

&lt;p&gt;React Data Grid provides TypeScript, editing, selection, virtualization, frozen columns, custom renderers, and keyboard accessibility in a focused open-source package.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Choose it when:&lt;/strong&gt; that capable, narrower scope is the destination.&lt;/p&gt;

&lt;h2&gt;
  
  
  6. Ace Grid: the staged product-grid choice
&lt;/h2&gt;

&lt;p&gt;Ace Grid is for teams that want to begin with a real application grid without deciding on every future layer today.&lt;/p&gt;

&lt;p&gt;Start with MIT Core.&lt;/p&gt;

&lt;p&gt;Add spreadsheet behavior when users need it.&lt;/p&gt;

&lt;p&gt;Move operations to the server when the dataset and permissions require it.&lt;/p&gt;

&lt;p&gt;Use compatibility diagnostics when an existing grid needs to move.&lt;/p&gt;

&lt;p&gt;Use structured schemas when AI-generated table output needs validation and control.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Choose it when:&lt;/strong&gt; your table is becoming a product, but you still want to decide when complexity enters the architecture.&lt;/p&gt;

&lt;h2&gt;
  
  
  A brutally short decision guide
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Need the broadest proven platform? Test &lt;strong&gt;AG Grid&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Need Material UI consistency? Test &lt;strong&gt;MUI X&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Need headless primitives? Test &lt;strong&gt;TanStack Table&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Need a spreadsheet experience? Test &lt;strong&gt;Handsontable&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Need a focused open-source component? Test &lt;strong&gt;React Data Grid&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Need a grid that can start free and grow into spreadsheet, server, migration, and AI-shaped workflows? Test &lt;strong&gt;Ace Grid&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Build one unpleasant prototype
&lt;/h2&gt;

&lt;p&gt;Do not compare the finalists using their homepages.&lt;/p&gt;

&lt;p&gt;Give both of them the same bad afternoon:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;stable row IDs&lt;/li&gt;
&lt;li&gt;a custom status cell&lt;/li&gt;
&lt;li&gt;editable money&lt;/li&gt;
&lt;li&gt;invalid clipboard data&lt;/li&gt;
&lt;li&gt;keyboard navigation&lt;/li&gt;
&lt;li&gt;selection and filters&lt;/li&gt;
&lt;li&gt;pinned totals&lt;/li&gt;
&lt;li&gt;horizontal and vertical scrolling&lt;/li&gt;
&lt;li&gt;a delayed request&lt;/li&gt;
&lt;li&gt;a rejected save&lt;/li&gt;
&lt;li&gt;restored state&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Write down how much code your team had to own.&lt;/p&gt;

&lt;p&gt;Check the license tier you actually used.&lt;/p&gt;

&lt;p&gt;Run the keyboard path.&lt;/p&gt;

&lt;p&gt;The winner is the grid that makes ordinary product chaos boring.&lt;/p&gt;

&lt;h2&gt;
  
  
  My conclusion
&lt;/h2&gt;

&lt;p&gt;Ace Grid should not be positioned as the grid that beats every other grid. Nobody trustworthy can make that claim.&lt;/p&gt;

&lt;p&gt;Its position is more useful:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Ace Grid is the product-grid challenger for teams that have outgrown a table but still want control over when spreadsheet and enterprise complexity enter the architecture.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;AG Grid has more history.&lt;/p&gt;

&lt;p&gt;Ace Grid offers a cleaner staged bet.&lt;/p&gt;

&lt;p&gt;For the right React product, that difference matters.&lt;/p&gt;

&lt;p&gt;Read the complete comparison and official source list:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://ace-grid.com/guides/best-react-data-grid-libraries" rel="noopener noreferrer"&gt;https://ace-grid.com/guides/best-react-data-grid-libraries&lt;/a&gt;&lt;/p&gt;

</description>
      <category>react</category>
      <category>javascript</category>
      <category>webdev</category>
      <category>opensource</category>
    </item>
    <item>
      <title>From Signals to Ownership: Why I Built a Dataflow Kernel</title>
      <dc:creator>Luciano0322</dc:creator>
      <pubDate>Mon, 15 Jun 2026 07:17:57 +0000</pubDate>
      <link>https://dev.to/luciano0322/from-signals-to-ownership-why-i-built-a-dataflow-kernel-1h0f</link>
      <guid>https://dev.to/luciano0322/from-signals-to-ownership-why-i-built-a-dataflow-kernel-1h0f</guid>
      <description>&lt;p&gt;When I first started building &lt;code&gt;signal-kernel&lt;/code&gt;, I thought I was simply writing a signal library—a fine-grained reactive system not tied to any specific UI framework. On the surface, it had all the basic building blocks you would expect from a signal library:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Core primitives:&lt;/strong&gt; &lt;code&gt;Signal&lt;/code&gt;, &lt;code&gt;Computed&lt;/code&gt;, and &lt;code&gt;Effect&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Mechanisms:&lt;/strong&gt; dependency tracking and scheduling&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Extensions:&lt;/strong&gt; async resources and framework adapters&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It could build a reactive graph, track dependencies, update derived state precisely when data changed, and bridge the result into React or Vue. But the deeper I dug into the implementation, the more I realized the real problem wasn't about building another signal library. The core question was actually this: &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;In a complex application, who should truly own the dataflow?&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Fragmented Dataflow and the Derived State Problem
&lt;/h2&gt;

&lt;p&gt;In modern frontend applications, dataflow often feels natural at first. API data comes back, gets written into state, and components render the result. If we need derived data, we use &lt;code&gt;useMemo&lt;/code&gt;. If we need side effects, we use &lt;code&gt;useEffect&lt;/code&gt;. If we need async requests, we use a query library, and if we need shared state, we introduce a store.&lt;/p&gt;

&lt;p&gt;Individually, none of these solutions are wrong. React is not wrong. Vue is not wrong. TanStack Query is not wrong. Zustand and Jotai are not wrong either. The real problem appears when the system grows larger. At that point, the exact same logical dataflow starts getting split across multiple ownership models.&lt;/p&gt;

&lt;p&gt;Some state belongs to components, while other state belongs to a store. Some derived state is trapped inside the render phase, and async state lives inside a query cache. The system still works, but the boundaries of the dataflow start to depend heavily on conventions, team discipline, and developer memory. It becomes incredibly hard to answer one seemingly simple question: &lt;strong&gt;Who actually owns this derived state?&lt;/strong&gt; Is it the component, the store, the framework runtime, or just a temporary value calculated inside a hook?&lt;/p&gt;

&lt;h2&gt;
  
  
  Render Should Not Naturally Own the Entire Dataflow
&lt;/h2&gt;

&lt;p&gt;Frontend developers often treat render as the center of the system. This is completely understandable—what we look at and debug every day is the UI. So when data changes, our first instinct is usually: &lt;em&gt;"Which component needs to re-render?"&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;But if we reverse the question, the architecture looks very different. When data changes, perhaps the first question should be: &lt;em&gt;"Which pieces of derived data are actually affected?"&lt;/em&gt; Render is simply one kind of side effect caused by data changes. It is extremely important, but it should not naturally own the entire dataflow.&lt;/p&gt;

&lt;p&gt;This became one of the core architectural lessons I learned: &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;The reactive graph should first describe the relationships between data, while render should only be one consumer of that graph.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  From Signal Library to Dataflow Kernel
&lt;/h2&gt;

&lt;p&gt;If I only saw &lt;code&gt;signal-kernel&lt;/code&gt; as a signal library, then most design questions would stay at the API surface: Should it feel more like Solid? Should computed values be lazy or eager? Should it support batching? These are important, but they hide the deeper issue: When a piece of state changes, who is responsible for deciding which derived states are affected?&lt;/p&gt;

&lt;p&gt;In a traditional component-driven model, this usually happens during render:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Data changes → component re-executes → derived data is recalculated.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This model works beautifully for small applications, but it forces the lifecycle of derived state to follow the lifecycle of render. Once derived state becomes expensive, needs to be shared across frameworks, or needs to be deeply connected with async streams, this model becomes fragile.&lt;/p&gt;

&lt;p&gt;That is why the real goal of &lt;code&gt;signal-kernel&lt;/code&gt; was never simply to “reduce re-renders.” The goal was to &lt;strong&gt;detach derived dataflow from render ownership&lt;/strong&gt;. What I actually wanted to build was a dataflow kernel.&lt;/p&gt;

&lt;p&gt;A system that focuses on lower-level architectural concerns:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;How state becomes a pure source of truth.&lt;/li&gt;
&lt;li&gt;How derived state is tracked stably inside a reactive graph.&lt;/li&gt;
&lt;li&gt;How effects can be separated cleanly from the render lifecycle.&lt;/li&gt;
&lt;li&gt;How async work and continuously written streams can become part of the reactive graph while keeping clear state boundaries.&lt;/li&gt;
&lt;li&gt;How render can return to its proper role: a consumer, not the owner.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Keeping the Boundary: Thin Framework Adapters
&lt;/h2&gt;

&lt;p&gt;This way of thinking also directly shaped how I designed the React and Vue adapters. At the beginning, I naturally wanted to provide many convenient hooks and APIs that felt familiar to framework users. But over time, I became much more conservative.&lt;/p&gt;

&lt;p&gt;If an adapter becomes too thick, it quietly pulls ownership back into the UI framework. And once that happens, the data independence that &lt;code&gt;signal-kernel&lt;/code&gt; is trying to preserve starts to fade away.&lt;/p&gt;

&lt;p&gt;A cleaner and more stable boundary should look like this:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Core owns the reactive graph.&lt;/li&gt;
&lt;li&gt;Async-runtime owns the consistency of async state.&lt;/li&gt;
&lt;li&gt;Framework adapters only subscribe to and read snapshots.&lt;/li&gt;
&lt;li&gt;Render only draws the current result to the screen.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;An adapter should not redefine the dataflow. It should only be a transparent pipe into the framework.&lt;/p&gt;

&lt;h2&gt;
  
  
  Rethinking Framework Responsibility
&lt;/h2&gt;

&lt;p&gt;I want to make one thing clear: this series is not meant to criticize React or any other UI tool. React is still excellent at handling UI consistency, and TanStack Query solves a very real, difficult server-state problem.&lt;/p&gt;

&lt;p&gt;What I want to explore is a deeper architectural question:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;When we habitually put all data logic into the model of a UI framework, are we accidentally making render responsible for too much?&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If reactive dataflow itself can be an independent system, then what role should a UI framework actually play?&lt;/p&gt;

&lt;h2&gt;
  
  
  What I Was Really Studying Was Ownership
&lt;/h2&gt;

&lt;p&gt;While implementing the core and async-runtime of &lt;code&gt;signal-kernel&lt;/code&gt;, I kept running into a series of uncomfortable architectural questions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;After a Promise resolves, is it really just a simple &lt;code&gt;setState&lt;/code&gt;?&lt;/li&gt;
&lt;li&gt;If a stream keeps emitting chunks, who should own its stable value, status, and error?&lt;/li&gt;
&lt;li&gt;After a mutation succeeds, is invalidation the responsibility of the query cache, or the reactive graph?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All of these questions eventually point to the same word: &lt;strong&gt;Ownership.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I originally thought I was building a signal library. But the more I built, the more I realized that what I was really studying was how the boundaries of dataflow should be redefined in increasingly complex frontend applications. APIs can change. Implementations can be replaced. But the core question remains the same:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;When data changes, who is responsible for understanding that change?&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If the answer is always render, then we are forced to keep layering workarounds around the UI framework. But if the answer is the reactive graph, then render can return to its most reasonable position. It is one outlet of the dataflow. It is one side effect. It is a consumer of the system, not the owner.&lt;/p&gt;

&lt;p&gt;That is the most important lesson I learned while building &lt;a href="https://github.com/Luciano0322/signal-kernel" rel="noopener noreferrer"&gt;&lt;code&gt;signal-kernel&lt;/code&gt;&lt;/a&gt;. If this idea resonates with you, I’m exploring it through &lt;a href="https://github.com/Luciano0322/signal-kernel" rel="noopener noreferrer"&gt;&lt;code&gt;signal-kernel&lt;/code&gt;&lt;/a&gt;, a framework-agnostic reactive dataflow kernel.&lt;/p&gt;

&lt;p&gt;The project is still evolving, but its direction is clear: &lt;strong&gt;render should be a consumer of the dataflow, not the owner.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In the next article, I want to continue exploring this question:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;What actually changes in frontend architecture when render no longer owns the entire dataflow?&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>webdev</category>
      <category>frontend</category>
      <category>architecture</category>
      <category>opensource</category>
    </item>
  </channel>
</rss>
