<?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: vo o</title>
    <description>The latest articles on DEV Community by vo o (@winky_ovo).</description>
    <link>https://dev.to/winky_ovo</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%2F4095913%2F72deb7d7-4995-4859-8a42-1d66ee34f92f.jpg</url>
      <title>DEV Community: vo o</title>
      <link>https://dev.to/winky_ovo</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/winky_ovo"/>
    <language>en</language>
    <item>
      <title>Building Sensei: an agent that sits next to you in the terminal</title>
      <dc:creator>vo o</dc:creator>
      <pubDate>Wed, 26 Aug 2026 14:30:07 +0000</pubDate>
      <link>https://dev.to/winky_ovo/building-sensei-an-agent-that-sits-next-to-you-in-the-terminal-cmf</link>
      <guid>https://dev.to/winky_ovo/building-sensei-an-agent-that-sits-next-to-you-in-the-terminal-cmf</guid>
      <description>&lt;p&gt;&lt;em&gt;This post was created for the purposes of entering the All Things Agentic Hackathon.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;I learn tools by breaking them. &lt;code&gt;git&lt;/code&gt;, Docker, an MCP server — I type, it errors, I search, I try again, and three hours later it works and I couldn't tell you why. Chat assistants don't help with the &lt;em&gt;doing&lt;/em&gt; part: they sit in another window, they only know what I paste, and they never see the stream.&lt;/p&gt;

&lt;p&gt;So for the All Things Agentic Hackathon I built the thing I wanted: a senior engineer who sits beside the terminal, says nothing until the evidence says I'm stuck, takes notes the whole time, and at the end hands me the write-up I'd never have written myself. It's called &lt;strong&gt;Sensei&lt;/strong&gt;, and it's a Collaborative Partner entry built on Gemini 3.7 Flash, the Google ADK for TypeScript, Cloud Firestore and Firebase Hosting.&lt;/p&gt;

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



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;sensei start &lt;span class="nt"&gt;-g&lt;/span&gt; &lt;span class="s2"&gt;"build my first MCP server"&lt;/span&gt; &lt;span class="nt"&gt;--public&lt;/span&gt;
&lt;span class="go"&gt;[sensei] watching · session 20260819-…
[sensei] agent: observer gemini-3.5-flash-lite · coach/compiler gemini-3.7-flash · triage gemma-4-26b-a4b-it
&lt;/span&gt;&lt;span class="gp"&gt;PS ~/mcp-demo&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;node server.js
&lt;span class="go"&gt;SyntaxError: Cannot use import statement outside a module
&lt;/span&gt;&lt;span class="gp"&gt;PS ~/mcp-demo&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;node server.js
&lt;span class="go"&gt;SyntaxError: Cannot use import statement outside a module

[sensei] Node.js 默认不支持在 .js 文件中直接使用 ES Module 的 import 语法。
         你可以根据报错提示，在 package.json 中添加一个配置项，或者更改文件的后缀名。
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;sensei start&lt;/code&gt; wraps your shell in a pty. Everything you type and everything the terminal prints is captured, redacted locally (API keys, tokens, emails, home paths never leave the machine), logged as JSONL, and mirrored to Firestore.&lt;/p&gt;

&lt;p&gt;A background &lt;strong&gt;Observer&lt;/strong&gt; agent reads the messy stream and decides, on evidence, whether you're flowing, exploring or stuck. Default is silence. It failed me once, I tried the same thing again, &lt;em&gt;then&lt;/em&gt; it spoke — one line, in my language, "hint-first" because that's what my profile says. If I'd rather just have the answer: &lt;code&gt;sensei fb just-tell-me&lt;/code&gt;. If I have a question: &lt;code&gt;sensei ask "stdio or http?"&lt;/code&gt; gets a grounded answer from the &lt;strong&gt;Coach&lt;/strong&gt;. If &lt;em&gt;it&lt;/em&gt; needs to know something, it asks one clarifying question and I &lt;code&gt;sensei reply&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;sensei done&lt;/code&gt; runs the &lt;strong&gt;Compiler&lt;/strong&gt;: the whole session — commands, errors, notes, milestones, Q&amp;amp;A — becomes a tutorial with a "pitfalls we hit" table and a 60-second script. I learned it; now I can teach it. (The 60-second script is going straight into my short-video pipeline.)&lt;/p&gt;

&lt;p&gt;A web panel on Firebase Hosting shows the live session, hints, notes, questions, the learner profile and the compiled tutorial; replies and feedback typed there flow back into the terminal through a Firestore &lt;code&gt;inbound&lt;/code&gt; collection.&lt;/p&gt;

&lt;h2&gt;
  
  
  How it's built
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;The gate, not the model, is the product.&lt;/strong&gt; The first version commented on everything. What fixed it was structural:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;a free regex pre-filter (prompt-only output → skip; error words → escalate),&lt;/li&gt;
&lt;li&gt;a &lt;strong&gt;Gemma 4&lt;/strong&gt; triage call ("worth a senior engineer's attention right now?"),&lt;/li&gt;
&lt;li&gt;only then the &lt;strong&gt;Observer&lt;/strong&gt; on Gemini, with a structured JSON output (&lt;code&gt;status&lt;/code&gt;, &lt;code&gt;stuck_reason&lt;/code&gt;, &lt;code&gt;hint&lt;/code&gt;, &lt;code&gt;question&lt;/code&gt;, &lt;code&gt;note&lt;/code&gt;, &lt;code&gt;milestone&lt;/code&gt;, &lt;code&gt;profile_update&lt;/code&gt;),&lt;/li&gt;
&lt;li&gt;plus a hint cooldown and a prompt that forbids cheerleading and restating.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;ADK for TypeScript&lt;/strong&gt; gave me &lt;code&gt;LlmAgent&lt;/code&gt; + &lt;code&gt;outputSchema&lt;/code&gt; (zod) + &lt;code&gt;Runner&lt;/code&gt; in a few lines. I run each observation as a one-shot run with the context assembled by my own code — the transcript window, notes, hints already given, the learner profile — instead of relying on session memory. That keeps every tick stateless and cheap to reason about.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Model tiers.&lt;/strong&gt; Observation is high-frequency and needs to be fast: 3.5 Flash-Lite with thinking off. Coaching and compiling are rarer and need quality: 3.7 Flash. Each call has a timeout; models that time out, return 503 or hit a quota rest on a circuit breaker and the next tier takes over. (The free tier allows 20 requests per day per Flash model; building a product on that budget taught me a lot about gates.)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why the agent runs next to the terminal.&lt;/strong&gt; The stream is the data source and it lives on your machine; so does your API key. Firestore is the shared brain and realtime bus; the panel is a pure client of it. Being in mainland China, where Cloud Billing isn't offered, pushed me to this shape — and it's the better design anyway: Sensei works fully offline, and the cloud half is a mirror, never a dependency.&lt;/p&gt;

&lt;h2&gt;
  
  
  What surprised me
&lt;/h2&gt;

&lt;p&gt;The Observer caught my own lie. During a test I typed a deliberately wrong note — "git commit failed because user.name wasn't set" — and it answered: &lt;em&gt;no, the commit succeeded, see &lt;code&gt;[master (root-commit) 5f85f9d] first&lt;/code&gt;; run &lt;code&gt;git log&lt;/code&gt; to confirm.&lt;/em&gt; It reads the actual output, not what I say about it. That was the moment it stopped being a demo.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's next
&lt;/h2&gt;

&lt;p&gt;Voice hints through Gemini Live, a VS Code terminal integration, per-tool skill packs (git, docker, MCP), and turning those 60-second scripts into real videos.&lt;/p&gt;

&lt;p&gt;Code: &lt;a href="https://github.com/Claude-Ovo/sensei" rel="noopener noreferrer"&gt;https://github.com/Claude-Ovo/sensei&lt;/a&gt; · Panel: &lt;a href="https://sensei-agent.web.app" rel="noopener noreferrer"&gt;https://sensei-agent.web.app&lt;/a&gt; · Video: &lt;a href="https://youtu.be/7MW7tj1ksP8" rel="noopener noreferrer"&gt;https://youtu.be/7MW7tj1ksP8&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  AllThingsAgenticHackathon
&lt;/h1&gt;

</description>
      <category>ai</category>
      <category>typescript</category>
      <category>hackathon</category>
      <category>googlecloud</category>
    </item>
  </channel>
</rss>
