<?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: RoTSL</title>
    <description>The latest articles on DEV Community by RoTSL (@rotsl).</description>
    <link>https://dev.to/rotsl</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3818774%2F3a43cf64-9ded-407d-829e-4555f203a82e.png</url>
      <title>DEV Community: RoTSL</title>
      <link>https://dev.to/rotsl</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/rotsl"/>
    <language>en</language>
    <item>
      <title>Google I/O 2026 dropped a bomb on Android tooling, and nobody's talking about it (or maybe they are 😅)</title>
      <dc:creator>RoTSL</dc:creator>
      <pubDate>Thu, 21 May 2026 12:34:48 +0000</pubDate>
      <link>https://dev.to/rotsl/google-io-2026-dropped-a-bomb-on-android-tooling-and-nobodys-talking-about-it-or-maybe-they-are-2b3f</link>
      <guid>https://dev.to/rotsl/google-io-2026-dropped-a-bomb-on-android-tooling-and-nobodys-talking-about-it-or-maybe-they-are-2b3f</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.to/challenges/google-io-writing-2026-05-19"&gt;Google I/O Writing Challenge&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Google I/O 2026 wrapped on May 20 at the Shoreline Amphitheater in Mountain View, and I've spent the last two days reading every blog post, watching every session replay &lt;a href="the%20[main%20keynote](https://www.youtube.com/watch?v=wYSncx9zLIU),%20the%20[developer%20keynote](https://www.youtube.com/watch?v=aqmpZocmR8o),%20and%20the%20[What's%20New%20in%20Google%20AI%20session](https://www.youtube.com/watch?v=tfoSeH63yCg)"&gt;almost but not all&lt;/a&gt;, and digging through the actual documentation. The headline everyone ran with was "Gemini Spark is your new 24/7 AI agent" and "Antigravity 2.0 built an operating system from scratch." Those are flashy. They make good tweets.&lt;/p&gt;

&lt;p&gt;But something much more interesting happened at this I/O, something that actually changes how Android developers will write code starting after the keynote address, and most of the coverage missed it entirely. I want to talk about that. I also want to walk through Antigravity 2.0 in detail, because Google fundamentally rebuilt it, and the technical decisions they made reveal a lot about where developer tooling is heading. Finally, I want to look at the bigger picture of what Google announced and what it means for the people who actually have to ship apps.&lt;/p&gt;

&lt;p&gt;There's a lot to cover. I'll try to keep it useful.&lt;/p&gt;

&lt;h2&gt;
  
  
  The big picture: Agents aren't a demo anymore
&lt;/h2&gt;

&lt;p&gt;Before diving into the specific tools, let's establish what actually launched.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Gemini 3.5 Flash&lt;/strong&gt; is the new default model powering most of this. It outperforms last year's Gemini 3.1 Pro on coding and agentic benchmarks: 76.2% on Terminal-Bench 2.1, 83.6% on MCP Atlas, 1656 Elo on GDPval-AA, and 84.2% on CharXiv Reasoning for multimodal understanding.That last number matters because it means the same model handles code and visual output, which is how agents can now render Compose previews and understand what they're looking at. It runs about four times faster than other frontier models, and the pricing is $1.50 per million input tokens and $9.00 per million output tokens, with cached input at $0.15 per million.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Gemini Spark&lt;/strong&gt; is Google's 24/7 personal AI agent. It runs on Google Cloud infrastructure so it doesn't need your device to stay on. It connects to Gmail, Docs, Calendar, and can interact with the web through Chrome and third-party services.You feed it context (wedding plans, a research project, whatever) and it keeps working. It's exclusive to Google AI Pro and Ultra subscribers, rolling out in beta in the U.S. first.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Antigravity 2.0&lt;/strong&gt; graduated from an AI coding tool into a full agent orchestration platform. Standalone desktop app. No IDE. CLI. SDK. Multiple agents running in parallel. I'll break this down in detail below.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Android CLI 1.0&lt;/strong&gt; reached stable. This is the one I keep coming back to. More on this in a moment.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Android XR smart glasses&lt;/strong&gt; made with Samsung. &lt;strong&gt;Gemini Omni&lt;/strong&gt; for video generation. &lt;strong&gt;Native Android app building&lt;/strong&gt; directly in Google AI Studio. A new intelligent Search box that generates custom UIs in real time. There's a lot.&lt;/p&gt;

&lt;p&gt;I genuinely don't know how to feel about all of it. The technology is real. The demos are real. A personal agent that monitors your inbox and handles calendar gymnastics while you sleep? That's genuinely useful. An AI that can port an iOS app to native Android in hours instead of weeks? That solves a real problem for small teams. But there's something unsettling about agents churning through your email at 3am while nobody's watching, and I don't think that tension goes away just because the demos are impressive.&lt;/p&gt;

&lt;p&gt;For developers specifically, the message was unmistakable: Google doesn't care which AI agent you use anymore. They shipped &lt;strong&gt;Android CLI 1.0&lt;/strong&gt;, which gives Claude Code, OpenAI Codex, and Antigravity programmatic access to Android Studio's toolchain from the command line.That's a remarkable concession from a company that spent years building walled gardens. They looked at how developers actually work (switching between Claude Code, Codex, and Gemini depending on the task) and decided to make Android tooling available to all of them instead of forcing everyone into their own stack.&lt;/p&gt;

&lt;p&gt;Pichai said the industry is in a period of "hyper progress" but also "where people want to see real value in the products they use on a day-to-day basis." That's the right thing to say. Whether the products deliver is a separate question.&lt;/p&gt;

&lt;h2&gt;
  
  
  Antigravity 2.0: What actually changed under the hood
&lt;/h2&gt;

&lt;p&gt;Antigravity 2.0 is not an IDE update. Google ripped the agent manager out of the original Antigravity IDE and built it into a standalone desktop application available on macOS, Linux, and Windows.The IDE itself still exists as a separate product, but 2.0 is a completely different thing. It's a desktop app where the primary interaction model is conversation with an agent, not a code editor with AI features bolted on.&lt;/p&gt;

&lt;p&gt;The interface is built around conversations and artifacts. You describe what you want. The agent works on it. You review the artifacts it produces (code, documents, screenshots, browser operation recordings) and provide feedback directly on those artifacts to guide toward your desired outcome.&lt;/p&gt;

&lt;p&gt;This is a philosophical shift. In the old model, you wrote code and the AI helped. In the new model, the AI does the work and you supervise. Whether that feels like progress or like being demoted to code reviewer depends on your disposition. I'm still figuring out where I land.&lt;/p&gt;

&lt;h2&gt;
  
  
  Dynamic subagents
&lt;/h2&gt;

&lt;p&gt;The most technically interesting feature in 2.0 is dynamic subagents. The main agent can define and invoke child agents during execution to handle focused subtasks.These subagents are spawned dynamically, run in parallel, and get destroyed when their work is done.&lt;/p&gt;

&lt;p&gt;Why this matters: every LLM has a finite context window. If you ask an agent to build a complex system, the intermediate steps (reading files, making edits, running tests) fill up that window fast. The agent starts forgetting what it was doing, or starts making decisions based on stale context. Dynamic subagents solve this by isolating subtasks into separate context windows that don't pollute the main agent's working memory.&lt;/p&gt;

&lt;p&gt;Google's launch demo used 93 parallel subagents to build a functional operating system from scratch. The primary agent acted like a CTO: it understood the system architecture, broke the goal into domains, and spawned specialized subagents (one for the kernel, one for memory management, one for the filesystem, one for video drivers, one for keyboard drivers). Those subagents worked independently and returned their results to the main agent for integration.&lt;/p&gt;

&lt;p&gt;The numbers: 15,314 model requests, 339 million input tokens (with cache reads, output, and thinking tokens, that goes to over 2.6 billion), 12 hours of wall-clock time, and under $1,000 in API costs using Gemini 3.5 Flash.The OS could run FreeDoom, which is a real open-source Doom implementation.&lt;/p&gt;

&lt;p&gt;The OS was not production quality. It had no floating-point math support, no hardware acceleration, no complex multi-threading, no sandboxing, no JIT compilation.But it was built from a single high-level prompt with zero human guidance. That's the part that sticks with me.&lt;/p&gt;

&lt;h2&gt;
  
  
  Asynchronous task management and scheduled tasks
&lt;/h2&gt;

&lt;p&gt;Tasks in Antigravity 2.0 can run asynchronously. You can fire off a long-running task and continue having other conversations with the agent while it works in the background.The results eventually surface in the main conversation when the task completes.&lt;/p&gt;

&lt;p&gt;Scheduled Tasks are cron-style invocations. You define a schedule and the agent triggers automatically at the specified time.The /schedule slash command lets you write things like "every morning at 9am, summarize my inbox" directly in natural language.This moves the agent from a tool you call to something closer to a persistent automation pipeline.&lt;/p&gt;

&lt;h2&gt;
  
  
  JSON hooks
&lt;/h2&gt;

&lt;p&gt;Hooks let you intercept and control agent behavior at key execution points. You define them in a JSON configuration file. When the agent hits a trigger event, the hook fires and can allow, deny, or ask the user before proceeding.The hooks system supports deny, allow, ask_user, and enforce rules per tool, which gives you fine-grained control over what the agent can and cannot do without reading the underlying code.&lt;/p&gt;

&lt;h2&gt;
  
  
  Projects, not repositories
&lt;/h2&gt;

&lt;p&gt;In Antigravity 1.0, agent conversations were grouped by workspace, which meant one repository. In 2.0, they're grouped by "project," which can span multiple folders and enforce its own agent settings and permissions.This matters for real-world development where a single product often spans multiple repositories or codebases.&lt;/p&gt;

&lt;h2&gt;
  
  
  Slash commands
&lt;/h2&gt;

&lt;p&gt;The four new slash commands are worth knowing:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;/goal&lt;/code&gt; tells the agent to keep running until the specified task is completely finished, no intermediate input from you.This is for fire-and-forget work where you trust the agent enough to not need check-ins.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;/grill-me&lt;/code&gt; flips the interaction: before starting to implement, the agent asks you clarifying questions to align on the specific details of the plan.I've found this genuinely useful for avoiding the "agent confidently builds the wrong thing" problem.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;/schedule&lt;/code&gt; creates a one-time timer or recurring schedule for agent invocation.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;/browser&lt;/code&gt; explicitly tells the agent to use browser primitives. Google found that agents were still not capable enough to determine on their own when to use the browser, so they made it an explicit command for now.&lt;/p&gt;

&lt;h2&gt;
  
  
  Voice input
&lt;/h2&gt;

&lt;p&gt;The mic icon next to text input boxes now does live transcription instead of collecting raw audio files to pass to the model.It's a small feature, but it changes the interaction dynamic. You can think out loud while the agent works, which feels more natural than typing everything.&lt;/p&gt;

&lt;h2&gt;
  
  
  The SDK
&lt;/h2&gt;

&lt;p&gt;The Antigravity SDK gives you programmatic access to the same agent harness that powers Antigravity 2.0 and the Antigravity CLI. Your agent inherits a rich built-in toolset, a declarative safety-policy engine, lifecycle hooks for observing and steering every tool call, and stateful multi-turn sessions that persist across interactions.You can define custom agent behaviors and host them on your own infrastructure.&lt;/p&gt;

&lt;p&gt;The SDK supports MCP integration for connecting to external Model Context Protocol servers, and the policy system lets you define permission rules at the tool level.&lt;/p&gt;

&lt;h2&gt;
  
  
  Pricing and availability
&lt;/h2&gt;

&lt;p&gt;Antigravity 2.0 is free for all users. The new Google AI Ultra plan starts at $100/month with a 5x higher usage limit than the Pro plan, and there's a limited-time $100 bonus credit for new and existing subscribers who hit their quota limit.The top-tier Ultra plan was cut from $250 to $200/month (20x the Pro limit).&lt;/p&gt;

&lt;p&gt;Gemini Spark is gated behind Pro and Ultra subscriptions. Android CLI 1.0 requires Android Studio Quail 2 Canary 1 or later for the &lt;code&gt;android studio&lt;/code&gt; commands.&lt;/p&gt;

&lt;h2&gt;
  
  
  Android CLI 1.0: The announcement that actually changes things
&lt;/h2&gt;

&lt;p&gt;Everyone's talking about Antigravity 2.0 building an operating system. That's a great demo. But the announcement that actually matters for working Android developers is Android CLI 1.0 reaching stable. Here's why.&lt;/p&gt;

&lt;p&gt;For years, if you wanted to build Android apps with an AI coding agent, you had two options. Option one: use Google's tools (Android Studio with Gemini). Option two: struggle. Third-party agents like Claude Code couldn't access Android Studio's static analysis engine, its refactoring tools, its Compose preview renderer, or its dependency management. They were flying blind. They generated code without being able to verify it against the actual Android toolchain.&lt;/p&gt;

&lt;p&gt;Android CLI 1.0 fixes that. Through a new &lt;code&gt;android studio&lt;/code&gt; command group, any AI agent can now perform semantic symbol resolution, analyze files for warnings, render Jetpack Compose previews, and execute end-to-end UI tests, all from the terminal without opening the IDE.&lt;/p&gt;

&lt;p&gt;Google is positioning this explicitly as supporting whatever agent you want to use: Gemini in Android Studio, Antigravity, Claude Code, or Codex.That is a real shift in strategy.&lt;/p&gt;

&lt;h2&gt;
  
  
  The &lt;code&gt;android studio&lt;/code&gt; command
&lt;/h2&gt;

&lt;p&gt;The April preview release of Android CLI gave agents a clean binary for scaffolding projects, managing emulators, and running apps. Useful, but nothing that forced a workflow change. The stable 1.0 release adds the 'android studio' command group, which is the part that actually matters.&lt;/p&gt;

&lt;p&gt;Here's what agents can now do from the terminal:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;android studio find-declaration&lt;/code&gt; performs semantic symbol resolution. Your agent can ask "where is HotelDetailScreen defined?" and get the actual answer, not a text-match guess.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;android studio find-usages&lt;/code&gt; finds every reference to a symbol across the entire project.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;android studio render-compose-preview&lt;/code&gt; renders a Jetpack Compose preview to an image file from the terminal.This is the one that changes things. Your agent can literally see what your Composable looks like before suggesting changes, instead of pattern-matching on text and hoping the layout looks right.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;android studio analyze-file&lt;/code&gt; runs Android Studio's full static analysis engine on a file: lint warnings, R8 hints, deprecation alerts.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;android studio version-lookup&lt;/code&gt; queries live repository data and returns the actual latest stable version of a dependency.This is quietly excellent because agents guessing at Compose or AGP versions and hallucinating dependency coordinates is a common failure mode. &lt;code&gt;version-lookup&lt;/code&gt; eliminates that entire class of error.&lt;/p&gt;

&lt;p&gt;These commands require Android Studio Quail 2 Canary 1 or later to be running alongside the CLI. If you're on the stable Android Studio channel, the &lt;code&gt;android studio&lt;/code&gt; commands do nothing.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why the token numbers are real
&lt;/h2&gt;

&lt;p&gt;Google's internal experiments showed that Android CLI reduced LLM token usage by over 70% for project setup tasks, with agents completing work up to 3x faster.These numbers are not vague marketing.&lt;/p&gt;

&lt;p&gt;The reduction comes from how Android CLI structures its output. Traditional agent workflows dump full text logs, entire file contents, and verbose SDK manager output at the model. Android CLI returns structured JSON and supports a &lt;code&gt;--diff&lt;/code&gt; mode that sends only the elements that changed since the last snapshot.&lt;/p&gt;

&lt;p&gt;Here's a concrete example: &lt;code&gt;android layout --diff&lt;/code&gt;. Instead of re-processing the entire UI hierarchy on every iteration, the agent sees only what changed. On a complex screen with dozens of composables, that's the difference between 8,000 tokens and 400.Multiplied across a development session, the savings compound quickly and translate directly into lower API costs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Agent Skills
&lt;/h2&gt;

&lt;p&gt;Android CLI ships with a skills system: modular markdown instruction sets that auto-trigger when a prompt matches their metadata. No manual context-stuffing, no copying documentation into system prompts.&lt;/p&gt;

&lt;p&gt;The stable release adds five skills not present in the preview: build for display glasses (Jetpack Compose Glimmer for Android XR glasses), implement AppFunctions (expose app workflows to Android's AI agent layer), analyze Perfetto traces (root cause latency, memory, and jank issues), use Perfetto SQL (natural language to Perfetto SQL query translation), and set up testing strategy (unit, UI, and screenshot test scaffolding).&lt;/p&gt;

&lt;p&gt;There are 16 skills total available. The full library lives at &lt;a href="//github.com/android/skills"&gt;github.com/android/skills&lt;/a&gt; and follows the agentskills.io open standard, which means community-contributed skills work in the same pipeline. Third-party repositories for Compose performance optimizations and Jetpack-specific workflows already exist.&lt;/p&gt;

&lt;p&gt;Adding a skill for Claude Code is one command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;android skills add &lt;span class="nt"&gt;--agent&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;claude-code &lt;span class="nt"&gt;--skill&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;migrate-xml-views-to-jetpack-compose
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The skills cover XML-to-Compose migration, AGP 9 upgrade, Navigation 3 setup, edge-to-edge display modernization, and R8 configuration auditing, among others.&lt;/p&gt;

&lt;h2&gt;
  
  
  Journeys: agent-driven UI testing
&lt;/h2&gt;

&lt;p&gt;Stable 1.0 also ships Journeys support, which lets agents execute natural language user experience tests.Instead of writing Espresso test code, you describe a user flow in plain English and the agent navigates through it, reporting what it finds.&lt;/p&gt;

&lt;h2&gt;
  
  
  Installation
&lt;/h2&gt;

&lt;p&gt;Android CLI is free. Installation varies by platform:&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="c"&gt;# macOS&lt;/span&gt;
brew &lt;span class="nb"&gt;install &lt;/span&gt;android-cli

&lt;span class="c"&gt;# Linux and Windows&lt;/span&gt;
&lt;span class="c"&gt;# Follow the setup guide at:&lt;/span&gt;
&lt;span class="c"&gt;# https://developer.android.com/tools/agents/android-cli&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you already have it installed from the preview, update with android update.&lt;/p&gt;

&lt;p&gt;Once installed, creating a new project and verifying it works:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;android &lt;span class="nt"&gt;--version&lt;/span&gt;
android create project &lt;span class="nt"&gt;--name&lt;/span&gt; MyApp &lt;span class="nt"&gt;--package&lt;/span&gt; com.example.myapp
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For Antigravity 2.0 users, the Android bundle (including Android CLI and skills) can be installed during onboarding or later from Settings &amp;gt; Customizations &amp;gt; Build With Google Plugins.&lt;/p&gt;

&lt;h2&gt;
  
  
  Getting started: what to try first
&lt;/h2&gt;

&lt;p&gt;If you want to cut through the noise and try something that'll actually make a difference this week, here's my recommendation.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Option A: Install Android CLI and pair it with your existing agent.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This is the low-friction path. If you already use Claude Code or Codex, add Android CLI and watch your agent suddenly get smarter about Android development. The difference is immediate. Agents stop hallucinating Compose APIs. They stop guessing at dependency versions. They can actually check their own work.&lt;/p&gt;

&lt;p&gt;After installing, try asking your agent to scaffold a new project, render a Compose preview, and check for warnings, all in one flow. That workflow used to require switching between terminal, IDE, and manual inspection. Now it's programmatic.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Option B: Download Antigravity 2.0 and try the &lt;code&gt;/grill-me&lt;/code&gt; workflow.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Go to &lt;a href="//antigravity.google/download"&gt;antigravity.google/download&lt;/a&gt; and grab the installer for your platform. Start a new project. Don't try to build an operating system. Ask it something concrete: "create a Jetpack Compose screen with a list of items, pull-to-refresh, and a detail view using Navigation 3." Then use &lt;code&gt;/grill-me&lt;/code&gt; to force the agent to ask clarifying questions before it starts coding. Review the artifacts it produces. Get a feel for the interaction model.&lt;/p&gt;

&lt;p&gt;The voice transcription button (the mic icon) is surprisingly useful. Talking through what you want while watching the agent work feels more natural than typing prompts, and you catch things you'd miss in text.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;8Option C: Both.&lt;/em&gt;*&lt;/p&gt;

&lt;p&gt;Install Android CLI for your agent of choice. Download Antigravity 2.0. Spend an afternoon with both. They address different needs: Android CLI is infrastructure that makes any agent better at Android, while Antigravity 2.0 is an opinionated platform that wants to be your primary interface to agents. You might end up using both.&lt;/p&gt;

&lt;h2&gt;
  
  
  What to expect
&lt;/h2&gt;

&lt;p&gt;Antigravity 2.0 feels different from traditional coding. You're not writing code line by line with AI autocomplete. You're describing goals and reviewing what comes back. It takes adjustment. I found myself over-specifying things at first (old habits), then gradually learning how much detail the agent actually needs. The &lt;code&gt;/grill-me&lt;/code&gt; command helps with that by forcing the agent to ask questions instead of charging ahead with assumptions.&lt;/p&gt;

&lt;p&gt;Android CLI is more straightforward. It's a bridge. If you already use Claude Code or Codex for non-Android work, adding Android CLI means those same agents can suddenly speak Android Studio's language. The productivity gains come from fewer context switches and fewer hallucinated APIs. There's no learning curve; the agent just gets better at its job.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I actually think
&lt;/h2&gt;

&lt;p&gt;Here's what gets me about this I/O.&lt;/p&gt;

&lt;p&gt;The demos are spectacular. An operating system built from a single prompt. Agents that never sleep. Video generated from any input. These are genuinely impressive technical achievements, and I'm not going to pretend otherwise.&lt;/p&gt;

&lt;p&gt;But spectacular demos have a short half-life. What lasts is whether the tools actually make developers' lives easier three months from now, when the keynote glow has faded and you're debugging a Compose layout at 11pm and wondering why your agent suggested a deprecated API from three versions ago.&lt;/p&gt;

&lt;p&gt;Android CLI 1.0 will make developers' lives easier. I'm confident about that one. It's boring infrastructure, but boring infrastructure is what lets the exciting stuff actually ship. The 70% token reduction isn't marketing. The &lt;code&gt;--diff&lt;/code&gt; mode on layout inspection isn't marketing. The &lt;code&gt;version-lookup&lt;/code&gt; command that eliminates dependency hallucination isn't marketing. These are concrete improvements to the development workflow that compound across hours and days of work.&lt;/p&gt;

&lt;p&gt;Antigravity 2.0 is harder to evaluate. The subagent architecture is smart. The 93-subagent OS demo proves the orchestration layer works at scale. The scheduled tasks and JSON hooks are genuinely useful primitives. But the interaction model (describe a goal, wait for artifacts, review, repeat) is still unproven for day-to-day development work. Some developers will love it. Some will find it slower than just writing the code themselves. The truth is probably somewhere boring in the middle.&lt;/p&gt;

&lt;p&gt;The agents? I'm still figuring out where I land. The technology is real. The demos are real. But there's a gap between "look what it can do" and "look what it does reliably in production," and that gap is where most developer skepticism lives. Google seems to know this. The Android CLI release, the openness to third-party agents, the emphasis on guardrails (JSON hooks, per-project permissions, &lt;code&gt;/grill-me&lt;/code&gt; for alignment) are all signs they understand that adoption depends on trust, not just capability.&lt;/p&gt;

&lt;p&gt;What I keep coming back to is the openness. Google spent years building walled gardens around Android development. Android Studio was the center of gravity and everything else orbited it. Android CLI 1.0 is the opposite: it makes Android Studio's capabilities available to whatever agent you prefer, from Claude Code to Codex to your own custom setup. That's not a concession born of weakness. It's a strategic bet that if you make Android the easiest platform to develop for with any AI tool, more developers will build for Android regardless of which agent they use. It's smart, and it's more developer-friendly than anything Google has done with Android tooling in years.&lt;/p&gt;

&lt;p&gt;Go install Android CLI and see if your agent of choice gets smarter about Android. That's a bet I'm comfortable making today. Antigravity 2.0 is worth trying too, especially if you're curious about what agent-first development actually feels like in practice.&lt;/p&gt;

&lt;p&gt;We'll see how it plays out. The tools are free. The documentation is live. The rest is up to us.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Note: The above cover image generated by AI&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>googleiochallenge</category>
    </item>
    <item>
      <title>The Ulysses Prediction Engine</title>
      <dc:creator>RoTSL</dc:creator>
      <pubDate>Wed, 20 May 2026 16:55:19 +0000</pubDate>
      <link>https://dev.to/rotsl/the-ulysses-prediction-engine-4nej</link>
      <guid>https://dev.to/rotsl/the-ulysses-prediction-engine-4nej</guid>
      <description>&lt;h2&gt;
  
  
  The Ulysses Prediction Engine: How I Built a Self‑Optimizing, Noise‑Proof Oracle That Learns Almost Anything
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;Three theorems stacked inside each other, twelve predictors, one Kalman filter, and a grid‑search optimiser that never stops tuning itself.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1024%2F0%2A6nGPUS71W3CPw0Ss" 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%2Fcdn-images-1.medium.com%2Fmax%2F1024%2F0%2A6nGPUS71W3CPw0Ss" alt="image" width="1024" height="556"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Photo by Egor Komarov on Unsplash&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Hardin – Taylor Nearly Perfect Prediction Theorem&lt;/strong&gt; says something outrageous: for any function – chaotic, discontinuous, or just plain weird – there exists a strategy that will guess its next value correctly at almost every point in time. The catch? The proof requires the Axiom of Choice; it tells you a perfect predictor exists but gives you absolutely no way to build one.&lt;/p&gt;

&lt;p&gt;That theorem has haunted me since Joel David Hamkins wrote about it in the Notices of the AMS. It felt like a dare: could you take that ineffable, non‑constructive guarantee and turn it into something real – something that runs in a browser, handles noise, adapts when the world changes, and actually works on messy, real‑world data?&lt;/p&gt;

&lt;p&gt;The answer is the &lt;strong&gt;&lt;em&gt;Ulysses Prediction Engine (UPE).&lt;/em&gt;&lt;/strong&gt; I’ve been developing it as a private research project, and there’s now a live demo running at upe‑app.vercel.app. This article is the technical story of how it works, why it’s structured the way it is, and what happens when you point it at temperature records, stock volatility, or EEG traces.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Big Idea: A Theorem Inside a Theorem Inside a Theorem
&lt;/h3&gt;

&lt;p&gt;UPE’s architecture is a Russian doll of guarantees. Each layer is a self‑contained result, and each outer layer uses the inner layer as a lemma in its own proof of convergence.&lt;/p&gt;

&lt;h4&gt;
  
  
  Layer 1 – The Inner Guarantee: Universal Bayesian Prediction
&lt;/h4&gt;

&lt;p&gt;The innermost layer is a direct computational approximation of &lt;strong&gt;Solomonoff induction&lt;/strong&gt;. The idea, due to Ray Solomonoff, is breathtakingly simple: maintain a Bayesian mixture over all computable models, weighted by their algorithmic complexity (shorter programs get more prior mass). As data arrives, you update the posterior and use the mixture to predict the next observation.&lt;/p&gt;

&lt;p&gt;Solomonoff proved that, for any computable data‑generating process, this predictor’s error goes to zero faster than any other method – in the limit. It is, in a precise sense, the optimal predictor.&lt;/p&gt;

&lt;p&gt;But the exact mixture is uncomputable (it requires running all possible Turing machines). UPE approximates it by maintaining an ensemble of &lt;strong&gt;12 base predictors:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;· Exponential smoothing (short and long memory)&lt;/p&gt;

&lt;p&gt;· AR(p) models with p = 1, 2, 3&lt;/p&gt;

&lt;p&gt;· Linear and quadratic trend models&lt;/p&gt;

&lt;p&gt;· Fourier predictors that capture periodicity&lt;/p&gt;

&lt;p&gt;· A random‑walk baseline as a fallback&lt;/p&gt;

&lt;p&gt;The ensemble weights are updated online using &lt;strong&gt;exponentiated gradient descent&lt;/strong&gt; – the same algorithm used in the classic “Prediction with Expert Advice” framework. Over time, the weight vector concentrates on whichever base predictors happen to match the true dynamics best. This is a bounded‑compute approximation to the full Solomonoff mixture, and it inherits the same asymptotic optimality guarantees within the class of models it can represent.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why 12?&lt;/strong&gt; The number is a deliberate trade‑off. Too few, and you miss important dynamics. Too many, and the regret bound (the penalty for having to learn which experts are good) grows. Twelve is enough to capture trend, seasonality, mean‑reversion, and momentum – the four horsemen of time‑series structure – without incurring excessive variance.&lt;/p&gt;

&lt;h4&gt;
  
  
  Layer 2 – Error Correction: Bayesian Filtering
&lt;/h4&gt;

&lt;p&gt;The inner predictor assumes it sees the true signal. In reality, every sensor is noisy. UPE wraps the universal predictor’s output inside a &lt;strong&gt;scalar Kalman filter&lt;/strong&gt; that treats the true signal as a hidden state and the observation as a noisy measurement.&lt;/p&gt;

&lt;p&gt;The Kalman filter does three things simultaneously:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;De-noises&lt;/strong&gt; the input to the predictor by maintaining a posterior over the hidden state.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Corrects systematic biases&lt;/strong&gt; – if the ensemble consistently over‑ or under‑predicts, the filter’s innovation term captures that and compensates.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Quantifies uncertainty&lt;/strong&gt; – the filter’s error covariance gives a principled confidence interval around every prediction.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The measurement noise covariance R is not fixed; it’s estimated online from the variance of recent residuals. This means the filter automatically adjusts its trust in new observations: when residuals are large (e.g., during a regime change), it trusts the dynamics model more; when residuals are small, it tracks the observations tightly.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Theorem connection:&lt;/strong&gt; As the inner universal predictor converges (which it does in Cesàro mean for any stationary ergodic process), the Kalman filter’s posterior covariance shrinks toward zero. The two layers together guarantee that the filtered predictions converge to the truth even when the raw observations are corrupted by i.i.d. noise with finite variance.&lt;/p&gt;

&lt;h4&gt;
  
  
  Layer 3 – The Meta‑Optimiser: Never Stop Tuning
&lt;/h4&gt;

&lt;p&gt;Every layer has hyper-parameters:&lt;/p&gt;

&lt;p&gt;· The learning rate &lt;strong&gt;η&lt;/strong&gt; for the expert weight updates&lt;/p&gt;

&lt;p&gt;· The process noise &lt;strong&gt;Q&lt;/strong&gt; in the Kalman filter (how much the true signal is allowed to drift)&lt;/p&gt;

&lt;p&gt;· The &lt;strong&gt;FFT window&lt;/strong&gt; size for the Fourier predictor&lt;/p&gt;

&lt;p&gt;Instead of setting these once and hoping for the best, UPE runs an &lt;strong&gt;online meta‑optimiser.&lt;/strong&gt; Every few steps, it performs a grid search over candidate hyper-parameter values, evaluates each candidate on a recent window of residuals, and blends the best configuration into the current one using exponential smoothing (to avoid abrupt jumps that would destabilise the filter).&lt;/p&gt;

&lt;p&gt;This is a form of &lt;strong&gt;no‑regret online learning&lt;/strong&gt;. Cesa‑Bianchi and Lugosi proved that such strategies guarantee that, in the long run, you perform as well as if you had chosen the single best hyper-parameter configuration in hindsight. UPE’s meta‑optimiser inherits this property: it asymptotically matches the performance of the best fixed configuration, even as the data‑generating process changes.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The full stack is therefore:&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Theorem 1 (Solomonoff) ⇒ Theorem 2 (Kalman convergence) ⇒ Theorem 3 (No‑regret meta‑learning)&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Each arrow is a rigorous implication. The whole system carries a logarithmic bound on cumulative squared prediction error almost surely for stationary ergodic processes.&lt;/p&gt;

&lt;h4&gt;
  
  
  2. Behind the App: What You’re Actually Seeing
&lt;/h4&gt;

&lt;p&gt;The live demo at &lt;a href="http://upe%E2%80%91app.vercel.app" rel="noopener noreferrer"&gt;upe‑app.vercel.app&lt;/a&gt; exposes this architecture directly. The interface is deliberately minimal – you select a domain, and the engine immediately begins ingesting a real‑world time series and producing predictions.&lt;/p&gt;

&lt;p&gt;The app supports seven prediction domains out of the box:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Domain&lt;/th&gt;
&lt;th&gt;Dataset&lt;/th&gt;
&lt;th&gt;What makes it hard&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Finance&lt;/td&gt;
&lt;td&gt;S&amp;amp;P 500 5-min realised volatility&lt;/td&gt;
&lt;td&gt;Heavy tails, volatility clustering&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Healthcare&lt;/td&gt;
&lt;td&gt;Intracranial EEG amplitude&lt;/td&gt;
&lt;td&gt;Non-stationarity, pre-ictal morphology changes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Climate&lt;/td&gt;
&lt;td&gt;Daily temperature (Berlin)&lt;/td&gt;
&lt;td&gt;Strong seasonality + long-term trend&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Industrial IoT&lt;/td&gt;
&lt;td&gt;Machine vibration amplitude&lt;/td&gt;
&lt;td&gt;Impulsive events, sensor noise&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Autonomous Systems&lt;/td&gt;
&lt;td&gt;IMU angular velocity&lt;/td&gt;
&lt;td&gt;High-frequency noise, drift&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Communications&lt;/td&gt;
&lt;td&gt;Network packet rate&lt;/td&gt;
&lt;td&gt;Bursty traffic, diurnal patterns&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Fundamental Research&lt;/td&gt;
&lt;td&gt;Telescope photometry flux&lt;/td&gt;
&lt;td&gt;Low signal-to-noise, transit events&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Each domain loads a pre‑processed sample dataset (several thousand points). The engine runs client‑side in the browser – no server round‑trips, no API keys. Every computation (the 12 base predictors, the Kalman filter step, the grid‑search optimiser) is implemented in plain TypeScript and executes in a web worker to keep the UI thread responsive.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The chart shows:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;· &lt;strong&gt;The noisy observation&lt;/strong&gt; (grey dots or line)&lt;/p&gt;

&lt;p&gt;· &lt;strong&gt;The UPE prediction&lt;/strong&gt; (blue line)&lt;/p&gt;

&lt;p&gt;· &lt;strong&gt;A confidence band&lt;/strong&gt; (±2σ from the Kalman filter’s error covariance)&lt;/p&gt;

&lt;p&gt;· &lt;strong&gt;The ensemble weight distribution&lt;/strong&gt; (a small bar chart showing which base predictors are currently dominant)&lt;/p&gt;

&lt;p&gt;You can watch the weights shift in real time as the data changes character – for example, when temperature transitions from a stable summer plateau into autumn cooling, the trend models gain weight and the seasonal Fourier model adjusts its phase.&lt;/p&gt;

&lt;h4&gt;
  
  
  3. What Happens When You Point It at Real Data
&lt;/h4&gt;

&lt;p&gt;The paper version of UPE (soon available in preprint form – see the references below) includes rigorous benchmarks against ARIMA, LSTM, fixed‑parameter Kalman filters, and Gaussian processes. Here’s a condensed summary of the results:&lt;/p&gt;

&lt;h4&gt;
  
  
  Temperature Forecasting (Berlin‑Tegel, 10 years)
&lt;/h4&gt;

&lt;p&gt;Under high noise (Laplace with scale 2), UPE achieves &lt;strong&gt;RMSE 1.84 °C&lt;/strong&gt; vs. 3.42 for ARIMA and 3.18 for LSTM. The Kalman filter is doing the heavy lifting here – it strips the Laplace noise without the over-smoothing that a fixed Kalman gain would produce, because the meta‑optimiser increases Q when the residuals spike.&lt;/p&gt;

&lt;h4&gt;
  
  
  Financial Volatility (S&amp;amp;P 500, 2020 – 2024)
&lt;/h4&gt;

&lt;p&gt;Volatility prediction is notoriously difficult because of heavy tails and regime changes (COVID, the 2022 bear market). Under Cauchy‑contaminated noise (1% outliers), UPE maintains a correlation of &lt;strong&gt;0.92&lt;/strong&gt; with true realised volatility vs. &lt;strong&gt;0.74&lt;/strong&gt; for LSTM. The secret: the exponentiated‑gradient weight update is robust to outliers by design – the loss gradient for a Cauchy outlier is bounded, so no single observation can hijack the ensemble.&lt;/p&gt;

&lt;h4&gt;
  
  
  Epileptic Seizure Prediction (CHB‑MIT Database)
&lt;/h4&gt;

&lt;p&gt;This is the hardest test. Intracranial EEG signals change morphology dramatically during the pre‑ictal period (the minutes before a seizure). Fixed‑parameter models diverge. UPE’s meta‑optimiser detects the increased residual variance and raises Q, allowing the filter to track the rapid amplitude changes. The result: &lt;strong&gt;RMSE 7.9 μV&lt;/strong&gt; under high noise (interference + electrode dropout) vs. 15.8 for LSTM and 15.1 for a fixed Kalman filter.&lt;/p&gt;

&lt;h4&gt;
  
  
  4. Why This Architecture Is Fundamentally Different
&lt;/h4&gt;

&lt;p&gt;Most production forecasting systems fall into one of two camps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Classical time‑series models&lt;/strong&gt; (ARIMA, exponential smoothing, GARCH) – fast and interpretable, but they assume a fixed structure and break under non‑stationarity.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Deep learning&lt;/strong&gt; (LSTMs, transformers) – flexible and powerful, but data‑hungry, slow to adapt, and famously fragile under distribution shift.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;UPE occupies a third category. It is:&lt;/p&gt;

&lt;p&gt;· &lt;strong&gt;Model‑agnostic:&lt;/strong&gt; The ensemble of 12 base predictors spans trend, seasonality, mean‑reversion, and momentum. The weight update discovers which combination is appropriate, so you don’t have to specify an ARIMA(p,d,q) order or a network architecture.&lt;/p&gt;

&lt;p&gt;· &lt;strong&gt;Provably adaptive:&lt;/strong&gt; The no‑regret guarantee on the meta‑optimiser means the hyperparameters converge to their optimal values without manual tuning, even if the environment changes.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;· Noise‑resilient by construction:&lt;/strong&gt; The Kalman filter layer isn’t a post‑processing hack; it’s an integral part of the architecture with its own convergence theorem.&lt;/p&gt;

&lt;p&gt;· &lt;strong&gt;Computationally cheap:&lt;/strong&gt; The entire stack runs in milliseconds per step in a browser. No GPU required. The heaviest operation is the grid search, and that runs asynchronously.&lt;/p&gt;

&lt;p&gt;The philosophical shift is this: instead of building a bespoke model for each problem, UPE provides a universal scaffold that configures itself to whatever computable structure the data exhibits. It’s the difference between crafting a key for each lock and building a lockpick that adjusts its shape.&lt;/p&gt;

&lt;h4&gt;
  
  
  5. Limitations (Let’s Be Honest)
&lt;/h4&gt;

&lt;p&gt;UPE is not magic. The guarantees are asymptotic, and the real world is finite. Specifically:&lt;/p&gt;

&lt;p&gt;· &lt;strong&gt;Stationarity assumption:&lt;/strong&gt; The theorems assume the data comes from a stationary ergodic process. Real data is never perfectly stationary. The meta‑optimiser mitigates this by adapting hyperparameters, but a sudden, permanent structural break will cause a transient spike in error.&lt;/p&gt;

&lt;p&gt;· &lt;strong&gt;Bounded model class:&lt;/strong&gt; The 12 base predictors are a finite approximation to the truly universal (and uncomputable) Solomonoff mixture. A process that requires, say, a long‑memory fractionally integrated model (ARFIMA) will not be perfectly captured.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;· Univariate only:&lt;/strong&gt; The current implementation predicts scalar time series. Extending to multivariate prediction with cross‑series dependencies is straightforward in principle (replace the scalar Kalman filter with a vector one), but the computational cost of the ensemble grows.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;· No causal inference:&lt;/strong&gt; UPE predicts; it does not explain. The mixture of programs is opaque – you can see which base predictors are weighted heavily, but you cannot extract a human‑readable equation.&lt;/p&gt;

&lt;p&gt;These are active areas of development in the private repository.&lt;/p&gt;

&lt;h4&gt;
  
  
  6. What’s Next
&lt;/h4&gt;

&lt;p&gt;The roadmap has three tracks:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Multivariate extension:&lt;/strong&gt; Replacing the scalar Kalman filter with an ensemble Kalman filter (EnKF) to handle vector‑valued observations and cross‑channel dependencies.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Hierarchical priors:&lt;/strong&gt; Adding a second‑order meta‑prior over the ensemble composition itself, so the engine can invent new base predictors when none of the existing 12 fit.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Explainability layer:&lt;/strong&gt; Building a program‑synthesis module that periodically extracts the most heavily weighted base predictor combination and attempts to refactor it into a compact, human‑readable formula (a symbolic regression layer on top of the ensemble).&lt;/li&gt;
&lt;/ol&gt;

&lt;h4&gt;
  
  
  7. Try It Yourself
&lt;/h4&gt;

&lt;p&gt;The live demo is at &lt;a href="http://upe%E2%80%91app.vercel.app" rel="noopener noreferrer"&gt;upe‑app.vercel.app&lt;/a&gt;. The app is client‑side only – your data never leaves your browser. You can select any of the seven built‑in domains, or (in a future release) upload your own CSV and watch the engine adapt in real time.&lt;/p&gt;

&lt;p&gt;The repository is currently private while I work on the roadmap , but if you’re interested in collaborating or learning more about the internals, feel free to reach out.&lt;/p&gt;

&lt;h4&gt;
  
  
  References
&lt;/h4&gt;

&lt;ol&gt;
&lt;li&gt;Hamkins, J. D. (2025). The Nearly Perfect Prediction Theorem. Notices of the AMS, 72(3), 308 – 309.&lt;/li&gt;
&lt;li&gt;2. Solomonoff, R. J. (1964). A Formal Theory of Inductive Inference. Information and Control, 7(1), 1 – 22.&lt;/li&gt;
&lt;li&gt;Hutter, M. (2005). Universal Artificial Intelligence. Springer.&lt;/li&gt;
&lt;li&gt;Cesa‑Bianchi, N. &amp;amp; Lugosi, G. (2006). Prediction, Learning, and Games. Cambridge University Press.&lt;/li&gt;
&lt;li&gt;Särkkä, S. (2013). Bayesian Filtering and Smoothing. Cambridge University Press.&lt;/li&gt;
&lt;li&gt;Hazan, E. (2016). Introduction to Online Convex Optimization. Foundations and Trends in Optimization, 2(3 – 4), 157 – 325.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If you found this interesting, hold that clap button – it helps other curious engineers find this article.&lt;/p&gt;

</description>
      <category>mathematics</category>
      <category>lstm</category>
      <category>arima</category>
      <category>predictions</category>
    </item>
    <item>
      <title>SMGP [Spectral Memory Graph Processor] : Building an AI That Actually Remembers What You Told It</title>
      <dc:creator>RoTSL</dc:creator>
      <pubDate>Mon, 18 May 2026 10:58:56 +0000</pubDate>
      <link>https://dev.to/rotsl/smgp-spectral-memory-graph-processor-building-an-ai-that-actually-remembers-what-you-told-it-1b6d</link>
      <guid>https://dev.to/rotsl/smgp-spectral-memory-graph-processor-building-an-ai-that-actually-remembers-what-you-told-it-1b6d</guid>
      <description>&lt;h3&gt;
  
  
  SMGP: Building an AI That Actually Remembers What You Told It
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;I spent a few months combining spectral graph theory, hyperdimensional computing, and a custom FPGA to solve the three things about LLMs that drive me crazy.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxwb678tlojnudvytjlke.jpeg" 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%2Fxwb678tlojnudvytjlke.jpeg" alt="image" width="784" height="1168"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Image Generated by Grok AI&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Large language models are impressive in a lot of ways. But after working with them for a while, three things started to really bother me:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;They forget everything between conversations. You can spend an hour giving context, and the next session it’s gone.&lt;/li&gt;
&lt;li&gt;The attention mechanism scales quadratically. Double your context, quadruple your compute. That’s why long documents get expensive fast.&lt;/li&gt;
&lt;li&gt;They make stuff up. Confidently. And there’s no built-in way to check if what they’re saying is actually true.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I wanted to see if there was a fundamentally different approach. Not patching transformers, not scaling them bigger. Something built from the ground up where memory, attention, and truthfulness aren’t afterthoughts.&lt;/p&gt;

&lt;p&gt;That’s what SMGP (Spectral Memory Graph Processor) tries to be. It stores knowledge in a persistent graph encoded with hyperdimensional vectors, does attention in O(N log N) using graph Fourier analysis, and verifies every factual claim by checking if a path exists in the graph. If there’s no path, the claim doesn’t get made.&lt;/p&gt;

&lt;p&gt;There’s also a full FPGA accelerator that offloads the heavy compute – but I’ll get to that.&lt;/p&gt;
&lt;h4&gt;
  
  
  How It’s Put Together
&lt;/h4&gt;

&lt;p&gt;Everything centers on what I’m calling a Spectral Memory Graph. It’s a directed, typed property graph where:&lt;/p&gt;

&lt;p&gt;· Each fact, concept, or word is a node. Nodes are addressed by 10,000-dimensional hyperdimensional bipolar vectors (+1 or -1).&lt;/p&gt;

&lt;p&gt;· Relationships are typed edges, also encoded with HD vectors.&lt;/p&gt;

&lt;p&gt;· The whole graph gets treated as a discrete manifold. All the signal processing happens in the spectral domain of the graph Laplacian.&lt;/p&gt;

&lt;p&gt;The rough architecture looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
+=============================================================+
| Application Layer |
| LLM | Knowledge Bases | Reasoning Agents | Chatbots |
+---------------------------+---------------------------------+
                            |
+=============================================================+
| Integration Layer |
| HuggingFace | LangChain | FastAPI | CLI | Python HAL |
+---------------------------+---------------------------------+
                            |
+=============================================================+
| Reasoning Layer |
| ClaimVerifier | NeuroSymbolicPlanner |
| DPO Rewrite Search |
+---------------------------+---------------------------------+
                            |
+=============================================================+
| Memory &amp;amp; Attention Layer |
| MemoryStore | AssociativeMemory | MemoryLifecycle |
| SpectralAttention: O(N log N) Multiscale |
+---------------------------+---------------------------------+
                            |
+=============================================================+
| Core Layer |
| SpectralMemoryGraph | HyperdimensionalMemory |
| SpectralMethods | TopologicalAnalyzer | GraphRewriter |
+=============================================================+
                            |
              +================================+
              | SOFTWARE: Python / CPU |
              | NumPy | SciPy | GUDHI |
              +--------------------------------+
                            |
              +===========================================+
              | HARDWARE: SMGPU FPGA |
              | Spectral | HD | Topo | Rewrite Engines |
              | NoC | HBM | CAM | Memristor Crossbar |
              +===========================================+
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  The Math (Or: Why This Actually Works)
&lt;/h4&gt;

&lt;h4&gt;
  
  
  Hyperdimensional Memory
&lt;/h4&gt;

&lt;p&gt;The memory system comes from hyper-dimensional computing. I first encountered HDC through Pentti Kanerva’s work at Berkeley, and it’s one of those ideas that feels almost too elegant. Every node and edge gets a bipolar vector v ∈ {-1, +1}ᴰ where D=10,000.&lt;/p&gt;

&lt;p&gt;The operations are simple:&lt;/p&gt;

&lt;p&gt;· &lt;strong&gt;Bind&lt;/strong&gt; (XOR for bipolar vectors): a ⊕ b forms an association, like a key-value pair.&lt;/p&gt;

&lt;p&gt;· &lt;strong&gt;Unbind&lt;/strong&gt; : c ⊕ a recovers b if c = a ⊕ b.&lt;/p&gt;

&lt;p&gt;· &lt;strong&gt;Bundle&lt;/strong&gt; (majority sum): ⊕ᵢ vᵢ = sign(Σᵢ vᵢ) superposes multiple vectors together.&lt;/p&gt;

&lt;p&gt;· &lt;strong&gt;Similarity&lt;/strong&gt; : sim(a,b) = (1/D)aᵀb – just normalized dot product.&lt;/p&gt;

&lt;p&gt;What’s wild is that these 10,000-dimensional vectors are incredibly robust. You can search across millions of nodes with dot products, and associative recall drops to O(1) when you implement it in content-addressable memory. The math guarantees that random high-dimensional vectors are nearly orthogonal, so interference between stored patterns is minimal.&lt;/p&gt;

&lt;h4&gt;
  
  
  Spectral Graph Processing
&lt;/h4&gt;

&lt;p&gt;This is where things get interesting. I take the knowledge graph’s adjacency matrix &lt;strong&gt;A&lt;/strong&gt; and build the normalized graph Laplacian:&lt;/p&gt;

&lt;p&gt;L = I – D⁻¹/² A D⁻¹/²&lt;/p&gt;

&lt;p&gt;where &lt;strong&gt;D&lt;/strong&gt; is the degree matrix. The eigenvectors &lt;strong&gt;uₖ&lt;/strong&gt; of &lt;strong&gt;L&lt;/strong&gt; give you a basis that captures the graph’s structure across different frequencies. Low-frequency eigenvectors encode broad community structure. High-frequency ones capture local details.&lt;/p&gt;

&lt;p&gt;The Graph Fourier Transform of a signal &lt;strong&gt;x&lt;/strong&gt; on the graph is:&lt;/p&gt;

&lt;p&gt;x̂(λₖ) = ⟨x, uₖ⟩&lt;/p&gt;

&lt;p&gt;A spectral convolution with filter gθ becomes:&lt;/p&gt;

&lt;p&gt;gθ ★ x = U gθ(Λ) Uᵀ x&lt;/p&gt;

&lt;p&gt;where &lt;strong&gt;U&lt;/strong&gt; holds the eigenvectors and &lt;strong&gt;Λ&lt;/strong&gt; is the diagonal eigenvalue matrix. Full eigendecomposition costs O(N³), so I approximate gθ using a Chebyshev polynomial expansion of order K. That gets you down to O(K|E|) – manageable even for large graphs.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Attention&lt;/strong&gt; runs in this spectral domain. Input tokens map to nodes in a context graph, and the spectral filter learns which frequencies to attend to. Coarsening the graph into a multiscale hierarchy via graph wavelets gives O(N log N) without losing global context. I was honestly surprised how well this worked in practice – the “lost middle” problem that plagues standard transformers just doesn’t show up.&lt;/p&gt;

&lt;h4&gt;
  
  
  Topological Persistence for Not Forgetting Things
&lt;/h4&gt;

&lt;p&gt;Continuous learning usually means catastrophic forgetting. I use persistent homology to monitor the graph’s topology as it evolves. You build a filtration of the graph (adding edges in similarity order) and compute the persistence diagram – points (bᵢ, dᵢ) tracking when topological features appear and disappear.&lt;/p&gt;

&lt;p&gt;When new knowledge arrives, I impose a stability constraint: the Wasserstein distance between old and new persistence diagrams can’t exceed a threshold ε. If an update would distort the global topology too much, it gets rejected or deferred. Existing knowledge stays intact.&lt;/p&gt;

&lt;p&gt;Pruning works the other direction. Low-persistence features tend to be noise or rarely-used facts, so removing them keeps the memory footprint bounded without touching anything important. This is genuine lifelong learning – the graph grows without collapsing.&lt;/p&gt;

&lt;h4&gt;
  
  
  Category-Theoretic Graph Rewriting for Reasoning
&lt;/h4&gt;

&lt;p&gt;Reasoning uses double-pushout (DPO) graph rewriting. A rule r = (L ← K → R) describes how to transform a graph pattern L into R. When the planner searches for an answer, it matches L in the knowledge graph and applies the rewrite. The sequence of rewrites becomes a proof trace – every step is a graph homomorphism.&lt;/p&gt;

&lt;p&gt;If a claim like “Socrates taught Plato” can be derived as a valid rewrite path, it’s verified. If no such path exists, the claim gets rejected. Every output has a constructive proof behind it or it doesn’t get generated. I’m not claiming this eliminates every possible error – garbage in, garbage out still applies – but it does eliminate the class of hallucination where the model just confidently invents things.&lt;/p&gt;

&lt;h4&gt;
  
  
  The Software Side
&lt;/h4&gt;

&lt;p&gt;The Python package (pip install smgp) splits into layers:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;| Module | What It Does |
| ------------------------- | ----------------------------------------------------------------------- |
| &lt;span class="sb"&gt;`core.graph`&lt;/span&gt; | &lt;span class="sb"&gt;`SpectralMemoryGraph`&lt;/span&gt; — the central knowledge graph with HD addressing |
| &lt;span class="sb"&gt;`core.hyperdim`&lt;/span&gt; | &lt;span class="sb"&gt;`HyperdimensionalMemory`&lt;/span&gt; — bind, unbind, bundle, similarity search |
| &lt;span class="sb"&gt;`core.spectral`&lt;/span&gt; | &lt;span class="sb"&gt;`SpectralMethods`&lt;/span&gt; — Laplacian, eigendecomposition, GFT, Chebyshev conv |
| &lt;span class="sb"&gt;`core.topology`&lt;/span&gt; | &lt;span class="sb"&gt;`TopologicalAnalyzer`&lt;/span&gt; — persistent homology, pruning |
| &lt;span class="sb"&gt;`core.category`&lt;/span&gt; | &lt;span class="sb"&gt;`GraphRewriter`&lt;/span&gt; — DPO-based rewriting |
| &lt;span class="sb"&gt;`memory`&lt;/span&gt; | &lt;span class="sb"&gt;`MemoryStore`&lt;/span&gt;, &lt;span class="sb"&gt;`AssociativeMemory`&lt;/span&gt;, &lt;span class="sb"&gt;`MemoryLifecycle`&lt;/span&gt;, pruning policies |
| &lt;span class="sb"&gt;`attention.spectral_attn`&lt;/span&gt; | &lt;span class="sb"&gt;`SpectralAttention`&lt;/span&gt; — O(N log N) multiscale attention |
| &lt;span class="sb"&gt;`reasoning`&lt;/span&gt; | &lt;span class="sb"&gt;`ClaimVerifier`&lt;/span&gt;, &lt;span class="sb"&gt;`NeuroSymbolicPlanner`&lt;/span&gt; with explainable variants |
| &lt;span class="sb"&gt;`integration`&lt;/span&gt; | HuggingFace, LangChain, FastAPI, ONNX/vLLM, vector DBs, federation |
| &lt;span class="sb"&gt;`utils`&lt;/span&gt; | Auto-tuning, multimodal embeddings, CLI, benchmarks |
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Using it as an LLM replacement:&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="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;smgp.integration.huggingface&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;SMGPForCausalLM&lt;/span&gt;
&lt;span class="n"&gt;model&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;SMGPForCausalLM&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;graph_hd_dim&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;10000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add_knowledge&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Socrates&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;person&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add_knowledge&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Socrates&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Plato&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;taught&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;output&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;generate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;prompt&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Who did Socrates teach?&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;verify_claims&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;SMGPForCausalLM subclasses PreTrainedModel and slots into any HuggingFace pipeline. The standard transformer feed-forward gets replaced with spectral attention over the knowledge graph, and generation calls the verifier to ground outputs. LangChain users get a persistent SMGPMemory and SMGPVerifierTool for agents that can fact-check themselves.&lt;/p&gt;

&lt;h4&gt;
  
  
  The Hardware Accelerator (SMGPU)
&lt;/h4&gt;

&lt;p&gt;The spectral transforms, HD operations, and topology calculations add up. Running everything in pure Python on a CPU works for small graphs, but it’s not fast. I designed SMGPU as a domain-specific accelerator in synthesisable SystemVerilog, targeting the Xilinx Alveo U280 (8 GB HBM2, 250 MHz).&lt;/p&gt;

&lt;h4&gt;
  
  
  Microarchitecture
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;                          +---------------------------+
                          | PCIe / AXI Host |
                          +-------------+-------------+
                                        |
                          +-------------v-------------+
                          | ISA Decoder |
                          | 32-bit Instruction |
                          | Fetch &amp;amp; Dispatch |
                          +------+------+------+-------+
                                 | | |
          +----------------------+ | +----------------------+
          | | |
 +--------v---------+ +--------v----------+ +--------v---------+
 | Spectral Engine | | HD Engine | | Topology Engine |
 | - Laplacian | | - Bundle: Maj | | - Union-Find |
 | - Eigen-decomp | | - Bind/Unbind | | - Barcode Emit |
 | - Chebyshev | | XOR | | - Wasserstein |
 | - GFT / Wavelet | | - Permute: Shift | | - Stability |
 | 16x16 Systolic | | - Similarity | | Check |
 +--------+---------+ | 16 Parallel Banks| +--------+--------+
          | +---------+----------+ |
          | | |
 +--------v---------+ +---------v----------+ +--------v---------+
 | Rewrite Engine | | Associative Cache | | Memristor |
 | - DPO Match |&amp;lt;--------&amp;gt;| CAM, 256 Entries |&amp;lt;--------&amp;gt;| Crossbar Array |
 | - DPO Apply | | - O(1) Recall | | - 1024x1024 |
 | - Proof Trace | | - 1024-dim HD Keys | | - Analog MVM |
 +--------+---------+ +--------------------+ +-----------------+
          |
 +--------v----------+ +-------------+-------------+ +-------------------+
 | Graph DMA |&amp;lt;---&amp;gt;| 2D Mesh NoC Router |&amp;lt;---&amp;gt;| HBM Controller |
 | Scatter-Gather | | 5-port, XY Routing | | 4-ch, 256-bit |
 +-------------------+ +---------------------------+ +---------+---------+
                                                                        |
                                                              +---------v---------+
                                                              | HBM2 External |
                                                              +-------------------+
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Compute Engines
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;| Engine | Architecture | Key Operations | Pipeline |
| -------- | ------------------------------- | -------------------------------------------------------------- | ------------ |
| Spectral | 16×16 systolic array | Laplacian, eigen-decomp, Chebyshev conv, GFT, wavelets | 4 stages |
| HD | 16 parallel banks | Bundle majority, bind/unbind XOR, permute, similarity popcount | 1–20 cycles |
| Topology | Union-Find with parallel prefix | Filtration, persistent homology, barcode, Wasserstein | 6 stages |
| Rewrite | Backtracking search FSM | DPO pattern match, rule apply, proof trace | 10-state FSM |
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Memory Subsystem
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;| Component | Specification |
| ------------------ | --------------------------------------------------------------------- |
| Associative Cache | 256-entry CAM, 1024-dim projected keys, O(N) parallel lookup |
| HBM2 Controller | 4 channels, 256-bit data, burst-16, AXI4-Stream |
| Memristor Crossbar | Behavioral, 1024×1024 conductance cells, 8-bit resolution, analog MVM |
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Interconnect
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;| Component | Specification |
| --------- | --------------------------------------------------------------------- |
| NoC | 2D mesh, 5-port routers, XY deterministic routing, 2 virtual channels |
| DMA | Scatter-gather, 256-entry descriptor queue, CSR-aware graph traversal |
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Instruction Set
&lt;/h4&gt;

&lt;p&gt;All instructions are 32-bit:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[31:28] opcode. – NOP, GRAPH_CTOR, SPECTRAL, HD, TOPOLOGY, REWRITE, MEMORY, SYSTEM
[27:24] sub_opcode. – sub-operation
[23:16] flags. – START, DONE_IRQ, CHAINED, STREAMING, BLOCKED, PRECISION_Q
[15:0] operand. – address, immediate, or register select
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;8 opcode classes with 3 – 7 sub-opcodes each. The Python HAL translates high-level graph operations into these instructions. If the FPGA isn’t available, everything falls back to pure Python automatically.&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="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;smgp.core.graph&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;SpectralMemoryGraph&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;hardware.sw.smgp_hal.executor&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;HWExecutor&lt;/span&gt;
&lt;span class="n"&gt;executor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;HWExecutor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;device&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/dev/smgpu0&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;fallback&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;graph&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;SpectralMemoryGraph&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;hd_dim&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;10000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;seed&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;42&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;executor&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;executor&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add_edge&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Socrates&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Plato&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;taught&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;smgp.core.spectral&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;SpectralMethods&lt;/span&gt;
&lt;span class="n"&gt;spectral&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;SpectralMethods&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;eigenvalues&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;spectral&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;compute_eigen&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="c1"&gt;# runs on FPGA at 250 MHz
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Benchmarks
&lt;/h4&gt;

&lt;h4&gt;
  
  
  Software (Pure Python)
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;| Operation | Throughput (queries/s) | Latency (μs) | Memory (MB) |
| --------------------------------------------- | ---------------------: | -----------: | ----------: |
| Graph node creation | 12,000 | 83 | 0.8 |
| HD similarity search: 10K-dim, 10K candidates | 2,400 | 416 | 381 |
| Claim verification: 100-node graph | 8,100 | 123 | 1.2 |
| Spectral attention: 1K tokens, 128-dim | 850 | 1,176 | 45 |
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;AMD Ryzen 9 5950X, 32 GB RAM, single-threaded.&lt;/em&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Hardware Acceleration (FPGA @ 250 MHz)
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;| Operation | Latency | Throughput | Speed-up vs. CPU |
| -------------------------- | ---------: | ------------------: | ---------------: |
| Laplacian: 4K nodes | ~82 μs | 49 M edges/s | 38× |
| Eigen-decomp: K=64 | ~5.2 ms | 12.3 K iterations/s | 15× |
| Chebyshev conv: K=4 | ~0.33 ms | 12.2 M nodes/s | 22× |
| HD bind/unbind: 10K-dim | 1 cycle | 250 M ops/s | 80× |
| HD similarity: 10K-dim | 313 cycles | 0.8 M queries/s | 12× |
| Topology barcode: 4K nodes | ~1.4 ms | 2.9 K graphs/s | 8× |
| Wasserstein distance | ~0.7 ms | 1.4 K comparisons/s | 11× |
| DPO match: pattern 4 nodes | ~32 μs | 31 K patterns/s | 24× |
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;CPU baseline: Intel Xeon Gold 6242, 32 cores. FPGA: Alveo U280, Vivado 2023.2, 250 MHz.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The HD bind/unbind hitting 80× speed-up makes sense – those are just XOR operations in parallel across 10,000-bit vectors. The topology numbers are lower because Union-Find has inherent serial dependencies that are harder to parallelize. I’m still looking at whether a different algorithm for persistence could close that gap.&lt;/p&gt;

&lt;h4&gt;
  
  
  FPGA Resource Utilization (Alveo U280, 16×16 systolic)
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;| Resource | Used | Available | Utilization |
| -------- | -----: | --------: | ----------: |
| LUTs | 95,328 | 1,043,000 | 9.1% |
| FFs | 78,112 | 2,086,000 | 3.7% |
| BRAM | 120 | 1,872 | 6.4% |
| DSPs | 384 | 9,024 | 4.3% |
| URAM | 48 | 960 | 5.0% |
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Plenty of room on the chip. The design is parameterized – you can scale the systolic array from 8×8 up to 32×32 depending on what fits. There’s also an OpenLane ASIC flow targeting SkyWater 130 nm if you want to go beyond FPGAs.&lt;/p&gt;

&lt;h4&gt;
  
  
  Testing
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;| Layer | Tests | Result | Method |
| ------------------------ | --------------: | ------------ | ----------------------------------------- |
| Python core | 210+ | All passing | pytest, Hypothesis property-based testing |
| Python integrations | 20+ | All passing | pytest with mock services |
| RTL unit tests | 6 engines | 6/6 | Verilator 5.048, Cocotb |
| Golden model comparisons | 2: spectral, HD | Bit-accurate | Python vs. RTL fixed-point |
| CI regression benchmarks | 8 | Tracked | Airspeed Velocity: ASV |
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The end-to-end RTL test loads a small knowledge graph, runs spectral attention, verifies a DPO rewrite, and checks the output against the software golden model. That’s been the most useful test for catching integration bugs between engines.&lt;/p&gt;

&lt;h4&gt;
  
  
  Running It in the Cloud
&lt;/h4&gt;

&lt;p&gt;You don’t need your own FPGA. The Chameleon Cloud testbed (NSF-funded, free for research) has bare-metal Alveo U280 nodes.&lt;/p&gt;

&lt;p&gt;Build the bitstream locally (requires Vivado 2023.2):&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;cd &lt;/span&gt;hardware/fpga/build
make synth &lt;span class="nv"&gt;BOARD&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;xcu280
make impl &lt;span class="nv"&gt;BOARD&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;xcu280
make xclbin. &lt;span class="c"&gt;# produces smgp_u280.xclbin&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Reserve a Chameleon node, upload the .xclbin, program the FPGA, and you’re running the same Python code with hardware acceleration. Full instructions are in the repo.&lt;/p&gt;

&lt;h4&gt;
  
  
  What’s Next
&lt;/h4&gt;

&lt;p&gt;The HAL-to-core wiring is designed but needs merging. The PCIe driver skeleton exists but needs the register map filled in to match the RTL. I’m also looking at multi-FPGA scaling – partitioning the knowledge graph across several accelerators – and at formal verification of the ISA.&lt;/p&gt;

&lt;p&gt;Power measurement is on the list too. I want to see how SMGPU compares to GPU inference in joules per query, not just latency. That might be the more interesting number.&lt;/p&gt;

&lt;p&gt;Where This Came From&lt;/p&gt;

&lt;p&gt;I got tired of patching the same problems over and over. Better prompting, RAG, fine-tuning – they all help around the edges but don’t change the fact that transformers have no persistent state and no built-in notion of truth. SMGP is an attempt to build something where memory, attention, and verification aren’t add-ons. They’re the foundation.&lt;/p&gt;

&lt;p&gt;If you want to dig in, contribute, or talk about taping out an ASIC, the repo is at &lt;a href="http://github.com/rotsl/smgp" rel="noopener noreferrer"&gt;github.com/rotsl/smgp.&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The thing I keep thinking about: we’ve spent a long time optimizing the transformer architecture within its inherent constraints. What if the constraints themselves are the problem?&lt;/p&gt;

&lt;p&gt;This project draws on ideas from spectral graph theory (Chung, 1997), hyperdimensional computing (Kanerva, 1988; Plate, 1995), topological data analysis (Edelsbrunner et al., 2002), and algebraic graph transformation (Ehrig et al., 2006). The full references are in the repository.&lt;/p&gt;

</description>
      <category>fpga</category>
      <category>memoryimprovement</category>
      <category>hyperdimensional</category>
      <category>ai</category>
    </item>
    <item>
      <title>What Happens When You Try to Reverse Biology? A Deep Look at the Protein DNA Analysis Simulator</title>
      <dc:creator>RoTSL</dc:creator>
      <pubDate>Fri, 24 Apr 2026 12:57:47 +0000</pubDate>
      <link>https://dev.to/rotsl/what-happens-when-you-try-to-reverse-biology-a-deep-look-at-the-protein-dna-analysis-simulator-5g41</link>
      <guid>https://dev.to/rotsl/what-happens-when-you-try-to-reverse-biology-a-deep-look-at-the-protein-dna-analysis-simulator-5g41</guid>
      <description>&lt;h4&gt;
  
  
  Most biology tools move in one direction. DNA becomes RNA. RNA becomes protein.
&lt;/h4&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%2Fcdn-images-1.medium.com%2Fmax%2F1024%2F0%2AxlozliPGyxtEpW0H" 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%2Fcdn-images-1.medium.com%2Fmax%2F1024%2F0%2AxlozliPGyxtEpW0H" alt="image" width="1024" height="576"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Photo by Warren Umoh on Unsplash&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;That flow is drilled into anyone who has taken genetics or molecular biology. After a while, it becomes background knowledge. You stop questioning it because the pathway feels settled.&lt;/p&gt;

&lt;p&gt;Then a project comes along and asks a slightly uncomfortable question:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;What if we tried to move backward?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;Protein → DNA Synthesis Simulator&lt;/strong&gt; explores that idea.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Project links:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://rotsl.github.io/protein2dna_synthesis-simulator/" rel="noopener noreferrer"&gt;https://rotsl.github.io/protein2dna_synthesis-simulator/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://protein-dna-simulator.vercel.app/" rel="noopener noreferrer"&gt;https://protein-dna-simulator.vercel.app/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;This is not laboratory software. It is not a validated bioinformatics pipeline. It is a simulation designed to explore a biological question.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That distinction matters from the beginning.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;This project is simulation and hypothetical only and has not been tested or validated. This project is for educational purposes only.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h4&gt;
  
  
  Why reverse biology is harder than it sounds
&lt;/h4&gt;

&lt;p&gt;At first glance, reverse translation seems simple.&lt;/p&gt;

&lt;p&gt;If DNA creates proteins, then proteins should point back to DNA.&lt;/p&gt;

&lt;p&gt;But biology does not preserve information perfectly.&lt;/p&gt;

&lt;p&gt;A protein sequence contains amino acids. DNA contains codons.&lt;/p&gt;

&lt;p&gt;The problem is that multiple codons can encode the same amino acid.&lt;/p&gt;

&lt;p&gt;For example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Leucine can be encoded by six codons&lt;/li&gt;
&lt;li&gt;Serine can be encoded by six codons&lt;/li&gt;
&lt;li&gt;Arginine can be encoded by six codons&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This redundancy is called &lt;strong&gt;degeneracy of the genetic code&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Once translation happens, part of the original DNA detail disappears.&lt;/p&gt;

&lt;p&gt;You keep the protein.&lt;/p&gt;

&lt;p&gt;You lose some of the nucleotide history.&lt;/p&gt;

&lt;p&gt;That means reverse translation is not reconstruction.&lt;/p&gt;

&lt;p&gt;It is estimation.&lt;/p&gt;

&lt;h4&gt;
  
  
  The simulator starts with a simple but useful idea
&lt;/h4&gt;

&lt;p&gt;The main GitHub project allows users to input a protein sequence and generate a possible DNA equivalent.&lt;/p&gt;

&lt;p&gt;The workflow is straightforward:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Enter a protein sequence&lt;/li&gt;
&lt;li&gt;Parse amino acids&lt;/li&gt;
&lt;li&gt;Match amino acids to codons&lt;/li&gt;
&lt;li&gt;Build a theoretical DNA sequence&lt;/li&gt;
&lt;li&gt;Display a reconstructed output&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The important word here is &lt;strong&gt;&lt;em&gt;possible&lt;/em&gt;&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The simulator &lt;strong&gt;does not claim&lt;/strong&gt; to discover the original DNA strand.&lt;/p&gt;

&lt;p&gt;It generates a biologically plausible candidate.&lt;/p&gt;

&lt;p&gt;That may sound like a small distinction, but it changes how the project should be understood.&lt;/p&gt;

&lt;p&gt;This is closer to a thought experiment than a prediction engine.&lt;/p&gt;

&lt;h4&gt;
  
  
  The protein analysis page adds a second layer
&lt;/h4&gt;

&lt;p&gt;The main simulator introduces reverse translation.&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%2Furdcvikz4aowgojotjst.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%2Furdcvikz4aowgojotjst.png" alt="image" width="800" height="405"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Main Page&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Link:&lt;/strong&gt; &lt;a href="https://rotsl.github.io/protein2dna_synthesis-simulator/protein_analysis/" rel="noopener noreferrer"&gt;https://rotsl.github.io/protein2dna_synthesis-simulator/protein_analysis/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Instead of immediately converting protein into DNA, the analysis layer pauses to inspect the sequence itself.&lt;/p&gt;

&lt;p&gt;That shift makes the project more interesting.&lt;/p&gt;

&lt;p&gt;A protein sequence contains more than letters.&lt;/p&gt;

&lt;p&gt;It contains patterns.&lt;/p&gt;

&lt;p&gt;The analysis process can reveal:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Amino acid composition&lt;/li&gt;
&lt;li&gt;Sequence length&lt;/li&gt;
&lt;li&gt;Repeating motifs&lt;/li&gt;
&lt;li&gt;Structural tendencies&lt;/li&gt;
&lt;li&gt;Hydrophobic or hydrophilic regions&lt;/li&gt;
&lt;li&gt;Codon ambiguity possibilities&lt;/li&gt;
&lt;li&gt;Conserved residue clusters&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This changes the role of the simulator.&lt;/p&gt;

&lt;p&gt;You stop treating proteins as outputs and start treating them as encoded information.&lt;/p&gt;

&lt;h4&gt;
  
  
  Protein sequences carry clues, not complete answers
&lt;/h4&gt;

&lt;p&gt;One misconception in biology education is that proteins behave like exact reflections of DNA.&lt;/p&gt;

&lt;p&gt;They do not.&lt;/p&gt;

&lt;p&gt;A protein preserves order.&lt;/p&gt;

&lt;p&gt;It does not preserve every codon decision.&lt;/p&gt;

&lt;p&gt;This becomes obvious during reverse translation.&lt;/p&gt;

&lt;p&gt;One protein sequence may correspond to many DNA sequences.&lt;/p&gt;

&lt;p&gt;Different organisms may also favor different codon usage patterns.&lt;/p&gt;

&lt;p&gt;A bacterial sequence and a mammalian sequence may encode the same amino acids using different codon preferences.&lt;/p&gt;

&lt;p&gt;The simulator exposes this uncertainty instead of hiding it.&lt;/p&gt;

&lt;p&gt;That is one of its strongest features.&lt;/p&gt;

&lt;h4&gt;
  
  
  The protein analysis page changes how users think
&lt;/h4&gt;

&lt;p&gt;Many educational biology tools focus on output.&lt;/p&gt;

&lt;p&gt;Input something. Receive a result.&lt;/p&gt;

&lt;p&gt;The analysis page encourages a different rhythm.&lt;/p&gt;

&lt;p&gt;You enter a sequence and ask:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What kind of protein is this?&lt;/li&gt;
&lt;li&gt;Are certain amino acids overrepresented?&lt;/li&gt;
&lt;li&gt;Are there repeating patterns?&lt;/li&gt;
&lt;li&gt;Could this suggest structural behavior?&lt;/li&gt;
&lt;li&gt;How ambiguous is reverse translation?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These questions matter because biological interpretation happens before prediction.&lt;/p&gt;

&lt;p&gt;Researchers rarely jump directly to answers.&lt;/p&gt;

&lt;p&gt;They inspect patterns first.&lt;/p&gt;

&lt;p&gt;The analysis page mirrors that mindset.&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%2F9b2ud9izoaxlwkbe9wuh.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%2F9b2ud9izoaxlwkbe9wuh.png" alt="image" width="800" height="462"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Analysis&lt;/em&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  The live simulation version feels more interactive
&lt;/h4&gt;

&lt;p&gt;The GitHub build introduces the idea.&lt;/p&gt;

&lt;p&gt;The version feels closer to a working prototype.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Try it out here&lt;/strong&gt; : &lt;a href="https://protein-dna-simulator.vercel.app/" rel="noopener noreferrer"&gt;https://protein-dna-simulator.vercel.app/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmlvt7m5ru7so8hijg9jr.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%2Fmlvt7m5ru7so8hijg9jr.png" alt="image" width="800" height="457"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Preview structures&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;At first, both versions appear similar.&lt;/p&gt;

&lt;p&gt;Protein input. DNA output. Translation logic.&lt;/p&gt;

&lt;p&gt;But the live build feels faster and more responsive.&lt;/p&gt;

&lt;p&gt;It behaves less like a static webpage and more like an active sequence workspace.&lt;/p&gt;

&lt;p&gt;You can experiment quickly.&lt;/p&gt;

&lt;p&gt;Change one amino acid.&lt;/p&gt;

&lt;p&gt;Watch the sequence shift.&lt;/p&gt;

&lt;p&gt;Remove residues.&lt;/p&gt;

&lt;p&gt;See how output changes.&lt;/p&gt;

&lt;p&gt;That immediate feedback matters.&lt;/p&gt;

&lt;p&gt;Learning becomes easier when interaction is continuous.&lt;/p&gt;

&lt;h4&gt;
  
  
  The live version works like a live sequence interpreter
&lt;/h4&gt;

&lt;p&gt;Many biology tools rely on a submission model:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Paste sequence&lt;/li&gt;
&lt;li&gt;Configure settings&lt;/li&gt;
&lt;li&gt;Submit request&lt;/li&gt;
&lt;li&gt;Wait for processing&lt;/li&gt;
&lt;li&gt;Read results&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The live version presented shortens that cycle.&lt;/p&gt;

&lt;p&gt;You enter data and receive near-instant interpretation.&lt;/p&gt;

&lt;p&gt;That makes experimentation feel natural.&lt;/p&gt;

&lt;p&gt;You stop thinking in terms of “jobs” and start thinking in terms of exploration.&lt;/p&gt;

&lt;h4&gt;
  
  
  The live simulator combines several biological layers
&lt;/h4&gt;

&lt;p&gt;The interface appears to merge multiple ideas into one workflow.&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%2F6tvlyjwunt6cweicd4xr.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%2F6tvlyjwunt6cweicd4xr.png" alt="image" width="800" height="457"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Engineering Tab&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The system includes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Protein parsing&lt;/li&gt;
&lt;li&gt;Amino acid recognition&lt;/li&gt;
&lt;li&gt;Codon mapping&lt;/li&gt;
&lt;li&gt;DNA sequence estimation&lt;/li&gt;
&lt;li&gt;Educational translation logic&lt;/li&gt;
&lt;li&gt;Sequence relationship visualization&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This matters because reverse translation is not a single operation.&lt;/p&gt;

&lt;p&gt;It is a chain of assumptions.&lt;/p&gt;

&lt;p&gt;Each amino acid creates branching possibilities.&lt;/p&gt;

&lt;p&gt;The simulator turns those possibilities into something visible.&lt;/p&gt;

&lt;h4&gt;
  
  
  Reverse translation exposes a hidden truth about biology
&lt;/h4&gt;

&lt;p&gt;Most diagrams simplify biology into arrows.&lt;/p&gt;

&lt;p&gt;DNA → RNA → Protein.&lt;/p&gt;

&lt;p&gt;That model is useful.&lt;/p&gt;

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

&lt;p&gt;Real biology includes ambiguity.&lt;/p&gt;

&lt;p&gt;Codon redundancy means several nucleotide sequences can create identical proteins.&lt;/p&gt;

&lt;p&gt;That creates uncertainty.&lt;/p&gt;

&lt;p&gt;The simulator does not remove uncertainty.&lt;/p&gt;

&lt;p&gt;It places uncertainty at the center of the experience.&lt;/p&gt;

&lt;p&gt;That makes the project more honest than many educational demos.&lt;/p&gt;

&lt;h4&gt;
  
  
  The project feels closer to computational biology than traditional teaching software
&lt;/h4&gt;

&lt;p&gt;There is a subtle shift that happens when using the simulator.&lt;/p&gt;

&lt;p&gt;You stop memorizing.&lt;/p&gt;

&lt;p&gt;You start interpreting.&lt;/p&gt;

&lt;p&gt;That makes the project feel closer to lightweight bioinformatics.&lt;/p&gt;

&lt;p&gt;Professional sequence-analysis tools often involve:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Pattern recognition&lt;/li&gt;
&lt;li&gt;Sequence comparison&lt;/li&gt;
&lt;li&gt;Codon usage analysis&lt;/li&gt;
&lt;li&gt;Structural inference&lt;/li&gt;
&lt;li&gt;Similarity scoring&lt;/li&gt;
&lt;li&gt;Translation mapping&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The simulator is not competing with research-grade systems.&lt;/p&gt;

&lt;p&gt;It borrows concepts from computational biology and simplifies them into something approachable.&lt;/p&gt;

&lt;h4&gt;
  
  
  Inspiration from published Science research
&lt;/h4&gt;

&lt;p&gt;The project notes inspiration from research published in &lt;em&gt;Science&lt;/em&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.science.org/doi/abs/10.1126/science.aed1656" rel="noopener noreferrer"&gt;https://www.science.org/doi/abs/10.1126/science.aed1656&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The simulator &lt;strong&gt;does not&lt;/strong&gt; reproduce the paper’s findings.&lt;/p&gt;

&lt;p&gt;The connection is &lt;strong&gt;conceptual.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Modern biology increasingly depends on inference.&lt;/p&gt;

&lt;p&gt;Researchers often estimate relationships between biological systems rather than directly observing every process.&lt;/p&gt;

&lt;p&gt;Protein folding prediction, sequence inference, and molecular modeling all rely on computational interpretation.&lt;/p&gt;

&lt;p&gt;The simulator fits within that broader idea.&lt;/p&gt;

&lt;p&gt;It asks:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;If proteins preserve traces of DNA history, how much can we estimate from those traces?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;That question alone makes the project worth exploring.&lt;/p&gt;

&lt;h4&gt;
  
  
  Why uncertainty is the most valuable part of the simulator
&lt;/h4&gt;

&lt;p&gt;The strongest lesson here is not reverse translation.&lt;/p&gt;

&lt;p&gt;It is uncertainty.&lt;/p&gt;

&lt;p&gt;Science education sometimes creates the illusion that biology always produces clean answers.&lt;/p&gt;

&lt;p&gt;The simulator quietly pushes against that assumption.&lt;/p&gt;

&lt;p&gt;You expect one DNA sequence.&lt;/p&gt;

&lt;p&gt;You discover many possibilities.&lt;/p&gt;

&lt;p&gt;You expect certainty.&lt;/p&gt;

&lt;p&gt;You find ambiguity.&lt;/p&gt;

&lt;p&gt;That is closer to how real biological reasoning works.&lt;/p&gt;

&lt;h4&gt;
  
  
  What makes the project useful for education
&lt;/h4&gt;

&lt;p&gt;The simulator works well for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Students learning transcription and translation&lt;/li&gt;
&lt;li&gt;Beginners exploring codon relationships&lt;/li&gt;
&lt;li&gt;Developers interested in biological computation&lt;/li&gt;
&lt;li&gt;Bioinformatics learners experimenting with sequence logic&lt;/li&gt;
&lt;li&gt;People curious about molecular coding systems&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The project does not require laboratory experience.&lt;/p&gt;

&lt;p&gt;It asks users to think.&lt;/p&gt;

&lt;p&gt;That alone gives it educational value.&lt;/p&gt;

&lt;h4&gt;
  
  
  Where the simulator could grow
&lt;/h4&gt;

&lt;p&gt;There are several additions that could deepen the learning experience.&lt;/p&gt;

&lt;h4&gt;
  
  
  Organism-specific codon bias
&lt;/h4&gt;

&lt;p&gt;Different organisms prefer different codons.&lt;/p&gt;

&lt;p&gt;Adding selectable species would make reverse translation more realistic.&lt;/p&gt;

&lt;h4&gt;
  
  
  Multiple DNA candidates
&lt;/h4&gt;

&lt;p&gt;Instead of returning one sequence, the simulator could generate ranked alternatives.&lt;/p&gt;

&lt;h4&gt;
  
  
  Probability scoring
&lt;/h4&gt;

&lt;p&gt;Codon likelihood could help explain why some outputs are more plausible.&lt;/p&gt;

&lt;h4&gt;
  
  
  Structural hints
&lt;/h4&gt;

&lt;p&gt;The analysis page could flag patterns associated with alpha helices or beta sheets.&lt;/p&gt;

&lt;h4&gt;
  
  
  Sequence comparison
&lt;/h4&gt;

&lt;p&gt;Comparing proteins side-by-side would help explain mutation and similarity.&lt;/p&gt;

&lt;p&gt;These additions would not make the simulator “correct.”&lt;/p&gt;

&lt;p&gt;They would make uncertainty easier to understand.&lt;/p&gt;

&lt;h4&gt;
  
  
  Final thoughts
&lt;/h4&gt;

&lt;p&gt;The &lt;em&gt;Protein → DNA Synthesis Simulator&lt;/em&gt; works best when treated as a reasoning tool.&lt;/p&gt;

&lt;p&gt;It does not reconstruct biology.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;It explores biological possibility.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The GitHub version explains the concept.&lt;/p&gt;

&lt;p&gt;The protein analysis page adds interpretation.&lt;/p&gt;

&lt;p&gt;The live web version makes the process interactive.&lt;/p&gt;

&lt;p&gt;Together, they create a small ecosystem for thinking about biological information in reverse.&lt;/p&gt;

&lt;p&gt;The project becomes more interesting once you stop asking:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;“Is this the original DNA?”&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;and start asking:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;“What assumptions make this sequence plausible?”&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;That shift changes the experience.&lt;/p&gt;

&lt;p&gt;You stop seeing proteins as endpoints.&lt;/p&gt;

&lt;p&gt;You start seeing them as traces.&lt;/p&gt;

&lt;p&gt;And sometimes, tracing hidden information is more interesting than certainty.&lt;/p&gt;

&lt;h4&gt;
  
  
  Project links
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Main simulator: &lt;a href="https://rotsl.github.io/protein2dna_synthesis-simulator/" rel="noopener noreferrer"&gt;https://rotsl.github.io/protein2dna_synthesis-simulator/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Protein analysis page :&lt;/li&gt;
&lt;li&gt;Interactive web version: &lt;a href="https://protein-dna-simulator.vercel.app/" rel="noopener noreferrer"&gt;https://protein-dna-simulator.vercel.app/&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  References
&lt;/h4&gt;

&lt;p&gt;[1] Peiwei Deng, Heewon Lee, Carlos Armijo, Hao Wang, and Albert Gao. Protein-templated synthesis of di-nucleotide repeat DNA by an anti-phage reverse transcriptase. Science, page aed1656, 2026. PDB: 9Z6Y.&lt;/p&gt;

&lt;p&gt;[2] Alexander A. Green, Pamela A. Silver, James J. Collins, and Peng Yin. Toehold switches: De-novo-designed regulators of gene expression. Cell, 159:925–939, 2014.&lt;/p&gt;

&lt;p&gt;[3] Andrew V. Anzalone, Peyton B. Randolph, Jessie R. Davis, Alexander A. Sousa, LukeW.Koblan, JonathanM.Levy, PeterJ.Chen, ChristopherWilson, GregoryA. Newby, Aditya Raguram, and David R. Liu. Search-and-replace genome editing without double-strand breaks or donor DNA. Nature, 576:149–157, 2019.&lt;/p&gt;

&lt;p&gt;[4] Andrew V. Anzalone, Xin D. Gao, Christopher J. Podracky, Andrew T. Nelson, Luke W. Koblan, Aditya Raguram, Jonathan M. Levy, Jeffry A. M. Mercer, and David R. Liu. Programmable deletion, replacement, integration and inversion of large DNA sequences with twin prime editing. Nature Biotechnology, 40:731–740, 2022.&lt;/p&gt;

&lt;p&gt;[5] Rohan R. DRT3b Engineering Studio: Protein →RNA →DNA simulator. &lt;a href="https://github.com/rotsl/protein2dna_synthesis-simulator," rel="noopener noreferrer"&gt;https://github.com/rotsl/protein2dna_synthesis-simulator,&lt;/a&gt; 2026. Open-source web simulation platform. Live app: &lt;a href="https://protein-dna-simulator." rel="noopener noreferrer"&gt;https://protein-dna-simulator.&lt;/a&gt;vercel.app/.&lt;/p&gt;

&lt;p&gt;[6] Mihaly Varadi, Stephen Anyango, Mandar Deshpande, Sreenath Nair, Cindy Natassia, Galabina Yordanova, David Yuan, Oana Stroe, Gemma Wood, Agata Laydon, Augustin Žídek, Tim Green, Kathryn Tunyasuvunakool, Stig Petersen, John Jumper, Ellen Clancy, Richard Green, Oriol Vinyals, Demis Hassabis, and Sameer Velankar. AlphaFold Protein Structure Database: massive structural coverage for biology and medicine. Nucleic Acids Research, 50:D439–D444, 2022.&lt;/p&gt;

&lt;p&gt;[7] John Jumper, Richard Evans, Alexander Pritzel, Tim Green, Michael Figurnov, Olaf Ronneberger, Kathryn Tunyasuvunakool, Russ Bates, Augustin Žídek, Anna Potapenko, Alex Bridgland, Clemens Meyer, Simon A. A. Kohl, Andrew J. Ballard, Andrew Cowie, Bernardino Romera-Paredes, Stanislav Nikolov, Rishub Jain, Jonas Adler, Trevor Back, Stig Petersen, David Reiman, Ellen Clancy, Michal Zielinski, Martin Steinegger, Michalina Pacholska, Tamas Berghammer, Sebastian Bodenstein, David Silver, Oriol Vinyals, Andrew W. Senior, Koray Kavukcuoglu, Pushmeet Kohli, and Demis Hassabis. Highly accurate protein structure prediction with AlphaFold. Nature, 596:583–589, 2021.&lt;/p&gt;

&lt;p&gt;[8] Kirsten L. Frieda, James M. Linton, Sahand Hormoz, Junhong Choi, Koo-Lok K. Chow, Zeba S. Singer, Mark W. Budde, Michael B. Elowitz, and Long Cai. Synthetic recording and in situ readout of lineage information in single cells. Nature, 541:107–111, 2017.&lt;/p&gt;

&lt;p&gt;[9] Bushra Raj, Daniel E. Wagner, Aaron McKenna, Shristi Pandey, Allon M. Klein, Jay Shendure, Deepak L. Bhatt, and Bhatt Bhatt. GESTALT: a method for tracing lineage and clonal dynamics at single-cell resolution. Nature Biotechnology, 36:442–450, 2018.&lt;/p&gt;

&lt;p&gt;[10] Wenyuan Tang, James H. Hu, and David R. Liu. PEAR: a highly multiplexed lineage recorder based on prime editing and in situ barcode readout. Nature Methods, 21:1054–1065, 2024.&lt;/p&gt;

&lt;p&gt;[11] Junhong Choi, Wei Chen, Anna Minkina, Florence M. Chardon, Chase C. Suiter, Samuel G. Regalado, Silvia Domcke, Nobuhiko Hamazaki, Choli Lee, Beth Martin, Ryan M. Daza, and Jay Shendure. A temporally resolved, multi-symbolic molecular recorder based on sequential DNA writing. Nature Chemical Biology, 18:1204–1212, 2022.&lt;/p&gt;

&lt;p&gt;[12] Nathaniel Roquet, Ava P. Soleimany, Alyssa C. Ferris, Scott Wick, and Timothy K. Lu. Synthetic recombinase-based state machines in living cells. Science, 353:aad8559, 2016.&lt;/p&gt;

&lt;h4&gt;
  
  
  ⚠️ Important disclaimer
&lt;/h4&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;This project is simulation and hypothetical only and has not been tested or validated. This project is for educational purposes only.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>research</category>
      <category>alphafold</category>
      <category>molecularbiology</category>
      <category>protiensynthesis</category>
    </item>
    <item>
      <title>Hypercontext: a framework for agents that actually know what they're doing</title>
      <dc:creator>RoTSL</dc:creator>
      <pubDate>Mon, 20 Apr 2026 16:41:25 +0000</pubDate>
      <link>https://dev.to/rotsl/hypercontext-a-framework-for-agents-that-actually-know-what-theyre-doing-3e7p</link>
      <guid>https://dev.to/rotsl/hypercontext-a-framework-for-agents-that-actually-know-what-theyre-doing-3e7p</guid>
      <description>&lt;p&gt;I built Hypercontext because I got tired of agent frameworks that treat context like a static blob you shove into a prompt and hope for the best. Most tools out there assume context is something you &lt;em&gt;pass&lt;/em&gt;. I wanted something that treats context as something you can &lt;em&gt;inspect&lt;/em&gt;, &lt;em&gt;compress&lt;/em&gt;, &lt;em&gt;score&lt;/em&gt;, and &lt;em&gt;rewrite&lt;/em&gt; while the agent is running.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Hypercontext is still in Alpha phase.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This isn't about adding another layer of abstraction over OpenAI's API. It's about making agents aware of their own reasoning so they can fix it when it breaks.&lt;/p&gt;

&lt;h2&gt;
  
  
  What it actually does
&lt;/h2&gt;

&lt;p&gt;Hypercontext is a self-referential agent framework for Python and TypeScript. The core idea is simple: agents should be able to read and modify their own system prompts, tool descriptions, memory, and runtime capabilities based on whether they're actually succeeding at the task.&lt;/p&gt;

&lt;p&gt;The framework ships with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A Python SDK with orchestration, agents, scoring, memory, compression, deduplication, convergence detection, archive helpers, and extensions&lt;/li&gt;
&lt;li&gt;A TypeScript SDK for &lt;code&gt;Node.js&lt;/code&gt; with the same primitives&lt;/li&gt;
&lt;li&gt;A modular extension system for adding capabilities without modifying the core runtime&lt;/li&gt;
&lt;li&gt;Built-in research tooling extensions for web search, retrieval, and evidence gathering&lt;/li&gt;
&lt;li&gt;A &lt;code&gt;CLI&lt;/code&gt; for running compression, archive queries, provider discovery, orchestration, and extension workflows&lt;/li&gt;
&lt;li&gt;A curses-based terminal UI for browsing and pinning commands without leaving the shell&lt;/li&gt;
&lt;li&gt;A browser dashboard for visual inspection&lt;/li&gt;
&lt;li&gt;An MCP stdio daemon for Claude Desktop, Claude Code, and Codex integration&lt;/li&gt;
&lt;li&gt;An HTTP MCP server for web integrations&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Both SDKs are zero-dependency where possible. The Python core is pure Python. The TypeScript SDK has minimal deps. You can run the whole thing against Ollama locally without touching a cloud provider.&lt;/p&gt;

&lt;h2&gt;
  
  
  The problem with most agent frameworks
&lt;/h2&gt;

&lt;p&gt;I've used agents. They all share the same blind spot: context is treated as immutable input. You construct a prompt, feed it to the model, get output back. If the output is wrong, you tweak the prompt and try again. The agent itself has no idea what worked and what didn't across runs.&lt;/p&gt;

&lt;p&gt;Hypercontext changes this by making context a first-class citizen that agents can manipulate. Each generation gets tracked as a node in a lineage tree. You can see which parent led to which result, which branch is going stale, and which context configuration produced the best score. Successful strategies get archived and reused. Failed ones get pruned.&lt;/p&gt;

&lt;p&gt;This isn't theoretical. The archive stores scored generations so later runs can compare branches and identify the strongest evolution path. Memory is split between persistent storage (lessons across runs) and episodic storage (context within a single session).&lt;/p&gt;

&lt;p&gt;Hypercontext also treats tooling as adaptive context. Extensions can expose capabilities dynamically during execution, allowing an agent to decide when external retrieval, research, or analysis should become part of its reasoning loop.&lt;/p&gt;

&lt;h2&gt;
  
  
  How the context loop works
&lt;/h2&gt;

&lt;p&gt;Here's the basic flow:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The agent receives a task and its current context window&lt;/li&gt;
&lt;li&gt;It generates a response and scores the result against a fitness function&lt;/li&gt;
&lt;li&gt;If the score is below threshold, the agent reflects on what went wrong&lt;/li&gt;
&lt;li&gt;It rewrites its own system prompt, tool descriptions, memory, or extension configuration based on that reflection&lt;/li&gt;
&lt;li&gt;The new context configuration gets tested in the next generation&lt;/li&gt;
&lt;li&gt;Successful configurations get archived; failed ones get discarded&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This happens automatically in the &lt;code&gt;TaskAgent&lt;/code&gt; and &lt;code&gt;MetaAgent&lt;/code&gt; classes. You don't need to hand-code the reflection logic unless you want to.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;MetaAgent&lt;/code&gt; goes further. It can perform repository-aware tool use, extension orchestration, and self-modification workflows. If you point it at a codebase with &lt;code&gt;--workdir&lt;/code&gt;, it can inspect files, suggest modifications, and track whether those modifications improved the code quality.&lt;/p&gt;

&lt;h2&gt;
  
  
  Extensions system
&lt;/h2&gt;

&lt;p&gt;One of the biggest additions to Hypercontext is the extension architecture.&lt;/p&gt;

&lt;p&gt;Extensions allow you to add runtime capabilities without bloating the core framework. Instead of hardcoding every tool into the agent runtime, Hypercontext lets you compose functionality based on the task.&lt;/p&gt;

&lt;p&gt;Extensions can provide:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Tool registries&lt;/li&gt;
&lt;li&gt;Retrieval pipelines&lt;/li&gt;
&lt;li&gt;Research workflows&lt;/li&gt;
&lt;li&gt;Context enrichers&lt;/li&gt;
&lt;li&gt;External APIs&lt;/li&gt;
&lt;li&gt;Scoring hooks&lt;/li&gt;
&lt;li&gt;Middleware layers&lt;/li&gt;
&lt;li&gt;Memory augmentation&lt;/li&gt;
&lt;li&gt;Custom orchestration behaviors&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This keeps the framework modular while still allowing deeply integrated workflows.&lt;/p&gt;

&lt;p&gt;Extensions are designed to be lightweight and composable. You can enable only what your workflow requires.&lt;/p&gt;

&lt;h2&gt;
  
  
  Research tools extension
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;research_tools&lt;/code&gt; extension adds structured information gathering to Hypercontext.&lt;/p&gt;

&lt;p&gt;Instead of forcing agents to rely purely on static context or hallucinated recall, the extension provides a research layer that can gather, refine, and reuse evidence during execution.&lt;/p&gt;

&lt;p&gt;The extension includes capabilities for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Query expansion&lt;/li&gt;
&lt;li&gt;Iterative research loops&lt;/li&gt;
&lt;li&gt;Evidence collection&lt;/li&gt;
&lt;li&gt;Citation-aware retrieval&lt;/li&gt;
&lt;li&gt;Multi-step search refinement&lt;/li&gt;
&lt;li&gt;Context injection from retrieved sources&lt;/li&gt;
&lt;li&gt;Search result scoring and filtering&lt;/li&gt;
&lt;li&gt;Research memory persistence across generations&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This matters because long-running reasoning tasks often fail not from poor prompting but from incomplete information. Research tooling allows the agent to actively reduce uncertainty.&lt;/p&gt;

&lt;p&gt;The extension integrates directly into the context evolution loop, meaning research results become part of the lineage and scoring process rather than existing as disconnected tool outputs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Installation and setup
&lt;/h2&gt;

&lt;p&gt;For Python:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pip &lt;span class="nb"&gt;install &lt;/span&gt;hypercontext
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For Node.js:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install &lt;/span&gt;hypercontext-node-sdk
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's it. No separate MCP package to install. No complex dependency tree.&lt;/p&gt;

&lt;p&gt;The Python package includes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Core SDK&lt;/li&gt;
&lt;li&gt;CLI&lt;/li&gt;
&lt;li&gt;TUI&lt;/li&gt;
&lt;li&gt;Browser dashboard launcher&lt;/li&gt;
&lt;li&gt;MCP stdio daemon&lt;/li&gt;
&lt;li&gt;HTTP server&lt;/li&gt;
&lt;li&gt;Built-in extensions&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The &lt;code&gt;npm&lt;/code&gt; package is the SDK layer for Node.js projects.&lt;/p&gt;

&lt;h2&gt;
  
  
  Provider setup
&lt;/h2&gt;

&lt;p&gt;Hypercontext doesn't lock you into a provider. It supports Claude, OpenAI, Ollama, OpenAI-compatible servers, and local transformers models. You set credentials via environment variables or a YAML config file with named presets.&lt;/p&gt;

&lt;p&gt;For Claude:&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="nv"&gt;HYPERCONTEXT_PROVIDER&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;anthropic
&lt;span class="nv"&gt;HYPERCONTEXT_MODEL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;claude-sonnet-4-20250514
&lt;span class="nv"&gt;ANTHROPIC_API_KEY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;your-key-here
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For Ollama (fully local):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ollama serve
ollama pull llama3

&lt;span class="nv"&gt;HYPERCONTEXT_PROVIDER&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;ollama
&lt;span class="nv"&gt;HYPERCONTEXT_MODEL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;llama3
&lt;span class="nv"&gt;OLLAMA_BASE_URL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;http://localhost:11434
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The named preset feature is useful when you want multiple backends in one project. You define them in a &lt;code&gt;YAML&lt;/code&gt; file and resolve by name at runtime. The framework expands &lt;code&gt;${VAR}&lt;/code&gt; values from the environment, so secrets stay out of config files.&lt;/p&gt;

&lt;h2&gt;
  
  
  Using extensions in Python
&lt;/h2&gt;

&lt;p&gt;Extensions are loaded directly into the runtime.&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="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;hypercontext&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;HyperContext&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;hypercontext.extensions&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;ResearchToolsExtension&lt;/span&gt;

&lt;span class="n"&gt;hc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;HyperContext&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;output_dir&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;./hypercontext_output&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;hc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nc"&gt;ResearchToolsExtension&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;summary&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;hc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;max_generations&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;summary&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can compose multiple extensions together depending on the workflow.&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;hc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;ResearchToolsExtension&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;span class="n"&gt;hc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;CustomMemoryExtension&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;span class="n"&gt;hc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;CustomScoringExtension&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Extensions participate in orchestration rather than existing as isolated plugins.&lt;/p&gt;

&lt;h2&gt;
  
  
  Using it in Python
&lt;/h2&gt;

&lt;p&gt;Direct orchestration is straightforward:&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="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;hypercontext&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;HyperContext&lt;/span&gt;

&lt;span class="n"&gt;hc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;HyperContext&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;output_dir&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;./hypercontext_output&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;summary&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;hc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;max_generations&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;summary&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you want provider-backed calls without the full orchestration loop:&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="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;hypercontext&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;LLMClient&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;hypercontext.providers&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;ProviderRegistry&lt;/span&gt;

&lt;span class="n"&gt;registry&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ProviderRegistry&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;instance&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="n"&gt;provider&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;registry&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;anthropic&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;claude-sonnet-4-20250514&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;api_key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;your-key-here&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;base_url&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://api.anthropic.com&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;LLMClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;provider&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;provider&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;history&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;metadata&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;complete&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Summarize this in one sentence.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For agent workflows, you choose between &lt;code&gt;TaskAgent&lt;/code&gt; (repeatable tasks) and &lt;code&gt;MetaAgent&lt;/code&gt; (repository-aware reasoning and self-modification). Both support context evolution and extension-aware execution.&lt;/p&gt;

&lt;h2&gt;
  
  
  Using it in TypeScript
&lt;/h2&gt;

&lt;p&gt;The Node SDK follows the same patterns:&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="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;ContextWindow&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;TaskAgent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;StructuredOutputParser&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;EnhancedToolRegistry&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;LoggingMiddleware&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;hypercontext-node-sdk&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="nb"&gt;window&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;ContextWindow&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;4096&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Important context&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;1.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;system&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;agent&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;TaskAgent&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;demo&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;maxTokens&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1024&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;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;agent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;forward&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;query&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;hello&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;parser&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;StructuredOutputParser&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="nx"&gt;parser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parseFirst&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Answer: {"status":"ok"}&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;registry&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;EnhancedToolRegistry&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="nx"&gt;registry&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;LoggingMiddleware&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;

&lt;span class="nx"&gt;registry&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;registerTool&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;echo&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Echo a payload back&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;parameters&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;object&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="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The TypeScript SDK includes context compression, retrieval, lineage tracking, persistent memory, fitness evaluation, structured output parsing, and extension support.&lt;/p&gt;

&lt;h2&gt;
  
  
  CLI and terminal UI
&lt;/h2&gt;

&lt;p&gt;The Python package includes a full CLI:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python &lt;span class="nt"&gt;-m&lt;/span&gt; hypercontext version
python &lt;span class="nt"&gt;-m&lt;/span&gt; hypercontext providers
python &lt;span class="nt"&gt;-m&lt;/span&gt; hypercontext run &lt;span class="nt"&gt;--generations&lt;/span&gt; 5 &lt;span class="nt"&gt;--output-dir&lt;/span&gt; ./runs/demo &lt;span class="nt"&gt;--workdir&lt;/span&gt; &lt;span class="nb"&gt;.&lt;/span&gt;
python &lt;span class="nt"&gt;-m&lt;/span&gt; hypercontext compress &lt;span class="nt"&gt;--input&lt;/span&gt; long_text.txt &lt;span class="nt"&gt;--ratio&lt;/span&gt; 0.4
python &lt;span class="nt"&gt;-m&lt;/span&gt; hypercontext archive &lt;span class="nt"&gt;--list&lt;/span&gt;
python &lt;span class="nt"&gt;-m&lt;/span&gt; hypercontext extensions &lt;span class="nt"&gt;--list&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;TUI&lt;/code&gt; is a curses dashboard for browsing commands, pinning favorites, and executing them without leaving the terminal.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python &lt;span class="nt"&gt;-m&lt;/span&gt; hypercontext tui &lt;span class="nt"&gt;--workdir&lt;/span&gt; /path/to/project
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For desktop assistants, the stdio MCP daemon handles Claude Desktop, Claude Code, and Codex:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python &lt;span class="nt"&gt;-m&lt;/span&gt; hypercontext mcp &lt;span class="nt"&gt;--workdir&lt;/span&gt; /path/to/project
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For browser integrations, the HTTP server exposes the same tools over a REST interface:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python &lt;span class="nt"&gt;-m&lt;/span&gt; hypercontext serve &lt;span class="nt"&gt;--port&lt;/span&gt; 8080 &lt;span class="nt"&gt;--workdir&lt;/span&gt; /path/to/project
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  MCP integration without the hassle
&lt;/h2&gt;

&lt;p&gt;Most MCP implementations require you to install a separate package and configure &lt;code&gt;JSON&lt;/code&gt; files.&lt;/p&gt;

&lt;p&gt;Hypercontext bundles the &lt;code&gt;stdio daemon&lt;/code&gt; and &lt;code&gt;HTTP&lt;/code&gt; server directly.&lt;/p&gt;

&lt;p&gt;You don't need to install additional MCP dependencies.&lt;/p&gt;

&lt;p&gt;The stdio daemon speaks the Model Context Protocol natively. Claude Desktop can discover and invoke Hypercontext tools without manual configuration. The HTTP server provides the same capability for browser and web integrations.&lt;/p&gt;

&lt;p&gt;Extensions can also expose MCP-accessible tools, making them available to external clients automatically.&lt;/p&gt;

&lt;h2&gt;
  
  
  Context compression and deduplication
&lt;/h2&gt;

&lt;p&gt;One of the practical problems with long-running agents is context bloat.&lt;/p&gt;

&lt;p&gt;Hypercontext includes a &lt;code&gt;ContextCompressor&lt;/code&gt; that reduces text size while preserving semantic meaning.&lt;/p&gt;

&lt;p&gt;There's also a validator that checks compression fidelity so you don't accidentally drop important information.&lt;/p&gt;

&lt;p&gt;The deduplication layer identifies repeated patterns across generations and collapses them.&lt;/p&gt;

&lt;p&gt;This matters when you're running evolutionary loops where similar context configurations get tested repeatedly.&lt;/p&gt;

&lt;h2&gt;
  
  
  Lineage tracking
&lt;/h2&gt;

&lt;p&gt;Every generation gets a unique ID and tracks its parent.&lt;/p&gt;

&lt;p&gt;You can query the lineage tree to answer questions like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Which generation produced the best score?&lt;/li&gt;
&lt;li&gt;Which parent led to this result?&lt;/li&gt;
&lt;li&gt;Which branch hasn't improved in the last 10 generations?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This isn't just logging.&lt;/p&gt;

&lt;p&gt;The lineage data feeds back into the parent selection strategy for the next generation.&lt;/p&gt;

&lt;p&gt;Stagnant branches get deprioritized. High-fitness branches get explored further.&lt;/p&gt;

&lt;p&gt;Research extension outputs can also become lineage artifacts, meaning evidence chains are tracked alongside prompt evolution.&lt;/p&gt;

&lt;h2&gt;
  
  
  Archive and transfer learning
&lt;/h2&gt;

&lt;p&gt;The archive stores proven context configurations ranked by fitness score.&lt;/p&gt;

&lt;p&gt;When you start a new task, the framework can query the archive for context patterns that worked well on similar tasks.&lt;/p&gt;

&lt;p&gt;This is transfer learning without neural network retraining.&lt;/p&gt;

&lt;p&gt;You're transferring context strategies instead of model weights.&lt;/p&gt;

&lt;p&gt;The archive is queryable via CLI:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python &lt;span class="nt"&gt;-m&lt;/span&gt; hypercontext archive &lt;span class="nt"&gt;--query&lt;/span&gt; &lt;span class="s2"&gt;"task:code-review fitness:&amp;gt;0.8"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Archived runs can include extension-derived context, allowing successful research workflows to be reused across future tasks.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I learned building this
&lt;/h2&gt;

&lt;p&gt;I started this project after reading the Hyperagents paper and getting frustrated that none of the existing frameworks implemented the meta-cognitive ideas in a practical way.&lt;/p&gt;

&lt;p&gt;Most research code is a mess of Jupyter notebooks and hardcoded paths.&lt;/p&gt;

&lt;p&gt;I wanted something you could actually install and use.&lt;/p&gt;

&lt;p&gt;The hardest part wasn't compression or lineage tracking.&lt;/p&gt;

&lt;p&gt;It was designing the agent loop so self-modification doesn't spiral into chaos.&lt;/p&gt;

&lt;p&gt;If an agent can rewrite its own system prompt, it can also break its own system prompt.&lt;/p&gt;

&lt;p&gt;The convergence detection layer stops the loop when scores plateau or when context configurations start cycling.&lt;/p&gt;

&lt;p&gt;I also learned that modularity matters more than feature count.&lt;/p&gt;

&lt;p&gt;Extensions let Hypercontext grow without turning the framework into an unmaintainable monolith.&lt;/p&gt;

&lt;h2&gt;
  
  
  Current state and what's next
&lt;/h2&gt;

&lt;p&gt;The framework is functional and I'm using it in my own projects.&lt;/p&gt;

&lt;p&gt;The Python package is on PyPI, the TypeScript SDK is on npm, and the docs are on GitHub Pages.&lt;/p&gt;

&lt;p&gt;I'm currently working on:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Better convergence heuristics for multi-objective optimization&lt;/li&gt;
&lt;li&gt;A web-based lineage visualizer&lt;/li&gt;
&lt;li&gt;Additional extension categories&lt;/li&gt;
&lt;li&gt;Improved research pipelines&lt;/li&gt;
&lt;li&gt;Benchmark suites to compare context strategies across tasks&lt;/li&gt;
&lt;li&gt;Better local model workflows&lt;/li&gt;
&lt;li&gt;More retrieval-aware orchestration patterns&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The repo includes runnable examples for evolution, lineage tracking, self-modifying agents, extensions, provider workflows, and research tooling.&lt;/p&gt;

&lt;p&gt;If you want to see what the framework can do without writing code, start with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;examples/python/feature_gallery.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Try it
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Python&lt;/span&gt;
pip &lt;span class="nb"&gt;install &lt;/span&gt;hypercontext
python &lt;span class="nt"&gt;-m&lt;/span&gt; hypercontext version

&lt;span class="c"&gt;# TypeScript&lt;/span&gt;
npm &lt;span class="nb"&gt;install &lt;/span&gt;hypercontext-node-sdk
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://rotsl.github.io/hypercontext/" rel="noopener noreferrer"&gt;Docs&lt;/a&gt;&lt;br&gt;
&lt;a href="https://rotsl.github.io/hypercontext/extensions/research_tools/" rel="noopener noreferrer"&gt;Extensions&lt;/a&gt;&lt;br&gt;
&lt;a href="https://pypi.org/project/hypercontext/" rel="noopener noreferrer"&gt;PyPI&lt;/a&gt;&lt;br&gt;
&lt;a href="https://www.npmjs.com/package/hypercontext-node-sdk" rel="noopener noreferrer"&gt;npm&lt;/a&gt;&lt;/p&gt;

</description>
      <category>python</category>
      <category>ai</category>
      <category>agents</category>
      <category>typescript</category>
    </item>
    <item>
      <title>NoB (Noticeably Better): a compiled language that tries to stay out of your way</title>
      <dc:creator>RoTSL</dc:creator>
      <pubDate>Mon, 13 Apr 2026 12:39:52 +0000</pubDate>
      <link>https://dev.to/rotsl/nob-noticeably-better-a-compiled-language-that-tries-to-stay-out-of-your-way-163</link>
      <guid>https://dev.to/rotsl/nob-noticeably-better-a-compiled-language-that-tries-to-stay-out-of-your-way-163</guid>
      <description>&lt;p&gt;Most new languages promise the same things: performance, simplicity, better tooling. NoB is trying to hit those too—but the interesting part is how it actually does it.&lt;/p&gt;

&lt;p&gt;At its core, NoB is a &lt;strong&gt;compiled language that targets C++20&lt;/strong&gt;, with a second execution path through a &lt;strong&gt;bytecode VM&lt;/strong&gt;. That split ends up being more practical than it sounds.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Website: &lt;a href="https://nob-lang.omni-flows.uk/" rel="noopener noreferrer"&gt;https://nob-lang.omni-flows.uk/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Source: private / proprietary
&lt;/li&gt;
&lt;li&gt;Platforms: macOS, Linux, Windows (via WSL2)&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  What NoB actually is
&lt;/h2&gt;

&lt;p&gt;NoB compiles &lt;code&gt;.nob&lt;/code&gt; code into C++20, then uses &lt;code&gt;clang++&lt;/code&gt; to produce a native binary.&lt;/p&gt;

&lt;p&gt;There’s also a VM mode that skips compilation entirely and runs bytecode instead.&lt;/p&gt;

&lt;p&gt;That gives you two very different workflows:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Native pipeline&lt;/strong&gt; → slower startup, fast runtime
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;VM pipeline&lt;/strong&gt; → instant startup, slower runtime
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In practice, it feels like using two tools under one language.&lt;/p&gt;




&lt;h2&gt;
  
  
  The two pipelines (and when they matter)
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Native (default)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;nob file.nob
nob file.nob &lt;span class="nt"&gt;-o&lt;/span&gt; app
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is what you’d use for anything serious.&lt;br&gt;
    • Compiles via C++20&lt;br&gt;
    • Uses clang++&lt;br&gt;
    • Runs as a native binary&lt;br&gt;
    • Supports everything (networking, threads, async, etc.)&lt;/p&gt;



&lt;p&gt;VM mode&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;nob &lt;span class="nt"&gt;--vm&lt;/span&gt; file.nob

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This skips the compiler completely.&lt;/p&gt;

&lt;p&gt;It’s useful for:&lt;br&gt;
    • quick scripts&lt;br&gt;
    • REPL work&lt;br&gt;
    • testing ideas&lt;/p&gt;

&lt;p&gt;But it’s not feature-complete. Networking, threading, and some advanced features don’t work here.&lt;/p&gt;



&lt;p&gt;The syntax (closer to Python than C++)&lt;/p&gt;

&lt;p&gt;The syntax leans readable without being too loose.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight lua"&gt;&lt;code&gt;
&lt;span class="n"&gt;set&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="n"&gt;to&lt;/span&gt; &lt;span class="s2"&gt;"Alice"&lt;/span&gt;

&lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;greet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s2"&gt;"Hello, {name}"&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="nb"&gt;print&lt;/span&gt; &lt;span class="n"&gt;greet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"Bob"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A few things stand out:&lt;br&gt;
    • set vs let (mutable vs immutable)&lt;br&gt;
    • 1-based indexing&lt;br&gt;
    • string interpolation built-in&lt;br&gt;
    • structured blocks without braces&lt;/p&gt;

&lt;p&gt;It’s easy to pick up, especially if you’ve used Python or Lua.&lt;/p&gt;



&lt;p&gt;Features that are actually interesting&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Tail-call optimization&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Recursive functions don’t blow the stack if written in tail form:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight lua"&gt;&lt;code&gt;
&lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;sum_tail&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;acc&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;acc&lt;/span&gt; &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;sum_tail&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;acc&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This gets compiled into a loop automatically.&lt;/p&gt;




&lt;ol&gt;
&lt;li&gt;Pipe operator
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight lua"&gt;&lt;code&gt;
&lt;span class="n"&gt;words&lt;/span&gt;
  &lt;span class="err"&gt;|&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt; &lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="err"&gt;|&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;upper&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="err"&gt;|&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;sort&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It makes chained transformations easier to read.&lt;/p&gt;




&lt;ol&gt;
&lt;li&gt;Macros (compile-time)
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight lua"&gt;&lt;code&gt;
&lt;span class="n"&gt;macro&lt;/span&gt; &lt;span class="n"&gt;swap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;set&lt;/span&gt; &lt;span class="n"&gt;tmp&lt;/span&gt; &lt;span class="n"&gt;to&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;
  &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;
  &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;tmp&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These run at compile time, not runtime.&lt;/p&gt;




&lt;ol&gt;
&lt;li&gt;Python backend
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;
nob py file.nob &lt;span class="nt"&gt;-o&lt;/span&gt; file.py &lt;span class="nt"&gt;--run&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This converts NoB into Python so you can use Python libraries like NumPy or OpenCV.&lt;/p&gt;

&lt;p&gt;There are limits (no macros, no pipe operator), but it’s useful when you need the ecosystem.&lt;/p&gt;




&lt;ol&gt;
&lt;li&gt;Built-in concurrency (native only)
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight lua"&gt;&lt;code&gt;
&lt;span class="n"&gt;set&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="n"&gt;to&lt;/span&gt; &lt;span class="n"&gt;thread_spawn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;function&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="nb"&gt;print&lt;/span&gt; &lt;span class="s2"&gt;"running"&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;thread_join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Includes threads, mutexes, channels, and async support.&lt;/p&gt;




&lt;p&gt;Tooling (built-in)&lt;/p&gt;

&lt;p&gt;NoB ships with a lot already included:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;
nob repl
nob check file.nob
nob profile file.nob
nob &lt;span class="nb"&gt;fmt &lt;/span&gt;file.nob
nob gui

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notable pieces:&lt;br&gt;
    • GUI REPL (nob gui)&lt;br&gt;
    • formatter and profiler included&lt;br&gt;
    • package manager (nob pkg)&lt;/p&gt;

&lt;p&gt;You don’t need to assemble a separate toolchain.&lt;/p&gt;



&lt;p&gt;Performance&lt;/p&gt;

&lt;p&gt;From the official benchmarks:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Benchmark&lt;/th&gt;
&lt;th&gt;Python&lt;/th&gt;
&lt;th&gt;NoB&lt;/th&gt;
&lt;th&gt;Speedup&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Simple loop&lt;/td&gt;
&lt;td&gt;0.498s&lt;/td&gt;
&lt;td&gt;0.046s&lt;/td&gt;
&lt;td&gt;~10.9×&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Prime count&lt;/td&gt;
&lt;td&gt;0.090s&lt;/td&gt;
&lt;td&gt;0.018s&lt;/td&gt;
&lt;td&gt;~4.9×&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Fibonacci&lt;/td&gt;
&lt;td&gt;0.734s&lt;/td&gt;
&lt;td&gt;0.484s&lt;/td&gt;
&lt;td&gt;~1.5×&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;What this means&lt;br&gt;
    • Big gains in loops and numeric work&lt;br&gt;
    • Smaller gains in recursive workloads&lt;br&gt;
    • Much faster than Python for CPU-heavy code&lt;/p&gt;



&lt;p&gt;Compilation targets&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;
nob file.nob &lt;span class="nt"&gt;--profile&lt;/span&gt; simd
nob file.nob &lt;span class="nt"&gt;--profile&lt;/span&gt; cuda
nob file.nob &lt;span class="nt"&gt;--profile&lt;/span&gt; wasm

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Supports:&lt;br&gt;
    • SIMD optimized builds&lt;br&gt;
    • CUDA / OpenCL&lt;br&gt;
    • WebAssembly&lt;br&gt;
    • LLVM IR&lt;/p&gt;




&lt;p&gt;Platform support&lt;/p&gt;

&lt;p&gt;Platform    Support&lt;br&gt;
macOS   Native&lt;br&gt;
Linux   Native&lt;br&gt;
Windows WSL2&lt;/p&gt;




&lt;p&gt;Pricing (indicative)&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Tier&lt;/th&gt;
&lt;th&gt;Price&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Free&lt;/td&gt;
&lt;td&gt;£0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Indie&lt;/td&gt;
&lt;td&gt;£5–10/month&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Pro&lt;/td&gt;
&lt;td&gt;£10–20/month&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;p&gt;Where it fits&lt;/p&gt;

&lt;p&gt;NoB makes sense if you want:&lt;br&gt;
    • something faster than Python&lt;br&gt;
    • something simpler than C++&lt;br&gt;
    • built-in tooling without extra setup&lt;/p&gt;

&lt;p&gt;Less ideal if you need:&lt;br&gt;
    • a large ecosystem&lt;br&gt;
    • long-established tooling&lt;/p&gt;




&lt;p&gt;Final thoughts&lt;/p&gt;

&lt;p&gt;NoB isn’t trying to reinvent programming. It’s trying to remove friction.&lt;/p&gt;

&lt;p&gt;The dual pipeline is the most practical part—you can prototype quickly in VM mode, then switch to native when performance matters.&lt;/p&gt;

&lt;p&gt;It’s early, but the core design is solid. Worth keeping an eye on.&lt;/p&gt;

</description>
      <category>programming</category>
      <category>oop</category>
      <category>nob</category>
      <category>architecture</category>
    </item>
    <item>
      <title>I built a safety net for python environments because I was tired of debugging “It works on my machine”</title>
      <dc:creator>RoTSL</dc:creator>
      <pubDate>Thu, 09 Apr 2026 09:59:33 +0000</pubDate>
      <link>https://dev.to/rotsl/i-built-a-safety-net-for-python-environments-because-i-was-tired-of-debugging-it-works-on-my-1hig</link>
      <guid>https://dev.to/rotsl/i-built-a-safety-net-for-python-environments-because-i-was-tired-of-debugging-it-works-on-my-1hig</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;Why every python developer needs a preflight check for their code&lt;/p&gt;
&lt;/blockquote&gt;

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

&lt;p&gt;I used to have a recurring nightmare. I’d be halfway through a machine learning experiment, three hours into training, when suddenly everything would explode. Not because my code was wrong, but because my environment was quietly broken in a way I couldn’t see coming. Wrong Python version. A package that got installed with pip instead of conda. A wheel that claimed to support my architecture but didn’t. &lt;strong&gt;Rosetta 2&lt;/strong&gt; running my &lt;strong&gt;arm64&lt;/strong&gt; Python as &lt;strong&gt;x86_64&lt;/strong&gt; and tanking my GPU acceleration.&lt;/p&gt;

&lt;p&gt;The error messages were always cryptic. The fixes were always tedious. And the worst part? I never knew if my environment was actually healthy until something went wrong.&lt;/p&gt;

&lt;p&gt;So I built &lt;a href="https://github.com/rotsl/envguard" rel="noopener noreferrer"&gt;&lt;strong&gt;EnvGuard&lt;/strong&gt;&lt;/a&gt;—a CLI tool that validates your Python environment &lt;strong&gt;before&lt;/strong&gt; you run your code, not after it breaks. Think of it as a preflight checklist for your Python projects. If something’s wrong, it blocks execution and tells you exactly what’s broken and how to fix it. If everything passes, your command runs in a validated environment.&lt;/p&gt;

&lt;p&gt;It’s macOS-first (because that’s where I do my work), runs on Linux with partial support, and deliberately doesn’t support Windows (because life’s too short for three-platform maintenance). You can install it from &lt;a href="https://pypi.org/project/envguard-tool/" rel="noopener noreferrer"&gt;&lt;strong&gt;PyPI&lt;/strong&gt;&lt;/a&gt; as &lt;code&gt;envguard-tool&lt;/code&gt; — the CLI command is just &lt;code&gt;envguard&lt;/code&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  The Problem: Python Environments Are Fragile and Invisible
&lt;/h4&gt;

&lt;p&gt;Python environment management is a solved problem in the same way that herding cats is a solved problem. Technically there are tools. Practically, things go wrong constantly.&lt;/p&gt;

&lt;p&gt;Here’s what actually happens in the wild:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The architecture confusion.&lt;/strong&gt; You install Python on an M1 Mac, but somehow you’re running the &lt;code&gt;x86\_64&lt;/code&gt; version under Rosetta 2. Everything works, but your Metal Performance Shaders (MPS) acceleration is silently disabled. PyTorch falls back to CPU. Your training takes 10x longer. You don’t notice until you check &lt;code&gt;activity monitor&lt;/code&gt; and see no GPU usage.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The mixed ownership trap.&lt;/strong&gt; You create a conda environment, but then you &lt;strong&gt;pip install&lt;/strong&gt; something because the conda version is outdated. Then you conda install something else. Now you have packages owned by two different managers, and &lt;code&gt;pip check&lt;/code&gt; is screaming about conflicts, but your code still runs so you ignore it until it doesn’t.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The CUDA delusion.&lt;/strong&gt; You’re on macOS, but your &lt;code&gt;requirements.txt&lt;/code&gt; includes &lt;code&gt;torch==2.0.0+cu118&lt;/code&gt; because you copied it from a Linux server. It installs fine. It even imports. But CUDA doesn’t exist on Apple Silicon, and your code fails three layers deep in a stack trace that mentions nothing about GPU compatibility.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The “it worked yesterday” mystery.&lt;/strong&gt; Your environment was fine. Then you updated one package. Now something else is broken. You have no idea what changed or when.&lt;/p&gt;

&lt;p&gt;These aren’t exotic edge cases. They’re daily experiences for Python developers working on ML, data science, or scientific computing projects. The existing tools — &lt;code&gt;conda&lt;/code&gt;, &lt;code&gt;pip&lt;/code&gt;, &lt;code&gt;poetry&lt;/code&gt;, &lt;code&gt;uv&lt;/code&gt;, &lt;code&gt;pyenv&lt;/code&gt; — are great at &lt;strong&gt;creating&lt;/strong&gt; environments. They’re terrible at &lt;strong&gt;validating&lt;/strong&gt; them continuously.&lt;/p&gt;

&lt;h4&gt;
  
  
  The Solution: Preflight Validation Every Single Time
&lt;/h4&gt;

&lt;p&gt;EnvGuard’s core idea is simple: instead of running &lt;code&gt;python train.py&lt;/code&gt; and hoping, you run &lt;code&gt;envguard run — python train.py&lt;/code&gt;. Before your code executes, EnvGuard runs a nine-step preflight pipeline:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Detect the host &lt;/strong&gt; — OS version, architecture (native &lt;code&gt;arm64&lt;/code&gt; vs &lt;code&gt;Intel&lt;/code&gt; vs &lt;code&gt;Rosetta 2&lt;/code&gt;), available package managers, network connectivity
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Discover the project&lt;/strong&gt;  — scan for &lt;code&gt;pyproject.toml&lt;/code&gt;, &lt;code&gt;requirements.txt&lt;/code&gt;, &lt;code&gt;environment.yml&lt;/code&gt;, &lt;code&gt;Pipfile&lt;/code&gt;, &lt;code&gt;poetry.lock&lt;/code&gt;, etc.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Analyze intent&lt;/strong&gt;  — figure out what environment type (venv/conda/pipenv/poetry), Python version, and accelerator targets (CPU/MPS/CUDA) the project needs
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Evaluate rules &lt;/strong&gt; — run 15+ validation rules to catch problems
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Fail-fast on critical issues &lt;/strong&gt; — block execution if anything is unrecoverable
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Create a resolution plan&lt;/strong&gt;  — determine exactly how to satisfy the environment requirements
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Create or repair the environment&lt;/strong&gt; — make sure the actual environment matches the requirements
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Validate the environment&lt;/strong&gt;  — run &lt;code&gt;pip check&lt;/code&gt; or equivalent to verify consistency
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Smoke test&lt;/strong&gt; — try importing key packages in an isolated subprocess to catch runtime failures&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If any step fails with a &lt;code&gt;CRITICAL&lt;/code&gt; finding, your command never runs. You get a clear error message explaining what went wrong and how to fix it. No cryptic tracebacks. No debugging environment issues at 2am.&lt;/p&gt;

&lt;h4&gt;
  
  
  What EnvGuard Actually Catches
&lt;/h4&gt;

&lt;p&gt;The rules engine evaluates 15+ specific checks. Here are the ones that have saved me the most pain:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Rule&lt;/th&gt;
&lt;th&gt;Severity&lt;/th&gt;
&lt;th&gt;What it catches&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;CUDA_ON_MACOS&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;CRITICAL&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Any CUDA dependency on macOS (hardware impossibility)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ROSETTA_TRANSLATION_DETECTED&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;WARNING&lt;/td&gt;
&lt;td&gt;x86_64 Python running under Rosetta 2 on Apple Silicon (kills MPS performance)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ARCHITECTURE_MISMATCH&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;ERROR&lt;/td&gt;
&lt;td&gt;Python architecture doesn't match project requirements&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;MIXED_PIP_CONDA_OWNERSHIP&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;WARNING&lt;/td&gt;
&lt;td&gt;Packages installed by both pip and conda (dependency hell indicator)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;WHEEL_INCOMPATIBLE&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;WARNING&lt;/td&gt;
&lt;td&gt;Wheel file doesn't match current platform/architecture&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;BROKEN_ENVIRONMENT&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;ERROR&lt;/td&gt;
&lt;td&gt;Active venv/conda is missing Python binary or critical files&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;PYTHON_VERSION_BELOW_MINIMUM&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;ERROR&lt;/td&gt;
&lt;td&gt;Python version below &lt;code&gt;requires-python&lt;/code&gt; in pyproject.toml&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;MPS_NOT_AVAILABLE&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;INFO&lt;/td&gt;
&lt;td&gt;Apple Silicon present but MPS not available (usually means PyTorch wasn't built with MPS support)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The &lt;code&gt;CUDA_ON_MACOS&lt;/code&gt; rule alone has probably saved me hours of debugging. Here’s what happens: you copy a &lt;code&gt;requirements.txt&lt;/code&gt; from a Linux machine that specifies &lt;code&gt;torch==2.1.0+cu118&lt;/code&gt;. You install it on your M1 Mac. It seems to work — pip doesn’t complain, the import succeeds. But when you actually try to move tensors to the GPU, you get a cryptic error about CUDA devices not being available. EnvGuard catches this at the dependency resolution stage and blocks execution with a message telling you to use &lt;code&gt;mps&lt;/code&gt; or &lt;code&gt;cpu&lt;/code&gt; targets instead.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;ROSETTA_TRANSLATION_DETECTED&lt;/code&gt; rule is subtler but equally important. If you’re running an x86_64 Python binary on an Apple Silicon Mac (usually because you installed it before Rosetta was properly configured, or you’re using an old pyenv), everything works — but MPS acceleration is silently disabled. Your ML training runs on CPU. Your inference is 10x slower than it should be. EnvGuard detects this via &lt;code&gt;sysctl proc_translated&lt;/code&gt; and warns you that you’re leaving performance on the table.&lt;/p&gt;

&lt;h4&gt;
  
  
  The Technical Architecture: How It Actually Works
&lt;/h4&gt;

&lt;p&gt;EnvGuard is built as a layered Python package with clear separation of concerns. The source is in &lt;a href="[https://github.com/rotsl/envguard](https://github.com/rotsl/envguard)"&gt;the GitHub repo&lt;/a&gt; under &lt;code&gt;src/envguard/&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;CLI Layer&lt;/strong&gt; (&lt;code&gt;cli.py&lt;/code&gt;): Typer-based interface with 25 commands across environment management, dependency resolution, lock files, publishing, and self-updating. Every command supports &lt;code&gt; — json&lt;/code&gt; output for CI/CD integration.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Orchestration Layer&lt;/strong&gt; (&lt;code&gt;preflight.py&lt;/code&gt;, &lt;code&gt;doctor.py&lt;/code&gt;): The preflight engine runs the nine-step pipeline. The doctor runs standalone diagnostics without execution. Both use the same underlying detection and rules systems.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Domain Layer&lt;/strong&gt; : The heavy lifting happens here:  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;detect.py&lt;/code&gt; — &lt;code&gt;HostDetector&lt;/code&gt; class gathers OS, architecture, Python, shell, network, and permission facts
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;rules.py&lt;/code&gt; — &lt;code&gt;RulesEngine&lt;/code&gt; evaluates all 15+ validation rules
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;repair.py&lt;/code&gt; — &lt;code&gt;RepairEngine&lt;/code&gt; can automatically fix broken environments (recreate venvs, fix mixed ownership, switch Python versions)
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;models.py&lt;/code&gt; — Pydantic models for &lt;code&gt;HostFacts&lt;/code&gt;, &lt;code&gt;ProjectIntent&lt;/code&gt;, &lt;code&gt;RuleFinding&lt;/code&gt;, &lt;code&gt;ResolutionRecord&lt;/code&gt;, etc.
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;project/&lt;/code&gt; — Discovery (scanning for project files), intent analysis (inferring requirements), resolution (dependency solving), and lifecycle management
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;resolver/&lt;/code&gt; — Pluggable backends for PyPI (BFS resolution via JSON API), uv, pip, and conda
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;lock/&lt;/code&gt; — Lock file generation and management (&lt;code&gt;envguard.lock&lt;/code&gt; in TOML format with SHA-256 content hashes)
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;update/&lt;/code&gt; — Self-updating mechanism with SHA-256 verification and rollback support&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Platform Layer&lt;/strong&gt; : macOS-specific code for permissions, Rosetta detection, Xcode CLI tools, and LaunchAgent management. Linux gets partial support here — core pipeline works, but no LaunchAgent, no MPS detection, no Rosetta checks.&lt;/p&gt;

&lt;p&gt;All state files (in &lt;code&gt;.envguard/&lt;/code&gt;) are written atomically using write-to-temp-then-rename to prevent corruption from interrupted writes. Every subprocess call has explicit timeouts. The security model is documented in detail — checksum verification for updates, no shell=True with string interpolation, path traversal protection for archive extraction.&lt;/p&gt;

&lt;h4&gt;
  
  
  Real Usage: What My Workflow Looks Like
&lt;/h4&gt;

&lt;p&gt;I work on a lot of ML projects with different requirements. Some need PyTorch with MPS. Some need TensorFlow (which has its own special hell on macOS). Some are pure Python data pipelines. Here’s how I actually use EnvGuard day-to-day.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Starting a new project:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd&lt;/span&gt; ~/projects/new-ml-experiment
envguard init
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This creates a &lt;code&gt;.envguard/&lt;/code&gt; directory with &lt;code&gt;state.json&lt;/code&gt;, &lt;code&gt;envguard.toml&lt;/code&gt; (config), and subdirectories for snapshots, cache, logs, and backups. It scans my project files to figure out what I’m building.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Checking if everything is healthy:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;envguard doctor
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This runs 10 diagnostic checks: host detection, project discovery, Python environment, package manager health, dependency consistency, accelerator support, permissions, network connectivity, and environment ownership. It outputs a report showing what’s working and what’s not.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Running my actual code:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;envguard run - python train.py - epochs 100 - batch-size 32
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Before &lt;code&gt;train.py&lt;/code&gt; executes, the preflight pipeline runs. If my environment has drifted — say, I updated PyTorch and now there’s a version conflict with torchvision — EnvGuard catches it and blocks execution. I can then run &lt;code&gt;envguard repair&lt;/code&gt; to fix it automatically, or &lt;code&gt;envguard lock sync&lt;/code&gt; to reinstall from my lock file.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Locking dependencies for reproducibility:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;envguard resolve
envguard lock generate
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;resolve&lt;/code&gt; uses the PyPI JSON API to resolve my project dependencies to exact pinned versions. &lt;code&gt;lock generate&lt;/code&gt; writes an &lt;code&gt;envguard.lock&lt;/code&gt; file with SHA-256 content hashes. I commit this to git. When someone else clones the repo, they run &lt;code&gt;envguard install — from-lock&lt;/code&gt; and get exactly the same environment I have.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Self-updating:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;envguard update - dry-run &lt;span class="c"&gt;# check if there's a new version&lt;/span&gt;
envguard update &lt;span class="c"&gt;# actually update with SHA-256 verification and automatic rollback snapshot&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;EnvGuard can update itself. Before applying an update, it creates a rollback snapshot. If something goes wrong, &lt;code&gt;envguard rollback&lt;/code&gt; restores the previous version.&lt;/p&gt;

&lt;h4&gt;
  
  
  The Lock File: Reproducibility Without the Pain
&lt;/h4&gt;

&lt;p&gt;Python dependency management has a reproducibility problem. &lt;code&gt;requirements.txt&lt;/code&gt; with loose version constraints means “install something that hopefully works.” &lt;code&gt;requirements.txt&lt;/code&gt; with pinned versions means “this worked on my machine at one specific moment, but good luck if you’re on a different architecture or Python version.”&lt;/p&gt;

&lt;p&gt;EnvGuard’s lock file (&lt;code&gt;envguard.lock&lt;/code&gt;) tries to be smarter. It’s a TOML file that includes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The exact resolved dependency graph with specific versions
&lt;/li&gt;
&lt;li&gt;SHA-256 content hashes for verification
&lt;/li&gt;
&lt;li&gt;Platform and Python version markers (so you can have different resolutions for macOS-arm64 vs Linux-x86_64 if needed)
&lt;/li&gt;
&lt;li&gt;The source files that contributed to the resolution (&lt;code&gt;pyproject.toml&lt;/code&gt;, &lt;code&gt;requirements.txt&lt;/code&gt;, etc.)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The lock file is human-readable but machine-generated. You don’t edit it manually. You regenerate it with &lt;code&gt;envguard lock generate&lt;/code&gt; or update specific packages with &lt;code&gt;envguard lock update — package &amp;lt;name&amp;gt;&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;In CI, you can run &lt;code&gt;envguard lock check&lt;/code&gt; to verify that the lock file is up-to-date with your source requirements. It exits with code 13 if stale, which you can use to fail builds that might have inconsistent dependencies.&lt;/p&gt;

&lt;h4&gt;
  
  
  What It Doesn’t Do (And Why)
&lt;/h4&gt;

&lt;p&gt;EnvGuard has deliberate limitations that are worth understanding:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;It doesn’t intercept unmanaged launches.&lt;/strong&gt; If you run &lt;code&gt;python train.py&lt;/code&gt; directly, EnvGuard doesn’t see it. Only commands routed through &lt;code&gt;envguard run&lt;/code&gt; get validated. This is by design — EnvGuard is opt-in, not a system-wide interceptor that could break other workflows.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;It doesn’t support Windows&lt;/strong&gt;. The codebase uses POSIX-specific APIs throughout (&lt;code&gt;os.access()&lt;/code&gt; for permissions, list-form subprocess arguments, &lt;code&gt;/tmp&lt;/code&gt; paths). Adding Windows support would require a parallel implementation of the platform layer, and I don’t use Windows enough to maintain that. WSL2 works if you need it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;It doesn’t make CUDA work on macOS&lt;/strong&gt;. Apple Silicon physically cannot run NVIDIA CUDA. EnvGuard detects CUDA dependencies and blocks them with a clear error, but it can’t magically add CUDA support where none exists.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;It doesn’t auto-activate environments on directory change.&lt;/strong&gt; If you want &lt;code&gt;cd my-project&lt;/code&gt; to automatically activate the right &lt;code&gt;venv&lt;/code&gt;, use &lt;code&gt;direnv&lt;/code&gt;. EnvGuard’s shell hooks are minimal and opt-in — they just load the integration, not the environments themselves.&lt;/p&gt;

&lt;p&gt;These limitations are documented in the repo’s &lt;code&gt;docs/limitations.md&lt;/code&gt; and tracked as architectural decisions in &lt;code&gt;docs/adrs/&lt;/code&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  Installation and Getting Started
&lt;/h4&gt;

&lt;p&gt;If you’re on macOS 12+ (Monterey) or Linux, installation is straightforward:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pip &lt;span class="nb"&gt;install &lt;/span&gt;envguard-tool
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The PyPI package is named &lt;code&gt;envguard-tool&lt;/code&gt; because &lt;code&gt;envguard&lt;/code&gt; was taken. The CLI command and Python import are both just &lt;code&gt;envguard&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;For macOS, there’s also a bootstrap script that installs shell hooks and the LaunchAgent for automatic update checking:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/rotsl/envguard.git
&lt;span class="nb"&gt;cd &lt;/span&gt;envguard
bash scripts/bootstrap.sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once installed, verify it works:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;envguard - version
envguard doctor
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then initialize any Python project:&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;cd&lt;/span&gt; /path/to/your/project
envguard init
envguard run - python your_script.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Why I Built This (And Who It’s For)
&lt;/h4&gt;

&lt;p&gt;I built EnvGuard for myself, primarily. I’m a researcher working on machine learning for biology — specifically computer vision for fungal pathogen analysis. I work on Apple Silicon Macs. I collaborate with people on Linux servers. I deal with PyTorch, TensorFlow, JAX, and a lot of scientific Python packages with complex native dependencies.&lt;/p&gt;

&lt;p&gt;I was tired of debugging environment issues that had nothing to do with my actual research. I wanted a tool that would catch problems before they cost me hours of training time or corrupted experimental results.&lt;/p&gt;

&lt;p&gt;EnvGuard is for Python developers who:  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Work on macOS (especially Apple Silicon) and are tired of Rosetta/architecture surprises
&lt;/li&gt;
&lt;li&gt;Need MPS acceleration for PyTorch and want to know when it’s not actually available
&lt;/li&gt;
&lt;li&gt;Collaborate across different machines and need reproducible environments
&lt;/li&gt;
&lt;li&gt;Are tired of “works on my machine” and want validation that happens &lt;strong&gt;before&lt;/strong&gt; execution
&lt;/li&gt;
&lt;li&gt;Prefer CLI tools that integrate into existing workflows rather than replacing them entirely&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It’s not for everyone. If you’re a web developer working with simple Python environments, you probably don’t need this. If you’re on Windows, this won’t help you (yet). If you want a full IDE-like environment manager with GUI buttons, look elsewhere.&lt;/p&gt;

&lt;p&gt;But if you’re doing scientific Python or ML and you’ve ever lost a day to a broken environment that you didn’t know was broken until it was too late — EnvGuard might save you some pain.&lt;/p&gt;

&lt;p&gt;Python environment management has been broken for a long time. We’ve accepted “it works on my machine” as an inevitable part of the development experience. We’ve normalized spending hours debugging issues that have nothing to do with our actual code.&lt;/p&gt;

&lt;p&gt;I don’t think it has to be this way. EnvGuard is my attempt to bring some of the safety and validation we expect from production systems (preflight checks, reproducible builds, clear error messages) to the messy world of Python development.&lt;/p&gt;

&lt;p&gt;It’s not perfect. It’s alpha software with known limitations. But it’s already saved me hours of debugging, and I hope it can do the same for you.&lt;/p&gt;

&lt;p&gt;If you’re tired of environment surprises, give it a try. Run &lt;code&gt;pip install envguard-tool&lt;/code&gt;, run &lt;code&gt;envguard doctor&lt;/code&gt; on your project, and see what it finds. You might discover that your “working” environment has been quietly broken in ways you never noticed.&lt;/p&gt;

&lt;h4&gt;
  
  
  Links:
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;GitHub: &lt;a href="https://github.com/rotsl/envguard" rel="noopener noreferrer"&gt;github.com/rotsl/envguard&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;PyPI: &lt;a href="https://pypi.org/project/envguard-tool/" rel="noopener noreferrer"&gt;pypi.org/project/envguard-tool/&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>cli</category>
      <category>developertools</category>
      <category>macos</category>
      <category>python</category>
    </item>
    <item>
      <title>Health AI on Notion with Tribe V2</title>
      <dc:creator>RoTSL</dc:creator>
      <pubDate>Thu, 02 Apr 2026 15:16:29 +0000</pubDate>
      <link>https://dev.to/rotsl/health-ai-on-notion-with-tribe-v2-2g1j</link>
      <guid>https://dev.to/rotsl/health-ai-on-notion-with-tribe-v2-2g1j</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;Local-first Notion health tracker with TRIBEv2 brain analysis, AI health insights, symptom logging, goals, medications, appointments, and a browser UI&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://dev.to/challenges/notion-2026-03-04"&gt;Notion MCP Challenge&lt;/a&gt;*&lt;/p&gt;

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

&lt;p&gt;This was supposed to be a Notion challenge submission.&lt;/p&gt;

&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/NJIflkjwPsM"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;I built most of it close to the deadline, got something working, and then missed the window. No big failure story. Just underestimated how long the messy parts would take.&lt;/p&gt;

&lt;p&gt;After that, keeping it private felt pointless. So I pushed it to GitHub.&lt;/p&gt;

&lt;p&gt;Around the same time, I came across &lt;strong&gt;Tribe v2&lt;/strong&gt;. That changed how I looked at this project. Instead of treating it like a failed submission, I started treating it like something that could keep evolving in public.&lt;/p&gt;

&lt;p&gt;That is what this is now. Not finished. Still useful.&lt;/p&gt;

&lt;h4&gt;
  
  
  The actual problem I was trying to solve
&lt;/h4&gt;

&lt;p&gt;I sometimes already track things in Notion:&lt;/p&gt;

&lt;p&gt;• Sleep&lt;/p&gt;

&lt;p&gt;• Workouts&lt;/p&gt;

&lt;p&gt;• Random notes about how I feel&lt;/p&gt;

&lt;p&gt;&lt;em&gt;The problem is not tracking. It is what happens after.&lt;/em&gt;&lt;/p&gt;

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

&lt;p&gt;No aggregation. No patterns. No feedback loop. Just logs sitting there.&lt;/p&gt;

&lt;p&gt;Every week I would think I should look at it properly. I never did.&lt;/p&gt;

&lt;p&gt;So this project is basically me outsourcing that thinking step.&lt;/p&gt;

&lt;h4&gt;
  
  
  System design
&lt;/h4&gt;

&lt;p&gt;The architecture is simple on paper and annoying in practice.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Pipeline&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;• Fetch data from Notion databases&lt;/p&gt;

&lt;p&gt;• Normalize it into a consistent structure&lt;/p&gt;

&lt;p&gt;• Send it to an LLM&lt;/p&gt;

&lt;p&gt;• Write the output back into Notion&lt;/p&gt;

&lt;p&gt;That is it. No fancy orchestration.&lt;/p&gt;

&lt;p&gt;The difficulty is everything in between.&lt;/p&gt;

&lt;h4&gt;
  
  
  Notion is not a real database
&lt;/h4&gt;

&lt;p&gt;At first glance, Notion feels structured. It is not.&lt;/p&gt;

&lt;p&gt;Things that break over time:&lt;/p&gt;

&lt;p&gt;• Property names change&lt;/p&gt;

&lt;p&gt;• Data types shift&lt;/p&gt;

&lt;p&gt;• Fields get added or removed&lt;/p&gt;

&lt;p&gt;If you build with fixed schemas, your system breaks quietly.&lt;/p&gt;

&lt;h4&gt;
  
  
  What I did instead
&lt;/h4&gt;

&lt;p&gt;I treated Notion as semi structured data:&lt;/p&gt;

&lt;p&gt;• Map fields dynamically instead of hardcoding&lt;/p&gt;

&lt;p&gt;• Use fallback parsing when fields do not match&lt;/p&gt;

&lt;p&gt;• Normalize everything into an internal schema&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Example internal format:&lt;/em&gt;&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="err"&gt;.&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"date"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2026–03–20"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="err"&gt;.&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"sleep_hours"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;6.5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="err"&gt;.&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"workout"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"strength"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="err"&gt;.&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"mood"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"low"&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;No matter how messy the source is, the model only sees this cleaned version.&lt;/p&gt;

&lt;h4&gt;
  
  
  Data normalization is the real system
&lt;/h4&gt;

&lt;p&gt;Most of the work went here.&lt;/p&gt;

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

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Extract raw values from Notion API&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Convert them into usable types&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Handle missing or inconsistent fields&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Align everything by time&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;em&gt;Examples:&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;• "6 hrs" becomes 6.0
 • Empty fields get dropped from inference
 • Mixed labels get standardized
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If this layer is weak, everything downstream gets worse.&lt;/p&gt;

&lt;h4&gt;
  
  
  LLM layer
&lt;/h4&gt;

&lt;p&gt;The model is not used as a general assistant.&lt;/p&gt;

&lt;p&gt;It has a narrow job:&lt;/p&gt;

&lt;p&gt;• Summarize recent data&lt;/p&gt;

&lt;p&gt;• Spot simple patterns&lt;/p&gt;

&lt;p&gt;• Suggest small adjustments&lt;/p&gt;

&lt;h4&gt;
  
  
  Input structure
&lt;/h4&gt;

&lt;p&gt;Each run includes:&lt;/p&gt;

&lt;p&gt;• Recent data window&lt;/p&gt;

&lt;p&gt;• Aggregated values&lt;/p&gt;

&lt;p&gt;• Instructions that limit scope&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Example:&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Sleep: [6, 5.5, 7, 6]
Workout: [yes, no, yes, yes]
Mood: [low, medium, medium, high]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;p&gt;Identify patterns&lt;/p&gt;

&lt;p&gt;Avoid assumptions without enough data&lt;/p&gt;

&lt;p&gt;State uncertainty clearly&lt;/p&gt;

&lt;p&gt;The main issue: the model guesses&lt;/p&gt;

&lt;p&gt;Even with weak data, it tries to sound confident.&lt;/p&gt;

&lt;p&gt;That is a problem, especially for anything health related.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What I added&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;• Minimum data thresholds before running inference&lt;/p&gt;

&lt;p&gt;• Prompts that force uncertainty&lt;/p&gt;

&lt;p&gt;• Restrictions on long term claims&lt;/p&gt;

&lt;p&gt;• Filtering outputs that sound too certain&lt;/p&gt;

&lt;p&gt;It still makes mistakes. It just makes fewer confident ones.&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Writing results back to Notion&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;Outputs are stored as:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;• Daily summaries&lt;/p&gt;

&lt;p&gt;• Weekly insights&lt;/p&gt;

&lt;p&gt;• Separate logs for traceability&lt;/p&gt;

&lt;p&gt;Each output includes:&lt;/p&gt;

&lt;p&gt;• Timestamp&lt;/p&gt;

&lt;p&gt;• Data window used&lt;/p&gt;

&lt;p&gt;• Generated insight&lt;/p&gt;

&lt;p&gt;This makes it easier to debug and iterate.&lt;/p&gt;

&lt;h4&gt;
  
  
  Why I stayed inside Notion
&lt;/h4&gt;

&lt;p&gt;I considered building a separate app.&lt;/p&gt;

&lt;p&gt;That would solve a lot of problems:&lt;/p&gt;

&lt;p&gt;• Cleaner schema&lt;/p&gt;

&lt;p&gt;• Better validation&lt;/p&gt;

&lt;p&gt;• Fewer edge cases&lt;/p&gt;

&lt;p&gt;But nobody wants another health app.&lt;/p&gt;

&lt;p&gt;Notion already has the data. So I built on top of it instead.&lt;/p&gt;

&lt;p&gt;The tradeoff is dealing with inconsistency.&lt;/p&gt;

&lt;h4&gt;
  
  
  Influence from Tribe v2
&lt;/h4&gt;

&lt;p&gt;This project shifted direction after I came across Tribe v2.&lt;/p&gt;

&lt;p&gt;The main idea that stuck:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;You do not wait until something feels ready.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;You ship it. Then improve it in the open.&lt;/p&gt;

&lt;p&gt;That is exactly what this repo reflects. Some parts are solid. Some are clearly not. That is fine.&lt;/p&gt;

&lt;h4&gt;
  
  
  What is still broken
&lt;/h4&gt;

&lt;p&gt;A few things are still rough:&lt;/p&gt;

&lt;p&gt;• Sparse data leads to weak outputs&lt;/p&gt;

&lt;p&gt;• The model confuses correlation with causation&lt;/p&gt;

&lt;p&gt;• Some insights sound better than they are&lt;/p&gt;

&lt;p&gt;• No feedback loop yet to measure usefulness&lt;/p&gt;

&lt;p&gt;The system works. It just does not always matter.&lt;/p&gt;

&lt;h4&gt;
  
  
  What I would change
&lt;/h4&gt;

&lt;p&gt;If I rebuilt/rework this:&lt;/p&gt;

&lt;p&gt;• Define a stricter schema earlier&lt;/p&gt;

&lt;p&gt;• Separate ingestion and AI layers properly&lt;/p&gt;

&lt;p&gt;• Add better logging from day one&lt;/p&gt;

&lt;p&gt;• Focus more on actionable insights, not just observations&lt;/p&gt;

&lt;h4&gt;
  
  
  Where this could go
&lt;/h4&gt;

&lt;p&gt;A few directions that feel real:&lt;/p&gt;

&lt;p&gt;• Long term memory instead of short windows&lt;/p&gt;

&lt;p&gt;• Feedback loops to track if suggestions help&lt;/p&gt;

&lt;p&gt;• Wearable integrations&lt;/p&gt;

&lt;p&gt;• Confidence scoring for outputs&lt;/p&gt;

&lt;p&gt;Or it might just stay like this. A small layer that makes Notion slightly smarter.&lt;/p&gt;

&lt;h4&gt;
  
  
  Closing
&lt;/h4&gt;

&lt;p&gt;Missing the deadline changed the trajectory of this project.&lt;/p&gt;

&lt;p&gt;If I had submitted it, I probably would have moved on.&lt;/p&gt;

&lt;p&gt;Instead, it is now something I can keep improving without pretending it is finished.&lt;/p&gt;

&lt;p&gt;Right now, it is useful enough to keep using.&lt;/p&gt;

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

&lt;p&gt;Repo: &lt;a href="https://github.com/rotsl/notion-Health-AI" rel="noopener noreferrer"&gt;https://github.com/rotsl/notion-Health-AI&lt;/a&gt;&lt;/p&gt;

</description>
      <category>opensource</category>
      <category>tribev2</category>
      <category>notion</category>
      <category>metaai</category>
    </item>
    <item>
      <title>☕ Pot.OF — AI-Powered HTCPCP Coffee Pot</title>
      <dc:creator>RoTSL</dc:creator>
      <pubDate>Thu, 02 Apr 2026 09:03:18 +0000</pubDate>
      <link>https://dev.to/rotsl/potof-ai-powered-htcpcp-coffee-pot-2cf8</link>
      <guid>https://dev.to/rotsl/potof-ai-powered-htcpcp-coffee-pot-2cf8</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.to/challenges/aprilfools-2026"&gt;DEV April Fools Challenge&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

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

&lt;p&gt;Pot.OF is a playful HTCPCP/1.0 coffee pot simulator inspired by RFC 2324. It includes an interactive terminal, a full &lt;code&gt;418 I'm a Teapot&lt;/code&gt; tea-rejection flow, decaf kernel panic mode, and three optional AI features powered by Google Gemini: an AI Coffee Therapist, an AI Brew Critic, and an AI RFC Generator.&lt;/p&gt;

&lt;p&gt;It solves no real problems, but it does let users argue with a coffee pot that has strong opinions.&lt;/p&gt;

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

&lt;p&gt;Deployed app: &lt;a href="https://pot-of-pj1j.vercel.app/" rel="noopener noreferrer"&gt;pot-of&lt;/a&gt;&lt;br&gt;
Video demo: &lt;a href="https://youtu.be/c_fYiGmoDxk?si=EML1dyDcmtQn1lIq" rel="noopener noreferrer"&gt;Youtube&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Code
&lt;/h2&gt;

&lt;p&gt;Built with Next.js 16, TypeScript, Tailwind CSS 4, shadcn/ui, Framer Motion, Zustand, Prisma, and Google Gemini.&lt;/p&gt;

&lt;p&gt;Repo link: &lt;a href="https://github.com/rotsl/pot.of" rel="noopener noreferrer"&gt;Github&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  How I Built It
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Built the app as a Next.js 16 App Router project with a single interactive coffee-pot interface and dedicated API routes for both protocol behavior and AI features.&lt;/li&gt;
&lt;li&gt;Implemented 3 Gemini-powered AI endpoints:

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;/api/htcpcp/ai-therapist&lt;/code&gt; — a sentient coffee pot therapist with a consistent personality, multi-turn chat, and coffee-themed advice&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;/api/htcpcp/ai-critic&lt;/code&gt; — a dramatic coffee snob that generates absurd tasting notes and scores&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;/api/htcpcp/ai-rfc&lt;/code&gt; — an RFC-style generator that creates fake HTCPCP protocol extensions with realistic formatting&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Added a bring-your-own-key flow in the GUI so users can paste their own Gemini API key locally to unlock AI features without requiring a deployment-wide secret&lt;/li&gt;

&lt;li&gt;Built 8 total API routes:

&lt;ul&gt;
&lt;li&gt;5 HTCPCP-inspired core routes for brewing, status, RFC display, teapot mode, and timing&lt;/li&gt;
&lt;li&gt;3 AI routes for therapist, critic, and RFC generation&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Added personality-driven UI behavior including pot moods like &lt;code&gt;idle&lt;/code&gt;, &lt;code&gt;brewing&lt;/code&gt;, &lt;code&gt;happy&lt;/code&gt;, &lt;code&gt;offended&lt;/code&gt;, &lt;code&gt;existential&lt;/code&gt;, and &lt;code&gt;decaf-panic&lt;/code&gt;
&lt;/li&gt;

&lt;li&gt;Implemented joke protocol interactions including:

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;BREW tea&lt;/code&gt; -&amp;gt; full-screen &lt;code&gt;418 I'm a Teapot&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;BREW decaf&lt;/code&gt; -&amp;gt; fake kernel panic&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;RFC&lt;/code&gt;, &lt;code&gt;STATUS&lt;/code&gt;, &lt;code&gt;WHEN&lt;/code&gt;, &lt;code&gt;PROPFIND&lt;/code&gt;, and other terminal commands&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Used three generated visual assets for the coffee pot mascot, teapot artwork, and coffee cup imagery&lt;/li&gt;

&lt;li&gt;Deployed it as a Vercel-friendly app with the AI key supplied by each user in the interface instead of hardcoding a shared secret&lt;/li&gt;

&lt;/ul&gt;

&lt;h2&gt;
  
  
  Prize Category
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Best Google AI Usage&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
The app uses Google Gemini across three distinct feature types: conversational AI through the therapist, creative generation through the brew critic, and structured document generation through the RFC generator. AI is not a side widget here; it is part of the product’s personality.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Best Ode to Larry Masinter&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
The project is built around RFC 2324, including the legendary &lt;code&gt;418 I'm a Teapot&lt;/code&gt;, HTCPCP-style commands, and a coffee pot that takes the protocol far too seriously.&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>418challenge</category>
      <category>showdev</category>
    </item>
    <item>
      <title>From Kidney Stones to Convergence</title>
      <dc:creator>RoTSL</dc:creator>
      <pubDate>Sat, 28 Mar 2026 08:16:21 +0000</pubDate>
      <link>https://dev.to/rotsl/from-kidney-stones-to-convergence-gno</link>
      <guid>https://dev.to/rotsl/from-kidney-stones-to-convergence-gno</guid>
      <description>&lt;h4&gt;
  
  
  The strange path from ultrasound physics to rethinking how solvers move through space
&lt;/h4&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%2F1y4owbcuuxn8awya5g7n.jpeg" 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%2F1y4owbcuuxn8awya5g7n.jpeg" alt="image1" width="392" height="584"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I didn’t expect this to start with kidney stones, but that’s honestly where it began.&lt;/p&gt;

&lt;p&gt;I was reading about ultrasound lithotripsy, how they break stones using focused waves, and I got stuck on the geometry of it. Ellipses, focal points, energy landing exactly where it needs to.&lt;/p&gt;

&lt;p&gt;It is one of those cases where physics feels less like equations and more like choreography.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;That idea just sat there for a while.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Then, separately, I was dealing with solver code. Big systems, messy residuals, the usual “why is this not converging” loop. At some point I stopped thinking in terms of matrices. The system started to feel like a place.&lt;/p&gt;

&lt;p&gt;Some parts resisted everything, like trying to push something heavy across rough ground. Other parts moved too easily and felt unstable. Residuals stopped feeling abstract and started feeling like forces pushing things out of balance.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;That is roughly where PICD came from.&lt;/em&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;PICD does not try to replace anything. It wraps what already works.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;GMRES, CG, Newton – Krylov, BDF. They still do the actual solving. PICD just watches what is happening and keeps some memory: residual history, how the system is partitioned, how different parts relate to each other.&lt;/p&gt;

&lt;p&gt;Then it adjusts the setup for the next solve. Preconditioners, damping, small corrections. Carefully.&lt;/p&gt;

&lt;p&gt;There is a hard boundary it does not cross. If a step does not reduce the residual, it does not count. The usual acceptance rules still apply.&lt;/p&gt;

&lt;p&gt;The “conic” part is just how the system gets split up.&lt;/p&gt;

&lt;p&gt;Instead of one big vector, you break it into regions. Each one tracks its own behavior. Its residual pattern, its neighbors, what worked last time.&lt;/p&gt;

&lt;p&gt;It sounds heavier than it feels. In practice it just gives the solver a bit of context it did not have before.&lt;/p&gt;

&lt;p&gt;The unusual part is treating those regions like they have physical properties.&lt;/p&gt;

&lt;p&gt;It sounds heavier than it feels. In practice it just gives the solver a bit of context it did not have before.&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%2Fg9wqs1bp5sz188wl1dym.jpeg" 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%2Fg9wqs1bp5sz188wl1dym.jpeg" alt="formulae" width="384" height="108"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Underneath all that is a graph.&lt;/p&gt;

&lt;p&gt;Connections between regions depend on how similar their residuals are, how often they activate together, and the actual structure of the problem. From that you get a Laplacian:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;L = D -W
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It does not replace the solver. It just helps decide what should be grouped together and what should be prioritized.&lt;/p&gt;

&lt;p&gt;The solve loop itself is pretty normal:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Pick a solver, partition, build state, adjust preconditioner, run, accept or reject, update.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The results are interesting.&lt;/p&gt;

&lt;p&gt;Everything in the current validation set runs. 98 tests, 22 examples.&lt;/p&gt;

&lt;p&gt;On direct comparisons, same solver with and without PICD, the PICD version is faster in the published benchmark set and uses less memory there as well.&lt;/p&gt;

&lt;p&gt;Linear problems stand out the most. Most cases improve, sometimes by a lot. There is a Helmholtz example that jumps by hundreds of times faster.&lt;/p&gt;

&lt;p&gt;Nonlinear and time-dependent cases are less clean. Some improve. Some do not. There is a turbulence example that clearly gets worse, with more rejected steps and slower runtime.&lt;/p&gt;

&lt;p&gt;That part I trust more than the wins.&lt;/p&gt;

&lt;p&gt;If there is one thing I would keep in mind, it is that PICD is deliberately limited in what it claims.&lt;/p&gt;

&lt;p&gt;It works well in same-method comparisons. Beyond that, it depends. It does not assume every physics-inspired term helps, and the controller can reduce or disable them when they start hurting convergence.&lt;/p&gt;

&lt;p&gt;I still come back to that original picture of energy being guided instead of forced.&lt;/p&gt;

&lt;p&gt;That is really what this is. Instead of brute-forcing convergence, you reshape the space a little so the solver has an easier path.&lt;/p&gt;

&lt;p&gt;But &lt;strong&gt;it changes how you think about the problem&lt;/strong&gt;. And for me, that shift was the interesting part.&lt;/p&gt;

&lt;p&gt;Read more on my reasearch here and cite it if you find it useful : &lt;a href="https://doi.org/10.13140/RG.2.2.10721.06243" rel="noopener noreferrer"&gt;https://doi.org/10.13140/RG.2.2.10721.06243&lt;/a&gt;&lt;/p&gt;

</description>
      <category>mathematics</category>
      <category>researchmethods</category>
      <category>algorithms</category>
      <category>physics</category>
    </item>
    <item>
      <title>Your LLM prompts are probably wasting 90% of tokens. Here’s how I fixed mine.</title>
      <dc:creator>RoTSL</dc:creator>
      <pubDate>Sun, 22 Mar 2026 13:04:10 +0000</pubDate>
      <link>https://dev.to/rotsl/your-llm-prompts-are-probably-wasting-90-of-tokens-heres-how-i-fixed-mine-1hg0</link>
      <guid>https://dev.to/rotsl/your-llm-prompts-are-probably-wasting-90-of-tokens-heres-how-i-fixed-mine-1hg0</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frlt9s712wk7xfidv3oz1.jpeg" 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%2Frlt9s712wk7xfidv3oz1.jpeg" alt="Tokens in LLM" width="582" height="327"&gt;&lt;/a&gt;&lt;br&gt;
I keep running into the same problem with LLM apps.&lt;/p&gt;

&lt;p&gt;This work is based on my previous article on dev.to &lt;a href="https://dev.to/rotsl/contextfusion-the-context-brain-your-llm-apps-are-missing-2gkm"&gt;https://dev.to/rotsl/contextfusion-the-context-brain-your-llm-apps-are-missing-2gkm&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You build a retrieval pipeline, hook it up to an API, and then quietly ship prompts that are full of stuff the model doesn’t need. Extra chunks. Duplicates. Half-relevant context that just bloats everything.&lt;/p&gt;

&lt;p&gt;And you pay for all of it.&lt;/p&gt;

&lt;p&gt;CFAdv is basically an attempt to stop doing that.&lt;/p&gt;

&lt;p&gt;It builds on context-fusion, but adds something that turns out to matter more than I expected: even if you pick the right context, you can still mess it up by putting it in the wrong place.&lt;/p&gt;



&lt;p&gt;&lt;strong&gt;Most pipelines are still doing this&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Let’s be honest about the default pattern:&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;chunks&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;retriever&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;top_k&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;prompt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n\n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;chunks&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;llm&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;prompt&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That’s it.&lt;/p&gt;

&lt;p&gt;No budget. No filtering beyond retrieval. No thought about ordering.&lt;/p&gt;

&lt;p&gt;More context is assumed to be better. It often isn’t.&lt;/p&gt;




&lt;p&gt;CFAdv splits the problem in two&lt;/p&gt;

&lt;p&gt;Instead of one “context step”, it does two separate things:&lt;br&gt;
    1.  Decide what gets in&lt;br&gt;
    2.  Decide where it goes&lt;/p&gt;

&lt;p&gt;That separation is the whole point.&lt;/p&gt;



&lt;p&gt;&lt;strong&gt;Step 1: selecting context under a budget&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Instead of top-k, CFAdv treats selection like an optimization problem.&lt;/p&gt;

&lt;p&gt;Each chunk gets a score based on things like:&lt;br&gt;
    • relevance&lt;br&gt;
    • trust&lt;br&gt;
    • freshness&lt;br&gt;
    • diversity&lt;br&gt;
    • token cost&lt;/p&gt;

&lt;p&gt;Then it tries to pick the best combination under a fixed token budget.&lt;/p&gt;

&lt;p&gt;At a high level:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;chunk&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;utility&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="mf"&gt;0.25&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;chunk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;relevance&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt;
        &lt;span class="mf"&gt;0.20&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;chunk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;trust&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt;
        &lt;span class="mf"&gt;0.15&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;chunk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;freshness&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt;
        &lt;span class="mf"&gt;0.15&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;chunk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;structure&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt;
        &lt;span class="mf"&gt;0.15&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;chunk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;diversity&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;risk&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="mf"&gt;0.40&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;chunk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;hallucination&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt;
        &lt;span class="mf"&gt;0.35&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;chunk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;staleness&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt;
        &lt;span class="mf"&gt;0.25&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;chunk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;privacy&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;utility&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;risk&lt;/span&gt;

&lt;span class="n"&gt;Then&lt;/span&gt; &lt;span class="n"&gt;rank&lt;/span&gt; &lt;span class="n"&gt;by&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="n"&gt;density&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;

&lt;span class="n"&gt;density&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;chunk&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="nf"&gt;max&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;chunk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tokens&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And greedily pack until you hit the budget.&lt;/p&gt;




&lt;p&gt;The small trick that makes a big difference&lt;/p&gt;

&lt;p&gt;There’s a simple filter before any of that:&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;floor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;max_score&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mf"&gt;0.15&lt;/span&gt;
&lt;span class="n"&gt;selected&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;candidates&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;score&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="n"&gt;floor&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Anything below 15% of the best chunk just gets dropped.&lt;/p&gt;

&lt;p&gt;That sounds minor, but it changes behavior a lot.&lt;br&gt;
    • If your data is clean, everything stays&lt;br&gt;
    • If it’s noisy, most of it disappears&lt;/p&gt;

&lt;p&gt;So you don’t fill your prompt with mediocre content just because you have space.&lt;/p&gt;



&lt;p&gt;&lt;strong&gt;Step 2: ordering for attention&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This is the part I underestimated.&lt;/p&gt;

&lt;p&gt;Even if you pick the right chunks, models don’t treat all positions equally. Stuff at the start tends to get more attention than stuff buried in the middle.&lt;/p&gt;

&lt;p&gt;So CFAdv reorders the selected chunks based on similarity to the query.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Basic version:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;cosine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="nf"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;@&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;norm&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nf"&gt;norm&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

&lt;span class="n"&gt;scores&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;cosine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;embed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nf"&gt;embed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;chunk&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;chunk&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;chunks&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="n"&gt;weights&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;softmax&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;scores&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;ordered&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;chunk&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;chunk&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;sorted&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nf"&gt;zip&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;weights&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;chunks&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="n"&gt;reverse&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;
&lt;span class="p"&gt;)]&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Higher weight goes earlier in the prompt.&lt;/p&gt;




&lt;p&gt;No embeddings API required&lt;/p&gt;

&lt;p&gt;Instead of calling an external model, it uses a simple hashed bag-of-words vector.&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="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;hashlib&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;numpy&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;np&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;re&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;embed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;dim&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;64&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;vec&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;zeros&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dim&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;tokens&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;re&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;findall&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;r&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;\b\w+\b&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;lower&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;

    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;tokens&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;h&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;hashlib&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sha256&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;encode&lt;/span&gt;&lt;span class="p"&gt;()).&lt;/span&gt;&lt;span class="nf"&gt;hexdigest&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;vec&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;h&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="n"&gt;dim&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mf"&gt;1.0&lt;/span&gt;
        &lt;span class="n"&gt;vec&lt;/span&gt;&lt;span class="p"&gt;[(&lt;/span&gt;&lt;span class="n"&gt;h&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="n"&gt;dim&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.5&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;vec&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;linalg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;norm&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;vec&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mf"&gt;1e-8&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It’s not fancy. No positional info, no learned weights. But for short chunks it works surprisingly well.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Two levels of ordering&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;There’s also a second layer.&lt;/p&gt;

&lt;p&gt;Instead of treating everything as one list, CFAdv groups context into blocks:&lt;br&gt;
    • system&lt;br&gt;
    • history&lt;br&gt;
    • retrieval&lt;br&gt;
    • tools&lt;/p&gt;

&lt;p&gt;Then it does:&lt;br&gt;
    1.  sort chunks inside each block&lt;br&gt;
    2.  sort the blocks themselves&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Sketch:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# intra-block
&lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;block&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;blocks&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;block&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;chunks&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sort&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;lambda&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;similarity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;reverse&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# cross-block
&lt;/span&gt;&lt;span class="n"&gt;block_scores&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;block&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;similarity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;mean_embed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;block&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;chunks&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;block&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;blocks&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="n"&gt;ordered_blocks&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;sorted&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;blocks&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;lambda&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;block_scores&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;reverse&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So you end up shaping the whole prompt, not just shuffling pieces.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;The full pipeline&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;CFAdv is an 8-stage pipeline, but it’s easier to think of it like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;docs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;ingest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;files&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;blocks&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;normalize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;docs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;variants&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;represent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;blocks&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;candidates&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;retrieve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;variants&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;selected&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;plan&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;candidates&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;budget&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;120&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;ordered&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;attention_fuse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;selected&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;packet&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;assemble&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ordered&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;prompt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;compile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;packet&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;mode&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;qa&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each step is stateless. That makes it easier to test and reason about.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;What happens in practice&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;You can cut most of the prompt without losing the answer, as long as:&lt;br&gt;
    • retrieval pulls in some noise&lt;br&gt;
    • there is redundancy&lt;br&gt;
    • the query only needs a subset of the data&lt;/p&gt;

&lt;p&gt;If everything is relevant, the system mostly leaves it alone.&lt;/p&gt;

&lt;p&gt;If only one chunk survives selection, ordering doesn’t matter.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Where this actually helps&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This kind of pipeline shines when:&lt;br&gt;
    • your retrieval step is messy&lt;br&gt;
    • you’re concatenating multiple documents&lt;br&gt;
    • prompts are long enough for attention effects to matter&lt;/p&gt;

&lt;p&gt;If you already have clean, minimal context, you won’t see much change.&lt;/p&gt;




&lt;p&gt;The part that stuck with me&lt;/p&gt;

&lt;p&gt;This isn’t really about attention or embeddings.&lt;/p&gt;

&lt;p&gt;It’s about treating prompt assembly as something worth optimizing.&lt;/p&gt;

&lt;p&gt;Right now most systems act like prompts are just containers. You throw things in and hope the model figures it out.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;CFAdv flips that.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It asks a simple question: what is the smallest amount of context that still works?&lt;/p&gt;

&lt;p&gt;Then it enforces it.&lt;/p&gt;

&lt;p&gt;And once you start thinking that way, it’s hard to go back to dumping chunks into a string and calling it a day.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Try it yourself&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If you want to see how this works in practice or plug it into your own workflow:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://github.com/rotsl/CFAdv" rel="noopener noreferrer"&gt;GitHub repo&lt;/a&gt; &lt;br&gt;
Contains the full Python library, CLI, benchmarks, and tests. You can run it locally, inspect the pipeline stages, or integrate it into your own RAG setup.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://rotsl.github.io/CFAdv/" rel="noopener noreferrer"&gt;Live demo&lt;/a&gt; &lt;br&gt;
Lets you compare raw prompts vs CFAdv-compiled prompts side by side. Useful for quickly seeing how much context gets removed and how ordering changes.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you’re already using retrieval + concatenation, the repo is the easiest place to start. Swap your prompt assembly step with CFAdv’s planner + fusion stages and see what drops out.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>promptengineering</category>
      <category>rag</category>
      <category>llm</category>
    </item>
    <item>
      <title>Resume Tailor</title>
      <dc:creator>RoTSL</dc:creator>
      <pubDate>Fri, 20 Mar 2026 14:31:02 +0000</pubDate>
      <link>https://dev.to/rotsl/resume-tailor-3gb3</link>
      <guid>https://dev.to/rotsl/resume-tailor-3gb3</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.to/challenges/notion-2026-03-04"&gt;Notion MCP Challenge&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

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

&lt;p&gt;Resume Tailor takes a job posting and your resume, then outputs a tailored resume and cover letter as PDFs. The whole thing runs in your browser. No sign-up, no server, no data stored anywhere except your Notion workspace if you want it there.&lt;/p&gt;

&lt;p&gt;You pick Claude or Gemini (Gemini has a free tier, no credit card), paste or upload the job description, upload your resume, and click go. Two PDFs come out the other side.&lt;/p&gt;

&lt;p&gt;It also runs as a local Flask app with more features (DOCX support, job URL fetching, richer PDFs) and a CLI if that's your thing.&lt;/p&gt;

&lt;h3&gt;
  
  
  The one rule I actually cared about
&lt;/h3&gt;

&lt;p&gt;The AI is not allowed to make things up. That sounds obvious but it's easy to get wrong. The system prompt on every single call says: you may reorder and reword existing content, you may use keywords from the job description if they honestly describe something the candidate already did, but you cannot add skills, invent metrics, or fabricate roles. If the job asks for five years of Kubernetes experience and the resume doesn't mention Kubernetes, that gap stays in the output.&lt;/p&gt;

&lt;p&gt;I've seen other resume tools confidently add skills the user never had. I didn't want to build that.&lt;/p&gt;




&lt;h2&gt;
  
  
  How Notion MCP works
&lt;/h2&gt;

&lt;p&gt;The Notion integration reads job descriptions from Notion pages and logs every run's output back. If you track jobs in Notion, pass the page ID directly instead of copy-pasting. The system reads the page via MCP.&lt;/p&gt;

&lt;p&gt;After each run, two databases get entries. A Job Applications table tracks company, role, date, and a snippet. A linked Outputs database stores the actual resume and cover letter text as readable blocks. A few weeks in, you have every application: what you sent and what they asked for.&lt;/p&gt;

&lt;p&gt;I also included &lt;code&gt;.mcp.json&lt;/code&gt; for the official &lt;code&gt;@notionhq/notion-mcp-server&lt;/code&gt;. Claude Desktop and Cursor pick it up, letting you ask Claude things like "which applications are pending?" or "draft a follow-up for the engineering role."&lt;/p&gt;

&lt;p&gt;The Notion API breaks if you write to a property that doesn't exist. Early versions failed when someone's title column wasn't "Name". The fix: introspect the database first, find the actual title property, and put everything else (status, date, company) in the page body as blocks instead of database properties. Works now regardless of configuration.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;_get_title_property_name&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;db_id&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;db&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;call_notion_mcp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;API-retrieve-a-database&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;database_id&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;db_id&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;db&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;properties&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{}).&lt;/span&gt;&lt;span class="nf"&gt;items&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;data&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;title&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Name&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The refactor (late 2024): Moved from the Notion SDK to a Python MCP client. All calls now route through &lt;code&gt;src/mcp_notion_client.py&lt;/code&gt;, which spawns the Node.js MCP server and communicates via stdio. Same behavior, but now the operations flow through MCP like the &lt;code&gt;.mcp.json&lt;/code&gt; config intended. The MCP server is launched on-demand—no persistent process—so it's transparent to the user.&lt;/p&gt;




&lt;h2&gt;
  
  
  Video demo
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://youtu.be/H5RqClzqvVo?si=7jYTx6aJIPEKH5-F" rel="noopener noreferrer"&gt;Resume Tailor Demo&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Show us the code
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;GitHub:&lt;/strong&gt; &lt;a href="https://github.com/rotsl/resume-tailor" rel="noopener noreferrer"&gt;https://github.com/rotsl/resume-tailor&lt;/a&gt;&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Live demo:&lt;/strong&gt; &lt;a href="https://rotsl.github.io/resume-tailor" rel="noopener noreferrer"&gt;https://rotsl.github.io/resume-tailor&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  How it's structured
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;resume-tailor/
├── docs/index.html                   ← the GitHub Pages app, fully self-contained
├── app.py                            ← local Flask server
├── main.py                           ← CLI
├── instruct.md                       ← formatting rules injected into every prompt
├── .mcp.json                         ← Notion MCP server config
├── .github/workflows/deploy.yml      ← deploys docs/ to GitHub Pages on push
├── scripts/
│   └── setup_notion_databases.py     ← creates the Notion DBs via MCP, writes IDs to .env
└── src/
    ├── tailor.py                     ← AI engine, supports Claude and Gemini
    ├── parser.py                     ← PDF / DOCX / text extraction
    ├── pdf_generator.py              ← PDF output via ReportLab
    ├── web_context.py                ← fetches company context from the web
    ├── mcp_notion_client.py          ← Python MCP client for Notion operations
    └── notion_integration.py         ← high-level Notion read/write (uses MCP)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  Supporting two AI providers
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;src/tailor.py&lt;/code&gt; has a single &lt;code&gt;tailor_resume()&lt;/code&gt; function that accepts a &lt;code&gt;provider&lt;/code&gt;, &lt;code&gt;model&lt;/code&gt;, and &lt;code&gt;api_key&lt;/code&gt; argument. The same prompts go to both. The browser version calls the APIs directly via &lt;code&gt;fetch()&lt;/code&gt;; the local version uses the Python SDKs.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Claude
&lt;/span&gt;&lt;span class="n"&gt;tailored&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;tailor_resume&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;resume&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;job_description&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;provider&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;claude&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;claude-sonnet-4-6&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;api_key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;sk-ant-...&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# Gemini free tier
&lt;/span&gt;&lt;span class="n"&gt;tailored&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;tailor_resume&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;resume&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;job_description&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;provider&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;gemini&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;gemini-2.5-flash&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;api_key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;AIza...&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When no key is passed, it falls back to environment variables, so the CLI reads from &lt;code&gt;.env&lt;/code&gt; without asking every time.&lt;/p&gt;

&lt;h3&gt;
  
  
  The prompt structure
&lt;/h3&gt;

&lt;p&gt;Two layers. The system prompt sets the hard rules (no fabrication, no adding skills). The user prompt gives the model the original resume, the job description, and any web context about the company as clearly labelled separate sections.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ABSOLUTE RULES — NEVER VIOLATE:
1. You may ONLY use information that exists in the candidate's original resume.
2. Do NOT invent, embellish, or assume any experience, skills, metrics, or facts.
3. You MAY reorder, reword, and emphasize existing content.
4. Mirror keywords from the job description only where they truthfully apply.
5. If the candidate lacks a required skill, do NOT add it. Leave it absent.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The cover letter call gets both the original resume and the already-tailored resume, so it can see exactly what was kept and what was cut.&lt;/p&gt;

&lt;h3&gt;
  
  
  Runtime config using &lt;code&gt;instruct.md&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Formatting rules live in &lt;code&gt;instruct.md&lt;/code&gt; and get injected into every prompt at call time. Swap the file out and the output changes — no code edits. Someone who wants a one-page resume with a specific section order can describe that there. Someone applying to academic roles can put a different set of rules in.&lt;/p&gt;

&lt;h3&gt;
  
  
  The GitHub Pages version
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;docs/index.html&lt;/code&gt; is the entire app. PDF.js reads uploaded PDFs in the browser, the AI APIs are called directly via fetch, jsPDF builds the output PDFs in memory. The GitHub Actions workflow just copies that one file to Pages on every push to main.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Upload Pages artifact&lt;/span&gt;
  &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/upload-pages-artifact@v3&lt;/span&gt;
  &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;docs/&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No build step, no npm, no bundler. The tradeoff is no Notion logging on the static version, since there's nowhere safe to store the Notion API key client-side.&lt;/p&gt;

&lt;h3&gt;
  
  
  Notion setup script
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python scripts/setup_notion_databases.py YOUR_NOTION_PAGE_ID
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Creates both databases via MCP, then writes their IDs into &lt;code&gt;.env&lt;/code&gt; automatically. No manual copy-paste needed. The script calls &lt;code&gt;call_notion_mcp("API-create-a-database", {...})&lt;/code&gt; for each database—same flow as the app itself.&lt;/p&gt;

&lt;h3&gt;
  
  
  Quick start
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/YOUR_USERNAME/resume-tailor.git
&lt;span class="nb"&gt;cd &lt;/span&gt;resume-tailor
python &lt;span class="nt"&gt;-m&lt;/span&gt; venv venv &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;source &lt;/span&gt;venv/bin/activate
pip &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt; requirements.txt
&lt;span class="nb"&gt;cp&lt;/span&gt; .env.example .env
&lt;span class="c"&gt;# Add GEMINI_API_KEY (free) or ANTHROPIC_API_KEY, plus NOTION_API_KEY&lt;/span&gt;

python scripts/setup_notion_databases.py YOUR_NOTION_PAGE_ID

python app.py  &lt;span class="c"&gt;# → http://localhost:5000&lt;/span&gt;
&lt;span class="c"&gt;# or&lt;/span&gt;
python main.py tailor &lt;span class="nt"&gt;--resume&lt;/span&gt; resume.pdf &lt;span class="nt"&gt;--job-url&lt;/span&gt; https://...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;p&gt;&lt;em&gt;Stack: Claude / Gemini, Notion MCP (Python mcp client + Node.js server), ReportLab, pdfplumber, jsPDF, PDF.js, Flask.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>notionchallenge</category>
      <category>mcp</category>
      <category>ai</category>
    </item>
  </channel>
</rss>
