<?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: Debmalya Sen</title>
    <description>The latest articles on DEV Community by Debmalya Sen (@debmalyasen34).</description>
    <link>https://dev.to/debmalyasen34</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3955552%2F90e5590d-1c27-4af4-be50-5520558d187e.png</url>
      <title>DEV Community: Debmalya Sen</title>
      <link>https://dev.to/debmalyasen34</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/debmalyasen34"/>
    <language>en</language>
    <item>
      <title>Designing Helium Agent</title>
      <dc:creator>Debmalya Sen</dc:creator>
      <pubDate>Tue, 23 Jun 2026 06:30:58 +0000</pubDate>
      <link>https://dev.to/debmalyasen34/designing-helium-agent-1b39</link>
      <guid>https://dev.to/debmalyasen34/designing-helium-agent-1b39</guid>
      <description>&lt;h2&gt;
  
  
  1. What is Helium Agent?
&lt;/h2&gt;

&lt;p&gt;Helium Agent is a lightweight, terminal-focused AI agent written in Python.&lt;br&gt;
  Think Codex or OpenCode, but without the overhead. It's published on PyPI (&lt;br&gt;
  &lt;code&gt;pip install helium-agent&lt;/code&gt; ), runs as  &lt;code&gt;helium .&lt;/code&gt;  from any directory, and works&lt;br&gt;
  with any OpenAI-compatible LLM endpoint — cloud or local.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Core capabilities:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;• General-purpose chat with tool calling&lt;br&gt;
  • Long-running coding tasks via an agentic loop&lt;br&gt;
  • Deep research with multi-source evidence collection and citation&lt;br&gt;
  • RAG (Retrieval-Augmented Generation) for file-based Q&amp;amp;A&lt;br&gt;
  • Persistent memory across sessions&lt;br&gt;
  • Hierarchical subagent delegation&lt;br&gt;
  • A plugin system via SKILL.md files&lt;/p&gt;

&lt;p&gt;The design philosophy is minimum viable complexity — every feature is&lt;br&gt;
  implemented in the simplest way that works, with no speculative&lt;br&gt;
  abstractions.&lt;/p&gt;
&lt;h2&gt;
  
  
  2. Architecture Overview
&lt;/h2&gt;

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

&lt;p&gt;The architecture is deliberately flat. There's no framework, no dependency&lt;br&gt;
  injection container, no event bus. Modules import each other directly (with&lt;br&gt;
  lazy imports where circular dependencies would otherwise occur). This is a&lt;br&gt;
  feature, not a bug — the codebase is navigable in a single sitting.&lt;/p&gt;
&lt;h2&gt;
  
  
  3. Design Choices
&lt;/h2&gt;
&lt;h3&gt;
  
  
  3.1 Prompt-Based Tool Calling
&lt;/h3&gt;

&lt;p&gt;Decision: Helium does NOT use OpenAI's function calling API. Instead, the&lt;br&gt;
  LLM is instructed (via the system prompt) to output tool calls as&lt;br&gt;
  &lt;code&gt;&amp;lt;action&amp;gt;{"tool": "...", "args": {...}}&amp;lt;/action&amp;gt;&lt;/code&gt;  XML tags.&lt;/p&gt;

&lt;p&gt;Why:&lt;/p&gt;

&lt;p&gt;• Model agnostic. Works with any LLM that can follow instructions — local&lt;br&gt;
  llama.cpp models, OpenRouter free tiers, fine-tuned models. No need for the&lt;br&gt;
  provider to support a specific tool-calling schema.&lt;br&gt;
  • Full control. The tool prompt is a plain string, editable without touching&lt;br&gt;
  code. Adding a new tool means adding a function and a description — no&lt;br&gt;
  schema generation, no API negotiation.&lt;br&gt;
  • Simpler debugging. The raw LLM output is human-readable. You can see&lt;br&gt;
  exactly what the model tried to do.&lt;/p&gt;

&lt;p&gt;Trade-off: JSON extraction becomes fragile. The model might output slightly&lt;br&gt;
  malformed JSON, wrap it in markdown code blocks, or include extra text. This&lt;br&gt;
  led to  &lt;code&gt;extract_json()&lt;/code&gt;  in  &lt;code&gt;utils/parser.py&lt;/code&gt;  — a 75-line cascade of&lt;br&gt;
  fallbacks:&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F0s2ie6c8c4tlq68npqtg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F0s2ie6c8c4tlq68npqtg.png" alt="prompt based tool calling" width="798" height="213"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This works in practice but is a maintenance liability. Every new edge case from a new model means another fallback branch.&lt;/p&gt;
&lt;h3&gt;
  
  
  3.2 Dependency Injection in the Agentic Loop
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Decision:&lt;/strong&gt; &lt;code&gt;AgenticLoop&lt;/code&gt; accepts two callables — &lt;code&gt;ask_model&lt;/code&gt; and &lt;code&gt;execute_tool_call&lt;/code&gt; — rather than importing the LLM and tool modules directly.&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;class&lt;/span&gt; &lt;span class="nc"&gt;AgenticLoop&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ask_model&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;execute_tool_call&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;max_turns&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ask_model&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ask_model&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;execute_tool_call&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;execute_tool_call&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;max_turns&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;max_turns&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Why:&lt;/strong&gt; This single decision enables the entire system's composability:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The &lt;strong&gt;general chat&lt;/strong&gt; loop uses the standard LLM and tool execution.&lt;/li&gt;
&lt;li&gt;The &lt;strong&gt;coding workflow&lt;/strong&gt; (&lt;code&gt;/code&lt;/code&gt;) creates an &lt;code&gt;AgenticLoop&lt;/code&gt; with auto-approved tools and max_turns=30.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Subagents&lt;/strong&gt; create their own &lt;code&gt;AgenticLoop&lt;/code&gt; with a filtered tool set (only the tools the parent allowed).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Skills&lt;/strong&gt; inject their SKILL.md body into the system prompt and run a fresh &lt;code&gt;AgenticLoop&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;No subclasses, no strategy pattern, no configuration objects. Just two callables.&lt;/p&gt;

&lt;h3&gt;
  
  
  3.3 Global Mutable State (by design)
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Decision:&lt;/strong&gt; Several modules use module-level singletons:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;conversation_history&lt;/code&gt; (list) in &lt;code&gt;core/llm.py&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;_manager&lt;/code&gt; in &lt;code&gt;tools/memory_ops.py&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;_todo_list&lt;/code&gt; in &lt;code&gt;tools/todo_tools.py&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;_manager&lt;/code&gt; in &lt;code&gt;tools/subagent_tools.py&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Why:&lt;/strong&gt; Helium is a single-user, single-threaded terminal agent. There is exactly one conversation, one memory store, one todo list at any time. Global state is the simplest representation of this reality.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Trade-off:&lt;/strong&gt; This rules out concurrency. You can't run two subagents in parallel because they'd share the same conversation history and tool state. This is acceptable today but is the first thing that would need to change for async support.&lt;/p&gt;

&lt;h3&gt;
  
  
  3.4 Three-Tier Permission Model
&lt;/h3&gt;

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

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;safe&lt;/strong&gt; — auto-execute. Reads, searches, memory lookups, todo queries.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;risky&lt;/strong&gt; — requires user confirmation. File writes, bash, app launching.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;conditional&lt;/strong&gt; (bash only) — &lt;code&gt;is_command_safe()&lt;/code&gt; inspects the command string. &lt;code&gt;ls&lt;/code&gt;, &lt;code&gt;cat&lt;/code&gt;, &lt;code&gt;pwd&lt;/code&gt; are safe. &lt;code&gt;rm&lt;/code&gt;, &lt;code&gt;mv&lt;/code&gt;, &lt;code&gt;chmod&lt;/code&gt; are risky.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The &lt;code&gt;--nuclear&lt;/code&gt; / &lt;code&gt;--auto-approve&lt;/code&gt; flag bypasses all checks. Useful for CI, dangerous for production.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why this matters:&lt;/strong&gt; The LLM can hallucinate tool calls. Without permission gates, a confused model could delete files or run arbitrary commands. The three-tier system lets harmless operations flow freely while blocking anything that could cause damage.&lt;/p&gt;

&lt;h3&gt;
  
  
  3.5 No SDK — Raw HTTP Only
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Decision:&lt;/strong&gt; All LLM communication uses &lt;code&gt;requests.post()&lt;/code&gt; with manual SSE parsing. No OpenAI SDK, no httpx, no abstraction layer.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Fewer dependencies.&lt;/strong&gt; The &lt;code&gt;requirements.txt&lt;/code&gt; stays small. Each dependency is a potential breakage point.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Full transparency.&lt;/strong&gt; You can see exactly what's being sent to the API and what's coming back.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Provider flexibility.&lt;/strong&gt; Any endpoint that accepts OpenAI-format chat completions works. No SDK version pinning, no API compatibility matrix.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Trade-off:&lt;/strong&gt; Manual SSE parsing is fiddly. &lt;code&gt;stream_openrouter_response()&lt;/code&gt; in &lt;code&gt;utils/check_llm_api.py&lt;/code&gt; handles chunked transfer encoding, &lt;code&gt;data: [DONE]&lt;/code&gt; markers, and error responses. This is code that a well-tested SDK would handle for you.&lt;/p&gt;

&lt;h3&gt;
  
  
  3.6 SKILL.md Plugin System
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Decision:&lt;/strong&gt; Skills are markdown files with YAML frontmatter, discovered from &lt;code&gt;~/.config/helium-agent/skills/&lt;/code&gt; and &lt;code&gt;.helium/skills/&lt;/code&gt;.&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="nn"&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;caveman&lt;/span&gt;
&lt;span class="na"&gt;trigger&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/caveman&lt;/span&gt;
&lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;slash&lt;/span&gt;
&lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Respond&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;like&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;a&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;caveman"&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="s"&gt;You are a caveman. Respond to everything in caveman speak.&lt;/span&gt;
&lt;span class="s"&gt;Use grunts and simple words. No modern language.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Zero code required.&lt;/strong&gt; Anyone can create a skill by writing a markdown file.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Two types:&lt;/strong&gt; Slash commands (triggered by &lt;code&gt;/name&lt;/code&gt;) and contextual skills (injected into the system prompt when relevant).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Skill-scoped tools.&lt;/strong&gt; A skill can declare &lt;code&gt;allowed_tools&lt;/code&gt; to restrict what the LLM can do within that skill's context.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is the simplest possible plugin system. No Python entry points, no registration APIs, no configuration files beyond the markdown itself.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Orchestration: How It All Fits Together
&lt;/h2&gt;

&lt;h3&gt;
  
  
  4.1 The Agentic Loop
&lt;/h3&gt;

&lt;p&gt;The core of Helium is a turn-based loop that alternates between the LLM and the tool system:&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fzt4xtofzlst18280x2rs.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fzt4xtofzlst18280x2rs.png" alt="agentic loop" width="800" height="486"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Key parameters:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;General chat:&lt;/strong&gt; &lt;code&gt;max_turns = 6&lt;/code&gt;. Enough for a few tool calls without runaway loops.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Coding workflow:&lt;/strong&gt; &lt;code&gt;max_turns = 30&lt;/code&gt;. Long enough for multi-file edits with verification.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Temperature:&lt;/strong&gt; &lt;code&gt;0.3&lt;/code&gt;. Low enough for consistency, high enough for natural language.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;History:&lt;/strong&gt; &lt;code&gt;MAX_HISTORY = 10&lt;/code&gt;. The last 10 messages are kept. Older ones are dropped.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The loop terminates when:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The LLM responds without an &lt;code&gt;&amp;lt;action&amp;gt;&lt;/code&gt; tag (final answer).&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;max_turns&lt;/code&gt; is reached (timeout).&lt;/li&gt;
&lt;li&gt;A tool call is invalid and the LLM can't recover.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  4.2 The Research Pipeline
&lt;/h3&gt;

&lt;p&gt;Deep research is the most complex orchestration in Helium. It's a multi-stage pipeline with iteration:&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Frbh63d57owv0e69sj0on.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Frbh63d57owv0e69sj0on.png" alt="deep research" width="229" height="1080"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The dual-provider search (DuckDuckGo + SearxNG) is a redundancy measure. If one provider is down or rate-limited, the other fills the gap. The &lt;code&gt;SourcePolicy&lt;/code&gt; scores URLs by source type (official docs &amp;gt; blogs &amp;gt; forums) to prioritize high-quality evidence.&lt;/p&gt;

&lt;h3&gt;
  
  
  4.3 The Subagent System
&lt;/h3&gt;

&lt;p&gt;Added in the June 15 session, the subagent system enables hierarchical delegation:&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ftmmmh00vp1rxuxeqrmkt.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ftmmmh00vp1rxuxeqrmkt.png" alt="subagent system" width="268" height="1080"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Critical design decisions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Reuses AgenticLoop.&lt;/strong&gt; No new execution engine. A subagent runs the same loop as the main agent, just with a filtered tool set.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tool filtering at the manager layer.&lt;/strong&gt; &lt;code&gt;_wrap_execute_tool()&lt;/code&gt; intercepts tool calls and rejects anything not in the subagent's &lt;code&gt;allowed_tools&lt;/code&gt;. The LLM doesn't know it's restricted.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;IDs are unique, names aren't.&lt;/strong&gt; You can have five "researcher" subagents with different IDs. This allows multiple instances of the same role.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Lazy imports.&lt;/strong&gt; &lt;code&gt;tools/registry.py&lt;/code&gt; imports subagent tools lazily to avoid a circular dependency chain (&lt;code&gt;registry → subagent_tools → subagent_manager → llm → registry&lt;/code&gt;).&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  4.4 The Memory System
&lt;/h3&gt;

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

&lt;p&gt;The three-layer approach means:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Flat store&lt;/strong&gt; handles keyword search well ("What's my preferred language?")&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Knowledge graph&lt;/strong&gt; handles relationship queries ("What do I prefer?") via SPO triplets&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Conversation store&lt;/strong&gt; provides session context without polluting long-term memory&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All three share a single SQLite connection. The memory is "persistent" within a project directory (stored as &lt;code&gt;memory.db&lt;/code&gt;), but not shared across projects.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Mistakes and How to Avoid Them
&lt;/h2&gt;

&lt;h3&gt;
  
  
  5.1 Circular Import Hell
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;What happened:&lt;/strong&gt; When adding the subagent system, the import chain &lt;code&gt;tools/registry.py → tools/subagent_tools.py → core/subagent_manager.py → core/llm.py → tools/registry.py&lt;/code&gt; created a circular dependency that crashed on startup.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The fix:&lt;/strong&gt; Lazy imports in &lt;code&gt;tools/registry.py&lt;/code&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;_create_subagent_lazy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&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;tools.subagent_tools&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;create_subagent&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;create_subagent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;How to avoid it:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Draw the import graph before adding new modules.&lt;/li&gt;
&lt;li&gt;If A → B → C → A is unavoidable, break the cycle at the point with the fewest dependents (usually the leaf module).&lt;/li&gt;
&lt;li&gt;Consider a registry/observer pattern instead of direct imports for tool systems.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  5.2 JSON Extraction Fragility
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;What happened:&lt;/strong&gt; Different LLMs produce tool calls in subtly different formats. Some wrap JSON in markdown code blocks. Some include trailing commas. Some add explanatory text before or after the JSON. Each new model exposed a new edge case in &lt;code&gt;extract_json()&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The current state:&lt;/strong&gt; A 75-line cascade of regex fallbacks. It works, but every new model is a potential breakage.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How to avoid it:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;If your LLM provider supports structured function calling, use it. Prompt-based tool calling is a fallback for models that don't support it.&lt;/li&gt;
&lt;li&gt;If you must use prompt-based calling, enforce a strict output format in the system prompt with examples, and reject anything that doesn't match.&lt;/li&gt;
&lt;li&gt;Consider a two-pass approach: first try to extract JSON, then if it fails, ask the LLM to reformat its response.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  6. Key Takeaways
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Simplicity scales.&lt;/strong&gt; Global state, raw HTTP, prompt-based tool calling — these are "wrong" by enterprise standards but right for a single-user terminal agent. Choose the simplest solution that works for your actual use case.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Dependency injection is cheap composability.&lt;/strong&gt; Two callables (&lt;code&gt;ask_model&lt;/code&gt;, &lt;code&gt;execute_tool_call&lt;/code&gt;) gave Helium four distinct execution modes (chat, coding, subagent, skill) without a single subclass.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;The tool prompt IS the API.&lt;/strong&gt; In prompt-based agents, the system prompt that describes available tools is as important as the code that implements them. Treat it as a first-class artifact.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Lazy imports are a design signal.&lt;/strong&gt; If you need lazy imports to avoid circular dependencies, your module boundaries are wrong. Fix the architecture, not the import strategy.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

</description>
      <category>ai</category>
      <category>programming</category>
      <category>agents</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Helium Agent</title>
      <dc:creator>Debmalya Sen</dc:creator>
      <pubDate>Sat, 06 Jun 2026 01:16:33 +0000</pubDate>
      <link>https://dev.to/debmalyasen34/helium-agent-3307</link>
      <guid>https://dev.to/debmalyasen34/helium-agent-3307</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.to/challenges/github-2026-05-21"&gt;GitHub Finish-Up-A-Thon Challenge&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

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

&lt;h3&gt;
  
  
  What is Helium
&lt;/h3&gt;

&lt;p&gt;Helium is a terminal based local AI agent that does everything a propriety agent does. It can code, research, execute bash, manipulate files, and more. It is built with a lightweight harness so that only things that you need are eating your ram.&lt;/p&gt;

&lt;h3&gt;
  
  
  How it started
&lt;/h3&gt;

&lt;p&gt;I was absolutely stunned by how good claude code and other big tech agents were. It felt almost magical but then when openclaw came into the light I got to know that under the hood it was run by &lt;strong&gt;Pi&lt;/strong&gt;. I looked around about it and found why it was being used. I was inspired by a speech of its creator telling to embrace the &lt;strong&gt;simplicity&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;I thought to myself why not built something that lives between the &lt;strong&gt;simplicity of Pi&lt;/strong&gt; and &lt;strong&gt;throughput of claude code&lt;/strong&gt;. Hence, Helium was conceived.&lt;/p&gt;

&lt;p&gt;I started coding it in python, keeping the stack as minimal as possible. I also added a voice wakeup command but scratched that because I couldn't get the voice recognition work properly without using a large model contradicting the entire &lt;strong&gt;lightweight&lt;/strong&gt; claim.&lt;/p&gt;

&lt;p&gt;This was when I took a break from it.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Helium is the biggest project I have ever made and worked on. I spent days looking for free LLM providers because my mac was not good enough for medium models and the small models were not satisfactory. Yes, I tried quantization but it was meh.&lt;br&gt;
I was lucky to get one and from there it was no looking back. &lt;/p&gt;
&lt;/blockquote&gt;

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

&lt;p&gt;The github repo is here: &lt;a href="https://github.com/DebmalyaSen34/helium-agent" rel="noopener noreferrer"&gt;https://github.com/DebmalyaSen34/helium-agent&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I made a video walkthrough here:&lt;br&gt;
&lt;a href="https://drive.google.com/file/d/14x6sn06KoIgq_b5kDoT_VdB7MYQC_HTG/view?usp=drive_link" rel="noopener noreferrer"&gt;Watch Demo video&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Screenshots:&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%2F1zyeljfufzklt0vmolsq.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%2F1zyeljfufzklt0vmolsq.png" alt="Helium TUI" width="800" height="300"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The Comeback Story
&lt;/h2&gt;

&lt;p&gt;Helium was just a few python files with no UI, no orchestrator, but only few tools that couldn't talk to each other. I lost the motivation to continue it and went to my home town. That time away from it made me complete it even more than when it started.&lt;/p&gt;

&lt;p&gt;I have had a lot of free time on my hand recently so I thought why not continue Helium. I was also motivated the &lt;strong&gt;AI Engineer&lt;/strong&gt; event in Europe to test new things. I continued researching on the harness development, context management, memory, tool execution and web search.&lt;/p&gt;

&lt;h3&gt;
  
  
  Features added
&lt;/h3&gt;

&lt;p&gt;The first feature that I added was a &lt;code&gt;web_search&lt;/code&gt; because I always fancied a agent that could utilize the internet. So, I used scraping libraries and duckduckgo search api. I tested it heavily like asking about very recent news in sports and geopolitical areas. Soon many tools and features followed:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Research/Deep research&lt;/li&gt;
&lt;li&gt;Bash execution&lt;/li&gt;
&lt;li&gt;File manipulation&lt;/li&gt;
&lt;li&gt;Coding workflows&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Moving on from past
&lt;/h3&gt;

&lt;p&gt;I had to remove the entire &lt;strong&gt;voice suite&lt;/strong&gt; because it was becoming heavy due to models being used for voice recognition and complex to maintain.&lt;/p&gt;

&lt;p&gt;I also removed the &lt;strong&gt;web ui&lt;/strong&gt; because it was difficult already to maintain the terminal operations so I scrapped that.&lt;/p&gt;

&lt;p&gt;Removing these features allowed me to completely focus on one task. Giving a beautiful experience in terminal.&lt;/p&gt;

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

&lt;blockquote&gt;
&lt;p&gt;We live in an era where you are limited only by your imagination and not the technology.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I have a student plan for &lt;strong&gt;Github Copilot&lt;/strong&gt;. Every idea was passed through it and double checked to make it is serving its purpose. Copilot &lt;strong&gt;wrote all the extensive tests&lt;/strong&gt; to make sure the agent behaves as intended.&lt;/p&gt;

&lt;p&gt;Github Copilot contributed heavily to the &lt;strong&gt;memory management&lt;/strong&gt; and &lt;strong&gt;coding workflow&lt;/strong&gt; implementation as I was unsure which directions to take. It and I conversed for long discussing different architecture designs and chose the one best suited for my constrains.&lt;/p&gt;

&lt;p&gt;It would create detailed &lt;code&gt;architecture-design.md&lt;/code&gt; files which I would review and then move on to the &lt;code&gt;implementation.md&lt;/code&gt; file where all the magic happened. These files were in detailed and contained all the edge cases for testing. I didn't expect this level of consistency and quality from any agent.&lt;/p&gt;

&lt;p&gt;Bottom line: without Github Copilot it would've taken few months to make it work and few more to make it not break.&lt;/p&gt;

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