<?xml version="1.0" encoding="UTF-8"?><rss xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title>dev.to top (week)</title><link>https://dev.to/top/week</link><atom:link href="http://rss.144-124-237-35.sslip.io/dev.to/top/week" rel="self" type="application/rss+xml"></atom:link><description>Top dev.to posts - Powered by AtomRSS</description><generator>AtomRSS</generator><webMaster>contact@atomgroup.dev (AtomRSS)</webMaster><language>en-us</language><lastBuildDate>Sat, 08 Aug 2026 05:06:05 GMT</lastBuildDate><ttl>5</ttl><item><title>Dev Opportunity Radar #11: Claude Community Ambassadors, YC Startup Internship Expo, Z Fellows, and Stanford&#39;s AI Agents Course</title><description>&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;TL;DR&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Welcome back to &lt;strong&gt;Dev Opportunity Radar&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;This is a weekly series where I share opportunities, resources, communities, and interesting finds that I come across, with the goal of helping people discover things they might otherwise miss.&lt;/p&gt;

&lt;p&gt;This week&#39;s edition features the &lt;strong&gt;Claude Community Ambassadors Program&lt;/strong&gt;, the &lt;strong&gt;YC Startup Internship Expo&lt;/strong&gt;, &lt;strong&gt;Z Fellows&lt;/strong&gt;, and &lt;strong&gt;CS329A: Self-Improving AI Agents&lt;/strong&gt;, a free graduate-level Stanford course exploring the latest research behind modern AI agents.&lt;/p&gt;

&lt;p&gt;If you&#39;re new to the series, you can also browse previous editions, search past opportunities, and explore &lt;strong&gt;Community Finds&lt;/strong&gt;, &lt;strong&gt;Reader Updates&lt;/strong&gt;, and &lt;strong&gt;Resources Worth Checking Out&lt;/strong&gt; on the &lt;strong&gt;Dev Opportunity Radar website&lt;/strong&gt;. I&#39;ve also written a short post about why I built it. You&#39;ll find links to both at the end of this article.&lt;/p&gt;

&lt;p&gt;This week&#39;s &lt;strong&gt;🌟 Community Finds&lt;/strong&gt; section features opportunities shared by &lt;strong&gt;Francis (&lt;a class=&quot;mentioned-user&quot; href=&quot;https://dev.to/francistrdev&quot;&gt;@francistrdev&lt;/a&gt;)&lt;/strong&gt; and &lt;strong&gt;Konark Sharma (&lt;a class=&quot;mentioned-user&quot; href=&quot;https://dev.to/konark_13&quot;&gt;@konark_13&lt;/a&gt;)&lt;/strong&gt;. I always love seeing readers help others discover opportunities they might otherwise have missed.&lt;/p&gt;

&lt;p&gt;If you&#39;ve discovered something through the radar, I&#39;d love to hear about it. Whether you applied to an opportunity, attended an event, joined a community, completed a program, built something, or found a resource you hadn&#39;t seen before, I&#39;d be happy to feature your experience in a future &lt;strong&gt;💙 Reader Updates&lt;/strong&gt; section (with your permission).&lt;/p&gt;

&lt;p&gt;And if you&#39;ve come across an opportunity, resource, community, program, event, or anything else you think deserves more attention, feel free to share it in the comments.&lt;/p&gt;

&lt;p&gt;If I feature one of your &lt;strong&gt;🌟 Community Finds&lt;/strong&gt; in a future edition, I&#39;ll always make sure to credit you. If you discovered it, that recognition belongs to you.&lt;/p&gt;
&lt;/blockquote&gt;


&lt;hr&gt;

&lt;h2&gt;
  &lt;a name=&quot;table-of-contents&quot; href=&quot;https://dev.to/devengers/dev-opportunity-radar-11-claude-community-ambassadors-yc-startup-internship-expo-z-fellows-and-25aa#table-of-contents&quot;&gt;
  &lt;/a&gt;
  Table of Contents
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://dev.to/devengers/dev-opportunity-radar-11-claude-community-ambassadors-yc-startup-internship-expo-z-fellows-and-25aa#quick-scan&quot;&gt;⚡ Quick Scan&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://dev.to/devengers/dev-opportunity-radar-11-claude-community-ambassadors-yc-startup-internship-expo-z-fellows-and-25aa#still-open-from-previous-editions&quot;&gt;🔄 Still Open From Previous Editions&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href=&quot;https://dev.to/devengers/dev-opportunity-radar-11-claude-community-ambassadors-yc-startup-internship-expo-z-fellows-and-25aa#this-weeks-opportunities&quot;&gt;📍 This Week&#39;s Opportunities&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://dev.to/devengers/dev-opportunity-radar-11-claude-community-ambassadors-yc-startup-internship-expo-z-fellows-and-25aa#claude-community-ambassadors&quot;&gt;📌 Claude Community Ambassadors&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://dev.to/devengers/dev-opportunity-radar-11-claude-community-ambassadors-yc-startup-internship-expo-z-fellows-and-25aa#yc-startup-internship-expo&quot;&gt;📌 YC Startup Internship Expo&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://dev.to/devengers/dev-opportunity-radar-11-claude-community-ambassadors-yc-startup-internship-expo-z-fellows-and-25aa#z-fellows&quot;&gt;📌 Z Fellows&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href=&quot;https://dev.to/devengers/dev-opportunity-radar-11-claude-community-ambassadors-yc-startup-internship-expo-z-fellows-and-25aa#resources-worth-checking-out&quot;&gt;📚 Resources Worth Checking Out&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://dev.to/devengers/dev-opportunity-radar-11-claude-community-ambassadors-yc-startup-internship-expo-z-fellows-and-25aa#cs329a&quot;&gt;CS329A: Self-Improving AI Agents&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href=&quot;https://dev.to/devengers/dev-opportunity-radar-11-claude-community-ambassadors-yc-startup-internship-expo-z-fellows-and-25aa#community-finds&quot;&gt;🌟 Community Finds&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://dev.to/devengers/dev-opportunity-radar-11-claude-community-ambassadors-yc-startup-internship-expo-z-fellows-and-25aa#calec-volunteer-and-internship-opportunities&quot;&gt;CALEC Volunteer and Internship Opportunities&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://dev.to/devengers/dev-opportunity-radar-11-claude-community-ambassadors-yc-startup-internship-expo-z-fellows-and-25aa#jpmorgan-code-for-good&quot;&gt;JPMorganChase Code for Good Singapore &amp;amp; Software Engineer Program&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://dev.to/devengers/dev-opportunity-radar-11-claude-community-ambassadors-yc-startup-internship-expo-z-fellows-and-25aa#reader-updates&quot;&gt;💙 Reader Updates&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://dev.to/devengers/dev-opportunity-radar-11-claude-community-ambassadors-yc-startup-internship-expo-z-fellows-and-25aa#until-next-friday&quot;&gt;👋 Until Next Friday&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://dev.to/devengers/dev-opportunity-radar-11-claude-community-ambassadors-yc-startup-internship-expo-z-fellows-and-25aa#dev-opportunity-radar-website&quot;&gt;🌐 Dev Opportunity Radar Website&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;hr&gt;

&lt;h2&gt;
  &lt;a name=&quot;quick-scan&quot; href=&quot;https://dev.to/devengers/dev-opportunity-radar-11-claude-community-ambassadors-yc-startup-internship-expo-z-fellows-and-25aa#quick-scan&quot;&gt;
  &lt;/a&gt;
  ⚡ Quick Scan
&lt;/h2&gt;

&lt;h3&gt;
  &lt;a name=&quot;opportunities&quot; href=&quot;https://dev.to/devengers/dev-opportunity-radar-11-claude-community-ambassadors-yc-startup-internship-expo-z-fellows-and-25aa#opportunities&quot;&gt;
  &lt;/a&gt;
  &lt;strong&gt;Opportunities&lt;/strong&gt;
&lt;/h3&gt;

&lt;div class=&quot;table-wrapper-paragraph&quot;&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Opportunity&lt;/th&gt;
&lt;th&gt;Organization&lt;/th&gt;
&lt;th&gt;Type&lt;/th&gt;
&lt;th&gt;Format&lt;/th&gt;
&lt;th&gt;Deadline&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Claude Community Ambassadors&lt;/td&gt;
&lt;td&gt;Anthropic&lt;/td&gt;
&lt;td&gt;Community Ambassador Program&lt;/td&gt;
&lt;td&gt;Hybrid (Local Events)&lt;/td&gt;
&lt;td&gt;Rolling&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;YC Startup Internship Expo&lt;/td&gt;
&lt;td&gt;Y Combinator&lt;/td&gt;
&lt;td&gt;Startup Career Expo&lt;/td&gt;
&lt;td&gt;In Person (San Francisco)&lt;/td&gt;
&lt;td&gt;August 15 (Event)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Z Fellows&lt;/td&gt;
&lt;td&gt;Z Fellows&lt;/td&gt;
&lt;td&gt;Founder Fellowship&lt;/td&gt;
&lt;td&gt;Hybrid&lt;/td&gt;
&lt;td&gt;Rolling&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  &lt;a name=&quot;resource-highlight&quot; href=&quot;https://dev.to/devengers/dev-opportunity-radar-11-claude-community-ambassadors-yc-startup-internship-expo-z-fellows-and-25aa#resource-highlight&quot;&gt;
  &lt;/a&gt;
  &lt;strong&gt;Resource Highlight&lt;/strong&gt;
&lt;/h3&gt;

&lt;div class=&quot;table-wrapper-paragraph&quot;&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Resource&lt;/th&gt;
&lt;th&gt;Why Check It Out&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;CS329A: Self-Improving AI Agents&lt;/td&gt;
&lt;td&gt;A free graduate-level Stanford course covering modern AI agent research, including constitutional AI, tool use, planning, reinforcement learning, memory, and evaluation frameworks.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  &lt;a name=&quot;community-finds&quot; href=&quot;https://dev.to/devengers/dev-opportunity-radar-11-claude-community-ambassadors-yc-startup-internship-expo-z-fellows-and-25aa#community-finds&quot;&gt;
  &lt;/a&gt;
  &lt;strong&gt;Community Finds&lt;/strong&gt;
&lt;/h3&gt;

&lt;div class=&quot;table-wrapper-paragraph&quot;&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Shared By&lt;/th&gt;
&lt;th&gt;Find&lt;/th&gt;
&lt;th&gt;Type&lt;/th&gt;
&lt;th&gt;Format&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Francis (&lt;a class=&quot;mentioned-user&quot; href=&quot;https://dev.to/francistrdev&quot;&gt;@francistrdev&lt;/a&gt;)&lt;/td&gt;
&lt;td&gt;CALEC Volunteer &amp;amp; Internship Opportunities&lt;/td&gt;
&lt;td&gt;Volunteer &amp;amp; Internship Opportunities&lt;/td&gt;
&lt;td&gt;Remote&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Konark Sharma (&lt;a class=&quot;mentioned-user&quot; href=&quot;https://dev.to/konark_13&quot;&gt;@konark_13&lt;/a&gt;)&lt;/td&gt;
&lt;td&gt;JPMorganChase Code for Good Singapore &amp;amp; Software Engineer Program&lt;/td&gt;
&lt;td&gt;Hackathon &amp;amp; Internship&lt;/td&gt;
&lt;td&gt;In Person (Singapore)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;blockquote&gt;
&lt;p&gt;📝 &lt;strong&gt;A quick note:&lt;/strong&gt; I spend a lot of time researching and verifying every opportunity before featuring it in Dev Opportunity Radar. However, deadlines, eligibility, program details, and application requirements can change after publication. Before applying, please take a few minutes to visit the official program page, review the latest information, and confirm that you&#39;re eligible.&lt;/p&gt;
&lt;/blockquote&gt;


&lt;hr&gt;

&lt;h2&gt;
  &lt;a name=&quot;still-open-from-previous-editions&quot; href=&quot;https://dev.to/devengers/dev-opportunity-radar-11-claude-community-ambassadors-yc-startup-internship-expo-z-fellows-and-25aa#still-open-from-previous-editions&quot;&gt;
  &lt;/a&gt;
  🔄 Still Open From Previous Editions
&lt;/h2&gt;

&lt;p&gt;Before we get into this week&#39;s opportunities, here are a few from previous editions that are still accepting applications.&lt;/p&gt;

&lt;p&gt;I&#39;ve already covered these in detail, so I won&#39;t repeat everything here. If any of them catch your attention, you can find the full overview, eligibility details, and application links in the original edition.&lt;/p&gt;

&lt;div class=&quot;table-wrapper-paragraph&quot;&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Opportunity&lt;/th&gt;
&lt;th&gt;Organization&lt;/th&gt;
&lt;th&gt;Type&lt;/th&gt;
&lt;th&gt;Format&lt;/th&gt;
&lt;th&gt;Deadline&lt;/th&gt;
&lt;th&gt;Featured In&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;FR8&lt;/td&gt;
&lt;td&gt;FR8&lt;/td&gt;
&lt;td&gt;Builder Residency&lt;/td&gt;
&lt;td&gt;In Person&lt;/td&gt;
&lt;td&gt;Rolling&lt;/td&gt;
&lt;td&gt;&lt;a href=&quot;https://dev.to/hemapriya_kanagala/dev-opportunity-radar-2-a-fully-funded-residency-in-finland-ai-research-program-and-a-60k-33l4&quot;&gt;Edition #2&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Anthropic Fellows Program&lt;/td&gt;
&lt;td&gt;Anthropic&lt;/td&gt;
&lt;td&gt;AI Research Fellowship&lt;/td&gt;
&lt;td&gt;In Person&lt;/td&gt;
&lt;td&gt;Rolling&lt;/td&gt;
&lt;td&gt;&lt;a href=&quot;https://dev.to/devengers/dev-opportunity-radar-4-anthropic-fellows-30k-for-founders-and-aws-she-builds-2a6b&quot;&gt;Edition #4&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Sentient Open Source AGI Grant Program&lt;/td&gt;
&lt;td&gt;Sentient Foundation&lt;/td&gt;
&lt;td&gt;AI Grant &amp;amp; Investment&lt;/td&gt;
&lt;td&gt;Remote&lt;/td&gt;
&lt;td&gt;Rolling&lt;/td&gt;
&lt;td&gt;&lt;a href=&quot;https://dev.to/devengers/dev-opportunity-radar-6-y-combinator-startup-school-open-source-ai-grants-and-a-60k-apac-4nlp&quot;&gt;Edition #6&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Solo Grants&lt;/td&gt;
&lt;td&gt;Solo Grants&lt;/td&gt;
&lt;td&gt;Microgrant for Solo Builders&lt;/td&gt;
&lt;td&gt;Remote&lt;/td&gt;
&lt;td&gt;Rolling&lt;/td&gt;
&lt;td&gt;&lt;a href=&quot;https://dev.to/devengers/dev-opportunity-radar-7-1000-solo-grants-free-claude-max-for-open-source-contributors-and-an-3i12&quot;&gt;Edition #7&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Claude for Open Source&lt;/td&gt;
&lt;td&gt;Anthropic&lt;/td&gt;
&lt;td&gt;Open Source Program&lt;/td&gt;
&lt;td&gt;Remote&lt;/td&gt;
&lt;td&gt;Rolling&lt;/td&gt;
&lt;td&gt;&lt;a href=&quot;https://dev.to/devengers/dev-opportunity-radar-7-1000-solo-grants-free-claude-max-for-open-source-contributors-and-an-3i12&quot;&gt;Edition #7&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;AIAF Fellowship 2026&lt;/td&gt;
&lt;td&gt;AIAF × AE Studio&lt;/td&gt;
&lt;td&gt;AI Research Fellowship&lt;/td&gt;
&lt;td&gt;Remote&lt;/td&gt;
&lt;td&gt;August 17&lt;/td&gt;
&lt;td&gt;&lt;a href=&quot;https://dev.to/devengers/dev-opportunity-radar-8-openai-build-week-aiaf-fellowship-the-residency-ai-dev-tools-zoomcamp-5bpc#aiaf-fellowship-2026&quot;&gt;Edition #8&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The Bridge&lt;/td&gt;
&lt;td&gt;Entrepreneurs First&lt;/td&gt;
&lt;td&gt;Founder Residency&lt;/td&gt;
&lt;td&gt;In Person&lt;/td&gt;
&lt;td&gt;August 30&lt;/td&gt;
&lt;td&gt;&lt;a href=&quot;https://dev.to/devengers/dev-opportunity-radar-9-a-fully-funded-ai-security-residency-sf-founder-residency-figma-campus-1j88&quot;&gt;Edition #9&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Develop for Good Winter 2027&lt;/td&gt;
&lt;td&gt;Develop for Good&lt;/td&gt;
&lt;td&gt;Student Volunteer Program&lt;/td&gt;
&lt;td&gt;Remote&lt;/td&gt;
&lt;td&gt;August 31&lt;/td&gt;
&lt;td&gt;&lt;a href=&quot;https://dev.to/devengers/dev-opportunity-radar-10-openai-student-collective-develop-for-good-mlh-global-hack-week--4kh2&quot;&gt;Edition #10&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;OpenAI Student Collective&lt;/td&gt;
&lt;td&gt;OpenAI&lt;/td&gt;
&lt;td&gt;Campus Leadership Program&lt;/td&gt;
&lt;td&gt;In Person (Campus-Based)&lt;/td&gt;
&lt;td&gt;August 10&lt;/td&gt;
&lt;td&gt;&lt;a href=&quot;https://dev.to/devengers/dev-opportunity-radar-10-openai-student-collective-develop-for-good-mlh-global-hack-week--4kh2&quot;&gt;Edition #10&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;


&lt;hr&gt;

&lt;h2&gt;
  &lt;a name=&quot;this-weeks-opportunities&quot; href=&quot;https://dev.to/devengers/dev-opportunity-radar-11-claude-community-ambassadors-yc-startup-internship-expo-z-fellows-and-25aa#this-weeks-opportunities&quot;&gt;
  &lt;/a&gt;
  📍 This Week&#39;s Opportunities
&lt;/h2&gt;

&lt;p&gt;Here are a few opportunities I came across this week that I thought were worth sharing.&lt;/p&gt;

&lt;h3&gt;
  &lt;a name=&quot;claude-community-ambassadors&quot; href=&quot;https://dev.to/devengers/dev-opportunity-radar-11-claude-community-ambassadors-yc-startup-internship-expo-z-fellows-and-25aa#claude-community-ambassadors&quot;&gt;
  &lt;/a&gt;
  📌 Claude Community Ambassadors
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Who it&#39;s for:&lt;/strong&gt; Developers, community organizers, meetup hosts, technical educators, and active Claude users who enjoy bringing people together and helping others learn. You don&#39;t need to be a professional developer, but you should have meaningful experience using Claude and a track record of community involvement.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What stands out:&lt;/strong&gt; The &lt;strong&gt;Claude Community Ambassadors&lt;/strong&gt; program gives community builders the opportunity to grow local Claude communities with support from &lt;strong&gt;Anthropic&lt;/strong&gt;. Ambassadors can host meetups, workshops, hackathons, and other community events while receiving event funding, monthly API credits, ready-to-use event materials, swag, and promotion through Anthropic&#39;s channels.&lt;/p&gt;

&lt;p&gt;I wanted to include this because most ambassador programs are focused on students. This one is different. It&#39;s designed for people who are already active in their local tech communities or online communities and want to help others explore Claude while building a stronger local developer ecosystem.&lt;/p&gt;

&lt;p&gt;Another thing I like is that the program goes beyond hosting events. Ambassadors get early access to selected features, opportunities to participate in Builders Council sessions, and a direct way to share feedback from their communities with Anthropic&#39;s product teams. If you enjoy teaching, organizing events, or building developer communities, this could be a great opportunity to make an impact while connecting with other community leaders around the world.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Program Duration:&lt;/strong&gt; Ongoing&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Cost:&lt;/strong&gt; Free&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Benefits:&lt;/strong&gt; Event sponsorship, monthly Claude API credits, exclusive swag, access to a private Ambassador Slack, pre-release features, and opportunities to provide product feedback.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Who can apply:&lt;/strong&gt; Community builders and experienced Claude users from anywhere in the world. Professional developer experience is not required.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Application Deadline:&lt;/strong&gt; Rolling&lt;/p&gt;

&lt;p&gt;🔗 &lt;strong&gt;&lt;a href=&quot;https://claude.com/community/ambassadors&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Learn More&lt;/a&gt;&lt;/strong&gt; | 🔗 &lt;strong&gt;&lt;a href=&quot;https://form.typeform.com/to/OIUYgsnS?typeform-source=claude.com&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Apply&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;


&lt;hr&gt;

&lt;h3&gt;
  &lt;a name=&quot;yc-startup-internship-expo&quot; href=&quot;https://dev.to/devengers/dev-opportunity-radar-11-claude-community-ambassadors-yc-startup-internship-expo-z-fellows-and-25aa#yc-startup-internship-expo&quot;&gt;
  &lt;/a&gt;
  📌 YC Startup Internship Expo
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Who it&#39;s for:&lt;/strong&gt; Students looking for internships, co-ops, semester internships, or new graduate roles who will be in the &lt;strong&gt;San Francisco Bay Area&lt;/strong&gt; on &lt;strong&gt;August 15&lt;/strong&gt;. YC is also encouraging applications from exceptional high school builders.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What stands out:&lt;/strong&gt; The &lt;strong&gt;YC Startup Internship Expo&lt;/strong&gt; is a one-day, acceptance-only event where students can meet founders, engineers, and hiring teams from &lt;strong&gt;50+ Y Combinator startups&lt;/strong&gt;. Rather than browsing job boards, attendees get the chance to explore what it&#39;s actually like to work at early-stage AI startups, participate in coding and AI challenges, network with startup teams, and even interview onsite with more than &lt;strong&gt;40 YC companies&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;I wanted to include this because opportunities like this don&#39;t come around very often. Instead of applying online and hoping someone sees your resume, you get to meet founders and engineers face-to-face, ask questions, and learn how some of today&#39;s fastest-growing AI startups actually build products.&lt;/p&gt;

&lt;p&gt;Another thing I like is that it&#39;s more than just a career fair. Alongside the startup expo, there will be coding and AI challenges, giveaways, food trucks, and onsite interviews happening throughout the day. If you&#39;re already spending the summer in San Francisco or studying in the Bay Area, this could be a great opportunity to explore internships while connecting with people building at the forefront of AI.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Event Date:&lt;/strong&gt; August 15, 2026&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Location:&lt;/strong&gt; San Francisco, California&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Cost:&lt;/strong&gt; Free (application required)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Who can apply:&lt;/strong&gt; Students interning in San Francisco, students attending Bay Area colleges or universities, and exceptional high school builders who will be in the Bay Area on the event date.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Application Process:&lt;/strong&gt; Acceptance only&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Travel Support:&lt;/strong&gt; No travel sponsorship is provided.&lt;/p&gt;

&lt;p&gt;🔗 &lt;strong&gt;&lt;a href=&quot;https://events.ycombinator.com/2027-summer-internship-expo&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Learn More &amp;amp; Apply&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;


&lt;hr&gt;

&lt;h3&gt;
  &lt;a name=&quot;z-fellows&quot; href=&quot;https://dev.to/devengers/dev-opportunity-radar-11-claude-community-ambassadors-yc-startup-internship-expo-z-fellows-and-25aa#z-fellows&quot;&gt;
  &lt;/a&gt;
  📌 Z Fellows
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Who it&#39;s for:&lt;/strong&gt; Technical builders, aspiring founders, students, recent graduates, researchers, engineers, and anyone working on a side project or startup. You can apply solo or with a team, and you don&#39;t need to have a company yet.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What stands out:&lt;/strong&gt; &lt;strong&gt;Z Fellows&lt;/strong&gt; is a one-week founder program that brings together a small group of ambitious builders with founders and investors behind companies like &lt;strong&gt;Figma, Vercel, Instacart, Netflix, DoorDash,&lt;/strong&gt; and &lt;strong&gt;AngelList&lt;/strong&gt;. The week is designed to help early builders learn from experienced founders, connect with other ambitious people, and accelerate whatever they&#39;re working on. The support doesn&#39;t stop after the program. Z Fellows continues helping founders throughout their journey.&lt;/p&gt;

&lt;p&gt;I wanted to include this because most startup programs expect you to already have a company, traction, or funding. Z Fellows takes a different approach. It&#39;s built for people who are still early and simply have the ambition to build something meaningful. Whether you&#39;re working on a side project, exploring an idea, or already building a startup, the focus is on backing people with potential before everyone else notices them.&lt;/p&gt;

&lt;p&gt;Another thing I like is how flexible the program is. You don&#39;t need to quit your job, leave school, or even have a co-founder to apply. The program is mostly virtual, with the final day taking place in &lt;strong&gt;San Francisco&lt;/strong&gt; or &lt;strong&gt;New York City&lt;/strong&gt;, making it accessible to builders from around the world. Applicants can also choose to participate without funding or accept an optional &lt;strong&gt;$10,000 investment&lt;/strong&gt; through a SAFE agreement if it makes sense for their company.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Program Duration:&lt;/strong&gt; One week (multiple cohorts each year)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Format:&lt;/strong&gt; Mostly virtual, with the final day held in San Francisco or New York City&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Funding:&lt;/strong&gt; Optional &lt;strong&gt;$10,000&lt;/strong&gt; investment through a SAFE agreement&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Who can apply:&lt;/strong&gt; Builders from anywhere in the world. No age restrictions. You can apply as an individual or as a team, and you don&#39;t need a company to get started.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Application Deadline:&lt;/strong&gt; Rolling&lt;/p&gt;

&lt;p&gt;🔗 &lt;strong&gt;&lt;a href=&quot;https://www.zfellows.com/&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Learn More&lt;/a&gt;&lt;/strong&gt; | 🔗 &lt;strong&gt;&lt;a href=&quot;https://docs.google.com/forms/d/1z5HG9Pj0hIxS2oZL_wcJS5QqDZlcVbkhYGHp5Kp_IGM/viewform?edit_requested=true&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Apply&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;


&lt;hr&gt;

&lt;h2&gt;
  &lt;a name=&quot;resources-worth-checking-out&quot; href=&quot;https://dev.to/devengers/dev-opportunity-radar-11-claude-community-ambassadors-yc-startup-internship-expo-z-fellows-and-25aa#resources-worth-checking-out&quot;&gt;
  &lt;/a&gt;
  📚 Resources Worth Checking Out
&lt;/h2&gt;

&lt;p&gt;Not every useful find comes with an application deadline.&lt;/p&gt;

&lt;p&gt;Here&#39;s one resource worth checking out this week.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;cs329a&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  &lt;a name=&quot;cs329a-selfimproving-ai-agents&quot; href=&quot;https://dev.to/devengers/dev-opportunity-radar-11-claude-community-ambassadors-yc-startup-internship-expo-z-fellows-and-25aa#cs329a-selfimproving-ai-agents&quot;&gt;
  &lt;/a&gt;
  CS329A: Self-Improving AI Agents
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Who it&#39;s for:&lt;/strong&gt; Developers, AI engineers, researchers, graduate students, and anyone who already has a basic understanding of large language models and wants to dive deeper into modern AI agent research.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What stands out:&lt;/strong&gt; &lt;strong&gt;CS329A: Self-Improving AI Agents&lt;/strong&gt; is a graduate-level course from &lt;strong&gt;Stanford University&lt;/strong&gt; that explores how AI agents can continuously improve through interaction with themselves and their environment. The lecture recordings cover many of the ideas shaping today&#39;s AI landscape, including constitutional AI, reinforcement learning, test-time scaling, tool use, memory, planning, multimodal agents, and evaluation frameworks for agentic systems.&lt;/p&gt;

&lt;p&gt;I wanted to include this because there&#39;s a lot of discussion about AI agents right now, but it can be difficult to separate hype from the underlying concepts. This course is taught by researchers working in the field and provides a structured way to understand many of the techniques behind modern agent systems.&lt;/p&gt;

&lt;p&gt;Another thing I like is that the course doesn&#39;t focus on a single framework or API. Instead, it explores the research ideas that are driving the next generation of AI agents, making it a resource that&#39;s likely to stay useful even as tools continue to evolve.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Format:&lt;/strong&gt; Free online lecture recordings&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Level:&lt;/strong&gt; Graduate / Advanced&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Topics Covered:&lt;/strong&gt; Self-improving LLMs, Constitutional AI, reinforcement learning, test-time scaling, tool use, memory, planning, multimodal agents, and AI evaluation.&lt;/p&gt;

&lt;p&gt;🔗 &lt;strong&gt;&lt;a href=&quot;https://youtube.com/playlist?list=PLangBM27OtEA&amp;amp;si=XosLB89xIxTAc-UW&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Watch the Lecture Playlist&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;


&lt;hr&gt;

&lt;h2&gt;
  &lt;a name=&quot;community-finds&quot; href=&quot;https://dev.to/devengers/dev-opportunity-radar-11-claude-community-ambassadors-yc-startup-internship-expo-z-fellows-and-25aa#community-finds&quot;&gt;
  &lt;/a&gt;
  🌟 Community Finds
&lt;/h2&gt;

&lt;p&gt;One of my favorite things about this series has been seeing people share opportunities, communities, and resources that others might not have discovered otherwise.&lt;/p&gt;

&lt;h3&gt;
  &lt;a name=&quot;calec-volunteer-and-internship-opportunities&quot; href=&quot;https://dev.to/devengers/dev-opportunity-radar-11-claude-community-ambassadors-yc-startup-internship-expo-z-fellows-and-25aa#calec-volunteer-and-internship-opportunities&quot;&gt;
  &lt;/a&gt;
  CALEC Volunteer and Internship Opportunities
&lt;/h3&gt;

&lt;p&gt;Back in &lt;strong&gt;Edition #6&lt;/strong&gt;, I featured &lt;strong&gt;CALEC&#39;s remote volunteer and internship opportunities&lt;/strong&gt; after &lt;strong&gt;Francis (&lt;a class=&quot;mentioned-user&quot; href=&quot;https://dev.to/francistrdev&quot;&gt;@francistrdev&lt;/a&gt;)&lt;/strong&gt; shared them with the community. If you missed it, you can find the full overview and all the details in &lt;strong&gt;Edition #6&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Since sharing this opportunity with the community, &lt;strong&gt;Francis&lt;/strong&gt; has also published a dedicated DEV post about the &lt;strong&gt;Full-Stack Developer&lt;/strong&gt; volunteer role at CALEC. If that role interests you, it&#39;s worth checking out for his perspective and some additional information about what the team is looking for.&lt;/p&gt;

&lt;p&gt;🔗 &lt;strong&gt;&lt;a href=&quot;https://dev.to/devengers/want-to-volunteer-with-me-as-a-full-stack-developer-join-me-at-calec-2hne&quot;&gt;Francis&#39; post&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;🔗 &lt;strong&gt;&lt;a href=&quot;https://calec.org/volunteers-internships/&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;CALEC Volunteer &amp;amp; Internship Opportunities&lt;/a&gt;&lt;/strong&gt; | 🔗 &lt;strong&gt;&lt;a href=&quot;https://dev.to/devengers/dev-opportunity-radar-6-y-combinator-startup-school-open-source-ai-grants-and-a-60k-apac-4nlp#calec-volunteer-and-internship-opportunities&quot;&gt;Edition #6&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;


&lt;hr&gt;

&lt;p&gt;&lt;a name=&quot;jpmorgan-code-for-good&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  &lt;a name=&quot;jpmorganchase-code-for-good-singapore-amp-software-engineer-program&quot; href=&quot;https://dev.to/devengers/dev-opportunity-radar-11-claude-community-ambassadors-yc-startup-internship-expo-z-fellows-and-25aa#jpmorganchase-code-for-good-singapore-amp-software-engineer-program&quot;&gt;
  &lt;/a&gt;
  JPMorganChase Code for Good Singapore &amp;amp; Software Engineer Program
&lt;/h3&gt;

&lt;p&gt;Shared by &lt;strong&gt;Konark Sharma (&lt;a class=&quot;mentioned-user&quot; href=&quot;https://dev.to/konark_13&quot;&gt;@konark_13&lt;/a&gt;)&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Konark shared two opportunities from &lt;strong&gt;JPMorganChase&lt;/strong&gt; that I thought would be worth passing along for students interested in software engineering.&lt;/p&gt;

&lt;p&gt;The first is &lt;strong&gt;Code for Good Singapore&lt;/strong&gt;, a two-day social impact hackathon where participants work alongside JPMorganChase engineers to build technology solutions for nonprofit organizations. Besides the experience itself, the event also serves as a pathway to the company&#39;s &lt;strong&gt;2027 Early Careers Software Engineer Program&lt;/strong&gt; in Singapore.&lt;/p&gt;

&lt;p&gt;He also shared the &lt;strong&gt;2027 Software Engineer Program - Summer Analyst (Singapore)&lt;/strong&gt;. Interns work on real software engineering projects, collaborate with experienced engineers, receive mentorship and training, and may be considered for a full-time graduate role based on their performance.&lt;/p&gt;

&lt;p&gt;I thought these were worth featuring because they offer more than just a hackathon or an internship. Together, they provide a chance to gain hands-on experience, connect with engineers, and potentially open the door to future opportunities at one of the world&#39;s largest technology employers.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Who it&#39;s for:&lt;/strong&gt; Students pursuing a bachelor&#39;s degree in computer science or a related field who are interested in software engineering opportunities in Singapore.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Application Deadlines:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Code for Good Singapore:&lt;/strong&gt; September 18, 2026&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Software Engineer Program - Summer Analyst (Singapore):&lt;/strong&gt; October 29, 2026&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;🔗 &lt;strong&gt;&lt;a href=&quot;https://jpmc.fa.oraclecloud.com/hcmUI/CandidateExperience/en/sites/CX_1001/job/210758929&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Code for Good Singapore&lt;/a&gt;&lt;/strong&gt; &lt;/p&gt;

&lt;p&gt;🔗 &lt;strong&gt;&lt;a href=&quot;https://jpmc.fa.oraclecloud.com/hcmUI/CandidateExperience/en/sites/CX_1001/job/210754425&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Software Engineer Program - Summer Analyst (Singapore)&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;


&lt;hr&gt;

&lt;p&gt;Thank you to &lt;strong&gt;Francis (&lt;a class=&quot;mentioned-user&quot; href=&quot;https://dev.to/francistrdev&quot;&gt;@francistrdev&lt;/a&gt;)&lt;/strong&gt; and &lt;strong&gt;Konark Sharma (&lt;a class=&quot;mentioned-user&quot; href=&quot;https://dev.to/konark_13&quot;&gt;@konark_13&lt;/a&gt;)&lt;/strong&gt; for thinking of the radar and sharing these with the community. It really means a lot 💙&lt;/p&gt;

&lt;p&gt;I&#39;d love for this section to keep growing.&lt;/p&gt;

&lt;p&gt;If you&#39;ve come across an opportunity, fellowship, grant, hackathon, conference, community, resource, or anything else you think more people should know about, feel free to share it in the comments.&lt;/p&gt;

&lt;p&gt;If I feature it in a future edition, I&#39;ll always make sure to credit you. If you discovered it, that recognition belongs to you.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;One small request:&lt;/strong&gt; If you&#39;re sharing an opportunity, please avoid posting raw URLs directly in the comments. DEV sometimes filters them before I get a chance to see them.&lt;/p&gt;

&lt;p&gt;A short description alongside the link makes it much easier for me to review and potentially feature it in a future edition.&lt;/p&gt;


&lt;hr&gt;

&lt;h2&gt;
  &lt;a name=&quot;reader-updates&quot; href=&quot;https://dev.to/devengers/dev-opportunity-radar-11-claude-community-ambassadors-yc-startup-internship-expo-z-fellows-and-25aa#reader-updates&quot;&gt;
  &lt;/a&gt;
  💙 Reader Updates
&lt;/h2&gt;

&lt;p&gt;I&#39;m looking forward to this section gradually growing over time, and I&#39;d still love to hear from you.&lt;/p&gt;

&lt;p&gt;One of my favorite parts of writing Dev Opportunity Radar has been hearing from people who discovered something they otherwise might have missed.&lt;/p&gt;

&lt;p&gt;If you discovered an opportunity through the radar, applied to something, joined a community, attended an event, or simply found a resource you hadn&#39;t seen before, I&#39;d genuinely love to hear about it.&lt;/p&gt;

&lt;p&gt;You don&#39;t need to have been accepted or have a big success story to share. Sometimes simply discovering the right opportunity at the right time is already a win.&lt;/p&gt;

&lt;p&gt;If you&#39;d like to share an update, feel free to leave a comment on this edition. With your permission, I may feature it in a future &lt;strong&gt;💙 Reader Updates&lt;/strong&gt; section and tag you so other readers can celebrate your journey too.&lt;/p&gt;

&lt;p&gt;I hope this section gradually becomes a place where we can celebrate those stories together, one update at a time.&lt;/p&gt;


&lt;hr&gt;

&lt;h2&gt;
  &lt;a name=&quot;until-next-friday&quot; href=&quot;https://dev.to/devengers/dev-opportunity-radar-11-claude-community-ambassadors-yc-startup-internship-expo-z-fellows-and-25aa#until-next-friday&quot;&gt;
  &lt;/a&gt;
  👋 Until Next Friday
&lt;/h2&gt;

&lt;p&gt;Before I go, I just want to say thank you.&lt;/p&gt;

&lt;p&gt;Every week, I spend time searching for opportunities, resources, and communities that I think deserve a little more attention. But one of my favorite parts of this series isn&#39;t the research. It&#39;s seeing what happens after an edition is published.&lt;/p&gt;

&lt;p&gt;Seeing someone discover an opportunity, apply to a program, share a resource, suggest a Community Find, or come back to tell us what they learned reminds me why I started Dev Opportunity Radar in the first place.&lt;/p&gt;

&lt;p&gt;The goal has always been simple:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Help people discover opportunities they otherwise might have missed.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Thanks to all of you, it feels like we&#39;re doing exactly that.&lt;/p&gt;

&lt;p&gt;Whether you&#39;ve been reading since the very first edition or this is your first time here, thank you for being part of the journey. Every comment, suggestion, and shared opportunity helps make this series better than I could build on my own.&lt;/p&gt;

&lt;p&gt;If you ever come across an opportunity, resource, event, community, or anything else you think deserves more attention, I&#39;d love for you to share it in the comments. And if Dev Opportunity Radar helped you discover something exciting, I&#39;d love to hear that too.&lt;/p&gt;

&lt;p&gt;Thank you for reading, for sharing, and for helping make this &lt;strong&gt;our radar&lt;/strong&gt;, not just mine.&lt;/p&gt;

&lt;p&gt;I&#39;ll be back next Friday with more opportunities, resources, and Community Finds.&lt;/p&gt;

&lt;p&gt;Until then, take care, and I hope you discover something amazing this week 💙&lt;/p&gt;


&lt;hr&gt;

&lt;h2&gt;
  &lt;a name=&quot;dev-opportunity-radar-website&quot; href=&quot;https://dev.to/devengers/dev-opportunity-radar-11-claude-community-ambassadors-yc-startup-internship-expo-z-fellows-and-25aa#dev-opportunity-radar-website&quot;&gt;
  &lt;/a&gt;
  🌐 Dev Opportunity Radar Website
&lt;/h2&gt;

&lt;p&gt;If this is your first time discovering the series, you can explore every edition, browse opportunities by category, discover Community Finds, and catch up on Reader Updates on the &lt;strong&gt;Dev Opportunity Radar website&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;👉 &lt;strong&gt;&lt;a href=&quot;https://devopportunityradar.ai.studio/&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Website&lt;/a&gt;&lt;/strong&gt; &lt;/p&gt;

&lt;p&gt;I also wrote a short post about why I built the website and the journey behind it.&lt;/p&gt;

&lt;p&gt;👉 &lt;strong&gt;&lt;a href=&quot;https://dev.to/hemapriya_kanagala/i-finally-built-the-dev-opportunity-radar-website-1dpi&quot;&gt;Website Launch Post&lt;/a&gt;&lt;/strong&gt; &lt;/p&gt;


            </description><link>https://dev.to/devengers/dev-opportunity-radar-11-claude-community-ambassadors-yc-startup-internship-expo-z-fellows-and-25aa</link><guid isPermaLink="false">https://dev.to/devengers/dev-opportunity-radar-11-claude-community-ambassadors-yc-startup-internship-expo-z-fellows-and-25aa</guid><pubDate>Fri, 07 Aug 2026 15:52:30 GMT</pubDate><author>Hemapriya Kanagala</author><enclosure url="https://media2.dev.to/dynamic/image/width=1000,height=420,fit=cover,gravity=auto,format=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F2kzyiy0emfpimr5ewjtw.jpeg" type="image/jpeg"></enclosure><category>discuss</category><category>community</category><category>opportunities</category><category>resources</category></item><item><title>Enterprise MCP Gateway with Built-In Security: OAuth 2.0, RBAC, and Tool Access Control</title><description>&lt;h2&gt;
  &lt;a name=&quot;tldr&quot; href=&quot;https://dev.to/anthonymax/enterprise-mcp-gateway-with-built-in-security-oauth-20-rbac-and-tool-access-control-68n#tldr&quot;&gt;
  &lt;/a&gt;
  TL;DR
&lt;/h2&gt;

&lt;p&gt;MCP servers are powerful, but they can provide access to production systems if anyone on the team can connect and run tools without guardrails.&lt;/p&gt;

&lt;p&gt;Imagine a new hire testing the app on their laptop and accidentally granting an MCP server access to the production database. Without governance, that is a realistic path to data leakage.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href=&quot;https://github.com/maximhq/bifrost.git&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Bifrost&lt;/a&gt; addresses this with three layers:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Human-in-the-loop execution&lt;/strong&gt; — Bifrost does not auto-execute tool calls. The LLM only &lt;em&gt;suggests&lt;/em&gt; tools; your application reviews them and explicitly calls &lt;code&gt;POST /v1/mcp/tool/execute&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Deny-by-default tool filtering&lt;/strong&gt; — A virtual key with no &lt;code&gt;mcp_configs&lt;/code&gt; gets zero MCP tools. Unlisted clients are implicitly blocked.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Governance&lt;/strong&gt; (optional) — RBAC, SSO, audit logs, and MCP Tool Groups control who can configure the gateway and review administrative activity.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Bifrost covers virtual keys, budgets, rate limits, routing, and MCP tool filtering, RBAC, SSO, audit logs, and MCP Tool.&lt;/p&gt;


&lt;hr&gt;

&lt;h2&gt;
  &lt;a name=&quot;using-mcp-server&quot; href=&quot;https://dev.to/anthonymax/enterprise-mcp-gateway-with-built-in-security-oauth-20-rbac-and-tool-access-control-68n#using-mcp-server&quot;&gt;
  &lt;/a&gt;
  🔧 Using MCP server
&lt;/h2&gt;

&lt;p&gt;First, let&#39;s open the app and set up the MCP server. To do this, I&#39;ll enter the following line in the terminal:&lt;br&gt;
&lt;/p&gt;

&lt;div class=&quot;highlight js-code-highlight&quot;&gt;
&lt;pre class=&quot;highlight shell&quot;&gt;&lt;code&gt;npx &lt;span class=&quot;nt&quot;&gt;-y&lt;/span&gt; @maximhq/bifrost
&lt;/code&gt;&lt;/pre&gt;
&lt;div class=&quot;highlight__panel js-actions-panel&quot;&gt;
&lt;div class=&quot;highlight__panel-action js-fullscreen-code-action&quot;&gt;
    &lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; width=&quot;20px&quot; height=&quot;20px&quot; viewBox=&quot;0 0 24 24&quot; class=&quot;highlight-action crayons-icon highlight-action--fullscreen-on&quot;&gt;&lt;title&gt;Enter fullscreen mode&lt;/title&gt;
    &lt;path d=&quot;M16 3h6v6h-2V5h-4V3zM2 3h6v2H4v4H2V3zm18 16v-4h2v6h-6v-2h4zM4 19h4v2H2v-6h2v4z&quot;&gt;&lt;/path&gt;
&lt;/svg&gt;

    &lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; width=&quot;20px&quot; height=&quot;20px&quot; viewBox=&quot;0 0 24 24&quot; class=&quot;highlight-action crayons-icon highlight-action--fullscreen-off&quot;&gt;&lt;title&gt;Exit fullscreen mode&lt;/title&gt;
    &lt;path d=&quot;M18 7h4v2h-6V3h2v4zM8 9H2V7h4V3h2v6zm10 8v4h-2v-6h6v2h-4zM8 15v6H6v-4H2v-2h6z&quot;&gt;&lt;/path&gt;
&lt;/svg&gt;

&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;



&lt;p&gt;After that, you will see the following interface (similar, depending on the version):&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;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%2F0sp0jm5kl6xf18gawppa.png&quot; class=&quot;article-body-image-wrapper&quot;&gt;&lt;img src=&quot;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%2F0sp0jm5kl6xf18gawppa.png&quot; alt=&quot;interface&quot; loading=&quot;lazy&quot; width=&quot;799&quot; height=&quot;385&quot; referrerpolicy=&quot;no-referrer&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Go to the &quot;MCP Library&quot; tab and you will see a huge list of pre-configured MCP servers that you can use in your projects.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;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%2Fclqzoxedzsd65w9ba5a2.png&quot; class=&quot;article-body-image-wrapper&quot;&gt;&lt;img src=&quot;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%2Fclqzoxedzsd65w9ba5a2.png&quot; alt=&quot;MCP Library&quot; loading=&quot;lazy&quot; width=&quot;799&quot; height=&quot;385&quot; referrerpolicy=&quot;no-referrer&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you want to set up your own MCP server, go to &lt;strong&gt;MCP Gateway&lt;/strong&gt; and click &lt;strong&gt;New MCP Server&lt;/strong&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;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%2F8sq3c1b29mi9rf6pfs42.png&quot; class=&quot;article-body-image-wrapper&quot;&gt;&lt;img src=&quot;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%2F8sq3c1b29mi9rf6pfs42.png&quot; alt=&quot;mcp settings&quot; loading=&quot;lazy&quot; width=&quot;799&quot; height=&quot;385&quot; referrerpolicy=&quot;no-referrer&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here you can specify the connection URL, auth type, tool allowlists, and other settings including &lt;strong&gt;Code Mode&lt;/strong&gt;, which can significantly reduce token usage when orchestrating many MCP servers.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/maximhq/bifrost&quot; class=&quot;crayons-btn crayons-btn--primary&quot; role=&quot;button&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;💎 Star Bifrost ☆&lt;/a&gt;
&lt;/p&gt;


&lt;hr&gt;

&lt;h2&gt;
  &lt;a name=&quot;humanintheloop-tool&quot; href=&quot;https://dev.to/anthonymax/enterprise-mcp-gateway-with-built-in-security-oauth-20-rbac-and-tool-access-control-68n#humanintheloop-tool&quot;&gt;
  &lt;/a&gt;
  ⚙️ Human-in-the-loop tool
&lt;/h2&gt;

&lt;p&gt;This is the most important security property for the scenario in the introduction.&lt;/p&gt;

&lt;p&gt;When an LLM returns tool calls, &lt;strong&gt;Bifrost does not automatically execute them&lt;/strong&gt;. Tool calls are suggestions only. Your application must explicitly approve and execute each one:&lt;br&gt;
&lt;/p&gt;

&lt;div class=&quot;highlight js-code-highlight&quot;&gt;
&lt;pre class=&quot;highlight plaintext&quot;&gt;&lt;code&gt;1. POST /v1/chat/completions   → LLM returns tool call suggestions (NOT executed)
2. Your app reviews tool calls → Apply security rules, get user approval if needed
3. POST /v1/mcp/tool/execute   → Execute approved tool calls explicitly
4. POST /v1/chat/completions   → Continue the conversation with tool results
&lt;/code&gt;&lt;/pre&gt;
&lt;div class=&quot;highlight__panel js-actions-panel&quot;&gt;
&lt;div class=&quot;highlight__panel-action js-fullscreen-code-action&quot;&gt;
    &lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; width=&quot;20px&quot; height=&quot;20px&quot; viewBox=&quot;0 0 24 24&quot; class=&quot;highlight-action crayons-icon highlight-action--fullscreen-on&quot;&gt;&lt;title&gt;Enter fullscreen mode&lt;/title&gt;
    &lt;path d=&quot;M16 3h6v6h-2V5h-4V3zM2 3h6v2H4v4H2V3zm18 16v-4h2v6h-6v-2h4zM4 19h4v2H2v-6h2v4z&quot;&gt;&lt;/path&gt;
&lt;/svg&gt;

    &lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; width=&quot;20px&quot; height=&quot;20px&quot; viewBox=&quot;0 0 24 24&quot; class=&quot;highlight-action crayons-icon highlight-action--fullscreen-off&quot;&gt;&lt;title&gt;Exit fullscreen mode&lt;/title&gt;
    &lt;path d=&quot;M18 7h4v2h-6V3h2v4zM8 9H2V7h4V3h2v6zm10 8v4h-2v-6h6v2h-4zM8 15v6H6v-4H2v-2h6z&quot;&gt;&lt;/path&gt;
&lt;/svg&gt;

&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;



&lt;p&gt;Example execution call:&lt;br&gt;
&lt;/p&gt;

&lt;div class=&quot;highlight js-code-highlight&quot;&gt;
&lt;pre class=&quot;highlight shell&quot;&gt;&lt;code&gt;curl &lt;span class=&quot;nt&quot;&gt;-X&lt;/span&gt; POST http://localhost:8080/v1/mcp/tool/execute &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;-H&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Content-Type: application/json&quot;&lt;/span&gt; &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;-d&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&#39;{
    &quot;id&quot;: &quot;call_xyz789&quot;,
    &quot;type&quot;: &quot;function&quot;,
    &quot;function&quot;: {
      &quot;name&quot;: &quot;database_query&quot;,
      &quot;arguments&quot;: &quot;{\&quot;sql\&quot;: \&quot;SELECT 1\&quot;}&quot;
    }
  }&#39;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;div class=&quot;highlight__panel js-actions-panel&quot;&gt;
&lt;div class=&quot;highlight__panel-action js-fullscreen-code-action&quot;&gt;
    &lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; width=&quot;20px&quot; height=&quot;20px&quot; viewBox=&quot;0 0 24 24&quot; class=&quot;highlight-action crayons-icon highlight-action--fullscreen-on&quot;&gt;&lt;title&gt;Enter fullscreen mode&lt;/title&gt;
    &lt;path d=&quot;M16 3h6v6h-2V5h-4V3zM2 3h6v2H4v4H2V3zm18 16v-4h2v6h-6v-2h4zM4 19h4v2H2v-6h2v4z&quot;&gt;&lt;/path&gt;
&lt;/svg&gt;

    &lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; width=&quot;20px&quot; height=&quot;20px&quot; viewBox=&quot;0 0 24 24&quot; class=&quot;highlight-action crayons-icon highlight-action--fullscreen-off&quot;&gt;&lt;title&gt;Exit fullscreen mode&lt;/title&gt;
    &lt;path d=&quot;M18 7h4v2h-6V3h2v4zM8 9H2V7h4V3h2v6zm10 8v4h-2v-6h6v2h-4zM8 15v6H6v-4H2v-2h6z&quot;&gt;&lt;/path&gt;
&lt;/svg&gt;

&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;



&lt;p&gt;So even if a new hire&#39;s agent &lt;em&gt;requests&lt;/em&gt; a dangerous database operation, nothing happens until your application deliberately executes it. Combined with deny-by-default virtual key filtering (below), this is Bifrost&#39;s real three-layer answer to accidental production access.&lt;/p&gt;

&lt;p&gt;You can opt into autonomous execution for specific tools via &lt;strong&gt;Agent Mode&lt;/strong&gt;, but that must be explicitly configured, it is not the default.&lt;/p&gt;


&lt;hr&gt;

&lt;h2&gt;
  &lt;a name=&quot;mcp-authentication&quot; href=&quot;https://dev.to/anthonymax/enterprise-mcp-gateway-with-built-in-security-oauth-20-rbac-and-tool-access-control-68n#mcp-authentication&quot;&gt;
  &lt;/a&gt;
  💻 MCP authentication
&lt;/h2&gt;

&lt;p&gt;Authentication is declared on the MCP client itself as a top-level &lt;code&gt;auth_type&lt;/code&gt; field, posted to &lt;code&gt;/api/mcp/client&lt;/code&gt;. There is no nested &lt;code&gt;auth&lt;/code&gt; object.&lt;/p&gt;

&lt;div class=&quot;table-wrapper-paragraph&quot;&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;code&gt;auth_type&lt;/code&gt;&lt;/th&gt;
&lt;th&gt;Who authenticates&lt;/th&gt;
&lt;th&gt;When to use&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;none&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;—&lt;/td&gt;
&lt;td&gt;Public MCP servers, local STDIO tools&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;headers&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Admin, once&lt;/td&gt;
&lt;td&gt;Shared API keys, bearer tokens, custom headers&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;oauth&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Admin, once&lt;/td&gt;
&lt;td&gt;Shared third-party service the whole team uses&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;per_user_oauth&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Each end-user, lazily&lt;/td&gt;
&lt;td&gt;Per-user services like Notion, GitHub, Sentry&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;per_user_headers&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Each end-user, lazily&lt;/td&gt;
&lt;td&gt;Per-user API keys, signed tokens&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;OAuth (&lt;code&gt;oauth&lt;/code&gt; and &lt;code&gt;per_user_oauth&lt;/code&gt;) is only valid for &lt;strong&gt;HTTP&lt;/strong&gt; and &lt;strong&gt;SSE&lt;/strong&gt; connections. Bifrost implements the &lt;strong&gt;Authorization Code&lt;/strong&gt; flow, there is no client-credentials / service-account mode.&lt;/p&gt;

&lt;h3&gt;
  &lt;a name=&quot;1-no-auth-development-only&quot; href=&quot;https://dev.to/anthonymax/enterprise-mcp-gateway-with-built-in-security-oauth-20-rbac-and-tool-access-control-68n#1-no-auth-development-only&quot;&gt;
  &lt;/a&gt;
  1. No auth (development only)
&lt;/h3&gt;



&lt;div class=&quot;highlight js-code-highlight&quot;&gt;
&lt;pre class=&quot;highlight json&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;local-tools&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;connection_type&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;stdio&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;stdio_config&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;command&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;npx&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;args&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;-y&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;@anthropic/mcp-filesystem&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;auth_type&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;none&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;tools_to_execute&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;read_file&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;list_directory&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;div class=&quot;highlight__panel js-actions-panel&quot;&gt;
&lt;div class=&quot;highlight__panel-action js-fullscreen-code-action&quot;&gt;
    &lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; width=&quot;20px&quot; height=&quot;20px&quot; viewBox=&quot;0 0 24 24&quot; class=&quot;highlight-action crayons-icon highlight-action--fullscreen-on&quot;&gt;&lt;title&gt;Enter fullscreen mode&lt;/title&gt;
    &lt;path d=&quot;M16 3h6v6h-2V5h-4V3zM2 3h6v2H4v4H2V3zm18 16v-4h2v6h-6v-2h4zM4 19h4v2H2v-6h2v4z&quot;&gt;&lt;/path&gt;
&lt;/svg&gt;

    &lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; width=&quot;20px&quot; height=&quot;20px&quot; viewBox=&quot;0 0 24 24&quot; class=&quot;highlight-action crayons-icon highlight-action--fullscreen-off&quot;&gt;&lt;title&gt;Exit fullscreen mode&lt;/title&gt;
    &lt;path d=&quot;M18 7h4v2h-6V3h2v4zM8 9H2V7h4V3h2v6zm10 8v4h-2v-6h6v2h-4zM8 15v6H6v-4H2v-2h6z&quot;&gt;&lt;/path&gt;
&lt;/svg&gt;

&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;



&lt;h3&gt;
  &lt;a name=&quot;2-static-headers-shared-api-keys&quot; href=&quot;https://dev.to/anthonymax/enterprise-mcp-gateway-with-built-in-security-oauth-20-rbac-and-tool-access-control-68n#2-static-headers-shared-api-keys&quot;&gt;
  &lt;/a&gt;
  2. Static headers (shared API keys)
&lt;/h3&gt;



&lt;div class=&quot;highlight js-code-highlight&quot;&gt;
&lt;pre class=&quot;highlight shell&quot;&gt;&lt;code&gt;curl &lt;span class=&quot;nt&quot;&gt;-X&lt;/span&gt; POST http://localhost:8080/api/mcp/client &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;-H&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Content-Type: application/json&quot;&lt;/span&gt; &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;-d&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&#39;{
    &quot;name&quot;: &quot;web_search&quot;,
    &quot;connection_type&quot;: &quot;http&quot;,
    &quot;connection_string&quot;: &quot;https://mcp.example.com/mcp&quot;,
    &quot;auth_type&quot;: &quot;headers&quot;,
    &quot;headers&quot;: {
      &quot;Authorization&quot;: &quot;Bearer your-api-key&quot;,
      &quot;X-Tenant-ID&quot;: &quot;acme-corp&quot;
    },
    &quot;tools_to_execute&quot;: [&quot;*&quot;]
  }&#39;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;div class=&quot;highlight__panel js-actions-panel&quot;&gt;
&lt;div class=&quot;highlight__panel-action js-fullscreen-code-action&quot;&gt;
    &lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; width=&quot;20px&quot; height=&quot;20px&quot; viewBox=&quot;0 0 24 24&quot; class=&quot;highlight-action crayons-icon highlight-action--fullscreen-on&quot;&gt;&lt;title&gt;Enter fullscreen mode&lt;/title&gt;
    &lt;path d=&quot;M16 3h6v6h-2V5h-4V3zM2 3h6v2H4v4H2V3zm18 16v-4h2v6h-6v-2h4zM4 19h4v2H2v-6h2v4z&quot;&gt;&lt;/path&gt;
&lt;/svg&gt;

    &lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; width=&quot;20px&quot; height=&quot;20px&quot; viewBox=&quot;0 0 24 24&quot; class=&quot;highlight-action crayons-icon highlight-action--fullscreen-off&quot;&gt;&lt;title&gt;Exit fullscreen mode&lt;/title&gt;
    &lt;path d=&quot;M18 7h4v2h-6V3h2v4zM8 9H2V7h4V3h2v6zm10 8v4h-2v-6h6v2h-4zM8 15v6H6v-4H2v-2h6z&quot;&gt;&lt;/path&gt;
&lt;/svg&gt;

&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;



&lt;h3&gt;
  &lt;a name=&quot;3-serverlevel-oauth-admin-authorizes-once&quot; href=&quot;https://dev.to/anthonymax/enterprise-mcp-gateway-with-built-in-security-oauth-20-rbac-and-tool-access-control-68n#3-serverlevel-oauth-admin-authorizes-once&quot;&gt;
  &lt;/a&gt;
  3. Server-level OAuth (admin authorizes once)
&lt;/h3&gt;

&lt;p&gt;The admin authenticates once during setup. Every subsequent request to that MCP server uses the same stored token, regardless of which caller hit Bifrost.&lt;br&gt;
&lt;/p&gt;

&lt;div class=&quot;highlight js-code-highlight&quot;&gt;
&lt;pre class=&quot;highlight shell&quot;&gt;&lt;code&gt;curl &lt;span class=&quot;nt&quot;&gt;-X&lt;/span&gt; POST http://localhost:8080/api/mcp/client &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;-H&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Content-Type: application/json&quot;&lt;/span&gt; &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;-d&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&#39;{
    &quot;name&quot;: &quot;authenticated_service&quot;,
    &quot;connection_type&quot;: &quot;http&quot;,
    &quot;connection_string&quot;: &quot;https://api.example.com/mcp&quot;,
    &quot;auth_type&quot;: &quot;oauth&quot;,
    &quot;oauth_config&quot;: {
      &quot;client_id&quot;: &quot;your-client-id&quot;,
      &quot;client_secret&quot;: &quot;your-client-secret&quot;,
      &quot;authorize_url&quot;: &quot;https://auth.example.com/oauth/authorize&quot;,
      &quot;token_url&quot;: &quot;https://auth.example.com/oauth/token&quot;,
      &quot;scopes&quot;: [&quot;mcp:read&quot;, &quot;mcp:write&quot;]
    },
    &quot;tools_to_execute&quot;: [&quot;*&quot;]
  }&#39;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;div class=&quot;highlight__panel js-actions-panel&quot;&gt;
&lt;div class=&quot;highlight__panel-action js-fullscreen-code-action&quot;&gt;
    &lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; width=&quot;20px&quot; height=&quot;20px&quot; viewBox=&quot;0 0 24 24&quot; class=&quot;highlight-action crayons-icon highlight-action--fullscreen-on&quot;&gt;&lt;title&gt;Enter fullscreen mode&lt;/title&gt;
    &lt;path d=&quot;M16 3h6v6h-2V5h-4V3zM2 3h6v2H4v4H2V3zm18 16v-4h2v6h-6v-2h4zM4 19h4v2H2v-6h2v4z&quot;&gt;&lt;/path&gt;
&lt;/svg&gt;

    &lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; width=&quot;20px&quot; height=&quot;20px&quot; viewBox=&quot;0 0 24 24&quot; class=&quot;highlight-action crayons-icon highlight-action--fullscreen-off&quot;&gt;&lt;title&gt;Exit fullscreen mode&lt;/title&gt;
    &lt;path d=&quot;M18 7h4v2h-6V3h2v4zM8 9H2V7h4V3h2v6zm10 8v4h-2v-6h6v2h-4zM8 15v6H6v-4H2v-2h6z&quot;&gt;&lt;/path&gt;
&lt;/svg&gt;

&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;oauth_config&lt;/code&gt; object accepts &lt;code&gt;client_id&lt;/code&gt;, &lt;code&gt;client_secret&lt;/code&gt;, &lt;code&gt;authorize_url&lt;/code&gt;, &lt;code&gt;token_url&lt;/code&gt;, &lt;code&gt;scopes&lt;/code&gt;, or &lt;code&gt;registration_url&lt;/code&gt; / &lt;code&gt;server_url&lt;/code&gt; for Dynamic Client Registration. After the admin completes the authorize step, finalize with &lt;code&gt;POST /api/mcp/client/{id}/complete-oauth&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  &lt;a name=&quot;4-peruser-oauth-each-user-authenticates-themselves&quot; href=&quot;https://dev.to/anthonymax/enterprise-mcp-gateway-with-built-in-security-oauth-20-rbac-and-tool-access-control-68n#4-peruser-oauth-each-user-authenticates-themselves&quot;&gt;
  &lt;/a&gt;
  4. Per-user OAuth (each user authenticates themselves)
&lt;/h3&gt;

&lt;p&gt;Use &lt;code&gt;auth_type: &quot;per_user_oauth&quot;&lt;/code&gt; when each end-user must connect under their own account. Bifrost stores one OAuth token per &lt;code&gt;(identity, mcp_client)&lt;/code&gt; and reuses it on later calls. Identity is required via virtual key, signed-in SSO user, or &lt;code&gt;x-bf-mcp-session-id&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  &lt;a name=&quot;5-peruser-headers-legacy-custom-peruser-keys&quot; href=&quot;https://dev.to/anthonymax/enterprise-mcp-gateway-with-built-in-security-oauth-20-rbac-and-tool-access-control-68n#5-peruser-headers-legacy-custom-peruser-keys&quot;&gt;
  &lt;/a&gt;
  5. Per-user headers (legacy / custom per-user keys)
&lt;/h3&gt;



&lt;div class=&quot;highlight js-code-highlight&quot;&gt;
&lt;pre class=&quot;highlight shell&quot;&gt;&lt;code&gt;curl &lt;span class=&quot;nt&quot;&gt;-X&lt;/span&gt; POST http://localhost:8080/api/mcp/client &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;-H&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Content-Type: application/json&quot;&lt;/span&gt; &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;-d&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&#39;{
    &quot;name&quot;: &quot;acme_api&quot;,
    &quot;connection_type&quot;: &quot;http&quot;,
    &quot;connection_string&quot;: &quot;https://api.acme.example.com/mcp&quot;,
    &quot;auth_type&quot;: &quot;per_user_headers&quot;,
    &quot;per_user_header_keys&quot;: [&quot;X-API-Key&quot;, &quot;X-Tenant-ID&quot;],
    &quot;tools_to_execute&quot;: [&quot;*&quot;]
  }&#39;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;div class=&quot;highlight__panel js-actions-panel&quot;&gt;
&lt;div class=&quot;highlight__panel-action js-fullscreen-code-action&quot;&gt;
    &lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; width=&quot;20px&quot; height=&quot;20px&quot; viewBox=&quot;0 0 24 24&quot; class=&quot;highlight-action crayons-icon highlight-action--fullscreen-on&quot;&gt;&lt;title&gt;Enter fullscreen mode&lt;/title&gt;
    &lt;path d=&quot;M16 3h6v6h-2V5h-4V3zM2 3h6v2H4v4H2V3zm18 16v-4h2v6h-6v-2h4zM4 19h4v2H2v-6h2v4z&quot;&gt;&lt;/path&gt;
&lt;/svg&gt;

    &lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; width=&quot;20px&quot; height=&quot;20px&quot; viewBox=&quot;0 0 24 24&quot; class=&quot;highlight-action crayons-icon highlight-action--fullscreen-off&quot;&gt;&lt;title&gt;Exit fullscreen mode&lt;/title&gt;
    &lt;path d=&quot;M18 7h4v2h-6V3h2v4zM8 9H2V7h4V3h2v6zm10 8v4h-2v-6h6v2h-4zM8 15v6H6v-4H2v-2h6z&quot;&gt;&lt;/path&gt;
&lt;/svg&gt;

&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Identity matters:&lt;/strong&gt; With &lt;code&gt;auth_type: &quot;oauth&quot;&lt;/code&gt; or &lt;code&gt;auth_type: &quot;headers&quot;&lt;/code&gt;, all callers share the same upstream credential. Bifrost does not attach a per-user identity to MCP requests. To know exactly &lt;em&gt;who&lt;/em&gt; performed an action upstream, use &lt;code&gt;per_user_oauth&lt;/code&gt; or &lt;code&gt;per_user_headers&lt;/code&gt;.&lt;/p&gt;


&lt;hr&gt;

&lt;h2&gt;
  &lt;a name=&quot;runtime-tool-access-control-virtual-keys&quot; href=&quot;https://dev.to/anthonymax/enterprise-mcp-gateway-with-built-in-security-oauth-20-rbac-and-tool-access-control-68n#runtime-tool-access-control-virtual-keys&quot;&gt;
  &lt;/a&gt;
  💻 Runtime tool access control (Virtual Keys)
&lt;/h2&gt;

&lt;p&gt;RBAC does &lt;strong&gt;not&lt;/strong&gt; govern which MCP tools an agent can invoke at runtime. That is controlled by &lt;strong&gt;virtual keys&lt;/strong&gt; and three stacked levels of tool filtering:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Client config&lt;/strong&gt; — &lt;code&gt;tools_to_execute&lt;/code&gt; on each MCP client (baseline)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Request headers&lt;/strong&gt; — &lt;code&gt;x-bf-mcp-include-clients&lt;/code&gt; and &lt;code&gt;x-bf-mcp-include-tools&lt;/code&gt; per request&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Virtual key config&lt;/strong&gt; — &lt;code&gt;mcp_configs&lt;/code&gt; array (takes precedence over request headers)&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  &lt;a name=&quot;denybydefault&quot; href=&quot;https://dev.to/anthonymax/enterprise-mcp-gateway-with-built-in-security-oauth-20-rbac-and-tool-access-control-68n#denybydefault&quot;&gt;
  &lt;/a&gt;
  Deny-by-default
&lt;/h3&gt;

&lt;p&gt;This is built-in behavior, not a config setting: &lt;strong&gt;a virtual key with no &lt;code&gt;mcp_configs&lt;/code&gt; gets zero MCP tools&lt;/strong&gt;, and clients not listed in &lt;code&gt;mcp_configs&lt;/code&gt; are implicitly blocked.&lt;/p&gt;

&lt;h3&gt;
  &lt;a name=&quot;virtual-key-configuration&quot; href=&quot;https://dev.to/anthonymax/enterprise-mcp-gateway-with-built-in-security-oauth-20-rbac-and-tool-access-control-68n#virtual-key-configuration&quot;&gt;
  &lt;/a&gt;
  Virtual key configuration
&lt;/h3&gt;



&lt;div class=&quot;highlight js-code-highlight&quot;&gt;
&lt;pre class=&quot;highlight shell&quot;&gt;&lt;code&gt;curl &lt;span class=&quot;nt&quot;&gt;-X&lt;/span&gt; POST http://localhost:8080/api/governance/virtual-keys &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;-H&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Content-Type: application/json&quot;&lt;/span&gt; &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;-d&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&#39;{
    &quot;name&quot;: &quot;new-dev-key&quot;,
    &quot;mcp_configs&quot;: [
      {
        &quot;mcp_client_name&quot;: &quot;internal_api&quot;,
        &quot;tools_to_execute&quot;: [&quot;search&quot;, &quot;get_article&quot;]
      },
      {
        &quot;mcp_client_name&quot;: &quot;staging_database&quot;,
        &quot;tools_to_execute&quot;: [&quot;query&quot;]
      }
    ]
  }&#39;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;div class=&quot;highlight__panel js-actions-panel&quot;&gt;
&lt;div class=&quot;highlight__panel-action js-fullscreen-code-action&quot;&gt;
    &lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; width=&quot;20px&quot; height=&quot;20px&quot; viewBox=&quot;0 0 24 24&quot; class=&quot;highlight-action crayons-icon highlight-action--fullscreen-on&quot;&gt;&lt;title&gt;Enter fullscreen mode&lt;/title&gt;
    &lt;path d=&quot;M16 3h6v6h-2V5h-4V3zM2 3h6v2H4v4H2V3zm18 16v-4h2v6h-6v-2h4zM4 19h4v2H2v-6h2v4z&quot;&gt;&lt;/path&gt;
&lt;/svg&gt;

    &lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; width=&quot;20px&quot; height=&quot;20px&quot; viewBox=&quot;0 0 24 24&quot; class=&quot;highlight-action crayons-icon highlight-action--fullscreen-off&quot;&gt;&lt;title&gt;Exit fullscreen mode&lt;/title&gt;
    &lt;path d=&quot;M18 7h4v2h-6V3h2v4zM8 9H2V7h4V3h2v6zm10 8v4h-2v-6h6v2h-4zM8 15v6H6v-4H2v-2h6z&quot;&gt;&lt;/path&gt;
&lt;/svg&gt;

&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;



&lt;div class=&quot;table-wrapper-paragraph&quot;&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;code&gt;tools_to_execute&lt;/code&gt;&lt;/th&gt;
&lt;th&gt;Result&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;[&quot;*&quot;]&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;All tools from this client&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;[&quot;a&quot;, &quot;b&quot;]&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Only specified tools&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;[]&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;No tools from this client&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Client not in &lt;code&gt;mcp_configs&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;All tools blocked from that client&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;This is where you enforce patterns like &quot;backend devs can hit staging APIs but not production databases&quot; by giving different virtual keys different &lt;code&gt;mcp_configs&lt;/code&gt;, not by RBAC permission strings.&lt;/p&gt;

&lt;h3&gt;
  &lt;a name=&quot;perrequest-narrowing&quot; href=&quot;https://dev.to/anthonymax/enterprise-mcp-gateway-with-built-in-security-oauth-20-rbac-and-tool-access-control-68n#perrequest-narrowing&quot;&gt;
  &lt;/a&gt;
  Per-request narrowing
&lt;/h3&gt;

&lt;p&gt;For one-off restrictions within a virtual key&#39;s allowlist:&lt;br&gt;
&lt;/p&gt;

&lt;div class=&quot;highlight js-code-highlight&quot;&gt;
&lt;pre class=&quot;highlight shell&quot;&gt;&lt;code&gt;curl &lt;span class=&quot;nt&quot;&gt;-X&lt;/span&gt; POST http://localhost:8080/v1/chat/completions &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;-H&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Authorization: Bearer vk_new_dev&quot;&lt;/span&gt; &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;-H&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;x-bf-mcp-include-tools: staging_database-query&quot;&lt;/span&gt; &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;-d&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&#39;...&#39;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;div class=&quot;highlight__panel js-actions-panel&quot;&gt;
&lt;div class=&quot;highlight__panel-action js-fullscreen-code-action&quot;&gt;
    &lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; width=&quot;20px&quot; height=&quot;20px&quot; viewBox=&quot;0 0 24 24&quot; class=&quot;highlight-action crayons-icon highlight-action--fullscreen-on&quot;&gt;&lt;title&gt;Enter fullscreen mode&lt;/title&gt;
    &lt;path d=&quot;M16 3h6v6h-2V5h-4V3zM2 3h6v2H4v4H2V3zm18 16v-4h2v6h-6v-2h4zM4 19h4v2H2v-6h2v4z&quot;&gt;&lt;/path&gt;
&lt;/svg&gt;

    &lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; width=&quot;20px&quot; height=&quot;20px&quot; viewBox=&quot;0 0 24 24&quot; class=&quot;highlight-action crayons-icon highlight-action--fullscreen-off&quot;&gt;&lt;title&gt;Exit fullscreen mode&lt;/title&gt;
    &lt;path d=&quot;M18 7h4v2h-6V3h2v4zM8 9H2V7h4V3h2v6zm10 8v4h-2v-6h6v2h-4zM8 15v6H6v-4H2v-2h6z&quot;&gt;&lt;/path&gt;
&lt;/svg&gt;

&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;



&lt;p&gt;Note: when a virtual key has &lt;code&gt;mcp_configs&lt;/code&gt;, it auto-generates &lt;code&gt;x-bf-mcp-include-tools&lt;/code&gt; and overrides any manually sent header.&lt;/p&gt;

&lt;p&gt;Bifrost does not parse SQL or block operations like &lt;code&gt;DELETE&lt;/code&gt; / &lt;code&gt;DROP&lt;/code&gt; at the query level. Restrict access by allowing only specific tool names (for example, a read-only &lt;code&gt;query&lt;/code&gt; tool instead of an &lt;code&gt;execute&lt;/code&gt; tool).&lt;/p&gt;


&lt;hr&gt;

&lt;h2&gt;
  &lt;a name=&quot;rbac-administrative-access&quot; href=&quot;https://dev.to/anthonymax/enterprise-mcp-gateway-with-built-in-security-oauth-20-rbac-and-tool-access-control-68n#rbac-administrative-access&quot;&gt;
  &lt;/a&gt;
  🔎 RBAC — administrative access
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Bifrost&lt;/strong&gt; provides Role-Based Access Control for the &lt;strong&gt;administrative surface&lt;/strong&gt; who can edit MCP gateway configs, read logs, configure guardrails, manage virtual keys, and so on. RBAC is &lt;strong&gt;not&lt;/strong&gt; runtime authorization for agents invoking MCP tools.&lt;/p&gt;

&lt;p&gt;Permissions are &lt;strong&gt;Resource × Operation&lt;/strong&gt; pairs, not permission strings like &lt;code&gt;mcp:tool:invoke&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  &lt;a name=&quot;system-roles&quot; href=&quot;https://dev.to/anthonymax/enterprise-mcp-gateway-with-built-in-security-oauth-20-rbac-and-tool-access-control-68n#system-roles&quot;&gt;
  &lt;/a&gt;
  System roles
&lt;/h3&gt;

&lt;div class=&quot;table-wrapper-paragraph&quot;&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Role&lt;/th&gt;
&lt;th&gt;Permissions&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Admin&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;42&lt;/td&gt;
&lt;td&gt;Full access to all resources and operations&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Developer&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;27&lt;/td&gt;
&lt;td&gt;CRUD on technical resources, view access to logs and cluster&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Viewer&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;14&lt;/td&gt;
&lt;td&gt;Read-only access to all resources&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;You can also create custom roles (for example, an Auditor role with &lt;code&gt;AuditLogs:View&lt;/code&gt; and &lt;code&gt;Logs:View&lt;/code&gt; only).&lt;/p&gt;

&lt;h3&gt;
  &lt;a name=&quot;protected-resources-include&quot; href=&quot;https://dev.to/anthonymax/enterprise-mcp-gateway-with-built-in-security-oauth-20-rbac-and-tool-access-control-68n#protected-resources-include&quot;&gt;
  &lt;/a&gt;
  Protected resources include
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;Logs&lt;/code&gt;, &lt;code&gt;VirtualKeys&lt;/code&gt;, &lt;code&gt;MCPGateway&lt;/code&gt;, &lt;code&gt;MCPToolGroups&lt;/code&gt;, &lt;code&gt;MCPLogs&lt;/code&gt;, &lt;code&gt;GuardrailsConfig&lt;/code&gt;, &lt;code&gt;AuditLogs&lt;/code&gt;, &lt;code&gt;Cluster&lt;/code&gt;, and others.&lt;/p&gt;

&lt;h3&gt;
  &lt;a name=&quot;operations-include&quot; href=&quot;https://dev.to/anthonymax/enterprise-mcp-gateway-with-built-in-security-oauth-20-rbac-and-tool-access-control-68n#operations-include&quot;&gt;
  &lt;/a&gt;
  Operations include
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;View&lt;/code&gt;, &lt;code&gt;Create&lt;/code&gt;, &lt;code&gt;Update&lt;/code&gt;, &lt;code&gt;Delete&lt;/code&gt;, &lt;code&gt;Download&lt;/code&gt;, &lt;code&gt;Reveal&lt;/code&gt;, and inference operations.&lt;/p&gt;

&lt;p&gt;Example: a custom Auditor role might grant &lt;code&gt;AuditLogs:View&lt;/code&gt; and &lt;code&gt;AuditLogs:Download&lt;/code&gt;, but not &lt;code&gt;MCPGateway:Update&lt;/code&gt;. That controls who can &lt;em&gt;configure&lt;/em&gt; the gateway in the dashboard, not which tools an agent executes at runtime.&lt;/p&gt;

&lt;p&gt;Roles and permissions are managed via &lt;strong&gt;Governance → Roles &amp;amp; Permissions&lt;/strong&gt; in the dashboard or the &lt;code&gt;/api/roles&lt;/code&gt; endpoints:&lt;br&gt;
&lt;/p&gt;

&lt;div class=&quot;highlight js-code-highlight&quot;&gt;
&lt;pre class=&quot;highlight shell&quot;&gt;&lt;code&gt;curl &lt;span class=&quot;nt&quot;&gt;-X&lt;/span&gt; GET http://localhost:8080/api/roles/&lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;role_id&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;/permissions &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;-H&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Authorization: Bearer &amp;lt;admin_token&amp;gt;&quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;div class=&quot;highlight__panel js-actions-panel&quot;&gt;
&lt;div class=&quot;highlight__panel-action js-fullscreen-code-action&quot;&gt;
    &lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; width=&quot;20px&quot; height=&quot;20px&quot; viewBox=&quot;0 0 24 24&quot; class=&quot;highlight-action crayons-icon highlight-action--fullscreen-on&quot;&gt;&lt;title&gt;Enter fullscreen mode&lt;/title&gt;
    &lt;path d=&quot;M16 3h6v6h-2V5h-4V3zM2 3h6v2H4v4H2V3zm18 16v-4h2v6h-6v-2h4zM4 19h4v2H2v-6h2v4z&quot;&gt;&lt;/path&gt;
&lt;/svg&gt;

    &lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; width=&quot;20px&quot; height=&quot;20px&quot; viewBox=&quot;0 0 24 24&quot; class=&quot;highlight-action crayons-icon highlight-action--fullscreen-off&quot;&gt;&lt;title&gt;Exit fullscreen mode&lt;/title&gt;
    &lt;path d=&quot;M18 7h4v2h-6V3h2v4zM8 9H2V7h4V3h2v6zm10 8v4h-2v-6h6v2h-4zM8 15v6H6v-4H2v-2h6z&quot;&gt;&lt;/path&gt;
&lt;/svg&gt;

&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;




&lt;hr&gt;

&lt;h2&gt;
  &lt;a name=&quot;user-provisioning-and-role-mapping&quot; href=&quot;https://dev.to/anthonymax/enterprise-mcp-gateway-with-built-in-security-oauth-20-rbac-and-tool-access-control-68n#user-provisioning-and-role-mapping&quot;&gt;
  &lt;/a&gt;
  🖥️ User Provisioning and role mapping
&lt;/h2&gt;

&lt;p&gt;There is no &lt;code&gt;role_sync&lt;/code&gt; config block. Role assignment comes from &lt;strong&gt;User Provisioning over OIDC&lt;/strong&gt;, supported for Okta, Microsoft Entra and others.&lt;/p&gt;

&lt;p&gt;When SSO is configured:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Users sign in with corporate credentials via OAuth 2.0 / OIDC (Authorization Code + PKCE)&lt;/li&gt;
&lt;li&gt;Roles are mapped from &lt;strong&gt;IdP groups&lt;/strong&gt;, &lt;strong&gt;app roles&lt;/strong&gt;, or &lt;strong&gt;custom claims&lt;/strong&gt; to Bifrost roles (Admin, Developer, Viewer, or custom roles)&lt;/li&gt;
&lt;li&gt;Role and team assignments are &lt;strong&gt;synchronized on each session&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Background reconciliation runs every &lt;strong&gt;24 hours&lt;/strong&gt;; OIDC session refresh checks run every &lt;strong&gt;15 minutes&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Inactive or deprovisioned users are decommissioned locally (including via inbound SCIM 2.0)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Configuration lives under &lt;code&gt;scim_config&lt;/code&gt; in &lt;code&gt;config.json&lt;/code&gt;. See the &lt;a href=&quot;https://docs.getbifrost.ai/enterprise/user-provisioning&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;User Provisioning docs&lt;/a&gt; for provider-specific setup guides.&lt;/p&gt;


&lt;hr&gt;

&lt;h2&gt;
  &lt;a name=&quot;audit-logs&quot; href=&quot;https://dev.to/anthonymax/enterprise-mcp-gateway-with-built-in-security-oauth-20-rbac-and-tool-access-control-68n#audit-logs&quot;&gt;
  &lt;/a&gt;
  📋 Audit logs
&lt;/h2&gt;

&lt;p&gt;Audit logs in Bifrost record &lt;strong&gt;administrative activity&lt;/strong&gt;  who changed what, when, and which resource was affected. They do not use a &lt;code&gt;log_level&lt;/code&gt; / &lt;code&gt;capture&lt;/code&gt; / &lt;code&gt;export_to&lt;/code&gt; block.&lt;/p&gt;

&lt;p&gt;Real configuration shape:&lt;br&gt;
&lt;/p&gt;

&lt;div class=&quot;highlight js-code-highlight&quot;&gt;
&lt;pre class=&quot;highlight json&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;audit_logs&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;disabled&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;hmac_key&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;env.AUDIT_HMAC_KEY&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;retention_days&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;365&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;object_storage&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;type&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;s3&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;bucket&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;acme-audit-archive&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;prefix&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;acme-prod&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;compress&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;region&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;us-east-1&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;access_key_id&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;env.AUDIT_S3_KEY&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;secret_access_key&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;env.AUDIT_S3_SECRET&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;div class=&quot;highlight__panel js-actions-panel&quot;&gt;
&lt;div class=&quot;highlight__panel-action js-fullscreen-code-action&quot;&gt;
    &lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; width=&quot;20px&quot; height=&quot;20px&quot; viewBox=&quot;0 0 24 24&quot; class=&quot;highlight-action crayons-icon highlight-action--fullscreen-on&quot;&gt;&lt;title&gt;Enter fullscreen mode&lt;/title&gt;
    &lt;path d=&quot;M16 3h6v6h-2V5h-4V3zM2 3h6v2H4v4H2V3zm18 16v-4h2v6h-6v-2h4zM4 19h4v2H2v-6h2v4z&quot;&gt;&lt;/path&gt;
&lt;/svg&gt;

    &lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; width=&quot;20px&quot; height=&quot;20px&quot; viewBox=&quot;0 0 24 24&quot; class=&quot;highlight-action crayons-icon highlight-action--fullscreen-off&quot;&gt;&lt;title&gt;Exit fullscreen mode&lt;/title&gt;
    &lt;path d=&quot;M18 7h4v2h-6V3h2v4zM8 9H2V7h4V3h2v6zm10 8v4h-2v-6h6v2h-4zM8 15v6H6v-4H2v-2h6z&quot;&gt;&lt;/path&gt;
&lt;/svg&gt;

&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;



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

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Signed events&lt;/strong&gt; — configure an HMAC key for verification&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Dashboard review&lt;/strong&gt; — filter by search text, action, outcome, and date range&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Export&lt;/strong&gt; — JSON, JSON Lines, or Syslog (requires &lt;code&gt;AuditLogs:Download&lt;/code&gt; permission)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Retention&lt;/strong&gt; — &lt;code&gt;retention_days&lt;/code&gt; controls database retention&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Object storage archival&lt;/strong&gt; — optional mirror to S3/GCS for long-term compliance retention&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;View audit entries at &lt;strong&gt;Governance → Audit Logs&lt;/strong&gt; in the dashboard.&lt;/p&gt;


&lt;hr&gt;

&lt;h2&gt;
  &lt;a name=&quot;implementation-best-practices&quot; href=&quot;https://dev.to/anthonymax/enterprise-mcp-gateway-with-built-in-security-oauth-20-rbac-and-tool-access-control-68n#implementation-best-practices&quot;&gt;
  &lt;/a&gt;
  ✅ Implementation best practices
&lt;/h2&gt;

&lt;h3&gt;
  &lt;a name=&quot;1-rely-on-denybydefault&quot; href=&quot;https://dev.to/anthonymax/enterprise-mcp-gateway-with-built-in-security-oauth-20-rbac-and-tool-access-control-68n#1-rely-on-denybydefault&quot;&gt;
  &lt;/a&gt;
  1. Rely on deny-by-default
&lt;/h3&gt;

&lt;p&gt;Do not look for a &lt;code&gt;&quot;policy&quot;: &quot;default_deny&quot;&lt;/code&gt; setting. It does not exist. Instead:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Create virtual keys with explicit &lt;code&gt;mcp_configs&lt;/code&gt; for each team or environment&lt;/li&gt;
&lt;li&gt;Set client-level &lt;code&gt;tools_to_execute&lt;/code&gt; to the minimum needed&lt;/li&gt;
&lt;li&gt;Leave production database tools off keys used for local development&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  &lt;a name=&quot;2-keep-humanintheloop-as-the-default&quot; href=&quot;https://dev.to/anthonymax/enterprise-mcp-gateway-with-built-in-security-oauth-20-rbac-and-tool-access-control-68n#2-keep-humanintheloop-as-the-default&quot;&gt;
  &lt;/a&gt;
  2. Keep human-in-the-loop as the default
&lt;/h3&gt;

&lt;p&gt;Only enable &lt;a href=&quot;https://docs.getbifrost.ai/mcp/agent-mode&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Agent Mode&lt;/a&gt; auto-execution for tools you have explicitly reviewed. The default flow — chat → review → &lt;code&gt;/v1/mcp/tool/execute&lt;/code&gt; — is your strongest safety net.&lt;/p&gt;

&lt;h3&gt;
  &lt;a name=&quot;3-separate-runtime-access-from-admin-access&quot; href=&quot;https://dev.to/anthonymax/enterprise-mcp-gateway-with-built-in-security-oauth-20-rbac-and-tool-access-control-68n#3-separate-runtime-access-from-admin-access&quot;&gt;
  &lt;/a&gt;
  3. Separate runtime access from admin access
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Runtime&lt;/strong&gt; (what agents can do): virtual keys + &lt;code&gt;mcp_configs&lt;/code&gt; + request headers&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Administration&lt;/strong&gt; (who can change configs): RBAC + SSO&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  &lt;a name=&quot;4-use-environmentscoped-virtual-keys&quot; href=&quot;https://dev.to/anthonymax/enterprise-mcp-gateway-with-built-in-security-oauth-20-rbac-and-tool-access-control-68n#4-use-environmentscoped-virtual-keys&quot;&gt;
  &lt;/a&gt;
  4. Use environment-scoped virtual keys
&lt;/h3&gt;



&lt;div class=&quot;highlight js-code-highlight&quot;&gt;
&lt;pre class=&quot;highlight json&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;production-readonly&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;mcp_configs&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;mcp_client_name&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;production_database&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;tools_to_execute&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;query&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;div class=&quot;highlight__panel js-actions-panel&quot;&gt;
&lt;div class=&quot;highlight__panel-action js-fullscreen-code-action&quot;&gt;
    &lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; width=&quot;20px&quot; height=&quot;20px&quot; viewBox=&quot;0 0 24 24&quot; class=&quot;highlight-action crayons-icon highlight-action--fullscreen-on&quot;&gt;&lt;title&gt;Enter fullscreen mode&lt;/title&gt;
    &lt;path d=&quot;M16 3h6v6h-2V5h-4V3zM2 3h6v2H4v4H2V3zm18 16v-4h2v6h-6v-2h4zM4 19h4v2H2v-6h2v4z&quot;&gt;&lt;/path&gt;
&lt;/svg&gt;

    &lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; width=&quot;20px&quot; height=&quot;20px&quot; viewBox=&quot;0 0 24 24&quot; class=&quot;highlight-action crayons-icon highlight-action--fullscreen-off&quot;&gt;&lt;title&gt;Exit fullscreen mode&lt;/title&gt;
    &lt;path d=&quot;M18 7h4v2h-6V3h2v4zM8 9H2V7h4V3h2v6zm10 8v4h-2v-6h6v2h-4zM8 15v6H6v-4H2v-2h6z&quot;&gt;&lt;/path&gt;
&lt;/svg&gt;

&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;





&lt;div class=&quot;highlight js-code-highlight&quot;&gt;
&lt;pre class=&quot;highlight json&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;staging-full&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;mcp_configs&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;mcp_client_name&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;staging_database&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;tools_to_execute&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;*&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;div class=&quot;highlight__panel js-actions-panel&quot;&gt;
&lt;div class=&quot;highlight__panel-action js-fullscreen-code-action&quot;&gt;
    &lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; width=&quot;20px&quot; height=&quot;20px&quot; viewBox=&quot;0 0 24 24&quot; class=&quot;highlight-action crayons-icon highlight-action--fullscreen-on&quot;&gt;&lt;title&gt;Enter fullscreen mode&lt;/title&gt;
    &lt;path d=&quot;M16 3h6v6h-2V5h-4V3zM2 3h6v2H4v4H2V3zm18 16v-4h2v6h-6v-2h4zM4 19h4v2H2v-6h2v4z&quot;&gt;&lt;/path&gt;
&lt;/svg&gt;

    &lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; width=&quot;20px&quot; height=&quot;20px&quot; viewBox=&quot;0 0 24 24&quot; class=&quot;highlight-action crayons-icon highlight-action--fullscreen-off&quot;&gt;&lt;title&gt;Exit fullscreen mode&lt;/title&gt;
    &lt;path d=&quot;M18 7h4v2h-6V3h2v4zM8 9H2V7h4V3h2v6zm10 8v4h-2v-6h6v2h-4zM8 15v6H6v-4H2v-2h6z&quot;&gt;&lt;/path&gt;
&lt;/svg&gt;

&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;



&lt;h3&gt;
  &lt;a name=&quot;5-configure-audit-logging-early&quot; href=&quot;https://dev.to/anthonymax/enterprise-mcp-gateway-with-built-in-security-oauth-20-rbac-and-tool-access-control-68n#5-configure-audit-logging-early&quot;&gt;
  &lt;/a&gt;
  5. Configure audit logging early
&lt;/h3&gt;

&lt;p&gt;Enable HMAC signing, set &lt;code&gt;retention_days&lt;/code&gt; comfortably above your archival window, and optionally mirror to object storage for compliance.&lt;/p&gt;

&lt;h3&gt;
  &lt;a name=&quot;6-perform-regular-access-reviews&quot; href=&quot;https://dev.to/anthonymax/enterprise-mcp-gateway-with-built-in-security-oauth-20-rbac-and-tool-access-control-68n#6-perform-regular-access-reviews&quot;&gt;
  &lt;/a&gt;
  6. Perform regular access reviews
&lt;/h3&gt;

&lt;p&gt;Schedule quarterly reviews to answer:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Which virtual keys grant access to production MCP clients?&lt;/li&gt;
&lt;li&gt;Who has Admin or Developer RBAC roles in Enterprise?&lt;/li&gt;
&lt;li&gt;Are there overprivileged virtual keys or dormant SSO accounts?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Use the dashboard and &lt;code&gt;/api/roles&lt;/code&gt; endpoints, there is no &lt;code&gt;bifrost audit&lt;/code&gt; CLI command. The &lt;code&gt;@maximhq/bifrost-cli&lt;/code&gt; package is an interactive launcher for coding agents (Claude Code, Codex CLI, Gemini CLI, Opencode), not an audit tool.&lt;/p&gt;


&lt;hr&gt;

&lt;h2&gt;
  &lt;a name=&quot;conclusion&quot; href=&quot;https://dev.to/anthonymax/enterprise-mcp-gateway-with-built-in-security-oauth-20-rbac-and-tool-access-control-68n#conclusion&quot;&gt;
  &lt;/a&gt;
  🖋️ Conclusion
&lt;/h2&gt;

&lt;p&gt;With Bifrost, you can configure your company&#39;s MCP server much more securely. This ready-made solution will save you not only money but also time, which can be spent on product development.&lt;/p&gt;


&lt;hr&gt;

&lt;h2&gt;
  &lt;a name=&quot;resources&quot; href=&quot;https://dev.to/anthonymax/enterprise-mcp-gateway-with-built-in-security-oauth-20-rbac-and-tool-access-control-68n#resources&quot;&gt;
  &lt;/a&gt;
  🔗 Resources:
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Bifrost GitHub&lt;/strong&gt;: &lt;a href=&quot;https://github.com/maximhq/bifrost&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;https://github.com/maximhq/bifrost&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Bifrost Docs&lt;/strong&gt;: &lt;a href=&quot;https://docs.getbifrost.ai/&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;https://docs.getbifrost.ai&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Bifrost CLI&lt;/strong&gt;: &lt;code&gt;npx -y @maximhq/bifrost-cli&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Thanks for reading this article! ❤️&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;I&#39;d love to hear your thoughts on this mode in the comments!&lt;/em&gt;&lt;/p&gt;


            </description><link>https://dev.to/anthonymax/enterprise-mcp-gateway-with-built-in-security-oauth-20-rbac-and-tool-access-control-68n</link><guid isPermaLink="false">https://dev.to/anthonymax/enterprise-mcp-gateway-with-built-in-security-oauth-20-rbac-and-tool-access-control-68n</guid><pubDate>Wed, 05 Aug 2026 19:41:55 GMT</pubDate><author>Anthony Max</author><enclosure url="https://media2.dev.to/dynamic/image/width=1000,height=420,fit=cover,gravity=auto,format=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F7tg65yri6bjji99xiwoz.png" type="image/jpeg"></enclosure><category>ai</category><category>webdev</category><category>programming</category><category>opensource</category></item><item><title>Welcome Thread - v387</title><description>&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Leave a comment below to introduce yourself! You can talk about what brought you here, what you&#39;re learning, or just a fun fact about&lt;br&gt;
yourself.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Reply to someone&#39;s comment, either with a question or just a hello. 👋&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href=&quot;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%2Fc7vgtg7my7g4hbxn6d4e.gif&quot; class=&quot;article-body-image-wrapper&quot;&gt;&lt;img src=&quot;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%2Fc7vgtg7my7g4hbxn6d4e.gif&quot; alt=&quot;A dog raises it&#39;s paw to hive-five a human hand with the caption &quot; loading=&quot;lazy&quot; width=&quot;480&quot; height=&quot;480&quot; referrerpolicy=&quot;no-referrer&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Come back next week to greet our new members so you can one day earn our &lt;a href=&quot;https://dev.to/community-badges?badge=warm-welcome&quot;&gt;Warm Welcome Badge&lt;/a&gt;!&lt;/p&gt;


            </description><link>https://dev.to/devteam/welcome-thread-v387-1iej</link><guid isPermaLink="false">https://dev.to/devteam/welcome-thread-v387-1iej</guid><pubDate>Wed, 05 Aug 2026 13:00:00 GMT</pubDate><author>Sloan the DEV Moderator</author><enclosure url="https://media2.dev.to/dynamic/image/width=1000,height=420,fit=cover,gravity=auto,format=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F8zwx5oo44gcrjx4t7hpr.jpeg" type="image/jpeg"></enclosure><category>welcome</category></item><item><title>How I Smashed a Bug in a Shared Authentication Library</title><description>&lt;p&gt;&lt;em&gt;This is a submission for &lt;a href=&quot;https://dev.to/bugsmash&quot;&gt;DEV&#39;s Summer Bug Smash: Smash Stories&lt;/a&gt; powered by &lt;a href=&quot;https://sentry.io/&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Sentry&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;This happened a while ago at one of the corporations where I worked.&lt;/p&gt;

&lt;p&gt;I was working on a web application as a full-stack developer, so I was responsible for both the frontend and the backend.&lt;/p&gt;

&lt;p&gt;Because the corporation was huge, there were several libraries and services shared across multiple teams and maintained by dedicated developers. It was basically open source inside a corporation. 😄&lt;/p&gt;

&lt;p&gt;And of course, we used some of those libraries and services, because why reinvent the wheel, right?&lt;/p&gt;

&lt;p&gt;So, after we released the first version of our web application, an interesting bug appeared.&lt;/p&gt;

&lt;p&gt;When a user opened the application in multiple browser tabs, authentication would sometimes randomly break in one of them. Once that happened, the tab could not recover until the user pressed F5 or closed it completely.&lt;/p&gt;

&lt;p&gt;Interesting.&lt;/p&gt;

&lt;p&gt;As the senior developer on the team, I took the bug and started investigating.&lt;/p&gt;

&lt;p&gt;After some time and a lot of attempts, I found that when the frontend tried to refresh the authentication token, it received a &lt;code&gt;403 Forbidden&lt;/code&gt; HTTP response, and the authentication flow broke completely.&lt;/p&gt;

&lt;p&gt;So I played around with session storage and local storage in Chrome and tried changing the authentication configuration. It did not help much, but one thing was clear: the bug appeared to be inside the shared frontend authentication library.&lt;/p&gt;

&lt;p&gt;Okay.&lt;/p&gt;

&lt;p&gt;I collected all the logs and everything I had learned about the bug and went to the frontend team responsible for maintaining the authentication library.&lt;/p&gt;

&lt;p&gt;After an hour-long discussion, they concluded that it was not their fault because the backend team maintaining the authentication service was not supposed to return that particular response code.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Yes, the frontend library and the backend authentication service were maintained by completely different teams.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;I was not fully convinced, but there were more of them. 😁&lt;/p&gt;

&lt;p&gt;So I collected all the logs again and went to the backend team.&lt;/p&gt;

&lt;p&gt;We had another discussion and found that they were returning a valid response code because the frontend authentication library was sending a refresh token that had already been invalidated. The underlying problem was a race condition between multiple tabs. One tab refreshed the token and invalidated the previous refresh token while another tab was still trying to use it.&lt;/p&gt;

&lt;p&gt;Okay...&lt;/p&gt;

&lt;p&gt;So, once again, I grabbed all the logs and went back to the frontend team.&lt;/p&gt;

&lt;p&gt;And in case you are wondering why the two teams did not simply communicate with each other, both teams gave me approximately the same answer:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;This is a problem in your application, so your team has to solve it.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Back to the frontend team.&lt;/p&gt;

&lt;p&gt;I presented the backend team’s conclusion, but they were still not convinced.&lt;/p&gt;

&lt;p&gt;At that point, I was starting to get a little angry, so I created a single ticket, added both teams to it, and included all the logs, requests, responses, timestamps, and everything else I had collected.&lt;/p&gt;

&lt;p&gt;Weeks passed.&lt;/p&gt;

&lt;p&gt;Conversations continued in the ticket and in chat.&lt;/p&gt;

&lt;p&gt;But the bug resolution still looked far, far away.&lt;/p&gt;

&lt;p&gt;So I decided to arrange a meeting for everyone involved.&lt;/p&gt;

&lt;p&gt;And finally, something happened.&lt;/p&gt;

&lt;p&gt;During the meeting, we agreed that the problem was in the frontend authentication library and that the frontend team would fix it.&lt;/p&gt;

&lt;p&gt;Success!&lt;/p&gt;

&lt;p&gt;Or so I thought.&lt;/p&gt;

&lt;p&gt;Two weeks later, while testers and users were getting increasingly angry because the application randomly failed to refresh authentication tokens, the frontend team came back with their final conclusion:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;They were unable to reproduce the problem.&lt;/p&gt;

&lt;p&gt;And users should not open the application in multiple tabs.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Until that moment, opening multiple tabs had been considered a perfectly normal user flow...&lt;/p&gt;

&lt;p&gt;At that moment, I closed the ticket, completely removed the corporate frontend authentication library from our project, and reimplemented the entire client-side authentication flow directly against the existing corporate authentication service.&lt;/p&gt;

&lt;p&gt;The main changes were in the Angular HTTP interceptor and the token refresh flow. I updated the interceptor to handle authentication-related responses, including &lt;code&gt;403 Forbidden&lt;/code&gt;, without leaving the entire tab stuck in a broken state.&lt;/p&gt;

&lt;p&gt;I also reworked how refreshed tokens were handled and stored in session storage. Invalidated tokens and failed refresh attempts were now handled explicitly instead of causing the authentication flow to stop completely.&lt;/p&gt;

&lt;p&gt;Yes, it took two days and one night. And yes, I took a few ideas from the corporate authentication library, because otherwise it would have taken much longer. 😄&lt;/p&gt;

&lt;p&gt;But I only have one set of nerves.&lt;/p&gt;

&lt;p&gt;And you know what?&lt;/p&gt;

&lt;p&gt;From that moment on, it worked like a charm. And whenever another bug appeared, it was fixed immediately because, this time, we actually owned the code.&lt;/p&gt;

&lt;p&gt;And that is my Bug Smash story where corporate life can sometimes be slightly ridiculous, and fixing one bug can mean rewriting the entire feature.&lt;/p&gt;


            </description><link>https://dev.to/gramli/how-i-smashed-a-bug-in-a-shared-authentication-library-33fm</link><guid isPermaLink="false">https://dev.to/gramli/how-i-smashed-a-bug-in-a-shared-authentication-library-33fm</guid><pubDate>Wed, 05 Aug 2026 06:58:57 GMT</pubDate><author>Daniel Balcarek</author><enclosure url="https://media2.dev.to/dynamic/image/width=1000,height=420,fit=cover,gravity=auto,format=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fhwmq8sywc3w0s6zwx0us.jpg" type="image/jpeg"></enclosure><category>devchallenge</category><category>bugsmash</category><category>angular</category><category>typescript</category></item><item><title>Top 7 Featured DEV Posts of the Week</title><description>&lt;p&gt;&lt;em&gt;Welcome to this week&#39;s Top 7, where the DEV editorial team handpicks their favorite posts from the previous week (Saturday-Friday).&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Congrats to all the authors that made it onto the list 👏&lt;/p&gt;


&lt;div class=&quot;ltag__link--embedded&quot;&gt;
  &lt;div class=&quot;crayons-story &quot; data-feed-content-id=&quot;4232408&quot; data-content-user-id=&quot;1898135&quot;&gt;
  &lt;a href=&quot;https://dev.to/le_beltagy/i-run-bare-metal-kubernetes-on-200-of-scrap-hardware-and-why-i-burned-3-sd-cards-learning-34cb&quot; aria-labelledby=&quot;article-link-4232408&quot; class=&quot;crayons-story__hidden-navigation-link&quot;&gt;I Run Bare-Metal Kubernetes on $200 of Scrap Hardware (And Why I Burned 3 SD Cards Learning)&lt;/a&gt;


  &lt;div class=&quot;crayons-story__body crayons-story__body-full_post&quot;&gt;
      &lt;a href=&quot;https://dev.to/le_beltagy/i-run-bare-metal-kubernetes-on-200-of-scrap-hardware-and-why-i-burned-3-sd-cards-learning-34cb&quot; class=&quot;crayons-article__context-note crayons-article__context-note__feed&quot;&gt;&lt;p&gt;Real failure stories beat sterile tutorials&lt;/p&gt;

&lt;/a&gt;
    &lt;div class=&quot;crayons-story__top&quot;&gt;
      &lt;div class=&quot;crayons-story__meta&quot;&gt;
        &lt;div class=&quot;crayons-story__author-pic&quot;&gt;

          &lt;a href=&quot;https://dev.to/le_beltagy&quot; class=&quot;crayons-avatar  crayons-avatar--l  &quot;&gt;
            &lt;img src=&quot;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%2Fuser%2Fprofile_image%2F1898135%2F5ef7f7dd-7439-4956-856d-fc2c3a00f2ac.jpeg&quot; alt=&quot;le_beltagy profile&quot; class=&quot;crayons-avatar__image&quot; loading=&quot;lazy&quot; referrerpolicy=&quot;no-referrer&quot;&gt;
          &lt;/a&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;div&gt;
            &lt;a href=&quot;https://dev.to/le_beltagy&quot; class=&quot;crayons-story__secondary fw-medium m:hidden&quot;&gt;
              Le Beltagy
            &lt;/a&gt;
            &lt;div class=&quot;profile-preview-card relative mb-4 s:mb-0 fw-medium hidden m:inline-block&quot;&gt;
              &lt;button id=&quot;story-author-preview-trigger-4232408&quot; aria-controls=&quot;story-author-preview-content-4232408&quot; class=&quot;profile-preview-card__trigger fs-s p-1 -ml-1 -my-2 crayons-btn crayons-btn--ghost&quot; aria-label=&quot;Le Beltagy profile details&quot;&gt;
                Le Beltagy
                
              &lt;/button&gt;
              &lt;div id=&quot;story-author-preview-content-4232408&quot; class=&quot;profile-preview-card__content crayons-dropdown branded-7 p-4 pt-0&quot; style=&quot;border-top-color: var(--card-color);&quot; data-repositioning-dropdown=&quot;true&quot; data-testid=&quot;profile-preview-card&quot;&gt;
                &lt;div class=&quot;gap-4 grid&quot;&gt;
                  &lt;div class=&quot;-mt-4&quot;&gt;
                    &lt;a href=&quot;https://dev.to/le_beltagy&quot; class=&quot;flex&quot;&gt;
                      &lt;span class=&quot;crayons-avatar crayons-avatar--xl mr-2 shrink-0&quot;&gt;
                        &lt;img src=&quot;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%2Fuser%2Fprofile_image%2F1898135%2F5ef7f7dd-7439-4956-856d-fc2c3a00f2ac.jpeg&quot; class=&quot;crayons-avatar__image&quot; alt=&quot;&quot; loading=&quot;lazy&quot; referrerpolicy=&quot;no-referrer&quot;&gt;
                      &lt;/span&gt;
                      &lt;span class=&quot;crayons-link crayons-subtitle-2 mt-5&quot;&gt;Le Beltagy&lt;/span&gt;
                    &lt;/a&gt;
                  &lt;/div&gt;
                  &lt;div class=&quot;print-hidden&quot;&gt;
                    &lt;button class=&quot;crayons-btn follow-action-button whitespace-nowrap follow-user w-100&quot; data-info=&quot;{&amp;quot;style&amp;quot;:&amp;quot;full&amp;quot;,&amp;quot;id&amp;quot;:1898135,&amp;quot;className&amp;quot;:&amp;quot;User&amp;quot;,&amp;quot;name&amp;quot;:&amp;quot;Le Beltagy&amp;quot;}&quot;&gt;
                      Follow
                    &lt;/button&gt;
                  &lt;/div&gt;
                  &lt;div class=&quot;author-preview-metadata-container&quot; data-author-id=&quot;1898135&quot;&gt;&lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
            &lt;/div&gt;

          &lt;/div&gt;
          &lt;a href=&quot;https://dev.to/le_beltagy/i-run-bare-metal-kubernetes-on-200-of-scrap-hardware-and-why-i-burned-3-sd-cards-learning-34cb&quot; class=&quot;crayons-story__tertiary fs-xs&quot;&gt;&lt;time datetime=&quot;2026-07-25T17:55:01Z&quot;&gt;Jul 25&lt;/time&gt;&lt;span class=&quot;time-ago-indicator-initial-placeholder&quot; data-seconds=&quot;1785002101&quot;&gt;&lt;/span&gt;&lt;/a&gt;
        &lt;/div&gt;
      &lt;/div&gt;

    &lt;/div&gt;

    &lt;div class=&quot;crayons-story__indention&quot;&gt;
      &lt;h2 class=&quot;crayons-story__title crayons-story__title-full_post&quot;&gt;
        &lt;a href=&quot;https://dev.to/le_beltagy/i-run-bare-metal-kubernetes-on-200-of-scrap-hardware-and-why-i-burned-3-sd-cards-learning-34cb&quot; data-preload-image=&quot;https://media2.dev.to/dynamic/image/width=1000,height=420,fit=cover,gravity=auto,format=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fmp807g893wizyzwkko8v.png&quot; id=&quot;article-link-4232408&quot;&gt;
          I Run Bare-Metal Kubernetes on $200 of Scrap Hardware (And Why I Burned 3 SD Cards Learning)
        &lt;/a&gt;
      &lt;/h2&gt;
        &lt;div class=&quot;crayons-story__tags&quot;&gt;
            &lt;a class=&quot;crayons-tag  crayons-tag--monochrome &quot; style=&quot;
        --tag-bg: rgba(50, 109, 230, 0.10);
        --tag-prefix: #326de6;
        --tag-bg-hover: rgba(50, 109, 230, 0.10);
        --tag-prefix-hover: #326de6;
      &quot; href=&quot;https://dev.to/t/kubernetes&quot;&gt;&lt;span class=&quot;crayons-tag__prefix&quot;&gt;#&lt;/span&gt;kubernetes&lt;/a&gt;
            &lt;a class=&quot;crayons-tag  crayons-tag--monochrome &quot; style=&quot;
        --tag-bg: rgba(59, 73, 223, 0.10);
        --tag-prefix: #3b49df;
        --tag-bg-hover: rgba(59, 73, 223, 0.10);
        --tag-prefix-hover: #3b49df;
      &quot; href=&quot;https://dev.to/t/homelab&quot;&gt;&lt;span class=&quot;crayons-tag__prefix&quot;&gt;#&lt;/span&gt;homelab&lt;/a&gt;
            &lt;a class=&quot;crayons-tag  crayons-tag--monochrome &quot; style=&quot;
        --tag-bg: rgba(6, 181, 0, 0.10);
        --tag-prefix: #06B500;
        --tag-bg-hover: rgba(6, 181, 0, 0.10);
        --tag-prefix-hover: #06B500;
      &quot; href=&quot;https://dev.to/t/devops&quot;&gt;&lt;span class=&quot;crayons-tag__prefix&quot;&gt;#&lt;/span&gt;devops&lt;/a&gt;
            &lt;a class=&quot;crayons-tag  crayons-tag--monochrome &quot; style=&quot;
        --tag-bg: rgba(59, 73, 223, 0.10);
        --tag-prefix: #3b49df;
        --tag-bg-hover: rgba(59, 73, 223, 0.10);
        --tag-prefix-hover: #3b49df;
      &quot; href=&quot;https://dev.to/t/talos&quot;&gt;&lt;span class=&quot;crayons-tag__prefix&quot;&gt;#&lt;/span&gt;talos&lt;/a&gt;
        &lt;/div&gt;
      &lt;div class=&quot;crayons-story__bottom&quot;&gt;
        &lt;div class=&quot;crayons-story__details&quot;&gt;
          &lt;a href=&quot;https://dev.to/le_beltagy/i-run-bare-metal-kubernetes-on-200-of-scrap-hardware-and-why-i-burned-3-sd-cards-learning-34cb&quot; class=&quot;crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left&quot; data-reaction-count=&quot;&quot; data-reactable-id=&quot;4232408&quot; aria-label=&quot;Add a comment to post - I Run Bare-Metal Kubernetes on $200 of Scrap Hardware (And Why I Burned 3 SD Cards Learning)&quot;&gt;
            &lt;div class=&quot;multiple_reactions_aggregate&quot;&gt;
              &lt;span class=&quot;multiple_reactions_icons_container&quot; dir=&quot;rtl&quot;&gt;
                  &lt;span class=&quot;crayons_icon_container&quot;&gt;
                    &lt;img src=&quot;https://assets.dev.to/assets/fire-f60e7a582391810302117f987b22a8ef04a2fe0df7e3258a5f49332df1cec71e.svg&quot; width=&quot;18&quot; height=&quot;18&quot; referrerpolicy=&quot;no-referrer&quot;&gt;
                  &lt;/span&gt;
                  &lt;span class=&quot;crayons_icon_container&quot;&gt;
                    &lt;img src=&quot;https://assets.dev.to/assets/multi-unicorn-b44d6f8c23cdd00964192bedc38af3e82463978aa611b4365bd33a0f1f4f3e97.svg&quot; width=&quot;18&quot; height=&quot;18&quot; referrerpolicy=&quot;no-referrer&quot;&gt;
                  &lt;/span&gt;
                  &lt;span class=&quot;crayons_icon_container&quot;&gt;
                    &lt;img src=&quot;https://assets.dev.to/assets/sparkle-heart-5f9bee3767e18deb1bb725290cb151c25234768a0e9a2bd39370c382d02920cf.svg&quot; width=&quot;18&quot; height=&quot;18&quot; referrerpolicy=&quot;no-referrer&quot;&gt;
                  &lt;/span&gt;
              &lt;/span&gt;
              &lt;span class=&quot;aggregate_reactions_counter&quot;&gt;59&lt;span class=&quot;hidden s:inline&quot;&gt;&amp;nbsp;reactions&lt;/span&gt;&lt;/span&gt;
            &lt;/div&gt;
          &lt;/a&gt;
            &lt;a href=&quot;https://dev.to/le_beltagy/i-run-bare-metal-kubernetes-on-200-of-scrap-hardware-and-why-i-burned-3-sd-cards-learning-34cb#comments&quot; class=&quot;crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left flex items-center&quot; aria-label=&quot;Add a comment to post - I Run Bare-Metal Kubernetes on $200 of Scrap Hardware (And Why I Burned 3 SD Cards Learning)&quot;&gt;
              &lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; width=&quot;24&quot; height=&quot;24&quot; role=&quot;img&quot; aria-labelledby=&quot;aqqrahhu80m93k9r4hltny32nfe69eoy&quot; class=&quot;crayons-icon&quot;&gt;&lt;title id=&quot;aqqrahhu80m93k9r4hltny32nfe69eoy&quot;&gt;Comments&lt;/title&gt;
&lt;path d=&quot;M10.5 5h3a6 6 0 110 12v2.625c-3.75-1.5-9-3.75-9-8.625a6 6 0 016-6zM12 15.5h1.5a4.501 4.501 0 001.722-8.657A4.5 4.5 0 0013.5 6.5h-3A4.5 4.5 0 006 11c0 2.707 1.846 4.475 6 6.36V15.5z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;

              11&lt;span class=&quot;hidden s:inline&quot;&gt;&amp;nbsp;comments&lt;/span&gt;
            &lt;/a&gt;
        &lt;/div&gt;
        &lt;div class=&quot;crayons-story__save&quot;&gt;
          &lt;small class=&quot;crayons-story__tertiary fs-xs mr-2&quot;&gt;
            8 min read
          &lt;/small&gt;
            &lt;button type=&quot;button&quot; id=&quot;article-save-button-4232408&quot; class=&quot;c-btn c-btn--icon-alone bookmark-button&quot; data-reactable-id=&quot;4232408&quot; data-article-author-id=&quot;1898135&quot; aria-label=&quot;Save post I Run Bare-Metal Kubernetes on $200 of Scrap Hardware (And Why I Burned 3 SD Cards Learning) to reading list&quot; title=&quot;Save post I Run Bare-Metal Kubernetes on $200 of Scrap Hardware (And Why I Burned 3 SD Cards Learning) to reading list&quot;&gt;
              &lt;span class=&quot;bm-initial crayons-icon c-btn__icon&quot;&gt;
                &lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; width=&quot;24&quot; height=&quot;24&quot; aria-hidden=&quot;true&quot;&gt;&lt;path d=&quot;M6.75 4.5h10.5a.75.75 0 01.75.75v14.357a.375.375 0 01-.575.318L12 16.523l-5.426 3.401A.375.375 0 016 19.607V5.25a.75.75 0 01.75-.75zM16.5 6h-9v11.574l4.5-2.82 4.5 2.82V6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;

              &lt;/span&gt;
              &lt;span class=&quot;bm-success crayons-icon c-btn__icon&quot;&gt;
                &lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; width=&quot;24&quot; height=&quot;24&quot; aria-hidden=&quot;true&quot;&gt;&lt;path d=&quot;M6.75 4.5h10.5a.75.75 0 01.75.75v14.357a.375.375 0 01-.575.318L12 16.523l-5.426 3.401A.375.375 0 016 19.607V5.25a.75.75 0 01.75-.75z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;

              &lt;/span&gt;
            &lt;/button&gt;
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;/div&gt;


&lt;p&gt;&lt;a class=&quot;mentioned-user&quot; href=&quot;https://dev.to/le_beltagy&quot;&gt;@le_beltagy&lt;/a&gt; turned a Dell OptiPlex rescued from a recycling pile and three Raspberry Pis into a four-node Talos Linux cluster running Cilium, ArgoCD, and Longhorn. The post reads less like a tutorial and more like an autopsy, walking through five failures, including three dead SD cards, a network policy lockout, and a corrupted etcd upgrade.&lt;/p&gt;


&lt;hr&gt;


&lt;div class=&quot;ltag__link--embedded&quot;&gt;
  &lt;div class=&quot;crayons-story &quot; data-feed-content-id=&quot;4248045&quot; data-content-user-id=&quot;3224358&quot;&gt;
  &lt;a href=&quot;https://dev.to/anchildress1/nine-months-of-nagging-zero-reading-2fgc&quot; aria-labelledby=&quot;article-link-4248045&quot; class=&quot;crayons-story__hidden-navigation-link&quot;&gt;Nine Months of Nagging, Zero Reading&lt;/a&gt;


  &lt;div class=&quot;crayons-story__body crayons-story__body-full_post&quot;&gt;
      &lt;a href=&quot;https://dev.to/anchildress1/nine-months-of-nagging-zero-reading-2fgc&quot; class=&quot;crayons-article__context-note crayons-article__context-note__feed&quot;&gt;&lt;p&gt;Turns git trailers into queryable data&lt;/p&gt;

&lt;/a&gt;
    &lt;div class=&quot;crayons-story__top&quot;&gt;
      &lt;div class=&quot;crayons-story__meta&quot;&gt;
        &lt;div class=&quot;crayons-story__author-pic&quot;&gt;

          &lt;a href=&quot;https://dev.to/anchildress1&quot; class=&quot;crayons-avatar  crayons-avatar--l  &quot;&gt;
            &lt;img src=&quot;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%2Fuser%2Fprofile_image%2F3224358%2Fd0d49299-08e2-460d-a1fb-9374ca313093.png&quot; alt=&quot;anchildress1 profile&quot; class=&quot;crayons-avatar__image&quot; loading=&quot;lazy&quot; referrerpolicy=&quot;no-referrer&quot;&gt;
          &lt;/a&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;div&gt;
            &lt;a href=&quot;https://dev.to/anchildress1&quot; class=&quot;crayons-story__secondary fw-medium m:hidden&quot;&gt;
              Ashley Childress
            &lt;/a&gt;
            &lt;div class=&quot;profile-preview-card relative mb-4 s:mb-0 fw-medium hidden m:inline-block&quot;&gt;
              &lt;button id=&quot;story-author-preview-trigger-4248045&quot; aria-controls=&quot;story-author-preview-content-4248045&quot; class=&quot;profile-preview-card__trigger fs-s p-1 -ml-1 -my-2 crayons-btn crayons-btn--ghost&quot; aria-label=&quot;Ashley Childress profile details&quot;&gt;
                Ashley Childress
                &lt;a style=&quot;display: inline;&quot; href=&quot;https://dev.to/++&quot;&gt;&lt;img alt=&quot;Subscriber&quot; class=&quot;subscription-icon&quot; src=&quot;https://assets.dev.to/assets/subscription-icon-805dfa7ac7dd660f07ed8d654877270825b07a92a03841aa99a1093bd00431b2.png&quot; referrerpolicy=&quot;no-referrer&quot;&gt;&lt;/a&gt;
              &lt;/button&gt;
              &lt;div id=&quot;story-author-preview-content-4248045&quot; class=&quot;profile-preview-card__content crayons-dropdown branded-7 p-4 pt-0&quot; style=&quot;border-top-color: var(--card-color);&quot; data-repositioning-dropdown=&quot;true&quot; data-testid=&quot;profile-preview-card&quot;&gt;
                &lt;div class=&quot;gap-4 grid&quot;&gt;
                  &lt;div class=&quot;-mt-4&quot;&gt;
                    &lt;a href=&quot;https://dev.to/anchildress1&quot; class=&quot;flex&quot;&gt;
                      &lt;span class=&quot;crayons-avatar crayons-avatar--xl mr-2 shrink-0&quot;&gt;
                        &lt;img src=&quot;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%2Fuser%2Fprofile_image%2F3224358%2Fd0d49299-08e2-460d-a1fb-9374ca313093.png&quot; class=&quot;crayons-avatar__image&quot; alt=&quot;&quot; loading=&quot;lazy&quot; referrerpolicy=&quot;no-referrer&quot;&gt;
                      &lt;/span&gt;
                      &lt;span class=&quot;crayons-link crayons-subtitle-2 mt-5&quot;&gt;Ashley Childress&lt;/span&gt;
                    &lt;/a&gt;
                  &lt;/div&gt;
                  &lt;div class=&quot;print-hidden&quot;&gt;
                    &lt;button class=&quot;crayons-btn follow-action-button whitespace-nowrap follow-user w-100&quot; data-info=&quot;{&amp;quot;style&amp;quot;:&amp;quot;full&amp;quot;,&amp;quot;id&amp;quot;:3224358,&amp;quot;className&amp;quot;:&amp;quot;User&amp;quot;,&amp;quot;name&amp;quot;:&amp;quot;Ashley Childress&amp;quot;}&quot;&gt;
                      Follow
                    &lt;/button&gt;
                  &lt;/div&gt;
                  &lt;div class=&quot;author-preview-metadata-container&quot; data-author-id=&quot;3224358&quot;&gt;&lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
            &lt;/div&gt;

          &lt;/div&gt;
          &lt;a href=&quot;https://dev.to/anchildress1/nine-months-of-nagging-zero-reading-2fgc&quot; class=&quot;crayons-story__tertiary fs-xs&quot;&gt;&lt;time datetime=&quot;2026-07-27T21:26:21Z&quot;&gt;Jul 27&lt;/time&gt;&lt;span class=&quot;time-ago-indicator-initial-placeholder&quot; data-seconds=&quot;1785187581&quot;&gt;&lt;/span&gt;&lt;/a&gt;
        &lt;/div&gt;
      &lt;/div&gt;

    &lt;/div&gt;

    &lt;div class=&quot;crayons-story__indention&quot;&gt;
      &lt;h2 class=&quot;crayons-story__title crayons-story__title-full_post&quot;&gt;
        &lt;a href=&quot;https://dev.to/anchildress1/nine-months-of-nagging-zero-reading-2fgc&quot; data-preload-image=&quot;https://media2.dev.to/dynamic/image/width=1000,height=420,fit=cover,gravity=auto,format=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fbxzjsa13cn5lhijx7myx.png&quot; id=&quot;article-link-4248045&quot;&gt;
          Nine Months of Nagging, Zero Reading
        &lt;/a&gt;
      &lt;/h2&gt;
        &lt;div class=&quot;crayons-story__tags&quot;&gt;
            &lt;a class=&quot;crayons-tag  crayons-tag--monochrome &quot; style=&quot;
        --tag-bg: rgba(23, 253, 26, 0.10);
        --tag-prefix: #17fd1a;
        --tag-bg-hover: rgba(23, 253, 26, 0.10);
        --tag-prefix-hover: #17fd1a;
      &quot; href=&quot;https://dev.to/t/ai&quot;&gt;&lt;span class=&quot;crayons-tag__prefix&quot;&gt;#&lt;/span&gt;ai&lt;/a&gt;
            &lt;a class=&quot;crayons-tag  crayons-tag--monochrome &quot; style=&quot;
        --tag-bg: rgba(245, 77, 39, 0.10);
        --tag-prefix: #F54D27;
        --tag-bg-hover: rgba(245, 77, 39, 0.10);
        --tag-prefix-hover: #F54D27;
      &quot; href=&quot;https://dev.to/t/git&quot;&gt;&lt;span class=&quot;crayons-tag__prefix&quot;&gt;#&lt;/span&gt;git&lt;/a&gt;
            &lt;a class=&quot;crayons-tag  crayons-tag--monochrome &quot; style=&quot;
        --tag-bg: rgba(0, 0, 0, 0.10);
        --tag-prefix: #000000;
        --tag-bg-hover: rgba(0, 0, 0, 0.10);
        --tag-prefix-hover: #000000;
      &quot; href=&quot;https://dev.to/t/githubactions&quot;&gt;&lt;span class=&quot;crayons-tag__prefix&quot;&gt;#&lt;/span&gt;githubactions&lt;/a&gt;
            &lt;a class=&quot;crayons-tag  crayons-tag--monochrome &quot; style=&quot;
        --tag-bg: rgba(59, 73, 223, 0.10);
        --tag-prefix: #3b49df;
        --tag-bg-hover: rgba(59, 73, 223, 0.10);
        --tag-prefix-hover: #3b49df;
      &quot; href=&quot;https://dev.to/t/automation&quot;&gt;&lt;span class=&quot;crayons-tag__prefix&quot;&gt;#&lt;/span&gt;automation&lt;/a&gt;
        &lt;/div&gt;
      &lt;div class=&quot;crayons-story__bottom&quot;&gt;
        &lt;div class=&quot;crayons-story__details&quot;&gt;
          &lt;a href=&quot;https://dev.to/anchildress1/nine-months-of-nagging-zero-reading-2fgc&quot; class=&quot;crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left&quot; data-reaction-count=&quot;&quot; data-reactable-id=&quot;4248045&quot; aria-label=&quot;Add a comment to post - Nine Months of Nagging, Zero Reading&quot;&gt;
            &lt;div class=&quot;multiple_reactions_aggregate&quot;&gt;
              &lt;span class=&quot;multiple_reactions_icons_container&quot; dir=&quot;rtl&quot;&gt;
                  &lt;span class=&quot;crayons_icon_container&quot;&gt;
                    &lt;img src=&quot;https://assets.dev.to/assets/fire-f60e7a582391810302117f987b22a8ef04a2fe0df7e3258a5f49332df1cec71e.svg&quot; width=&quot;18&quot; height=&quot;18&quot; referrerpolicy=&quot;no-referrer&quot;&gt;
                  &lt;/span&gt;
                  &lt;span class=&quot;crayons_icon_container&quot;&gt;
                    &lt;img src=&quot;https://assets.dev.to/assets/raised-hands-74b2099fd66a39f2d7eed9305ee0f4553df0eb7b4f11b01b6b1b499973048fe5.svg&quot; width=&quot;18&quot; height=&quot;18&quot; referrerpolicy=&quot;no-referrer&quot;&gt;
                  &lt;/span&gt;
                  &lt;span class=&quot;crayons_icon_container&quot;&gt;
                    &lt;img src=&quot;https://assets.dev.to/assets/sparkle-heart-5f9bee3767e18deb1bb725290cb151c25234768a0e9a2bd39370c382d02920cf.svg&quot; width=&quot;18&quot; height=&quot;18&quot; referrerpolicy=&quot;no-referrer&quot;&gt;
                  &lt;/span&gt;
              &lt;/span&gt;
              &lt;span class=&quot;aggregate_reactions_counter&quot;&gt;24&lt;span class=&quot;hidden s:inline&quot;&gt;&amp;nbsp;reactions&lt;/span&gt;&lt;/span&gt;
            &lt;/div&gt;
          &lt;/a&gt;
            &lt;a href=&quot;https://dev.to/anchildress1/nine-months-of-nagging-zero-reading-2fgc#comments&quot; class=&quot;crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left flex items-center&quot; aria-label=&quot;Add a comment to post - Nine Months of Nagging, Zero Reading&quot;&gt;
              &lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; width=&quot;24&quot; height=&quot;24&quot; role=&quot;img&quot; aria-labelledby=&quot;ao1xlp9sptupcqnvsqi244x6sfozq0lo&quot; class=&quot;crayons-icon&quot;&gt;&lt;title id=&quot;ao1xlp9sptupcqnvsqi244x6sfozq0lo&quot;&gt;Comments&lt;/title&gt;
&lt;path d=&quot;M10.5 5h3a6 6 0 110 12v2.625c-3.75-1.5-9-3.75-9-8.625a6 6 0 016-6zM12 15.5h1.5a4.501 4.501 0 001.722-8.657A4.5 4.5 0 0013.5 6.5h-3A4.5 4.5 0 006 11c0 2.707 1.846 4.475 6 6.36V15.5z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;

              7&lt;span class=&quot;hidden s:inline&quot;&gt;&amp;nbsp;comments&lt;/span&gt;
            &lt;/a&gt;
        &lt;/div&gt;
        &lt;div class=&quot;crayons-story__save&quot;&gt;
          &lt;small class=&quot;crayons-story__tertiary fs-xs mr-2&quot;&gt;
            7 min read
          &lt;/small&gt;
            &lt;button type=&quot;button&quot; id=&quot;article-save-button-4248045&quot; class=&quot;c-btn c-btn--icon-alone bookmark-button&quot; data-reactable-id=&quot;4248045&quot; data-article-author-id=&quot;3224358&quot; aria-label=&quot;Save post Nine Months of Nagging, Zero Reading to reading list&quot; title=&quot;Save post Nine Months of Nagging, Zero Reading to reading list&quot;&gt;
              &lt;span class=&quot;bm-initial crayons-icon c-btn__icon&quot;&gt;
                &lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; width=&quot;24&quot; height=&quot;24&quot; aria-hidden=&quot;true&quot;&gt;&lt;path d=&quot;M6.75 4.5h10.5a.75.75 0 01.75.75v14.357a.375.375 0 01-.575.318L12 16.523l-5.426 3.401A.375.375 0 016 19.607V5.25a.75.75 0 01.75-.75zM16.5 6h-9v11.574l4.5-2.82 4.5 2.82V6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;

              &lt;/span&gt;
              &lt;span class=&quot;bm-success crayons-icon c-btn__icon&quot;&gt;
                &lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; width=&quot;24&quot; height=&quot;24&quot; aria-hidden=&quot;true&quot;&gt;&lt;path d=&quot;M6.75 4.5h10.5a.75.75 0 01.75.75v14.357a.375.375 0 01-.575.318L12 16.523l-5.426 3.401A.375.375 0 016 19.607V5.25a.75.75 0 01.75-.75z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;

              &lt;/span&gt;
            &lt;/button&gt;
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;/div&gt;


&lt;p&gt;&lt;a class=&quot;mentioned-user&quot; href=&quot;https://dev.to/anchildress1&quot;&gt;@anchildress1&lt;/a&gt; spent nine months enforcing commit footers that record how much of each commit AI actually wrote, then never once read the data back. The post covers the GitHub Action built to finally score that history, the weight assigned to each footer type, and the gaps the number still leaves open.&lt;/p&gt;


&lt;hr&gt;


&lt;div class=&quot;ltag__link--embedded&quot;&gt;
  &lt;div class=&quot;crayons-story &quot; data-feed-content-id=&quot;4215779&quot; data-content-user-id=&quot;14347&quot;&gt;
  &lt;a href=&quot;https://dev.to/temporalio/i-had-two-weeks-an-8-foot-keyboard-and-a-wordle-workflow-15h&quot; aria-labelledby=&quot;article-link-4215779&quot; class=&quot;crayons-story__hidden-navigation-link&quot;&gt;I had two weeks, an 8-foot keyboard, and a Wordle Workflow&lt;/a&gt;


  &lt;div class=&quot;crayons-story__body crayons-story__body-full_post&quot;&gt;
    &lt;div class=&quot;crayons-story__top&quot;&gt;
      &lt;div class=&quot;crayons-story__meta&quot;&gt;
        &lt;div class=&quot;crayons-story__author-pic&quot;&gt;
          &lt;a class=&quot;crayons-logo crayons-logo--l&quot; href=&quot;https://dev.to/temporalio&quot;&gt;
            &lt;img alt=&quot;Temporal logo&quot; src=&quot;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%2Forganization%2Fprofile_image%2F3146%2F0ad3097f-4bc5-469a-9263-de293ef2ab2e.png&quot; class=&quot;crayons-logo__image&quot; loading=&quot;lazy&quot; referrerpolicy=&quot;no-referrer&quot;&gt;
          &lt;/a&gt;

          &lt;a href=&quot;https://dev.to/shy&quot; class=&quot;crayons-avatar  crayons-avatar--s absolute -right-2 -bottom-2 border-solid border-2 border-base-inverted  &quot;&gt;
            &lt;img src=&quot;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%2Fuser%2Fprofile_image%2F14347%2F5d245040-80e5-46dd-b210-ff3640bb9cbf.jpg&quot; alt=&quot;shy profile&quot; class=&quot;crayons-avatar__image&quot; loading=&quot;lazy&quot; referrerpolicy=&quot;no-referrer&quot;&gt;
          &lt;/a&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;div&gt;
            &lt;a href=&quot;https://dev.to/shy&quot; class=&quot;crayons-story__secondary fw-medium m:hidden&quot;&gt;
              Shy Ruparel
            &lt;/a&gt;
            &lt;div class=&quot;profile-preview-card relative mb-4 s:mb-0 fw-medium hidden m:inline-block&quot;&gt;
              &lt;button id=&quot;story-author-preview-trigger-4215779&quot; aria-controls=&quot;story-author-preview-content-4215779&quot; class=&quot;profile-preview-card__trigger fs-s p-1 -ml-1 -my-2 crayons-btn crayons-btn--ghost&quot; aria-label=&quot;Shy Ruparel profile details&quot;&gt;
                Shy Ruparel
                
              &lt;/button&gt;
              &lt;div id=&quot;story-author-preview-content-4215779&quot; class=&quot;profile-preview-card__content crayons-dropdown branded-7 p-4 pt-0&quot; style=&quot;border-top-color: var(--card-color);&quot; data-repositioning-dropdown=&quot;true&quot; data-testid=&quot;profile-preview-card&quot;&gt;
                &lt;div class=&quot;gap-4 grid&quot;&gt;
                  &lt;div class=&quot;-mt-4&quot;&gt;
                    &lt;a href=&quot;https://dev.to/shy&quot; class=&quot;flex&quot;&gt;
                      &lt;span class=&quot;crayons-avatar crayons-avatar--xl mr-2 shrink-0&quot;&gt;
                        &lt;img src=&quot;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%2Fuser%2Fprofile_image%2F14347%2F5d245040-80e5-46dd-b210-ff3640bb9cbf.jpg&quot; class=&quot;crayons-avatar__image&quot; alt=&quot;&quot; loading=&quot;lazy&quot; referrerpolicy=&quot;no-referrer&quot;&gt;
                      &lt;/span&gt;
                      &lt;span class=&quot;crayons-link crayons-subtitle-2 mt-5&quot;&gt;Shy Ruparel&lt;/span&gt;
                    &lt;/a&gt;
                  &lt;/div&gt;
                  &lt;div class=&quot;print-hidden&quot;&gt;
                    &lt;button class=&quot;crayons-btn follow-action-button whitespace-nowrap follow-user w-100&quot; data-info=&quot;{&amp;quot;style&amp;quot;:&amp;quot;full&amp;quot;,&amp;quot;id&amp;quot;:14347,&amp;quot;className&amp;quot;:&amp;quot;User&amp;quot;,&amp;quot;name&amp;quot;:&amp;quot;Shy Ruparel&amp;quot;}&quot;&gt;
                      Follow
                    &lt;/button&gt;
                  &lt;/div&gt;
                  &lt;div class=&quot;author-preview-metadata-container&quot; data-author-id=&quot;14347&quot;&gt;&lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
            &lt;/div&gt;

            &lt;span&gt;
              &lt;span class=&quot;crayons-story__tertiary fw-normal&quot;&gt; for &lt;/span&gt;&lt;a href=&quot;https://dev.to/temporalio&quot; class=&quot;crayons-story__secondary fw-medium&quot;&gt;Temporal&lt;/a&gt;
            &lt;/span&gt;
          &lt;/div&gt;
          &lt;a href=&quot;https://dev.to/temporalio/i-had-two-weeks-an-8-foot-keyboard-and-a-wordle-workflow-15h&quot; class=&quot;crayons-story__tertiary fs-xs&quot;&gt;&lt;time datetime=&quot;2026-07-28T14:00:00Z&quot;&gt;Jul 28&lt;/time&gt;&lt;span class=&quot;time-ago-indicator-initial-placeholder&quot; data-seconds=&quot;1785247200&quot;&gt;&lt;/span&gt;&lt;/a&gt;
        &lt;/div&gt;
      &lt;/div&gt;

    &lt;/div&gt;

    &lt;div class=&quot;crayons-story__indention&quot;&gt;
      &lt;h2 class=&quot;crayons-story__title crayons-story__title-full_post&quot;&gt;
        &lt;a href=&quot;https://dev.to/temporalio/i-had-two-weeks-an-8-foot-keyboard-and-a-wordle-workflow-15h&quot; data-preload-image=&quot;https://media2.dev.to/dynamic/image/width=1000,height=420,fit=cover,gravity=auto,format=auto/https%3A%2F%2Fimages.ctfassets.net%2F0uuz8ydxyd9p%2F77EA3CO7pz5bMyIqBx5cT8%2F75fafc7b99bd9a4212ca261a20b302b8%2FPXL_20260629_225400155.jpg&quot; id=&quot;article-link-4215779&quot;&gt;
          I had two weeks, an 8-foot keyboard, and a Wordle Workflow
        &lt;/a&gt;
      &lt;/h2&gt;
        &lt;div class=&quot;crayons-story__tags&quot;&gt;
            &lt;a class=&quot;crayons-tag  crayons-tag--monochrome &quot; style=&quot;
        --tag-bg: rgba(59, 73, 223, 0.10);
        --tag-prefix: #3b49df;
        --tag-bg-hover: rgba(59, 73, 223, 0.10);
        --tag-prefix-hover: #3b49df;
      &quot; href=&quot;https://dev.to/t/temporal&quot;&gt;&lt;span class=&quot;crayons-tag__prefix&quot;&gt;#&lt;/span&gt;temporal&lt;/a&gt;
            &lt;a class=&quot;crayons-tag  crayons-tag--monochrome &quot; style=&quot;
        --tag-bg: rgba(59, 73, 223, 0.10);
        --tag-prefix: #3b49df;
        --tag-bg-hover: rgba(59, 73, 223, 0.10);
        --tag-prefix-hover: #3b49df;
      &quot; href=&quot;https://dev.to/t/codesamples&quot;&gt;&lt;span class=&quot;crayons-tag__prefix&quot;&gt;#&lt;/span&gt;codesamples&lt;/a&gt;
            &lt;a class=&quot;crayons-tag  crayons-tag--monochrome &quot; style=&quot;
        --tag-bg: rgba(59, 73, 223, 0.10);
        --tag-prefix: #3b49df;
        --tag-bg-hover: rgba(59, 73, 223, 0.10);
        --tag-prefix-hover: #3b49df;
      &quot; href=&quot;https://dev.to/t/industryevents&quot;&gt;&lt;span class=&quot;crayons-tag__prefix&quot;&gt;#&lt;/span&gt;industryevents&lt;/a&gt;
            &lt;a class=&quot;crayons-tag  crayons-tag--monochrome &quot; style=&quot;
        --tag-bg: rgba(59, 73, 223, 0.10);
        --tag-prefix: #3b49df;
        --tag-bg-hover: rgba(59, 73, 223, 0.10);
        --tag-prefix-hover: #3b49df;
      &quot; href=&quot;https://dev.to/t/durableexecution&quot;&gt;&lt;span class=&quot;crayons-tag__prefix&quot;&gt;#&lt;/span&gt;durableexecution&lt;/a&gt;
        &lt;/div&gt;
      &lt;div class=&quot;crayons-story__bottom&quot;&gt;
        &lt;div class=&quot;crayons-story__details&quot;&gt;
          &lt;a href=&quot;https://dev.to/temporalio/i-had-two-weeks-an-8-foot-keyboard-and-a-wordle-workflow-15h&quot; class=&quot;crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left&quot; data-reaction-count=&quot;&quot; data-reactable-id=&quot;4215779&quot; aria-label=&quot;Add a comment to post - I had two weeks, an 8-foot keyboard, and a Wordle Workflow&quot;&gt;
            &lt;div class=&quot;multiple_reactions_aggregate&quot;&gt;
              &lt;span class=&quot;multiple_reactions_icons_container&quot; dir=&quot;rtl&quot;&gt;
                  &lt;span class=&quot;crayons_icon_container&quot;&gt;
                    &lt;img src=&quot;https://assets.dev.to/assets/exploding-head-daceb38d627e6ae9b730f36a1e390fca556a4289d5a41abb2c35068ad3e2c4b5.svg&quot; width=&quot;18&quot; height=&quot;18&quot; referrerpolicy=&quot;no-referrer&quot;&gt;
                  &lt;/span&gt;
                  &lt;span class=&quot;crayons_icon_container&quot;&gt;
                    &lt;img src=&quot;https://assets.dev.to/assets/multi-unicorn-b44d6f8c23cdd00964192bedc38af3e82463978aa611b4365bd33a0f1f4f3e97.svg&quot; width=&quot;18&quot; height=&quot;18&quot; referrerpolicy=&quot;no-referrer&quot;&gt;
                  &lt;/span&gt;
                  &lt;span class=&quot;crayons_icon_container&quot;&gt;
                    &lt;img src=&quot;https://assets.dev.to/assets/sparkle-heart-5f9bee3767e18deb1bb725290cb151c25234768a0e9a2bd39370c382d02920cf.svg&quot; width=&quot;18&quot; height=&quot;18&quot; referrerpolicy=&quot;no-referrer&quot;&gt;
                  &lt;/span&gt;
              &lt;/span&gt;
              &lt;span class=&quot;aggregate_reactions_counter&quot;&gt;14&lt;span class=&quot;hidden s:inline&quot;&gt;&amp;nbsp;reactions&lt;/span&gt;&lt;/span&gt;
            &lt;/div&gt;
          &lt;/a&gt;
            &lt;a href=&quot;https://dev.to/temporalio/i-had-two-weeks-an-8-foot-keyboard-and-a-wordle-workflow-15h#comments&quot; class=&quot;crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left flex items-center&quot; aria-label=&quot;Add a comment to post - I had two weeks, an 8-foot keyboard, and a Wordle Workflow&quot;&gt;
              &lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; width=&quot;24&quot; height=&quot;24&quot; role=&quot;img&quot; aria-labelledby=&quot;aqazk8bg11q4vcr253vhticcuqjemrkd&quot; class=&quot;crayons-icon&quot;&gt;&lt;title id=&quot;aqazk8bg11q4vcr253vhticcuqjemrkd&quot;&gt;Comments&lt;/title&gt;
&lt;path d=&quot;M10.5 5h3a6 6 0 110 12v2.625c-3.75-1.5-9-3.75-9-8.625a6 6 0 016-6zM12 15.5h1.5a4.501 4.501 0 001.722-8.657A4.5 4.5 0 0013.5 6.5h-3A4.5 4.5 0 006 11c0 2.707 1.846 4.475 6 6.36V15.5z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;

              6&lt;span class=&quot;hidden s:inline&quot;&gt;&amp;nbsp;comments&lt;/span&gt;
            &lt;/a&gt;
        &lt;/div&gt;
        &lt;div class=&quot;crayons-story__save&quot;&gt;
          &lt;small class=&quot;crayons-story__tertiary fs-xs mr-2&quot;&gt;
            10 min read
          &lt;/small&gt;
            &lt;button type=&quot;button&quot; id=&quot;article-save-button-4215779&quot; class=&quot;c-btn c-btn--icon-alone bookmark-button&quot; data-reactable-id=&quot;4215779&quot; data-article-author-id=&quot;14347&quot; aria-label=&quot;Save post I had two weeks, an 8-foot keyboard, and a Wordle Workflow to reading list&quot; title=&quot;Save post I had two weeks, an 8-foot keyboard, and a Wordle Workflow to reading list&quot;&gt;
              &lt;span class=&quot;bm-initial crayons-icon c-btn__icon&quot;&gt;
                &lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; width=&quot;24&quot; height=&quot;24&quot; aria-hidden=&quot;true&quot;&gt;&lt;path d=&quot;M6.75 4.5h10.5a.75.75 0 01.75.75v14.357a.375.375 0 01-.575.318L12 16.523l-5.426 3.401A.375.375 0 016 19.607V5.25a.75.75 0 01.75-.75zM16.5 6h-9v11.574l4.5-2.82 4.5 2.82V6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;

              &lt;/span&gt;
              &lt;span class=&quot;bm-success crayons-icon c-btn__icon&quot;&gt;
                &lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; width=&quot;24&quot; height=&quot;24&quot; aria-hidden=&quot;true&quot;&gt;&lt;path d=&quot;M6.75 4.5h10.5a.75.75 0 01.75.75v14.357a.375.375 0 01-.575.318L12 16.523l-5.426 3.401A.375.375 0 016 19.607V5.25a.75.75 0 01.75-.75z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;

              &lt;/span&gt;
            &lt;/button&gt;
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;/div&gt;


&lt;p&gt;&lt;a class=&quot;mentioned-user&quot; href=&quot;https://dev.to/shy&quot;&gt;@shy&lt;/a&gt; recounts the two weeks spent turning a pallet-sized 8-foot USB-C keyboard and a pair of holographic fans into a working conference demo built around a Wordle clone. The post argues for modeling the durable part of a system first, which is what made it safe to keep patching everything else live for four days.&lt;/p&gt;


&lt;hr&gt;


&lt;div class=&quot;ltag__link--embedded&quot;&gt;
  &lt;div class=&quot;crayons-story &quot; data-feed-content-id=&quot;4236815&quot; data-content-user-id=&quot;1002302&quot;&gt;
  &lt;a href=&quot;https://dev.to/lovestaco/how-terminal-sharing-tools-put-your-shell-in-a-browser-328&quot; aria-labelledby=&quot;article-link-4236815&quot; class=&quot;crayons-story__hidden-navigation-link&quot;&gt;How terminal-sharing tools put your shell in a browser&lt;/a&gt;


  &lt;div class=&quot;crayons-story__body crayons-story__body-full_post&quot;&gt;
    &lt;div class=&quot;crayons-story__top&quot;&gt;
      &lt;div class=&quot;crayons-story__meta&quot;&gt;
        &lt;div class=&quot;crayons-story__author-pic&quot;&gt;

          &lt;a href=&quot;https://dev.to/lovestaco&quot; class=&quot;crayons-avatar  crayons-avatar--l  &quot;&gt;
            &lt;img src=&quot;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%2Fuser%2Fprofile_image%2F1002302%2F9dbe5057-f6da-4c08-9b5d-37fe9d281476.png&quot; alt=&quot;lovestaco profile&quot; class=&quot;crayons-avatar__image&quot; loading=&quot;lazy&quot; referrerpolicy=&quot;no-referrer&quot;&gt;
          &lt;/a&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;div&gt;
            &lt;a href=&quot;https://dev.to/lovestaco&quot; class=&quot;crayons-story__secondary fw-medium m:hidden&quot;&gt;
              Athreya aka Maneshwar
            &lt;/a&gt;
            &lt;div class=&quot;profile-preview-card relative mb-4 s:mb-0 fw-medium hidden m:inline-block&quot;&gt;
              &lt;button id=&quot;story-author-preview-trigger-4236815&quot; aria-controls=&quot;story-author-preview-content-4236815&quot; class=&quot;profile-preview-card__trigger fs-s p-1 -ml-1 -my-2 crayons-btn crayons-btn--ghost&quot; aria-label=&quot;Athreya aka Maneshwar profile details&quot;&gt;
                Athreya aka Maneshwar
                
              &lt;/button&gt;
              &lt;div id=&quot;story-author-preview-content-4236815&quot; class=&quot;profile-preview-card__content crayons-dropdown branded-7 p-4 pt-0&quot; style=&quot;border-top-color: var(--card-color);&quot; data-repositioning-dropdown=&quot;true&quot; data-testid=&quot;profile-preview-card&quot;&gt;
                &lt;div class=&quot;gap-4 grid&quot;&gt;
                  &lt;div class=&quot;-mt-4&quot;&gt;
                    &lt;a href=&quot;https://dev.to/lovestaco&quot; class=&quot;flex&quot;&gt;
                      &lt;span class=&quot;crayons-avatar crayons-avatar--xl mr-2 shrink-0&quot;&gt;
                        &lt;img src=&quot;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%2Fuser%2Fprofile_image%2F1002302%2F9dbe5057-f6da-4c08-9b5d-37fe9d281476.png&quot; class=&quot;crayons-avatar__image&quot; alt=&quot;&quot; loading=&quot;lazy&quot; referrerpolicy=&quot;no-referrer&quot;&gt;
                      &lt;/span&gt;
                      &lt;span class=&quot;crayons-link crayons-subtitle-2 mt-5&quot;&gt;Athreya aka Maneshwar&lt;/span&gt;
                    &lt;/a&gt;
                  &lt;/div&gt;
                  &lt;div class=&quot;print-hidden&quot;&gt;
                    &lt;button class=&quot;crayons-btn follow-action-button whitespace-nowrap follow-user w-100&quot; data-info=&quot;{&amp;quot;style&amp;quot;:&amp;quot;full&amp;quot;,&amp;quot;id&amp;quot;:1002302,&amp;quot;className&amp;quot;:&amp;quot;User&amp;quot;,&amp;quot;name&amp;quot;:&amp;quot;Athreya aka Maneshwar&amp;quot;}&quot;&gt;
                      Follow
                    &lt;/button&gt;
                  &lt;/div&gt;
                  &lt;div class=&quot;author-preview-metadata-container&quot; data-author-id=&quot;1002302&quot;&gt;&lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
            &lt;/div&gt;

          &lt;/div&gt;
          &lt;a href=&quot;https://dev.to/lovestaco/how-terminal-sharing-tools-put-your-shell-in-a-browser-328&quot; class=&quot;crayons-story__tertiary fs-xs&quot;&gt;&lt;time datetime=&quot;2026-07-26T16:43:17Z&quot;&gt;Jul 26&lt;/time&gt;&lt;span class=&quot;time-ago-indicator-initial-placeholder&quot; data-seconds=&quot;1785084197&quot;&gt;&lt;/span&gt;&lt;/a&gt;
        &lt;/div&gt;
      &lt;/div&gt;

    &lt;/div&gt;

    &lt;div class=&quot;crayons-story__indention&quot;&gt;
      &lt;h2 class=&quot;crayons-story__title crayons-story__title-full_post&quot;&gt;
        &lt;a href=&quot;https://dev.to/lovestaco/how-terminal-sharing-tools-put-your-shell-in-a-browser-328&quot; data-preload-image=&quot;https://media2.dev.to/dynamic/image/width=1000,height=420,fit=cover,gravity=auto,format=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fycowu2xt3i11rfbe9qfz.png&quot; id=&quot;article-link-4236815&quot;&gt;
          How terminal-sharing tools put your shell in a browser
        &lt;/a&gt;
      &lt;/h2&gt;
        &lt;div class=&quot;crayons-story__tags&quot;&gt;
            &lt;a class=&quot;crayons-tag  crayons-tag--monochrome &quot; style=&quot;
        --tag-bg: rgba(86, 39, 101, 0.10);
        --tag-prefix: #562765;
        --tag-bg-hover: rgba(86, 39, 101, 0.10);
        --tag-prefix-hover: #562765;
      &quot; href=&quot;https://dev.to/t/webdev&quot;&gt;&lt;span class=&quot;crayons-tag__prefix&quot;&gt;#&lt;/span&gt;webdev&lt;/a&gt;
            &lt;a class=&quot;crayons-tag  crayons-tag--monochrome &quot; style=&quot;
        --tag-bg: rgba(137, 6, 6, 0.10);
        --tag-prefix: #890606;
        --tag-bg-hover: rgba(137, 6, 6, 0.10);
        --tag-prefix-hover: #890606;
      &quot; href=&quot;https://dev.to/t/programming&quot;&gt;&lt;span class=&quot;crayons-tag__prefix&quot;&gt;#&lt;/span&gt;programming&lt;/a&gt;
            &lt;a class=&quot;crayons-tag  crayons-tag--monochrome &quot; style=&quot;
        --tag-bg: rgba(42, 7, 152, 0.10);
        --tag-prefix: #2A0798;
        --tag-bg-hover: rgba(42, 7, 152, 0.10);
        --tag-prefix-hover: #2A0798;
      &quot; href=&quot;https://dev.to/t/productivity&quot;&gt;&lt;span class=&quot;crayons-tag__prefix&quot;&gt;#&lt;/span&gt;productivity&lt;/a&gt;
            &lt;a class=&quot;crayons-tag  crayons-tag--monochrome &quot; style=&quot;
        --tag-bg: rgba(0, 0, 0, 0.10);
        --tag-prefix: #000000;
        --tag-bg-hover: rgba(0, 0, 0, 0.10);
        --tag-prefix-hover: #000000;
      &quot; href=&quot;https://dev.to/t/cli&quot;&gt;&lt;span class=&quot;crayons-tag__prefix&quot;&gt;#&lt;/span&gt;cli&lt;/a&gt;
        &lt;/div&gt;
      &lt;div class=&quot;crayons-story__bottom&quot;&gt;
        &lt;div class=&quot;crayons-story__details&quot;&gt;
          &lt;a href=&quot;https://dev.to/lovestaco/how-terminal-sharing-tools-put-your-shell-in-a-browser-328&quot; class=&quot;crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left&quot; data-reaction-count=&quot;&quot; data-reactable-id=&quot;4236815&quot; aria-label=&quot;Add a comment to post - How terminal-sharing tools put your shell in a browser&quot;&gt;
            &lt;div class=&quot;multiple_reactions_aggregate&quot;&gt;
              &lt;span class=&quot;multiple_reactions_icons_container&quot; dir=&quot;rtl&quot;&gt;
                  &lt;span class=&quot;crayons_icon_container&quot;&gt;
                    &lt;img src=&quot;https://assets.dev.to/assets/raised-hands-74b2099fd66a39f2d7eed9305ee0f4553df0eb7b4f11b01b6b1b499973048fe5.svg&quot; width=&quot;18&quot; height=&quot;18&quot; referrerpolicy=&quot;no-referrer&quot;&gt;
                  &lt;/span&gt;
                  &lt;span class=&quot;crayons_icon_container&quot;&gt;
                    &lt;img src=&quot;https://assets.dev.to/assets/multi-unicorn-b44d6f8c23cdd00964192bedc38af3e82463978aa611b4365bd33a0f1f4f3e97.svg&quot; width=&quot;18&quot; height=&quot;18&quot; referrerpolicy=&quot;no-referrer&quot;&gt;
                  &lt;/span&gt;
                  &lt;span class=&quot;crayons_icon_container&quot;&gt;
                    &lt;img src=&quot;https://assets.dev.to/assets/sparkle-heart-5f9bee3767e18deb1bb725290cb151c25234768a0e9a2bd39370c382d02920cf.svg&quot; width=&quot;18&quot; height=&quot;18&quot; referrerpolicy=&quot;no-referrer&quot;&gt;
                  &lt;/span&gt;
              &lt;/span&gt;
              &lt;span class=&quot;aggregate_reactions_counter&quot;&gt;65&lt;span class=&quot;hidden s:inline&quot;&gt;&amp;nbsp;reactions&lt;/span&gt;&lt;/span&gt;
            &lt;/div&gt;
          &lt;/a&gt;
            &lt;a href=&quot;https://dev.to/lovestaco/how-terminal-sharing-tools-put-your-shell-in-a-browser-328#comments&quot; class=&quot;crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left flex items-center&quot; aria-label=&quot;Add a comment to post - How terminal-sharing tools put your shell in a browser&quot;&gt;
              &lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; width=&quot;24&quot; height=&quot;24&quot; role=&quot;img&quot; aria-labelledby=&quot;a3apa4h4sswgsq7sqzcqmqhbd4v7qez8&quot; class=&quot;crayons-icon&quot;&gt;&lt;title id=&quot;a3apa4h4sswgsq7sqzcqmqhbd4v7qez8&quot;&gt;Comments&lt;/title&gt;
&lt;path d=&quot;M10.5 5h3a6 6 0 110 12v2.625c-3.75-1.5-9-3.75-9-8.625a6 6 0 016-6zM12 15.5h1.5a4.501 4.501 0 001.722-8.657A4.5 4.5 0 0013.5 6.5h-3A4.5 4.5 0 006 11c0 2.707 1.846 4.475 6 6.36V15.5z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;

              7&lt;span class=&quot;hidden s:inline&quot;&gt;&amp;nbsp;comments&lt;/span&gt;
            &lt;/a&gt;
        &lt;/div&gt;
        &lt;div class=&quot;crayons-story__save&quot;&gt;
          &lt;small class=&quot;crayons-story__tertiary fs-xs mr-2&quot;&gt;
            9 min read
          &lt;/small&gt;
            &lt;button type=&quot;button&quot; id=&quot;article-save-button-4236815&quot; class=&quot;c-btn c-btn--icon-alone bookmark-button&quot; data-reactable-id=&quot;4236815&quot; data-article-author-id=&quot;1002302&quot; aria-label=&quot;Save post How terminal-sharing tools put your shell in a browser to reading list&quot; title=&quot;Save post How terminal-sharing tools put your shell in a browser to reading list&quot;&gt;
              &lt;span class=&quot;bm-initial crayons-icon c-btn__icon&quot;&gt;
                &lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; width=&quot;24&quot; height=&quot;24&quot; aria-hidden=&quot;true&quot;&gt;&lt;path d=&quot;M6.75 4.5h10.5a.75.75 0 01.75.75v14.357a.375.375 0 01-.575.318L12 16.523l-5.426 3.401A.375.375 0 016 19.607V5.25a.75.75 0 01.75-.75zM16.5 6h-9v11.574l4.5-2.82 4.5 2.82V6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;

              &lt;/span&gt;
              &lt;span class=&quot;bm-success crayons-icon c-btn__icon&quot;&gt;
                &lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; width=&quot;24&quot; height=&quot;24&quot; aria-hidden=&quot;true&quot;&gt;&lt;path d=&quot;M6.75 4.5h10.5a.75.75 0 01.75.75v14.357a.375.375 0 01-.575.318L12 16.523l-5.426 3.401A.375.375 0 016 19.607V5.25a.75.75 0 01.75-.75z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;

              &lt;/span&gt;
            &lt;/button&gt;
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;/div&gt;


&lt;p&gt;&lt;a class=&quot;mentioned-user&quot; href=&quot;https://dev.to/lovestaco&quot;&gt;@lovestaco&lt;/a&gt; cloned ttyd, TermPair, and sshx, then read all three to work out how they get a live shell into someone else&#39;s browser. The post traces each one from the pseudoterminal up through key delivery, encryption, and session recovery, and finds three very different answers to the same problem.&lt;/p&gt;


&lt;hr&gt;


&lt;div class=&quot;ltag__link--embedded&quot;&gt;
  &lt;div class=&quot;crayons-story &quot; data-feed-content-id=&quot;4247992&quot; data-content-user-id=&quot;18254&quot;&gt;
  &lt;a href=&quot;https://dev.to/thomasbnt/passkeys-explained-simply-52jk&quot; aria-labelledby=&quot;article-link-4247992&quot; class=&quot;crayons-story__hidden-navigation-link&quot;&gt;Passkeys Explained Simply&lt;/a&gt;


  &lt;div class=&quot;crayons-story__body crayons-story__body-full_post&quot;&gt;
      &lt;a href=&quot;https://dev.to/thomasbnt/passkeys-explained-simply-52jk&quot; class=&quot;crayons-article__context-note crayons-article__context-note__feed&quot;&gt;&lt;p&gt;Comments warn account recovery is the weak link&lt;/p&gt;

&lt;/a&gt;
    &lt;div class=&quot;crayons-story__top&quot;&gt;
      &lt;div class=&quot;crayons-story__meta&quot;&gt;
        &lt;div class=&quot;crayons-story__author-pic&quot;&gt;

          &lt;a href=&quot;https://dev.to/thomasbnt&quot; class=&quot;crayons-avatar  crayons-avatar--l  &quot;&gt;
            &lt;img src=&quot;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%2Fuser%2Fprofile_image%2F18254%2F58d30567-4c1f-4053-8e31-9dfa5af5783c.jpg&quot; alt=&quot;thomasbnt profile&quot; class=&quot;crayons-avatar__image&quot; loading=&quot;lazy&quot; referrerpolicy=&quot;no-referrer&quot;&gt;
          &lt;/a&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;div&gt;
            &lt;a href=&quot;https://dev.to/thomasbnt&quot; class=&quot;crayons-story__secondary fw-medium m:hidden&quot;&gt;
              Thomas Bnt
            &lt;/a&gt;
            &lt;div class=&quot;profile-preview-card relative mb-4 s:mb-0 fw-medium hidden m:inline-block&quot;&gt;
              &lt;button id=&quot;story-author-preview-trigger-4247992&quot; aria-controls=&quot;story-author-preview-content-4247992&quot; class=&quot;profile-preview-card__trigger fs-s p-1 -ml-1 -my-2 crayons-btn crayons-btn--ghost&quot; aria-label=&quot;Thomas Bnt profile details&quot;&gt;
                Thomas Bnt
                &lt;a style=&quot;display: inline;&quot; href=&quot;https://dev.to/++&quot;&gt;&lt;img alt=&quot;Subscriber&quot; class=&quot;subscription-icon&quot; src=&quot;https://assets.dev.to/assets/subscription-icon-805dfa7ac7dd660f07ed8d654877270825b07a92a03841aa99a1093bd00431b2.png&quot; referrerpolicy=&quot;no-referrer&quot;&gt;&lt;/a&gt;
              &lt;/button&gt;
              &lt;div id=&quot;story-author-preview-content-4247992&quot; class=&quot;profile-preview-card__content crayons-dropdown branded-7 p-4 pt-0&quot; style=&quot;border-top-color: var(--card-color);&quot; data-repositioning-dropdown=&quot;true&quot; data-testid=&quot;profile-preview-card&quot;&gt;
                &lt;div class=&quot;gap-4 grid&quot;&gt;
                  &lt;div class=&quot;-mt-4&quot;&gt;
                    &lt;a href=&quot;https://dev.to/thomasbnt&quot; class=&quot;flex&quot;&gt;
                      &lt;span class=&quot;crayons-avatar crayons-avatar--xl mr-2 shrink-0&quot;&gt;
                        &lt;img src=&quot;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%2Fuser%2Fprofile_image%2F18254%2F58d30567-4c1f-4053-8e31-9dfa5af5783c.jpg&quot; class=&quot;crayons-avatar__image&quot; alt=&quot;&quot; loading=&quot;lazy&quot; referrerpolicy=&quot;no-referrer&quot;&gt;
                      &lt;/span&gt;
                      &lt;span class=&quot;crayons-link crayons-subtitle-2 mt-5&quot;&gt;Thomas Bnt&lt;/span&gt;
                    &lt;/a&gt;
                  &lt;/div&gt;
                  &lt;div class=&quot;print-hidden&quot;&gt;
                    &lt;button class=&quot;crayons-btn follow-action-button whitespace-nowrap follow-user w-100&quot; data-info=&quot;{&amp;quot;style&amp;quot;:&amp;quot;full&amp;quot;,&amp;quot;id&amp;quot;:18254,&amp;quot;className&amp;quot;:&amp;quot;User&amp;quot;,&amp;quot;name&amp;quot;:&amp;quot;Thomas Bnt&amp;quot;}&quot;&gt;
                      Follow
                    &lt;/button&gt;
                  &lt;/div&gt;
                  &lt;div class=&quot;author-preview-metadata-container&quot; data-author-id=&quot;18254&quot;&gt;&lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
            &lt;/div&gt;

          &lt;/div&gt;
          &lt;a href=&quot;https://dev.to/thomasbnt/passkeys-explained-simply-52jk&quot; class=&quot;crayons-story__tertiary fs-xs&quot;&gt;&lt;time datetime=&quot;2026-07-27T21:09:04Z&quot;&gt;Jul 27&lt;/time&gt;&lt;span class=&quot;time-ago-indicator-initial-placeholder&quot; data-seconds=&quot;1785186544&quot;&gt;&lt;/span&gt;&lt;/a&gt;
        &lt;/div&gt;
      &lt;/div&gt;

    &lt;/div&gt;

    &lt;div class=&quot;crayons-story__indention&quot;&gt;
      &lt;h2 class=&quot;crayons-story__title crayons-story__title-full_post&quot;&gt;
        &lt;a href=&quot;https://dev.to/thomasbnt/passkeys-explained-simply-52jk&quot; data-preload-image=&quot;https://media2.dev.to/dynamic/image/width=1000,height=420,fit=cover,gravity=auto,format=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fbelk4tf8yj77u4d7772o.webp&quot; id=&quot;article-link-4247992&quot;&gt;
          Passkeys Explained Simply
        &lt;/a&gt;
      &lt;/h2&gt;
        &lt;div class=&quot;crayons-story__tags&quot;&gt;
            &lt;a class=&quot;crayons-tag crayons-tag--filled  &quot; style=&quot;
        --tag-bg: rgba(113, 234, 139, 0.10);
        --tag-prefix: #71EA8B;
        --tag-bg-hover: rgba(113, 234, 139, 0.10);
        --tag-prefix-hover: #71EA8B;
      &quot; href=&quot;https://dev.to/t/discuss&quot;&gt;&lt;span class=&quot;crayons-tag__prefix&quot;&gt;#&lt;/span&gt;discuss&lt;/a&gt;
            &lt;a class=&quot;crayons-tag  crayons-tag--monochrome &quot; style=&quot;
        --tag-bg: rgba(27, 172, 128, 0.10);
        --tag-prefix: #1bac80;
        --tag-bg-hover: rgba(27, 172, 128, 0.10);
        --tag-prefix-hover: #1bac80;
      &quot; href=&quot;https://dev.to/t/security&quot;&gt;&lt;span class=&quot;crayons-tag__prefix&quot;&gt;#&lt;/span&gt;security&lt;/a&gt;
            &lt;a class=&quot;crayons-tag  crayons-tag--monochrome &quot; style=&quot;
        --tag-bg: rgba(151, 37, 234, 0.10);
        --tag-prefix: #9725ea;
        --tag-bg-hover: rgba(151, 37, 234, 0.10);
        --tag-prefix-hover: #9725ea;
      &quot; href=&quot;https://dev.to/t/api&quot;&gt;&lt;span class=&quot;crayons-tag__prefix&quot;&gt;#&lt;/span&gt;api&lt;/a&gt;
            &lt;a class=&quot;crayons-tag  crayons-tag--monochrome &quot; style=&quot;
        --tag-bg: rgba(86, 39, 101, 0.10);
        --tag-prefix: #562765;
        --tag-bg-hover: rgba(86, 39, 101, 0.10);
        --tag-prefix-hover: #562765;
      &quot; href=&quot;https://dev.to/t/webdev&quot;&gt;&lt;span class=&quot;crayons-tag__prefix&quot;&gt;#&lt;/span&gt;webdev&lt;/a&gt;
        &lt;/div&gt;
      &lt;div class=&quot;crayons-story__bottom&quot;&gt;
        &lt;div class=&quot;crayons-story__details&quot;&gt;
          &lt;a href=&quot;https://dev.to/thomasbnt/passkeys-explained-simply-52jk&quot; class=&quot;crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left&quot; data-reaction-count=&quot;&quot; data-reactable-id=&quot;4247992&quot; aria-label=&quot;Add a comment to post - Passkeys Explained Simply&quot;&gt;
            &lt;div class=&quot;multiple_reactions_aggregate&quot;&gt;
              &lt;span class=&quot;multiple_reactions_icons_container&quot; dir=&quot;rtl&quot;&gt;
                  &lt;span class=&quot;crayons_icon_container&quot;&gt;
                    &lt;img src=&quot;https://assets.dev.to/assets/fire-f60e7a582391810302117f987b22a8ef04a2fe0df7e3258a5f49332df1cec71e.svg&quot; width=&quot;18&quot; height=&quot;18&quot; referrerpolicy=&quot;no-referrer&quot;&gt;
                  &lt;/span&gt;
                  &lt;span class=&quot;crayons_icon_container&quot;&gt;
                    &lt;img src=&quot;https://assets.dev.to/assets/raised-hands-74b2099fd66a39f2d7eed9305ee0f4553df0eb7b4f11b01b6b1b499973048fe5.svg&quot; width=&quot;18&quot; height=&quot;18&quot; referrerpolicy=&quot;no-referrer&quot;&gt;
                  &lt;/span&gt;
                  &lt;span class=&quot;crayons_icon_container&quot;&gt;
                    &lt;img src=&quot;https://assets.dev.to/assets/sparkle-heart-5f9bee3767e18deb1bb725290cb151c25234768a0e9a2bd39370c382d02920cf.svg&quot; width=&quot;18&quot; height=&quot;18&quot; referrerpolicy=&quot;no-referrer&quot;&gt;
                  &lt;/span&gt;
              &lt;/span&gt;
              &lt;span class=&quot;aggregate_reactions_counter&quot;&gt;108&lt;span class=&quot;hidden s:inline&quot;&gt;&amp;nbsp;reactions&lt;/span&gt;&lt;/span&gt;
            &lt;/div&gt;
          &lt;/a&gt;
            &lt;a href=&quot;https://dev.to/thomasbnt/passkeys-explained-simply-52jk#comments&quot; class=&quot;crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left flex items-center&quot; aria-label=&quot;Add a comment to post - Passkeys Explained Simply&quot;&gt;
              &lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; width=&quot;24&quot; height=&quot;24&quot; role=&quot;img&quot; aria-labelledby=&quot;a2keliub28jokxml9ktiqwcziipxacmx&quot; class=&quot;crayons-icon&quot;&gt;&lt;title id=&quot;a2keliub28jokxml9ktiqwcziipxacmx&quot;&gt;Comments&lt;/title&gt;
&lt;path d=&quot;M10.5 5h3a6 6 0 110 12v2.625c-3.75-1.5-9-3.75-9-8.625a6 6 0 016-6zM12 15.5h1.5a4.501 4.501 0 001.722-8.657A4.5 4.5 0 0013.5 6.5h-3A4.5 4.5 0 006 11c0 2.707 1.846 4.475 6 6.36V15.5z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;

              32&lt;span class=&quot;hidden s:inline&quot;&gt;&amp;nbsp;comments&lt;/span&gt;
            &lt;/a&gt;
        &lt;/div&gt;
        &lt;div class=&quot;crayons-story__save&quot;&gt;
          &lt;small class=&quot;crayons-story__tertiary fs-xs mr-2&quot;&gt;
            6 min read
          &lt;/small&gt;
            &lt;button type=&quot;button&quot; id=&quot;article-save-button-4247992&quot; class=&quot;c-btn c-btn--icon-alone bookmark-button&quot; data-reactable-id=&quot;4247992&quot; data-article-author-id=&quot;18254&quot; aria-label=&quot;Save post Passkeys Explained Simply to reading list&quot; title=&quot;Save post Passkeys Explained Simply to reading list&quot;&gt;
              &lt;span class=&quot;bm-initial crayons-icon c-btn__icon&quot;&gt;
                &lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; width=&quot;24&quot; height=&quot;24&quot; aria-hidden=&quot;true&quot;&gt;&lt;path d=&quot;M6.75 4.5h10.5a.75.75 0 01.75.75v14.357a.375.375 0 01-.575.318L12 16.523l-5.426 3.401A.375.375 0 016 19.607V5.25a.75.75 0 01.75-.75zM16.5 6h-9v11.574l4.5-2.82 4.5 2.82V6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;

              &lt;/span&gt;
              &lt;span class=&quot;bm-success crayons-icon c-btn__icon&quot;&gt;
                &lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; width=&quot;24&quot; height=&quot;24&quot; aria-hidden=&quot;true&quot;&gt;&lt;path d=&quot;M6.75 4.5h10.5a.75.75 0 01.75.75v14.357a.375.375 0 01-.575.318L12 16.523l-5.426 3.401A.375.375 0 016 19.607V5.25a.75.75 0 01.75-.75z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;

              &lt;/span&gt;
            &lt;/button&gt;
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;/div&gt;


&lt;p&gt;&lt;a class=&quot;mentioned-user&quot; href=&quot;https://dev.to/thomasbnt&quot;&gt;@thomasbnt&lt;/a&gt; breaks down what a passkey actually is, from the key pair your device generates to the domain binding that makes phishing so much harder to pull off. The post also tackles the question everyone asks first, which is what happens when the phone holding your keys disappears.&lt;/p&gt;


&lt;hr&gt;


&lt;div class=&quot;ltag__link--embedded&quot;&gt;
  &lt;div class=&quot;crayons-story &quot; data-feed-content-id=&quot;4256220&quot; data-content-user-id=&quot;885064&quot;&gt;
  &lt;a href=&quot;https://dev.to/varshithvhegde/i-built-a-chat-app-that-rewrites-its-own-ui-in-real-time-21m5&quot; aria-labelledby=&quot;article-link-4256220&quot; class=&quot;crayons-story__hidden-navigation-link&quot;&gt;I Built a Chat App That Rewrites Its Own UI in Real Time&lt;/a&gt;


  &lt;div class=&quot;crayons-story__body crayons-story__body-full_post&quot;&gt;
      &lt;a href=&quot;https://dev.to/varshithvhegde/i-built-a-chat-app-that-rewrites-its-own-ui-in-real-time-21m5&quot; class=&quot;crayons-article__context-note crayons-article__context-note__feed&quot;&gt;&lt;p&gt;Streams raw HTML to dynamically transform the DOM&lt;/p&gt;

&lt;/a&gt;
    &lt;div class=&quot;crayons-story__top&quot;&gt;
      &lt;div class=&quot;crayons-story__meta&quot;&gt;
        &lt;div class=&quot;crayons-story__author-pic&quot;&gt;

          &lt;a href=&quot;https://dev.to/varshithvhegde&quot; class=&quot;crayons-avatar  crayons-avatar--l  &quot;&gt;
            &lt;img src=&quot;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%2Fuser%2Fprofile_image%2F885064%2F4ab304f4-a3f3-409c-8217-9ce130e57c18.jpeg&quot; alt=&quot;varshithvhegde profile&quot; class=&quot;crayons-avatar__image&quot; loading=&quot;lazy&quot; referrerpolicy=&quot;no-referrer&quot;&gt;
          &lt;/a&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;div&gt;
            &lt;a href=&quot;https://dev.to/varshithvhegde&quot; class=&quot;crayons-story__secondary fw-medium m:hidden&quot;&gt;
              Varshith V Hegde
            &lt;/a&gt;
            &lt;div class=&quot;profile-preview-card relative mb-4 s:mb-0 fw-medium hidden m:inline-block&quot;&gt;
              &lt;button id=&quot;story-author-preview-trigger-4256220&quot; aria-controls=&quot;story-author-preview-content-4256220&quot; class=&quot;profile-preview-card__trigger fs-s p-1 -ml-1 -my-2 crayons-btn crayons-btn--ghost&quot; aria-label=&quot;Varshith V Hegde profile details&quot;&gt;
                Varshith V Hegde
                &lt;a style=&quot;display: inline;&quot; href=&quot;https://dev.to/++&quot;&gt;&lt;img alt=&quot;Subscriber&quot; class=&quot;subscription-icon&quot; src=&quot;https://assets.dev.to/assets/subscription-icon-805dfa7ac7dd660f07ed8d654877270825b07a92a03841aa99a1093bd00431b2.png&quot; referrerpolicy=&quot;no-referrer&quot;&gt;&lt;/a&gt;
              &lt;/button&gt;
              &lt;div id=&quot;story-author-preview-content-4256220&quot; class=&quot;profile-preview-card__content crayons-dropdown branded-7 p-4 pt-0&quot; style=&quot;border-top-color: var(--card-color);&quot; data-repositioning-dropdown=&quot;true&quot; data-testid=&quot;profile-preview-card&quot;&gt;
                &lt;div class=&quot;gap-4 grid&quot;&gt;
                  &lt;div class=&quot;-mt-4&quot;&gt;
                    &lt;a href=&quot;https://dev.to/varshithvhegde&quot; class=&quot;flex&quot;&gt;
                      &lt;span class=&quot;crayons-avatar crayons-avatar--xl mr-2 shrink-0&quot;&gt;
                        &lt;img src=&quot;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%2Fuser%2Fprofile_image%2F885064%2F4ab304f4-a3f3-409c-8217-9ce130e57c18.jpeg&quot; class=&quot;crayons-avatar__image&quot; alt=&quot;&quot; loading=&quot;lazy&quot; referrerpolicy=&quot;no-referrer&quot;&gt;
                      &lt;/span&gt;
                      &lt;span class=&quot;crayons-link crayons-subtitle-2 mt-5&quot;&gt;Varshith V Hegde&lt;/span&gt;
                    &lt;/a&gt;
                  &lt;/div&gt;
                  &lt;div class=&quot;print-hidden&quot;&gt;
                    &lt;button class=&quot;crayons-btn follow-action-button whitespace-nowrap follow-user w-100&quot; data-info=&quot;{&amp;quot;style&amp;quot;:&amp;quot;full&amp;quot;,&amp;quot;id&amp;quot;:885064,&amp;quot;className&amp;quot;:&amp;quot;User&amp;quot;,&amp;quot;name&amp;quot;:&amp;quot;Varshith V Hegde&amp;quot;}&quot;&gt;
                      Follow
                    &lt;/button&gt;
                  &lt;/div&gt;
                  &lt;div class=&quot;author-preview-metadata-container&quot; data-author-id=&quot;885064&quot;&gt;&lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
            &lt;/div&gt;

          &lt;/div&gt;
          &lt;a href=&quot;https://dev.to/varshithvhegde/i-built-a-chat-app-that-rewrites-its-own-ui-in-real-time-21m5&quot; class=&quot;crayons-story__tertiary fs-xs&quot;&gt;&lt;time datetime=&quot;2026-07-28T18:35:05Z&quot;&gt;Jul 28&lt;/time&gt;&lt;span class=&quot;time-ago-indicator-initial-placeholder&quot; data-seconds=&quot;1785263705&quot;&gt;&lt;/span&gt;&lt;/a&gt;
        &lt;/div&gt;
      &lt;/div&gt;

    &lt;/div&gt;

    &lt;div class=&quot;crayons-story__indention&quot;&gt;
      &lt;h2 class=&quot;crayons-story__title crayons-story__title-full_post&quot;&gt;
        &lt;a href=&quot;https://dev.to/varshithvhegde/i-built-a-chat-app-that-rewrites-its-own-ui-in-real-time-21m5&quot; data-preload-image=&quot;https://media2.dev.to/dynamic/image/width=1000,height=420,fit=cover,gravity=auto,format=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fv9amfydao61xyszazb3n.gif&quot; id=&quot;article-link-4256220&quot;&gt;
          I Built a Chat App That Rewrites Its Own UI in Real Time
        &lt;/a&gt;
      &lt;/h2&gt;
        &lt;div class=&quot;crayons-story__tags&quot;&gt;
            &lt;a class=&quot;crayons-tag  crayons-tag--monochrome &quot; style=&quot;
        --tag-bg: rgba(23, 253, 26, 0.10);
        --tag-prefix: #17fd1a;
        --tag-bg-hover: rgba(23, 253, 26, 0.10);
        --tag-prefix-hover: #17fd1a;
      &quot; href=&quot;https://dev.to/t/ai&quot;&gt;&lt;span class=&quot;crayons-tag__prefix&quot;&gt;#&lt;/span&gt;ai&lt;/a&gt;
            &lt;a class=&quot;crayons-tag  crayons-tag--monochrome &quot; style=&quot;
        --tag-bg: rgba(11, 226, 245, 0.10);
        --tag-prefix: #0be2f5;
        --tag-bg-hover: rgba(11, 226, 245, 0.10);
        --tag-prefix-hover: #0be2f5;
      &quot; href=&quot;https://dev.to/t/agents&quot;&gt;&lt;span class=&quot;crayons-tag__prefix&quot;&gt;#&lt;/span&gt;agents&lt;/a&gt;
            &lt;a class=&quot;crayons-tag  crayons-tag--monochrome &quot; style=&quot;
        --tag-bg: rgba(86, 39, 101, 0.10);
        --tag-prefix: #562765;
        --tag-bg-hover: rgba(86, 39, 101, 0.10);
        --tag-prefix-hover: #562765;
      &quot; href=&quot;https://dev.to/t/webdev&quot;&gt;&lt;span class=&quot;crayons-tag__prefix&quot;&gt;#&lt;/span&gt;webdev&lt;/a&gt;
            &lt;a class=&quot;crayons-tag  crayons-tag--monochrome &quot; style=&quot;
        --tag-bg: rgba(42, 7, 152, 0.10);
        --tag-prefix: #2A0798;
        --tag-bg-hover: rgba(42, 7, 152, 0.10);
        --tag-prefix-hover: #2A0798;
      &quot; href=&quot;https://dev.to/t/productivity&quot;&gt;&lt;span class=&quot;crayons-tag__prefix&quot;&gt;#&lt;/span&gt;productivity&lt;/a&gt;
        &lt;/div&gt;
      &lt;div class=&quot;crayons-story__bottom&quot;&gt;
        &lt;div class=&quot;crayons-story__details&quot;&gt;
          &lt;a href=&quot;https://dev.to/varshithvhegde/i-built-a-chat-app-that-rewrites-its-own-ui-in-real-time-21m5&quot; class=&quot;crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left&quot; data-reaction-count=&quot;&quot; data-reactable-id=&quot;4256220&quot; aria-label=&quot;Add a comment to post - I Built a Chat App That Rewrites Its Own UI in Real Time&quot;&gt;
            &lt;div class=&quot;multiple_reactions_aggregate&quot;&gt;
              &lt;span class=&quot;multiple_reactions_icons_container&quot; dir=&quot;rtl&quot;&gt;
                  &lt;span class=&quot;crayons_icon_container&quot;&gt;
                    &lt;img src=&quot;https://assets.dev.to/assets/fire-f60e7a582391810302117f987b22a8ef04a2fe0df7e3258a5f49332df1cec71e.svg&quot; width=&quot;18&quot; height=&quot;18&quot; referrerpolicy=&quot;no-referrer&quot;&gt;
                  &lt;/span&gt;
                  &lt;span class=&quot;crayons_icon_container&quot;&gt;
                    &lt;img src=&quot;https://assets.dev.to/assets/multi-unicorn-b44d6f8c23cdd00964192bedc38af3e82463978aa611b4365bd33a0f1f4f3e97.svg&quot; width=&quot;18&quot; height=&quot;18&quot; referrerpolicy=&quot;no-referrer&quot;&gt;
                  &lt;/span&gt;
                  &lt;span class=&quot;crayons_icon_container&quot;&gt;
                    &lt;img src=&quot;https://assets.dev.to/assets/sparkle-heart-5f9bee3767e18deb1bb725290cb151c25234768a0e9a2bd39370c382d02920cf.svg&quot; width=&quot;18&quot; height=&quot;18&quot; referrerpolicy=&quot;no-referrer&quot;&gt;
                  &lt;/span&gt;
              &lt;/span&gt;
              &lt;span class=&quot;aggregate_reactions_counter&quot;&gt;63&lt;span class=&quot;hidden s:inline&quot;&gt;&amp;nbsp;reactions&lt;/span&gt;&lt;/span&gt;
            &lt;/div&gt;
          &lt;/a&gt;
            &lt;a href=&quot;https://dev.to/varshithvhegde/i-built-a-chat-app-that-rewrites-its-own-ui-in-real-time-21m5#comments&quot; class=&quot;crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left flex items-center&quot; aria-label=&quot;Add a comment to post - I Built a Chat App That Rewrites Its Own UI in Real Time&quot;&gt;
              &lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; width=&quot;24&quot; height=&quot;24&quot; role=&quot;img&quot; aria-labelledby=&quot;aptcr8ovq5rarzatf45u5yczxcj6ecjp&quot; class=&quot;crayons-icon&quot;&gt;&lt;title id=&quot;aptcr8ovq5rarzatf45u5yczxcj6ecjp&quot;&gt;Comments&lt;/title&gt;
&lt;path d=&quot;M10.5 5h3a6 6 0 110 12v2.625c-3.75-1.5-9-3.75-9-8.625a6 6 0 016-6zM12 15.5h1.5a4.501 4.501 0 001.722-8.657A4.5 4.5 0 0013.5 6.5h-3A4.5 4.5 0 006 11c0 2.707 1.846 4.475 6 6.36V15.5z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;

              17&lt;span class=&quot;hidden s:inline&quot;&gt;&amp;nbsp;comments&lt;/span&gt;
            &lt;/a&gt;
        &lt;/div&gt;
        &lt;div class=&quot;crayons-story__save&quot;&gt;
          &lt;small class=&quot;crayons-story__tertiary fs-xs mr-2&quot;&gt;
            9 min read
          &lt;/small&gt;
            &lt;button type=&quot;button&quot; id=&quot;article-save-button-4256220&quot; class=&quot;c-btn c-btn--icon-alone bookmark-button&quot; data-reactable-id=&quot;4256220&quot; data-article-author-id=&quot;885064&quot; aria-label=&quot;Save post I Built a Chat App That Rewrites Its Own UI in Real Time to reading list&quot; title=&quot;Save post I Built a Chat App That Rewrites Its Own UI in Real Time to reading list&quot;&gt;
              &lt;span class=&quot;bm-initial crayons-icon c-btn__icon&quot;&gt;
                &lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; width=&quot;24&quot; height=&quot;24&quot; aria-hidden=&quot;true&quot;&gt;&lt;path d=&quot;M6.75 4.5h10.5a.75.75 0 01.75.75v14.357a.375.375 0 01-.575.318L12 16.523l-5.426 3.401A.375.375 0 016 19.607V5.25a.75.75 0 01.75-.75zM16.5 6h-9v11.574l4.5-2.82 4.5 2.82V6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;

              &lt;/span&gt;
              &lt;span class=&quot;bm-success crayons-icon c-btn__icon&quot;&gt;
                &lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; width=&quot;24&quot; height=&quot;24&quot; aria-hidden=&quot;true&quot;&gt;&lt;path d=&quot;M6.75 4.5h10.5a.75.75 0 01.75.75v14.357a.375.375 0 01-.575.318L12 16.523l-5.426 3.401A.375.375 0 016 19.607V5.25a.75.75 0 01.75-.75z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;

              &lt;/span&gt;
            &lt;/button&gt;
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;/div&gt;


&lt;p&gt;&lt;a class=&quot;mentioned-user&quot; href=&quot;https://dev.to/varshithvhegde&quot;&gt;@varshithvhegde&lt;/a&gt; built a chat app where the model replies with raw HTML instead of markdown, so a request for Tic Tac Toe returns a playable board and a request for a Barbie theme repaints the entire interface. The post covers the streaming protocol behind it and the bugs that took days to find, including one that stayed invisible until the second message arrived.&lt;/p&gt;


&lt;hr&gt;


&lt;div class=&quot;ltag__link--embedded&quot;&gt;
  &lt;div class=&quot;crayons-story &quot; data-feed-content-id=&quot;4280228&quot; data-content-user-id=&quot;286761&quot;&gt;
  &lt;a href=&quot;https://dev.to/rdiegoss/your-rag-copilot-cant-count-stop-letting-it-try-2ie3&quot; aria-labelledby=&quot;article-link-4280228&quot; class=&quot;crayons-story__hidden-navigation-link&quot;&gt;Your RAG copilot can&#39;t count — stop letting it try&lt;/a&gt;


  &lt;div class=&quot;crayons-story__body crayons-story__body-full_post&quot;&gt;
      &lt;a href=&quot;https://dev.to/rdiegoss/your-rag-copilot-cant-count-stop-letting-it-try-2ie3&quot; class=&quot;crayons-article__context-note crayons-article__context-note__feed&quot;&gt;&lt;p&gt;Highlights how retrieval limits ruin math&lt;/p&gt;

&lt;/a&gt;
    &lt;div class=&quot;crayons-story__top&quot;&gt;
      &lt;div class=&quot;crayons-story__meta&quot;&gt;
        &lt;div class=&quot;crayons-story__author-pic&quot;&gt;

          &lt;a href=&quot;https://dev.to/rdiegoss&quot; class=&quot;crayons-avatar  crayons-avatar--l  &quot;&gt;
            &lt;img src=&quot;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%2Fuser%2Fprofile_image%2F286761%2F5cc3b14e-ca66-4ff4-8fa8-9c82ec874054.jpeg&quot; alt=&quot;rdiegoss profile&quot; class=&quot;crayons-avatar__image&quot; loading=&quot;lazy&quot; referrerpolicy=&quot;no-referrer&quot;&gt;
          &lt;/a&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;div&gt;
            &lt;a href=&quot;https://dev.to/rdiegoss&quot; class=&quot;crayons-story__secondary fw-medium m:hidden&quot;&gt;
              Rodrigo Diego
            &lt;/a&gt;
            &lt;div class=&quot;profile-preview-card relative mb-4 s:mb-0 fw-medium hidden m:inline-block&quot;&gt;
              &lt;button id=&quot;story-author-preview-trigger-4280228&quot; aria-controls=&quot;story-author-preview-content-4280228&quot; class=&quot;profile-preview-card__trigger fs-s p-1 -ml-1 -my-2 crayons-btn crayons-btn--ghost&quot; aria-label=&quot;Rodrigo Diego profile details&quot;&gt;
                Rodrigo Diego
                
              &lt;/button&gt;
              &lt;div id=&quot;story-author-preview-content-4280228&quot; class=&quot;profile-preview-card__content crayons-dropdown branded-7 p-4 pt-0&quot; style=&quot;border-top-color: var(--card-color);&quot; data-repositioning-dropdown=&quot;true&quot; data-testid=&quot;profile-preview-card&quot;&gt;
                &lt;div class=&quot;gap-4 grid&quot;&gt;
                  &lt;div class=&quot;-mt-4&quot;&gt;
                    &lt;a href=&quot;https://dev.to/rdiegoss&quot; class=&quot;flex&quot;&gt;
                      &lt;span class=&quot;crayons-avatar crayons-avatar--xl mr-2 shrink-0&quot;&gt;
                        &lt;img src=&quot;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%2Fuser%2Fprofile_image%2F286761%2F5cc3b14e-ca66-4ff4-8fa8-9c82ec874054.jpeg&quot; class=&quot;crayons-avatar__image&quot; alt=&quot;&quot; loading=&quot;lazy&quot; referrerpolicy=&quot;no-referrer&quot;&gt;
                      &lt;/span&gt;
                      &lt;span class=&quot;crayons-link crayons-subtitle-2 mt-5&quot;&gt;Rodrigo Diego&lt;/span&gt;
                    &lt;/a&gt;
                  &lt;/div&gt;
                  &lt;div class=&quot;print-hidden&quot;&gt;
                    &lt;button class=&quot;crayons-btn follow-action-button whitespace-nowrap follow-user w-100&quot; data-info=&quot;{&amp;quot;style&amp;quot;:&amp;quot;full&amp;quot;,&amp;quot;id&amp;quot;:286761,&amp;quot;className&amp;quot;:&amp;quot;User&amp;quot;,&amp;quot;name&amp;quot;:&amp;quot;Rodrigo Diego&amp;quot;}&quot;&gt;
                      Follow
                    &lt;/button&gt;
                  &lt;/div&gt;
                  &lt;div class=&quot;author-preview-metadata-container&quot; data-author-id=&quot;286761&quot;&gt;&lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
            &lt;/div&gt;

          &lt;/div&gt;
          &lt;a href=&quot;https://dev.to/rdiegoss/your-rag-copilot-cant-count-stop-letting-it-try-2ie3&quot; class=&quot;crayons-story__tertiary fs-xs&quot;&gt;&lt;time datetime=&quot;2026-07-31T11:00:29Z&quot;&gt;Jul 31&lt;/time&gt;&lt;span class=&quot;time-ago-indicator-initial-placeholder&quot; data-seconds=&quot;1785495629&quot;&gt;&lt;/span&gt;&lt;/a&gt;
        &lt;/div&gt;
      &lt;/div&gt;

    &lt;/div&gt;

    &lt;div class=&quot;crayons-story__indention&quot;&gt;
      &lt;h2 class=&quot;crayons-story__title crayons-story__title-full_post&quot;&gt;
        &lt;a href=&quot;https://dev.to/rdiegoss/your-rag-copilot-cant-count-stop-letting-it-try-2ie3&quot; data-preload-image=&quot;https://media2.dev.to/dynamic/image/width=1000,height=420,fit=cover,gravity=auto,format=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fp1mra9jqtap83daxu43x.png&quot; id=&quot;article-link-4280228&quot;&gt;
          Your RAG copilot can&#39;t count — stop letting it try
        &lt;/a&gt;
      &lt;/h2&gt;
        &lt;div class=&quot;crayons-story__tags&quot;&gt;
            &lt;a class=&quot;crayons-tag  crayons-tag--monochrome &quot; style=&quot;
        --tag-bg: rgba(0, 0, 0, 0.10);
        --tag-prefix: #000000;
        --tag-bg-hover: rgba(0, 0, 0, 0.10);
        --tag-prefix-hover: #000000;
      &quot; href=&quot;https://dev.to/t/rag&quot;&gt;&lt;span class=&quot;crayons-tag__prefix&quot;&gt;#&lt;/span&gt;rag&lt;/a&gt;
            &lt;a class=&quot;crayons-tag  crayons-tag--monochrome &quot; style=&quot;
        --tag-bg: rgba(23, 253, 26, 0.10);
        --tag-prefix: #17fd1a;
        --tag-bg-hover: rgba(23, 253, 26, 0.10);
        --tag-prefix-hover: #17fd1a;
      &quot; href=&quot;https://dev.to/t/ai&quot;&gt;&lt;span class=&quot;crayons-tag__prefix&quot;&gt;#&lt;/span&gt;ai&lt;/a&gt;
            &lt;a class=&quot;crayons-tag  crayons-tag--monochrome &quot; style=&quot;
        --tag-bg: rgba(59, 73, 223, 0.10);
        --tag-prefix: #3b49df;
        --tag-bg-hover: rgba(59, 73, 223, 0.10);
        --tag-prefix-hover: #3b49df;
      &quot; href=&quot;https://dev.to/t/llm&quot;&gt;&lt;span class=&quot;crayons-tag__prefix&quot;&gt;#&lt;/span&gt;llm&lt;/a&gt;
            &lt;a class=&quot;crayons-tag  crayons-tag--monochrome &quot; style=&quot;
        --tag-bg: rgba(59, 73, 223, 0.10);
        --tag-prefix: #3b49df;
        --tag-bg-hover: rgba(59, 73, 223, 0.10);
        --tag-prefix-hover: #3b49df;
      &quot; href=&quot;https://dev.to/t/bedrock&quot;&gt;&lt;span class=&quot;crayons-tag__prefix&quot;&gt;#&lt;/span&gt;bedrock&lt;/a&gt;
        &lt;/div&gt;
      &lt;div class=&quot;crayons-story__bottom&quot;&gt;
        &lt;div class=&quot;crayons-story__details&quot;&gt;
          &lt;a href=&quot;https://dev.to/rdiegoss/your-rag-copilot-cant-count-stop-letting-it-try-2ie3&quot; class=&quot;crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left&quot; data-reaction-count=&quot;&quot; data-reactable-id=&quot;4280228&quot; aria-label=&quot;Add a comment to post - Your RAG copilot can&#39;t count — stop letting it try&quot;&gt;
            &lt;div class=&quot;multiple_reactions_aggregate&quot;&gt;
              &lt;span class=&quot;multiple_reactions_icons_container&quot; dir=&quot;rtl&quot;&gt;
                  &lt;span class=&quot;crayons_icon_container&quot;&gt;
                    &lt;img src=&quot;https://assets.dev.to/assets/multi-unicorn-b44d6f8c23cdd00964192bedc38af3e82463978aa611b4365bd33a0f1f4f3e97.svg&quot; width=&quot;18&quot; height=&quot;18&quot; referrerpolicy=&quot;no-referrer&quot;&gt;
                  &lt;/span&gt;
                  &lt;span class=&quot;crayons_icon_container&quot;&gt;
                    &lt;img src=&quot;https://assets.dev.to/assets/exploding-head-daceb38d627e6ae9b730f36a1e390fca556a4289d5a41abb2c35068ad3e2c4b5.svg&quot; width=&quot;18&quot; height=&quot;18&quot; referrerpolicy=&quot;no-referrer&quot;&gt;
                  &lt;/span&gt;
                  &lt;span class=&quot;crayons_icon_container&quot;&gt;
                    &lt;img src=&quot;https://assets.dev.to/assets/sparkle-heart-5f9bee3767e18deb1bb725290cb151c25234768a0e9a2bd39370c382d02920cf.svg&quot; width=&quot;18&quot; height=&quot;18&quot; referrerpolicy=&quot;no-referrer&quot;&gt;
                  &lt;/span&gt;
              &lt;/span&gt;
              &lt;span class=&quot;aggregate_reactions_counter&quot;&gt;12&lt;span class=&quot;hidden s:inline&quot;&gt;&amp;nbsp;reactions&lt;/span&gt;&lt;/span&gt;
            &lt;/div&gt;
          &lt;/a&gt;
            &lt;a href=&quot;https://dev.to/rdiegoss/your-rag-copilot-cant-count-stop-letting-it-try-2ie3#comments&quot; class=&quot;crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left flex items-center&quot; aria-label=&quot;Add a comment to post - Your RAG copilot can&#39;t count — stop letting it try&quot;&gt;
              &lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; width=&quot;24&quot; height=&quot;24&quot; role=&quot;img&quot; aria-labelledby=&quot;anu82b9dysdmrhac015dd85ev2vy0r1m&quot; class=&quot;crayons-icon&quot;&gt;&lt;title id=&quot;anu82b9dysdmrhac015dd85ev2vy0r1m&quot;&gt;Comments&lt;/title&gt;
&lt;path d=&quot;M10.5 5h3a6 6 0 110 12v2.625c-3.75-1.5-9-3.75-9-8.625a6 6 0 016-6zM12 15.5h1.5a4.501 4.501 0 001.722-8.657A4.5 4.5 0 0013.5 6.5h-3A4.5 4.5 0 006 11c0 2.707 1.846 4.475 6 6.36V15.5z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;

              17&lt;span class=&quot;hidden s:inline&quot;&gt;&amp;nbsp;comments&lt;/span&gt;
            &lt;/a&gt;
        &lt;/div&gt;
        &lt;div class=&quot;crayons-story__save&quot;&gt;
          &lt;small class=&quot;crayons-story__tertiary fs-xs mr-2&quot;&gt;
            6 min read
          &lt;/small&gt;
            &lt;button type=&quot;button&quot; id=&quot;article-save-button-4280228&quot; class=&quot;c-btn c-btn--icon-alone bookmark-button&quot; data-reactable-id=&quot;4280228&quot; data-article-author-id=&quot;286761&quot; aria-label=&quot;Save post Your RAG copilot can&#39;t count — stop letting it try to reading list&quot; title=&quot;Save post Your RAG copilot can&#39;t count — stop letting it try to reading list&quot;&gt;
              &lt;span class=&quot;bm-initial crayons-icon c-btn__icon&quot;&gt;
                &lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; width=&quot;24&quot; height=&quot;24&quot; aria-hidden=&quot;true&quot;&gt;&lt;path d=&quot;M6.75 4.5h10.5a.75.75 0 01.75.75v14.357a.375.375 0 01-.575.318L12 16.523l-5.426 3.401A.375.375 0 016 19.607V5.25a.75.75 0 01.75-.75zM16.5 6h-9v11.574l4.5-2.82 4.5 2.82V6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;

              &lt;/span&gt;
              &lt;span class=&quot;bm-success crayons-icon c-btn__icon&quot;&gt;
                &lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; width=&quot;24&quot; height=&quot;24&quot; aria-hidden=&quot;true&quot;&gt;&lt;path d=&quot;M6.75 4.5h10.5a.75.75 0 01.75.75v14.357a.375.375 0 01-.575.318L12 16.523l-5.426 3.401A.375.375 0 016 19.607V5.25a.75.75 0 01.75-.75z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;

              &lt;/span&gt;
            &lt;/button&gt;
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;/div&gt;


&lt;p&gt;&lt;a class=&quot;mentioned-user&quot; href=&quot;https://dev.to/rdiegoss&quot;&gt;@rdiegoss&lt;/a&gt; digs into why a document-search copilot kept miscounting, and why that particular bug is more dangerous than a crash. Tracking down the issue meant walking every stage of the retrieval pipeline to see what each one did to the count.&lt;/p&gt;


&lt;hr&gt;

&lt;p&gt;&lt;em&gt;And that&#39;s a wrap for this week&#39;s Top 7 roundup! 🎬 We hope you enjoyed this eclectic mix of insights, stories, and tips from our talented authors. Keep coding, keep learning, and stay tuned to DEV for more captivating content and &lt;a href=&quot;https://dev.to/settings/notifications&quot;&gt;make sure you’re opted in to our Weekly Newsletter&lt;/a&gt; 📩 for all the best articles, discussions, and updates.&lt;/em&gt;&lt;/p&gt;


            </description><link>https://dev.to/devteam/top-7-featured-dev-posts-of-the-week-4pk2</link><guid isPermaLink="false">https://dev.to/devteam/top-7-featured-dev-posts-of-the-week-4pk2</guid><pubDate>Tue, 04 Aug 2026 19:29:09 GMT</pubDate><author>Jess Lee</author><enclosure url="https://media2.dev.to/dynamic/image/width=1000,height=420,fit=cover,gravity=auto,format=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F8uyqy9ibkln948xhrdsj.jpg" type="image/jpeg"></enclosure><category>top7</category><category>discuss</category></item><item><title>Channels SDK: How to bring your Agent to any Channel (Slack, Microsoft Teams)</title><description>&lt;p&gt;Getting any agent into messaging platforms like Slack is complex. You create a Slack app, handle its events, format messages to the platform&#39;s format, handle deliveries with retries, and so on. &lt;/p&gt;

&lt;p&gt;Taking that to production is much harder. Then, if you want to bring it into another messaging platform, you do most of the work again, and again for the next platform.&lt;/p&gt;

&lt;p&gt;To remove that manual work, we&#39;re excited to release the &lt;a href=&quot;https://github.com/copilotKit/channels-sdk&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Channels SDK&lt;/a&gt;, which brings any &lt;a href=&quot;https://github.com/ag-ui-protocol/ag-ui&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;AG-UI&lt;/a&gt; agent to any channel from one codebase, with a persistence layer so it keeps its memory and context.&lt;/p&gt;

&lt;p&gt;Today, we will bring an agent into Slack, learn how everything works along with the architecture, the core patterns and connecting it to real tools like Notion using MCP.&lt;br&gt;
&lt;/p&gt;

&lt;div class=&quot;highlight js-code-highlight&quot;&gt;
&lt;pre class=&quot;highlight shell&quot;&gt;&lt;code&gt;npx copilotkit@latest channels setup
&lt;/code&gt;&lt;/pre&gt;
&lt;div class=&quot;highlight__panel js-actions-panel&quot;&gt;
&lt;div class=&quot;highlight__panel-action js-fullscreen-code-action&quot;&gt;
    &lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; width=&quot;20px&quot; height=&quot;20px&quot; viewBox=&quot;0 0 24 24&quot; class=&quot;highlight-action crayons-icon highlight-action--fullscreen-on&quot;&gt;&lt;title&gt;Enter fullscreen mode&lt;/title&gt;
    &lt;path d=&quot;M16 3h6v6h-2V5h-4V3zM2 3h6v2H4v4H2V3zm18 16v-4h2v6h-6v-2h4zM4 19h4v2H2v-6h2v4z&quot;&gt;&lt;/path&gt;
&lt;/svg&gt;

    &lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; width=&quot;20px&quot; height=&quot;20px&quot; viewBox=&quot;0 0 24 24&quot; class=&quot;highlight-action crayons-icon highlight-action--fullscreen-off&quot;&gt;&lt;title&gt;Exit fullscreen mode&lt;/title&gt;
    &lt;path d=&quot;M18 7h4v2h-6V3h2v4zM8 9H2V7h4V3h2v6zm10 8v4h-2v-6h6v2h-4zM8 15v6H6v-4H2v-2h6z&quot;&gt;&lt;/path&gt;
&lt;/svg&gt;

&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;


&lt;blockquote&gt;
&lt;p&gt;To try the agent live, we have created public channels on Slack and MS Teams. Head to &lt;a href=&quot;https://www.copilotkit.ai/try-channels&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;copilotkit.ai/try-channels&lt;/a&gt; and we&#39;ll get you in.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;  &lt;iframe src=&quot;https://www.youtube.com/embed/wUD8IHNYbks&quot; style=&quot;width: 100%; aspect-ratio: 16 / 9;&quot; allowfullscreen=&quot;&quot; loading=&quot;lazy&quot; referrerpolicy=&quot;no-referrer&quot;&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

&lt;hr&gt;
&lt;h2&gt;
  &lt;a name=&quot;what-you-will-build&quot; href=&quot;https://dev.to/copilotkit/channels-sdk-how-to-bring-your-agent-to-any-channel-slack-microsoft-teams-1bof#what-you-will-build&quot;&gt;
  &lt;/a&gt;
  What you will build
&lt;/h2&gt;

&lt;p&gt;A Slack bot running on your own agent, that can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;answer in a thread with the context already around it&lt;/li&gt;
&lt;li&gt;act through real tools (Notion over MCP)&lt;/li&gt;
&lt;li&gt;reply with native cards&lt;/li&gt;
&lt;li&gt;ask for approval before it changes anything&lt;/li&gt;
&lt;li&gt;read files and images people drop in&lt;/li&gt;
&lt;li&gt;remember a user across conversations and platforms&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Prefer a complete working example? &lt;a href=&quot;https://github.com/CopilotKit/OpenTag&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Clone OpenTag on GitHub&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If you want to explore on your own, &lt;a href=&quot;https://docs.copilotkit.ai/channels&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;read the Channels docs&lt;/a&gt;, or copy a ready-made prompt from the &lt;a href=&quot;https://docs.copilotkit.ai/&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;docs homepage&lt;/a&gt; and your coding agent builds your first channel with you.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;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%2F8nlqcid8ec85q4zrw1yx.png&quot; class=&quot;article-body-image-wrapper&quot;&gt;&lt;img src=&quot;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%2F8nlqcid8ec85q4zrw1yx.png&quot; alt=&quot;docs homepage&quot; loading=&quot;lazy&quot; width=&quot;800&quot; height=&quot;400&quot; referrerpolicy=&quot;no-referrer&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;hr&gt;
&lt;h2&gt;
  &lt;a name=&quot;what-is-the-channels-sdk&quot; href=&quot;https://dev.to/copilotkit/channels-sdk-how-to-bring-your-agent-to-any-channel-slack-microsoft-teams-1bof#what-is-the-channels-sdk&quot;&gt;
  &lt;/a&gt;
  What is the Channels SDK?
&lt;/h2&gt;

&lt;p&gt;The Channels SDK is an open source TypeScript library that takes any &lt;a href=&quot;https://github.com/ag-ui-protocol/ag-ui&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;AG-UI&lt;/a&gt; agent into Slack, Microsoft Teams, Discord, Telegram, WhatsApp and other channels, from one codebase.&lt;br&gt;
&lt;/p&gt;
&lt;div class=&quot;highlight js-code-highlight&quot;&gt;
&lt;pre class=&quot;highlight shell&quot;&gt;&lt;code&gt;npm i @copilotkit/channels
&lt;/code&gt;&lt;/pre&gt;
&lt;div class=&quot;highlight__panel js-actions-panel&quot;&gt;
&lt;div class=&quot;highlight__panel-action js-fullscreen-code-action&quot;&gt;
    &lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; width=&quot;20px&quot; height=&quot;20px&quot; viewBox=&quot;0 0 24 24&quot; class=&quot;highlight-action crayons-icon highlight-action--fullscreen-on&quot;&gt;&lt;title&gt;Enter fullscreen mode&lt;/title&gt;
    &lt;path d=&quot;M16 3h6v6h-2V5h-4V3zM2 3h6v2H4v4H2V3zm18 16v-4h2v6h-6v-2h4zM4 19h4v2H2v-6h2v4z&quot;&gt;&lt;/path&gt;
&lt;/svg&gt;

    &lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; width=&quot;20px&quot; height=&quot;20px&quot; viewBox=&quot;0 0 24 24&quot; class=&quot;highlight-action crayons-icon highlight-action--fullscreen-off&quot;&gt;&lt;title&gt;Exit fullscreen mode&lt;/title&gt;
    &lt;path d=&quot;M18 7h4v2h-6V3h2v4zM8 9H2V7h4V3h2v6zm10 8v4h-2v-6h6v2h-4zM8 15v6H6v-4H2v-2h6z&quot;&gt;&lt;/path&gt;
&lt;/svg&gt;

&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;It&#39;s built on the &lt;a href=&quot;https://github.com/ag-ui-protocol/ag-ui&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;AG-UI protocol&lt;/a&gt;, so the app and the agent stay decoupled.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;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%2Fhmaptudxfu6iwfftdjgz.png&quot; class=&quot;article-body-image-wrapper&quot;&gt;&lt;img src=&quot;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%2Fhmaptudxfu6iwfftdjgz.png&quot; alt=&quot;bring your agent to any channel&quot; loading=&quot;lazy&quot; width=&quot;800&quot; height=&quot;428&quot; referrerpolicy=&quot;no-referrer&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can bring any AG-UI compatible agent framework (LangChain, Google ADK, Mastra, Pydantic AI, Claude Agent SDK, etc.) and swap it later without touching the channel code.&lt;/p&gt;

&lt;p&gt;And if you don&#39;t want to bring your own framework, we ship a BuiltInAgent that runs on any model, hosted or local (via Ollama, LM Studio, or vLLM). We will be using this for the setup.&lt;/p&gt;

&lt;p&gt;You write replies as &lt;code&gt;&amp;lt;Message&amp;gt;&lt;/code&gt; JSX, and each platform renders them natively: Block Kit in Slack, Adaptive Cards in Teams.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;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%2Fkvf90eqp5h3ai967xwyq.png&quot; class=&quot;article-body-image-wrapper&quot;&gt;&lt;img src=&quot;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%2Fkvf90eqp5h3ai967xwyq.png&quot; alt=&quot;write it once, run in any channel&quot; loading=&quot;lazy&quot; width=&quot;800&quot; height=&quot;320&quot; referrerpolicy=&quot;no-referrer&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;hr&gt;
&lt;h2&gt;
  &lt;a name=&quot;managed-path-for-slack-and-microsoft-teams&quot; href=&quot;https://dev.to/copilotkit/channels-sdk-how-to-bring-your-agent-to-any-channel-slack-microsoft-teams-1bof#managed-path-for-slack-and-microsoft-teams&quot;&gt;
  &lt;/a&gt;
  Managed Path for Slack and Microsoft Teams
&lt;/h2&gt;

&lt;p&gt;Getting an agent to your channels usually involves:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;provider setup, tokens, and permissions&lt;/li&gt;
&lt;li&gt;webhook or socket connection&lt;/li&gt;
&lt;li&gt;durable state so threads resume on the right agent&lt;/li&gt;
&lt;li&gt;reliable delivery with retries&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That&#39;s the direct path, and we do ship adapters for it. But to run in production, we give you managed Slack and Microsoft Teams today with &lt;a href=&quot;https://intelligence.copilotkit.ai/&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;CopilotKit Intelligence&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;It holds the connection and delivers each turn to your app, so your process just runs the agent, with no public URL to expose, and adding a platform is a click in the dashboard.&lt;/p&gt;

&lt;p&gt;This guide uses the managed path, since it&#39;s the one you run in production. The integration code is mostly identical either way. &lt;/p&gt;

&lt;p&gt;The diagram below shows the boundary between your app and CopilotKit Intelligence, and the path each message takes.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;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%2Fme04n8a6z7ztg4ay1u3n.png&quot; class=&quot;article-body-image-wrapper&quot;&gt;&lt;img src=&quot;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%2Fme04n8a6z7ztg4ay1u3n.png&quot; alt=&quot;intelligence&quot; loading=&quot;lazy&quot; width=&quot;800&quot; height=&quot;551&quot; referrerpolicy=&quot;no-referrer&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;hr&gt;
&lt;h2&gt;
  &lt;a name=&quot;channels-ui&quot; href=&quot;https://dev.to/copilotkit/channels-sdk-how-to-bring-your-agent-to-any-channel-slack-microsoft-teams-1bof#channels-ui&quot;&gt;
  &lt;/a&gt;
  Channels UI
&lt;/h2&gt;

&lt;p&gt;There&#39;s a &lt;a href=&quot;https://docs.copilotkit.ai/reference/channels&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;component library&lt;/a&gt; with the building blocks: Message, Section, Header, Table, Image, Chart, Actions, Button, and more to help you compose UI blocks easily.&lt;/p&gt;

&lt;p&gt;Put a few together and you get a rich reply, rendered natively for you.&lt;br&gt;
&lt;/p&gt;
&lt;div class=&quot;highlight js-code-highlight&quot;&gt;
&lt;pre class=&quot;highlight tsx&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Message&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Header&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Section&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Context&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;@copilotkit/channels/ui&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Message&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Header&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;Deploy complete&lt;span class=&quot;p&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Header&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Section&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;v1.4.2 is live in production.&lt;span class=&quot;p&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Section&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Context&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;Shipped by the deploy bot · 12:04 PM&lt;span class=&quot;p&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Context&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Message&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;div class=&quot;highlight__panel js-actions-panel&quot;&gt;
&lt;div class=&quot;highlight__panel-action js-fullscreen-code-action&quot;&gt;
    &lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; width=&quot;20px&quot; height=&quot;20px&quot; viewBox=&quot;0 0 24 24&quot; class=&quot;highlight-action crayons-icon highlight-action--fullscreen-on&quot;&gt;&lt;title&gt;Enter fullscreen mode&lt;/title&gt;
    &lt;path d=&quot;M16 3h6v6h-2V5h-4V3zM2 3h6v2H4v4H2V3zm18 16v-4h2v6h-6v-2h4zM4 19h4v2H2v-6h2v4z&quot;&gt;&lt;/path&gt;
&lt;/svg&gt;

    &lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; width=&quot;20px&quot; height=&quot;20px&quot; viewBox=&quot;0 0 24 24&quot; class=&quot;highlight-action crayons-icon highlight-action--fullscreen-off&quot;&gt;&lt;title&gt;Exit fullscreen mode&lt;/title&gt;
    &lt;path d=&quot;M18 7h4v2h-6V3h2v4zM8 9H2V7h4V3h2v6zm10 8v4h-2v-6h6v2h-4zM8 15v6H6v-4H2v-2h6z&quot;&gt;&lt;/path&gt;
&lt;/svg&gt;

&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;


&lt;hr&gt;
&lt;h2&gt;
  &lt;a name=&quot;complete-setup-slack-agent&quot; href=&quot;https://dev.to/copilotkit/channels-sdk-how-to-bring-your-agent-to-any-channel-slack-microsoft-teams-1bof#complete-setup-slack-agent&quot;&gt;
  &lt;/a&gt;
  Complete setup: Slack agent
&lt;/h2&gt;

&lt;p&gt;You&#39;ll need Node.js 22+, a Slack workspace where you can install apps, a free &lt;a href=&quot;https://intelligence.copilotkit.ai/&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;CopilotKit Intelligence&lt;/a&gt; key, and a model API key like OpenAI.&lt;/p&gt;

&lt;p&gt;Here is the project structure. As we add capabilities below (tools, cards, MCP), we will do it in &lt;code&gt;components.tsx&lt;/code&gt; for the cards and buttons, and &lt;code&gt;mcp.ts&lt;/code&gt; for the Notion client. Everything else stays as is.&lt;br&gt;
&lt;/p&gt;
&lt;div class=&quot;highlight js-code-highlight&quot;&gt;
&lt;pre class=&quot;highlight plaintext&quot;&gt;&lt;code&gt;slack-bot/
├── agent.ts        # BuiltInAgent + your model
├── channel.tsx     # the app
├── tsconfig.json   # JSX transform pointed at @copilotkit/channels
├── package.json  
└── .env            # INTELLIGENCE_API_KEY, ...
&lt;/code&gt;&lt;/pre&gt;
&lt;div class=&quot;highlight__panel js-actions-panel&quot;&gt;
&lt;div class=&quot;highlight__panel-action js-fullscreen-code-action&quot;&gt;
    &lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; width=&quot;20px&quot; height=&quot;20px&quot; viewBox=&quot;0 0 24 24&quot; class=&quot;highlight-action crayons-icon highlight-action--fullscreen-on&quot;&gt;&lt;title&gt;Enter fullscreen mode&lt;/title&gt;
    &lt;path d=&quot;M16 3h6v6h-2V5h-4V3zM2 3h6v2H4v4H2V3zm18 16v-4h2v6h-6v-2h4zM4 19h4v2H2v-6h2v4z&quot;&gt;&lt;/path&gt;
&lt;/svg&gt;

    &lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; width=&quot;20px&quot; height=&quot;20px&quot; viewBox=&quot;0 0 24 24&quot; class=&quot;highlight-action crayons-icon highlight-action--fullscreen-off&quot;&gt;&lt;title&gt;Exit fullscreen mode&lt;/title&gt;
    &lt;path d=&quot;M18 7h4v2h-6V3h2v4zM8 9H2V7h4V3h2v6zm10 8v4h-2v-6h6v2h-4zM8 15v6H6v-4H2v-2h6z&quot;&gt;&lt;/path&gt;
&lt;/svg&gt;

&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;

&lt;h3&gt;
  &lt;a name=&quot;step-1-create-the-channel-and-connect-slack&quot; href=&quot;https://dev.to/copilotkit/channels-sdk-how-to-bring-your-agent-to-any-channel-slack-microsoft-teams-1bof#step-1-create-the-channel-and-connect-slack&quot;&gt;
  &lt;/a&gt;
  Step 1: Create the channel and connect Slack
&lt;/h3&gt;

&lt;p&gt;In the Intelligence dashboard, create a channel, choose the platform and set its name like &lt;code&gt;support-slack&lt;/code&gt;. Your app declares this exact name later.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;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%2Fdis2tb752f56cgh0uzk7.png&quot; class=&quot;article-body-image-wrapper&quot;&gt;&lt;img src=&quot;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%2Fdis2tb752f56cgh0uzk7.png&quot; alt=&quot;create a channel&quot; loading=&quot;lazy&quot; width=&quot;800&quot; height=&quot;464&quot; referrerpolicy=&quot;no-referrer&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Intelligence generates a Slack app manifest. Create the Slack app from it at &lt;a href=&quot;https://api.slack.com/apps&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;api.slack.com/apps&lt;/a&gt;, install it, and paste two values back into Intelligence:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the &lt;strong&gt;Bot token&lt;/strong&gt; (&lt;code&gt;xoxb-…&lt;/code&gt;), from &lt;em&gt;OAuth &amp;amp; Permissions&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;the &lt;strong&gt;Signing Secret&lt;/strong&gt;, from &lt;em&gt;Basic Information&lt;/em&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Both are required. The bot token lets Intelligence post as your app and the signing secret lets it verify Slack&#39;s events. Without the secret, events are never delivered.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;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%2Fjvda05ct8c8m8nq6j3uk.png&quot; class=&quot;article-body-image-wrapper&quot;&gt;&lt;img src=&quot;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%2Fjvda05ct8c8m8nq6j3uk.png&quot; alt=&quot;intelligence dashboard&quot; loading=&quot;lazy&quot; width=&quot;800&quot; height=&quot;633&quot; referrerpolicy=&quot;no-referrer&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;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%2Fbm0ckl251c802n4paav6.png&quot; class=&quot;article-body-image-wrapper&quot;&gt;&lt;img src=&quot;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%2Fbm0ckl251c802n4paav6.png&quot; alt=&quot;intelligence dashboard&quot; loading=&quot;lazy&quot; width=&quot;800&quot; height=&quot;556&quot; referrerpolicy=&quot;no-referrer&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once you create the channel, the dashboard will look like this.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;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%2Fkjpodez2zoivfrjlxakf.png&quot; class=&quot;article-body-image-wrapper&quot;&gt;&lt;img src=&quot;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%2Fkjpodez2zoivfrjlxakf.png&quot; alt=&quot;dashboard&quot; loading=&quot;lazy&quot; width=&quot;800&quot; height=&quot;349&quot; referrerpolicy=&quot;no-referrer&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  &lt;a name=&quot;step-2-turn-on-interactivity-and-scopes&quot; href=&quot;https://dev.to/copilotkit/channels-sdk-how-to-bring-your-agent-to-any-channel-slack-microsoft-teams-1bof#step-2-turn-on-interactivity-and-scopes&quot;&gt;
  &lt;/a&gt;
  Step 2: Turn on interactivity and scopes
&lt;/h3&gt;

&lt;p&gt;The manifest you installed already turns these on, so there&#39;s nothing to add. It&#39;s worth knowing what they do, since the features later in this guide depend on them. &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Interactivity is on, which is what makes buttons and approvals work.&lt;/li&gt;
&lt;li&gt;The scopes are set to enable memory, read uploaded files and remember context.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you ever build the Slack app manually instead of from the manifest, this is where you&#39;d enable those, then reinstall the Slack app in your workspace.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;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%2F3o7ae88fbcnbnr7iz5h1.png&quot; class=&quot;article-body-image-wrapper&quot;&gt;&lt;img src=&quot;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%2F3o7ae88fbcnbnr7iz5h1.png&quot; alt=&quot;manifest&quot; loading=&quot;lazy&quot; width=&quot;799&quot; height=&quot;569&quot; referrerpolicy=&quot;no-referrer&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  &lt;a name=&quot;step-3-create-the-agent&quot; href=&quot;https://dev.to/copilotkit/channels-sdk-how-to-bring-your-agent-to-any-channel-slack-microsoft-teams-1bof#step-3-create-the-agent&quot;&gt;
  &lt;/a&gt;
  Step 3: Create the agent
&lt;/h3&gt;

&lt;p&gt;The built-in agent runs inside your app, so there&#39;s no second server to run. Here&#39;s the code.&lt;br&gt;
&lt;/p&gt;
&lt;div class=&quot;highlight js-code-highlight&quot;&gt;
&lt;pre class=&quot;highlight typescript&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;// agent.ts&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;BuiltInAgent&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;@copilotkit/runtime/v2&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;makeAgent&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;threadId&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;agent&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;BuiltInAgent&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;model&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;openai/gpt-5.5&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;agent&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;threadId&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;threadId&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;agent&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;div class=&quot;highlight__panel js-actions-panel&quot;&gt;
&lt;div class=&quot;highlight__panel-action js-fullscreen-code-action&quot;&gt;
    &lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; width=&quot;20px&quot; height=&quot;20px&quot; viewBox=&quot;0 0 24 24&quot; class=&quot;highlight-action crayons-icon highlight-action--fullscreen-on&quot;&gt;&lt;title&gt;Enter fullscreen mode&lt;/title&gt;
    &lt;path d=&quot;M16 3h6v6h-2V5h-4V3zM2 3h6v2H4v4H2V3zm18 16v-4h2v6h-6v-2h4zM4 19h4v2H2v-6h2v4z&quot;&gt;&lt;/path&gt;
&lt;/svg&gt;

    &lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; width=&quot;20px&quot; height=&quot;20px&quot; viewBox=&quot;0 0 24 24&quot; class=&quot;highlight-action crayons-icon highlight-action--fullscreen-off&quot;&gt;&lt;title&gt;Exit fullscreen mode&lt;/title&gt;
    &lt;path d=&quot;M18 7h4v2h-6V3h2v4zM8 9H2V7h4V3h2v6zm10 8v4h-2v-6h6v2h-4zM8 15v6H6v-4H2v-2h6z&quot;&gt;&lt;/path&gt;
&lt;/svg&gt;

&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;The &lt;code&gt;model&lt;/code&gt; string is &lt;code&gt;provider/model&lt;/code&gt;. It works with OpenAI, Anthropic, and Google out of the box, and with any OpenAI-compatible endpoint, so you can point it at a local model (Ollama, a self-hosted gateway) instead of a hosted one. See &lt;a href=&quot;https://docs.copilotkit.ai/model-selection&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Model Selection&lt;/a&gt; for the local and custom-provider setup.&lt;/p&gt;
&lt;h3&gt;
  &lt;a name=&quot;step-4-set-up-the-app&quot; href=&quot;https://dev.to/copilotkit/channels-sdk-how-to-bring-your-agent-to-any-channel-slack-microsoft-teams-1bof#step-4-set-up-the-app&quot;&gt;
  &lt;/a&gt;
  Step 4: Set up the app
&lt;/h3&gt;

&lt;p&gt;Initialize the project and install the SDK, plus the dev tools to run TypeScript.&lt;br&gt;
&lt;/p&gt;
&lt;div class=&quot;highlight js-code-highlight&quot;&gt;
&lt;pre class=&quot;highlight shell&quot;&gt;&lt;code&gt;npm init &lt;span class=&quot;nt&quot;&gt;-y&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; npm pkg &lt;span class=&quot;nb&quot;&gt;set type&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;module
npm &lt;span class=&quot;nb&quot;&gt;install&lt;/span&gt; @copilotkit/channels @copilotkit/runtime
npm &lt;span class=&quot;nb&quot;&gt;install&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-D&lt;/span&gt; tsx typescript @types/node dotenv
&lt;/code&gt;&lt;/pre&gt;
&lt;div class=&quot;highlight__panel js-actions-panel&quot;&gt;
&lt;div class=&quot;highlight__panel-action js-fullscreen-code-action&quot;&gt;
    &lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; width=&quot;20px&quot; height=&quot;20px&quot; viewBox=&quot;0 0 24 24&quot; class=&quot;highlight-action crayons-icon highlight-action--fullscreen-on&quot;&gt;&lt;title&gt;Enter fullscreen mode&lt;/title&gt;
    &lt;path d=&quot;M16 3h6v6h-2V5h-4V3zM2 3h6v2H4v4H2V3zm18 16v-4h2v6h-6v-2h4zM4 19h4v2H2v-6h2v4z&quot;&gt;&lt;/path&gt;
&lt;/svg&gt;

    &lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; width=&quot;20px&quot; height=&quot;20px&quot; viewBox=&quot;0 0 24 24&quot; class=&quot;highlight-action crayons-icon highlight-action--fullscreen-off&quot;&gt;&lt;title&gt;Exit fullscreen mode&lt;/title&gt;
    &lt;path d=&quot;M18 7h4v2h-6V3h2v4zM8 9H2V7h4V3h2v6zm10 8v4h-2v-6h6v2h-4zM8 15v6H6v-4H2v-2h6z&quot;&gt;&lt;/path&gt;
&lt;/svg&gt;

&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;Channels JSX does not use React. Point the JSX transform at &lt;code&gt;@copilotkit/channels&lt;/code&gt; so &lt;code&gt;&amp;lt;Message&amp;gt;&lt;/code&gt; and &lt;code&gt;&amp;lt;Button&amp;gt;&lt;/code&gt; become type-checked Slack UI instead of React elements. Put JSX in &lt;code&gt;.tsx&lt;/code&gt; files and include them.&lt;br&gt;
&lt;/p&gt;
&lt;div class=&quot;highlight js-code-highlight&quot;&gt;
&lt;pre class=&quot;highlight json&quot;&gt;&lt;code&gt;&lt;span class=&quot;err&quot;&gt;//&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;tsconfig.json&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;compilerOptions&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;target&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;ES2022&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;module&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;NodeNext&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;moduleResolution&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;NodeNext&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;jsx&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;react-jsx&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;jsxImportSource&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;@copilotkit/channels&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;strict&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;noEmit&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;include&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;*.ts&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;*.tsx&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;div class=&quot;highlight__panel js-actions-panel&quot;&gt;
&lt;div class=&quot;highlight__panel-action js-fullscreen-code-action&quot;&gt;
    &lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; width=&quot;20px&quot; height=&quot;20px&quot; viewBox=&quot;0 0 24 24&quot; class=&quot;highlight-action crayons-icon highlight-action--fullscreen-on&quot;&gt;&lt;title&gt;Enter fullscreen mode&lt;/title&gt;
    &lt;path d=&quot;M16 3h6v6h-2V5h-4V3zM2 3h6v2H4v4H2V3zm18 16v-4h2v6h-6v-2h4zM4 19h4v2H2v-6h2v4z&quot;&gt;&lt;/path&gt;
&lt;/svg&gt;

    &lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; width=&quot;20px&quot; height=&quot;20px&quot; viewBox=&quot;0 0 24 24&quot; class=&quot;highlight-action crayons-icon highlight-action--fullscreen-off&quot;&gt;&lt;title&gt;Exit fullscreen mode&lt;/title&gt;
    &lt;path d=&quot;M18 7h4v2h-6V3h2v4zM8 9H2V7h4V3h2v6zm10 8v4h-2v-6h6v2h-4zM8 15v6H6v-4H2v-2h6z&quot;&gt;&lt;/path&gt;
&lt;/svg&gt;

&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;Note: If a component throws &quot;React is not defined,&quot; it&#39;s because the JSX fell back to React. The &lt;code&gt;jsxImportSource&lt;/code&gt; line above is what prevents it.&lt;/p&gt;

&lt;p&gt;Create a &lt;code&gt;.env&lt;/code&gt; in the root and add your API keys. You can create a &lt;a href=&quot;https://intelligence.copilotkit.ai/&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;free CopilotKit Intelligence key&lt;/a&gt; from the dashboard.&lt;br&gt;
&lt;/p&gt;
&lt;div class=&quot;highlight js-code-highlight&quot;&gt;
&lt;pre class=&quot;highlight plaintext&quot;&gt;&lt;code&gt;INTELLIGENCE_API_KEY=cpk-…
INTELLIGENCE_CHANNEL_NAME=toothless
OPENAI_API_KEY=sk-…
PORT=3000
&lt;/code&gt;&lt;/pre&gt;
&lt;div class=&quot;highlight__panel js-actions-panel&quot;&gt;
&lt;div class=&quot;highlight__panel-action js-fullscreen-code-action&quot;&gt;
    &lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; width=&quot;20px&quot; height=&quot;20px&quot; viewBox=&quot;0 0 24 24&quot; class=&quot;highlight-action crayons-icon highlight-action--fullscreen-on&quot;&gt;&lt;title&gt;Enter fullscreen mode&lt;/title&gt;
    &lt;path d=&quot;M16 3h6v6h-2V5h-4V3zM2 3h6v2H4v4H2V3zm18 16v-4h2v6h-6v-2h4zM4 19h4v2H2v-6h2v4z&quot;&gt;&lt;/path&gt;
&lt;/svg&gt;

    &lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; width=&quot;20px&quot; height=&quot;20px&quot; viewBox=&quot;0 0 24 24&quot; class=&quot;highlight-action crayons-icon highlight-action--fullscreen-off&quot;&gt;&lt;title&gt;Exit fullscreen mode&lt;/title&gt;
    &lt;path d=&quot;M18 7h4v2h-6V3h2v4zM8 9H2V7h4V3h2v6zm10 8v4h-2v-6h6v2h-4zM8 15v6H6v-4H2v-2h6z&quot;&gt;&lt;/path&gt;
&lt;/svg&gt;

&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;&lt;a href=&quot;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%2F1c0f6siheylgvkm6y8am.png&quot; class=&quot;article-body-image-wrapper&quot;&gt;&lt;img src=&quot;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%2F1c0f6siheylgvkm6y8am.png&quot; alt=&quot;api keys&quot; loading=&quot;lazy&quot; width=&quot;800&quot; height=&quot;173&quot; referrerpolicy=&quot;no-referrer&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  &lt;a name=&quot;step-5-build-the-app&quot; href=&quot;https://dev.to/copilotkit/channels-sdk-how-to-bring-your-agent-to-any-channel-slack-microsoft-teams-1bof#step-5-build-the-app&quot;&gt;
  &lt;/a&gt;
  Step 5: Build the app
&lt;/h3&gt;

&lt;p&gt;The app ties the two sides together: &lt;code&gt;createChannel&lt;/code&gt; sets it up, one &lt;code&gt;onMessage&lt;/code&gt; handler runs the agent, and a listener keeps the process alive.&lt;/p&gt;

&lt;p&gt;Here&#39;s what the code does:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;createChannel&lt;/code&gt; declares the bot, which channel, which agent, and &lt;code&gt;store&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;onMessage&lt;/code&gt; runs the agent on each message and streams the reply back to the thread.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The runtime and listener connect to Intelligence with your API key and keep the process alive.&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&quot;highlight js-code-highlight&quot;&gt;
&lt;pre class=&quot;highlight tsx&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;// channel.tsx&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;dotenv/config&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;createServer&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;node:http&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;createChannel&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;@copilotkit/channels&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;CopilotRuntime&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;CopilotKitIntelligence&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;@copilotkit/runtime/v2&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;createCopilotNodeListener&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;@copilotkit/runtime/v2/node&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;makeAgent&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;./agent&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;channel&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;createChannel&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;process&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;env&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;INTELLIGENCE_CHANNEL_NAME&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// the channel Code from step 1&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;identifyUser&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;platform&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;agent&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;makeAgent&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;// Drop duplicate deliveries so a Slack retry can&#39;t double-run the agent.&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;store&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;concurrency&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;drop&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;lockTtl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;60&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;_000&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;dedupTtl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;300&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;_000&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;

&lt;span class=&quot;nx&quot;&gt;channel&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;onMessage&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;async &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;thread&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;message&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;})&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;thread&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;runAgent&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;prompt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;message&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;text&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;intelligence&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;CopilotKitIntelligence&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;apiKey&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;process&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;env&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;INTELLIGENCE_API_KEY&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;!&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;runtime&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;CopilotRuntime&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;agents&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{},&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;intelligence&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;channels&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;channel&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;listener&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;createCopilotNodeListener&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;runtime&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;basePath&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;/api/copilotkit&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;listener&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;channels&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;?.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;ready&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;timeoutMs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;30&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;_000&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
&lt;span class=&quot;nf&quot;&gt;createServer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;listener&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;listen&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Number&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;process&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;env&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;PORT&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;??&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3000&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;Channel online.&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;div class=&quot;highlight__panel js-actions-panel&quot;&gt;
&lt;div class=&quot;highlight__panel-action js-fullscreen-code-action&quot;&gt;
    &lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; width=&quot;20px&quot; height=&quot;20px&quot; viewBox=&quot;0 0 24 24&quot; class=&quot;highlight-action crayons-icon highlight-action--fullscreen-on&quot;&gt;&lt;title&gt;Enter fullscreen mode&lt;/title&gt;
    &lt;path d=&quot;M16 3h6v6h-2V5h-4V3zM2 3h6v2H4v4H2V3zm18 16v-4h2v6h-6v-2h4zM4 19h4v2H2v-6h2v4z&quot;&gt;&lt;/path&gt;
&lt;/svg&gt;

    &lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; width=&quot;20px&quot; height=&quot;20px&quot; viewBox=&quot;0 0 24 24&quot; class=&quot;highlight-action crayons-icon highlight-action--fullscreen-off&quot;&gt;&lt;title&gt;Exit fullscreen mode&lt;/title&gt;
    &lt;path d=&quot;M18 7h4v2h-6V3h2v4zM8 9H2V7h4V3h2v6zm10 8v4h-2v-6h6v2h-4zM8 15v6H6v-4H2v-2h6z&quot;&gt;&lt;/path&gt;
&lt;/svg&gt;

&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;Slack retries any message it doesn&#39;t get a quick reply for, and without a &lt;code&gt;store&lt;/code&gt; those retries turn into duplicate runs. The store keeps one run per conversation and drops the repeats.&lt;/p&gt;
&lt;h3&gt;
  &lt;a name=&quot;step-6-run-it&quot; href=&quot;https://dev.to/copilotkit/channels-sdk-how-to-bring-your-agent-to-any-channel-slack-microsoft-teams-1bof#step-6-run-it&quot;&gt;
  &lt;/a&gt;
  Step 6: Run it
&lt;/h3&gt;

&lt;p&gt;The agent runs inside the app, so one command starts everything.&lt;br&gt;
&lt;/p&gt;
&lt;div class=&quot;highlight js-code-highlight&quot;&gt;
&lt;pre class=&quot;highlight shell&quot;&gt;&lt;code&gt;node &lt;span class=&quot;nt&quot;&gt;--env-file&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;.env &lt;span class=&quot;nt&quot;&gt;--import&lt;/span&gt; tsx channel.tsx
&lt;/code&gt;&lt;/pre&gt;
&lt;div class=&quot;highlight__panel js-actions-panel&quot;&gt;
&lt;div class=&quot;highlight__panel-action js-fullscreen-code-action&quot;&gt;
    &lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; width=&quot;20px&quot; height=&quot;20px&quot; viewBox=&quot;0 0 24 24&quot; class=&quot;highlight-action crayons-icon highlight-action--fullscreen-on&quot;&gt;&lt;title&gt;Enter fullscreen mode&lt;/title&gt;
    &lt;path d=&quot;M16 3h6v6h-2V5h-4V3zM2 3h6v2H4v4H2V3zm18 16v-4h2v6h-6v-2h4zM4 19h4v2H2v-6h2v4z&quot;&gt;&lt;/path&gt;
&lt;/svg&gt;

    &lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; width=&quot;20px&quot; height=&quot;20px&quot; viewBox=&quot;0 0 24 24&quot; class=&quot;highlight-action crayons-icon highlight-action--fullscreen-off&quot;&gt;&lt;title&gt;Exit fullscreen mode&lt;/title&gt;
    &lt;path d=&quot;M18 7h4v2h-6V3h2v4zM8 9H2V7h4V3h2v6zm10 8v4h-2v-6h6v2h-4zM8 15v6H6v-4H2v-2h6z&quot;&gt;&lt;/path&gt;
&lt;/svg&gt;

&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;If you have followed the steps, the channel status should change from &quot;Waiting for runtime&quot; to &quot;Online&quot;.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;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%2Fmmkff25fbe9x96idsvby.png&quot; class=&quot;article-body-image-wrapper&quot;&gt;&lt;img src=&quot;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%2Fmmkff25fbe9x96idsvby.png&quot; alt=&quot;runtime online&quot; loading=&quot;lazy&quot; width=&quot;800&quot; height=&quot;575&quot; referrerpolicy=&quot;no-referrer&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Invite the app to a channel and mention it. It should reply in threads accordingly.&lt;br&gt;
&lt;/p&gt;
&lt;div class=&quot;highlight js-code-highlight&quot;&gt;
&lt;pre class=&quot;highlight plaintext&quot;&gt;&lt;code&gt;/invite @your-app
@your-app what can you help with?
&lt;/code&gt;&lt;/pre&gt;
&lt;div class=&quot;highlight__panel js-actions-panel&quot;&gt;
&lt;div class=&quot;highlight__panel-action js-fullscreen-code-action&quot;&gt;
    &lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; width=&quot;20px&quot; height=&quot;20px&quot; viewBox=&quot;0 0 24 24&quot; class=&quot;highlight-action crayons-icon highlight-action--fullscreen-on&quot;&gt;&lt;title&gt;Enter fullscreen mode&lt;/title&gt;
    &lt;path d=&quot;M16 3h6v6h-2V5h-4V3zM2 3h6v2H4v4H2V3zm18 16v-4h2v6h-6v-2h4zM4 19h4v2H2v-6h2v4z&quot;&gt;&lt;/path&gt;
&lt;/svg&gt;

    &lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; width=&quot;20px&quot; height=&quot;20px&quot; viewBox=&quot;0 0 24 24&quot; class=&quot;highlight-action crayons-icon highlight-action--fullscreen-off&quot;&gt;&lt;title&gt;Exit fullscreen mode&lt;/title&gt;
    &lt;path d=&quot;M18 7h4v2h-6V3h2v4zM8 9H2V7h4V3h2v6zm10 8v4h-2v-6h6v2h-4zM8 15v6H6v-4H2v-2h6z&quot;&gt;&lt;/path&gt;
&lt;/svg&gt;

&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;&lt;a href=&quot;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%2Ffer87bfe8pn1dvbi601d.png&quot; class=&quot;article-body-image-wrapper&quot;&gt;&lt;img src=&quot;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%2Ffer87bfe8pn1dvbi601d.png&quot; alt=&quot;slack app running&quot; loading=&quot;lazy&quot; width=&quot;800&quot; height=&quot;365&quot; referrerpolicy=&quot;no-referrer&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;That&#39;s the whole setup. Slack application code on one side, your agent on the other. &lt;/p&gt;

&lt;p&gt;Now let&#39;s make the agent actually useful by implementing Generative UI, Human-in-the-loop, MCP Tools, Threads and more.&lt;/p&gt;

&lt;hr&gt;
&lt;h2&gt;
  &lt;a name=&quot;generative-ui-reply-with-native-cards&quot; href=&quot;https://dev.to/copilotkit/channels-sdk-how-to-bring-your-agent-to-any-channel-slack-microsoft-teams-1bof#generative-ui-reply-with-native-cards&quot;&gt;
  &lt;/a&gt;
  Generative UI: reply with native cards
&lt;/h2&gt;

&lt;p&gt;Generative UI lets your Slack agent create interfaces on the fly. Instead of answering in text, it builds what the moment needs and posts it into the thread.&lt;/p&gt;

&lt;p&gt;Native cards make it possible. You write them as JSX from &lt;code&gt;@copilotkit/channels/ui&lt;/code&gt;, and they render as real, interactive Slack UI: headers, sections, buttons, and more.&lt;br&gt;
&lt;/p&gt;
&lt;div class=&quot;highlight js-code-highlight&quot;&gt;
&lt;pre class=&quot;highlight tsx&quot;&gt;&lt;code&gt;&lt;span class=&quot;cm&quot;&gt;/** @jsxImportSource @copilotkit/channels */&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Message&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Header&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Section&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Context&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;@copilotkit/channels/ui&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;TaskCard&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;task&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;owner&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;priority&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;status&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;TaskRow&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;return &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Message&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Header&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;`🔴 &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;task&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Header&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Section&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;`*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;priority&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;*   ·   &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;status&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Section&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Context&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;`👤 &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;owner&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Context&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Message&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;div class=&quot;highlight__panel js-actions-panel&quot;&gt;
&lt;div class=&quot;highlight__panel-action js-fullscreen-code-action&quot;&gt;
    &lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; width=&quot;20px&quot; height=&quot;20px&quot; viewBox=&quot;0 0 24 24&quot; class=&quot;highlight-action crayons-icon highlight-action--fullscreen-on&quot;&gt;&lt;title&gt;Enter fullscreen mode&lt;/title&gt;
    &lt;path d=&quot;M16 3h6v6h-2V5h-4V3zM2 3h6v2H4v4H2V3zm18 16v-4h2v6h-6v-2h4zM4 19h4v2H2v-6h2v4z&quot;&gt;&lt;/path&gt;
&lt;/svg&gt;

    &lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; width=&quot;20px&quot; height=&quot;20px&quot; viewBox=&quot;0 0 24 24&quot; class=&quot;highlight-action crayons-icon highlight-action--fullscreen-off&quot;&gt;&lt;title&gt;Exit fullscreen mode&lt;/title&gt;
    &lt;path d=&quot;M18 7h4v2h-6V3h2v4zM8 9H2V7h4V3h2v6zm10 8v4h-2v-6h6v2h-4zM8 15v6H6v-4H2v-2h6z&quot;&gt;&lt;/path&gt;
&lt;/svg&gt;

&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;Native components cover more than text. Alongside cards, you get charts, tables, and images, all rendered natively in Slack. Here&#39;s a chart:&lt;br&gt;
&lt;/p&gt;
&lt;div class=&quot;highlight js-code-highlight&quot;&gt;
&lt;pre class=&quot;highlight tsx&quot;&gt;&lt;code&gt;&lt;span class=&quot;cm&quot;&gt;/** @jsxImportSource @copilotkit/channels */&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Chart&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;@copilotkit/channels/ui&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;CloseTimeChart&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;rows&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;rows&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;area&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;avgDays&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;number&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}[]&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;})&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;return &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Chart&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;verticalBar&quot;&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Avg days to close, by area&quot;&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;xAxisTitle&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Area&quot;&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;yAxisTitle&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Days&quot;&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;rows&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;({&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;label&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;area&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;avgDays&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}))&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;div class=&quot;highlight__panel js-actions-panel&quot;&gt;
&lt;div class=&quot;highlight__panel-action js-fullscreen-code-action&quot;&gt;
    &lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; width=&quot;20px&quot; height=&quot;20px&quot; viewBox=&quot;0 0 24 24&quot; class=&quot;highlight-action crayons-icon highlight-action--fullscreen-on&quot;&gt;&lt;title&gt;Enter fullscreen mode&lt;/title&gt;
    &lt;path d=&quot;M16 3h6v6h-2V5h-4V3zM2 3h6v2H4v4H2V3zm18 16v-4h2v6h-6v-2h4zM4 19h4v2H2v-6h2v4z&quot;&gt;&lt;/path&gt;
&lt;/svg&gt;

    &lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; width=&quot;20px&quot; height=&quot;20px&quot; viewBox=&quot;0 0 24 24&quot; class=&quot;highlight-action crayons-icon highlight-action--fullscreen-off&quot;&gt;&lt;title&gt;Exit fullscreen mode&lt;/title&gt;
    &lt;path d=&quot;M18 7h4v2h-6V3h2v4zM8 9H2V7h4V3h2v6zm10 8v4h-2v-6h6v2h-4zM8 15v6H6v-4H2v-2h6z&quot;&gt;&lt;/path&gt;
&lt;/svg&gt;

&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;The agent fills the data from the conversation, so &quot;chart close times by area&quot; becomes real bars in the thread.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;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%2Fmqgl53zt2vu2zngmel3s.png&quot; class=&quot;article-body-image-wrapper&quot;&gt;&lt;img src=&quot;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%2Fmqgl53zt2vu2zngmel3s.png&quot; alt=&quot;chart&quot; loading=&quot;lazy&quot; width=&quot;800&quot; height=&quot;709&quot; referrerpolicy=&quot;no-referrer&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;An image&lt;/strong&gt; is for what native components can&#39;t draw, a flowchart of what the team just brainstormed, or a fully styled widget. You render it to a PNG and post it as a file, and Intelligence hosts it.&lt;br&gt;
&lt;/p&gt;
&lt;div class=&quot;highlight js-code-highlight&quot;&gt;
&lt;pre class=&quot;highlight typescript&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;png&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;renderFlowchart&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;triage&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// mermaid or HTML → PNG&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;thread&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;postFile&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;bytes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;png&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;filename&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;flow.png&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;Docs issue backlog triage flow&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;altText&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;Triage path from raw issue state to the main backlog risk&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;div class=&quot;highlight__panel js-actions-panel&quot;&gt;
&lt;div class=&quot;highlight__panel-action js-fullscreen-code-action&quot;&gt;
    &lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; width=&quot;20px&quot; height=&quot;20px&quot; viewBox=&quot;0 0 24 24&quot; class=&quot;highlight-action crayons-icon highlight-action--fullscreen-on&quot;&gt;&lt;title&gt;Enter fullscreen mode&lt;/title&gt;
    &lt;path d=&quot;M16 3h6v6h-2V5h-4V3zM2 3h6v2H4v4H2V3zm18 16v-4h2v6h-6v-2h4zM4 19h4v2H2v-6h2v4z&quot;&gt;&lt;/path&gt;
&lt;/svg&gt;

    &lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; width=&quot;20px&quot; height=&quot;20px&quot; viewBox=&quot;0 0 24 24&quot; class=&quot;highlight-action crayons-icon highlight-action--fullscreen-off&quot;&gt;&lt;title&gt;Exit fullscreen mode&lt;/title&gt;
    &lt;path d=&quot;M18 7h4v2h-6V3h2v4zM8 9H2V7h4V3h2v6zm10 8v4h-2v-6h6v2h-4zM8 15v6H6v-4H2v-2h6z&quot;&gt;&lt;/path&gt;
&lt;/svg&gt;

&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;&lt;a href=&quot;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%2Fax4ftabeuf1nsm80lj6d.png&quot; class=&quot;article-body-image-wrapper&quot;&gt;&lt;img src=&quot;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%2Fax4ftabeuf1nsm80lj6d.png&quot; alt=&quot;flowchart&quot; loading=&quot;lazy&quot; width=&quot;799&quot; height=&quot;595&quot; referrerpolicy=&quot;no-referrer&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Read more on the &lt;a href=&quot;https://docs.copilotkit.ai/slack/rich-messages&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Rich messages docs&lt;/a&gt;.&lt;/p&gt;

&lt;hr&gt;
&lt;h2&gt;
  &lt;a name=&quot;give-the-agent-a-tool&quot; href=&quot;https://dev.to/copilotkit/channels-sdk-how-to-bring-your-agent-to-any-channel-slack-microsoft-teams-1bof#give-the-agent-a-tool&quot;&gt;
  &lt;/a&gt;
  Give the agent a tool
&lt;/h2&gt;

&lt;p&gt;An agent with only a model can answer from what it knows. A tool lets it call your code, hit an API, run a search, read from your database, and use the result in its reply. &lt;/p&gt;

&lt;p&gt;You define one with &lt;code&gt;defineChannelTool&lt;/code&gt;: the &lt;code&gt;parameters&lt;/code&gt; schema becomes the tool&#39;s input, and your &lt;code&gt;handler&lt;/code&gt; runs when the agent calls it. &lt;/p&gt;

&lt;p&gt;Here&#39;s the trimmed snippet showing the flow - you can use Tavily or another suitable provider for web search.&lt;br&gt;
&lt;/p&gt;
&lt;div class=&quot;highlight js-code-highlight&quot;&gt;
&lt;pre class=&quot;highlight typescript&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;// tools.ts&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;defineChannelTool&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;@copilotkit/channels&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;z&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;zod&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;webSearch&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;defineChannelTool&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;web_search&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;description&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;Search the web and return the top results.&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;parameters&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;z&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;object&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;query&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;z&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;describe&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;What to search for&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}),&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;handler&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;query&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;})&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;results&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;search&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;query&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// your search call, e.g. Tavily&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;results&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// objects are serialized for the model&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;div class=&quot;highlight__panel js-actions-panel&quot;&gt;
&lt;div class=&quot;highlight__panel-action js-fullscreen-code-action&quot;&gt;
    &lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; width=&quot;20px&quot; height=&quot;20px&quot; viewBox=&quot;0 0 24 24&quot; class=&quot;highlight-action crayons-icon highlight-action--fullscreen-on&quot;&gt;&lt;title&gt;Enter fullscreen mode&lt;/title&gt;
    &lt;path d=&quot;M16 3h6v6h-2V5h-4V3zM2 3h6v2H4v4H2V3zm18 16v-4h2v6h-6v-2h4zM4 19h4v2H2v-6h2v4z&quot;&gt;&lt;/path&gt;
&lt;/svg&gt;

    &lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; width=&quot;20px&quot; height=&quot;20px&quot; viewBox=&quot;0 0 24 24&quot; class=&quot;highlight-action crayons-icon highlight-action--fullscreen-off&quot;&gt;&lt;title&gt;Exit fullscreen mode&lt;/title&gt;
    &lt;path d=&quot;M18 7h4v2h-6V3h2v4zM8 9H2V7h4V3h2v6zm10 8v4h-2v-6h6v2h-4zM8 15v6H6v-4H2v-2h6z&quot;&gt;&lt;/path&gt;
&lt;/svg&gt;

&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;Register it on the channel:&lt;br&gt;
&lt;/p&gt;
&lt;div class=&quot;highlight js-code-highlight&quot;&gt;
&lt;pre class=&quot;highlight typescript&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;channel&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;createChannel&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;process&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;env&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;INTELLIGENCE_CHANNEL_NAME&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;identifyUser&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;platform&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;agent&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;makeAgent&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;tools&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;webSearch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;div class=&quot;highlight__panel js-actions-panel&quot;&gt;
&lt;div class=&quot;highlight__panel-action js-fullscreen-code-action&quot;&gt;
    &lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; width=&quot;20px&quot; height=&quot;20px&quot; viewBox=&quot;0 0 24 24&quot; class=&quot;highlight-action crayons-icon highlight-action--fullscreen-on&quot;&gt;&lt;title&gt;Enter fullscreen mode&lt;/title&gt;
    &lt;path d=&quot;M16 3h6v6h-2V5h-4V3zM2 3h6v2H4v4H2V3zm18 16v-4h2v6h-6v-2h4zM4 19h4v2H2v-6h2v4z&quot;&gt;&lt;/path&gt;
&lt;/svg&gt;

    &lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; width=&quot;20px&quot; height=&quot;20px&quot; viewBox=&quot;0 0 24 24&quot; class=&quot;highlight-action crayons-icon highlight-action--fullscreen-off&quot;&gt;&lt;title&gt;Exit fullscreen mode&lt;/title&gt;
    &lt;path d=&quot;M18 7h4v2h-6V3h2v4zM8 9H2V7h4V3h2v6zm10 8v4h-2v-6h6v2h-4zM8 15v6H6v-4H2v-2h6z&quot;&gt;&lt;/path&gt;
&lt;/svg&gt;

&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;Now &quot;search for the latest Anthropic Claude news and summarize it&quot; runs your &lt;code&gt;web_search&lt;/code&gt;, reads the results, and answers in the thread with that context. &lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;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%2F3xv5l1czokw2ma8vr3ni.png&quot; class=&quot;article-body-image-wrapper&quot;&gt;&lt;img src=&quot;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%2F3xv5l1czokw2ma8vr3ni.png&quot; alt=&quot;multimodal attachment&quot; loading=&quot;lazy&quot; width=&quot;800&quot; height=&quot;347&quot; referrerpolicy=&quot;no-referrer&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A few rules of thumb from the API: return raw objects or arrays for data tools, return a short confirmation when the handler already posted UI, and throw the real error so the agent can recover, avoid &lt;code&gt;JSON.stringify&lt;/code&gt; on your own success data. &lt;/p&gt;

&lt;p&gt;Read &lt;a href=&quot;https://docs.copilotkit.ai/slack/tools&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Tools and context docs&lt;/a&gt;.&lt;/p&gt;

&lt;hr&gt;
&lt;h2&gt;
  &lt;a name=&quot;connect-a-tool-with-mcp-a-notion-example&quot; href=&quot;https://dev.to/copilotkit/channels-sdk-how-to-bring-your-agent-to-any-channel-slack-microsoft-teams-1bof#connect-a-tool-with-mcp-a-notion-example&quot;&gt;
  &lt;/a&gt;
  Connect a tool with MCP: a Notion example
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;defineChannelTool&lt;/code&gt; is for actions you write yourself. To give the agent a whole set of tools something else already exposes, connect an MCP server, and it can search a knowledge base, create a ticket, or update a page.&lt;/p&gt;

&lt;p&gt;Let&#39;s connect Notion MCP for instance.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Create an internal integration at &lt;a href=&quot;https://www.notion.so/profile/integrations&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;notion.so/profile/integrations&lt;/a&gt; and copy its token (&lt;code&gt;ntn_…&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;Open a Notion page, top-right ••• → &lt;strong&gt;Connections&lt;/strong&gt; → add your integration. The agent sees only the pages you connect.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href=&quot;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%2Fjehygn91qkzq2ftyygah.png&quot; class=&quot;article-body-image-wrapper&quot;&gt;&lt;img src=&quot;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%2Fjehygn91qkzq2ftyygah.png&quot; alt=&quot;notion mcp&quot; loading=&quot;lazy&quot; width=&quot;799&quot; height=&quot;331&quot; referrerpolicy=&quot;no-referrer&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Add the token to &lt;code&gt;.env&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;
&lt;div class=&quot;highlight js-code-highlight&quot;&gt;
&lt;pre class=&quot;highlight plaintext&quot;&gt;&lt;code&gt;NOTION_TOKEN=ntn_...
&lt;/code&gt;&lt;/pre&gt;
&lt;div class=&quot;highlight__panel js-actions-panel&quot;&gt;
&lt;div class=&quot;highlight__panel-action js-fullscreen-code-action&quot;&gt;
    &lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; width=&quot;20px&quot; height=&quot;20px&quot; viewBox=&quot;0 0 24 24&quot; class=&quot;highlight-action crayons-icon highlight-action--fullscreen-on&quot;&gt;&lt;title&gt;Enter fullscreen mode&lt;/title&gt;
    &lt;path d=&quot;M16 3h6v6h-2V5h-4V3zM2 3h6v2H4v4H2V3zm18 16v-4h2v6h-6v-2h4zM4 19h4v2H2v-6h2v4z&quot;&gt;&lt;/path&gt;
&lt;/svg&gt;

    &lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; width=&quot;20px&quot; height=&quot;20px&quot; viewBox=&quot;0 0 24 24&quot; class=&quot;highlight-action crayons-icon highlight-action--fullscreen-off&quot;&gt;&lt;title&gt;Exit fullscreen mode&lt;/title&gt;
    &lt;path d=&quot;M18 7h4v2h-6V3h2v4zM8 9H2V7h4V3h2v6zm10 8v4h-2v-6h6v2h-4zM8 15v6H6v-4H2v-2h6z&quot;&gt;&lt;/path&gt;
&lt;/svg&gt;

&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;Then wire the Notion MCP server as one of the agent&#39;s MCP clients. It runs as a local process (&lt;code&gt;npx @notionhq/notion-mcp-server&lt;/code&gt;) and hands the agent Notion&#39;s tools: search, fetch, create, update.&lt;br&gt;
&lt;/p&gt;
&lt;div class=&quot;highlight js-code-highlight&quot;&gt;
&lt;pre class=&quot;highlight typescript&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;BuiltInAgent&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;@copilotkit/runtime/v2&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Client&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;@modelcontextprotocol/sdk/client/index.js&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;StdioClientTransport&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;getDefaultEnvironment&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;@modelcontextprotocol/sdk/client/stdio.js&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;notionMcp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;client&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Client&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;my-bot&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;version&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;0.1.0&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;capabilities&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{}&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;tools&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;client&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;connect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;StdioClientTransport&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt;
          &lt;span class=&quot;na&quot;&gt;command&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;npx&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
          &lt;span class=&quot;na&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;-y&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;@notionhq/notion-mcp-server&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
          &lt;span class=&quot;c1&quot;&gt;// Forward env, or NOTION_TOKEN never reaches the spawned server.&lt;/span&gt;
          &lt;span class=&quot;na&quot;&gt;env&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;getDefaultEnvironment&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(),&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;process&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;env&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;Record&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;kr&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}),&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
      &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;tools&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;client&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;listTools&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
      &lt;span class=&quot;c1&quot;&gt;// Expose each MCP tool to the agent (full mapping in the repo&#39;s mcp.ts).&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;toToolSet&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;client&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;tools&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;makeAgent&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;threadId&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;agent&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;BuiltInAgent&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;model&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;openai/gpt-5.5&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;maxSteps&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;          &lt;span class=&quot;c1&quot;&gt;// let it call a tool, read the result, then answer&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;mcpClients&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;notionMcp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()],&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;agent&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;threadId&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;threadId&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;agent&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;div class=&quot;highlight__panel js-actions-panel&quot;&gt;
&lt;div class=&quot;highlight__panel-action js-fullscreen-code-action&quot;&gt;
    &lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; width=&quot;20px&quot; height=&quot;20px&quot; viewBox=&quot;0 0 24 24&quot; class=&quot;highlight-action crayons-icon highlight-action--fullscreen-on&quot;&gt;&lt;title&gt;Enter fullscreen mode&lt;/title&gt;
    &lt;path d=&quot;M16 3h6v6h-2V5h-4V3zM2 3h6v2H4v4H2V3zm18 16v-4h2v6h-6v-2h4zM4 19h4v2H2v-6h2v4z&quot;&gt;&lt;/path&gt;
&lt;/svg&gt;

    &lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; width=&quot;20px&quot; height=&quot;20px&quot; viewBox=&quot;0 0 24 24&quot; class=&quot;highlight-action crayons-icon highlight-action--fullscreen-off&quot;&gt;&lt;title&gt;Exit fullscreen mode&lt;/title&gt;
    &lt;path d=&quot;M18 7h4v2h-6V3h2v4zM8 9H2V7h4V3h2v6zm10 8v4h-2v-6h6v2h-4zM8 15v6H6v-4H2v-2h6z&quot;&gt;&lt;/path&gt;
&lt;/svg&gt;

&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;Now &quot;what&#39;s in my Q3 roadmap?&quot; searches Notion and answers from the real page. If the page isn&#39;t connected to the integration, the agent says it can&#39;t find it instead of guessing. You can enable generative UI as well if you want to reply in a structured way.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;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%2Fbqep91kcgj4lwcx3nfo8.png&quot; class=&quot;article-body-image-wrapper&quot;&gt;&lt;img src=&quot;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%2Fbqep91kcgj4lwcx3nfo8.png&quot; alt=&quot;web search&quot; loading=&quot;lazy&quot; width=&quot;800&quot; height=&quot;542&quot; referrerpolicy=&quot;no-referrer&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here&#39;s an example of fetching Linear tickets, with a similar pattern.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;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%2F0ynl25d7iri7qnbtqcsv.png&quot; class=&quot;article-body-image-wrapper&quot;&gt;&lt;img src=&quot;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%2F0ynl25d7iri7qnbtqcsv.png&quot; alt=&quot;linear&quot; loading=&quot;lazy&quot; width=&quot;800&quot; height=&quot;782&quot; referrerpolicy=&quot;no-referrer&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;hr&gt;
&lt;h2&gt;
  &lt;a name=&quot;humanintheloop-approve-before-the-agent-acts&quot; href=&quot;https://dev.to/copilotkit/channels-sdk-how-to-bring-your-agent-to-any-channel-slack-microsoft-teams-1bof#humanintheloop-approve-before-the-agent-acts&quot;&gt;
  &lt;/a&gt;
  Human-in-the-loop: approve before the agent acts
&lt;/h2&gt;

&lt;p&gt;Some actions shouldn&#39;t happen without a person approving them. For those critical actions, the agent can do it via human-in-the-loop.&lt;/p&gt;

&lt;p&gt;You author the prompt as a card with two buttons, and the click carries your own value back to the handler.&lt;br&gt;
&lt;/p&gt;
&lt;div class=&quot;highlight js-code-highlight&quot;&gt;
&lt;pre class=&quot;highlight tsx&quot;&gt;&lt;code&gt;&lt;span class=&quot;cm&quot;&gt;/** @jsxImportSource @copilotkit/channels */&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Message&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Header&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Actions&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Button&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;InteractionContext&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;@copilotkit/channels/ui&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// The click runs in your runtime; the platform only sends back the button&#39;s value.&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;onDecision&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;action&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;thread&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;InteractionContext&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;ok&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;boolean&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;what&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;v&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;action&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;if &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;v&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// the click value can be undefined, so guard it first&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;thread&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;post&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;v&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;ok&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;`Approved: &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;v&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;what&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;`&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;Cancelled.&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;if &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;v&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;ok&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;thread&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;runAgent&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;prompt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;`The user approved &quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;v&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;what&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;. Do it now, then confirm.`&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;ConfirmAction&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;what&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;what&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;})&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;return &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Message&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Header&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;`Approve: &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;what&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Header&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Actions&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Button&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;ok&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;what&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;style&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;primary&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;onClick&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;onDecision&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;Approve&lt;span class=&quot;p&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Button&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Button&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;ok&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;what&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;style&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;danger&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;onClick&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;onDecision&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;Deny&lt;span class=&quot;p&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Button&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Actions&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Message&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;div class=&quot;highlight__panel js-actions-panel&quot;&gt;
&lt;div class=&quot;highlight__panel-action js-fullscreen-code-action&quot;&gt;
    &lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; width=&quot;20px&quot; height=&quot;20px&quot; viewBox=&quot;0 0 24 24&quot; class=&quot;highlight-action crayons-icon highlight-action--fullscreen-on&quot;&gt;&lt;title&gt;Enter fullscreen mode&lt;/title&gt;
    &lt;path d=&quot;M16 3h6v6h-2V5h-4V3zM2 3h6v2H4v4H2V3zm18 16v-4h2v6h-6v-2h4zM4 19h4v2H2v-6h2v4z&quot;&gt;&lt;/path&gt;
&lt;/svg&gt;

    &lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; width=&quot;20px&quot; height=&quot;20px&quot; viewBox=&quot;0 0 24 24&quot; class=&quot;highlight-action crayons-icon highlight-action--fullscreen-off&quot;&gt;&lt;title&gt;Exit fullscreen mode&lt;/title&gt;
    &lt;path d=&quot;M18 7h4v2h-6V3h2v4zM8 9H2V7h4V3h2v6zm10 8v4h-2v-6h6v2h-4zM8 15v6H6v-4H2v-2h6z&quot;&gt;&lt;/path&gt;
&lt;/svg&gt;

&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;Tell the agent to ask for approval before any write. It posts the prompt, pauses, and continues only once approved. Read more on the &lt;a href=&quot;https://docs.copilotkit.ai/slack/interactive&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Interactive messages docs&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;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%2Fvv362xy06f4vh0zc1v4a.png&quot; class=&quot;article-body-image-wrapper&quot;&gt;&lt;img src=&quot;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%2Fvv362xy06f4vh0zc1v4a.png&quot; alt=&quot;human in the loop&quot; loading=&quot;lazy&quot; width=&quot;800&quot; height=&quot;301&quot; referrerpolicy=&quot;no-referrer&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can also add more context using the &lt;code&gt;what&lt;/code&gt; field.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;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%2Fw4wdbc38okqu339ja5tg.png&quot; class=&quot;article-body-image-wrapper&quot;&gt;&lt;img src=&quot;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%2Fw4wdbc38okqu339ja5tg.png&quot; alt=&quot;human in the loop&quot; loading=&quot;lazy&quot; width=&quot;800&quot; height=&quot;395&quot; referrerpolicy=&quot;no-referrer&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;hr&gt;
&lt;h2&gt;
  &lt;a name=&quot;read-files-and-images-users-upload&quot; href=&quot;https://dev.to/copilotkit/channels-sdk-how-to-bring-your-agent-to-any-channel-slack-microsoft-teams-1bof#read-files-and-images-users-upload&quot;&gt;
  &lt;/a&gt;
  Read files and images users upload
&lt;/h2&gt;

&lt;p&gt;People drop files into Slack, screenshots, PDFs, logs. The agent forwards what the message carries into the run and the attachment goes with the text.&lt;br&gt;
&lt;/p&gt;
&lt;div class=&quot;highlight js-code-highlight&quot;&gt;
&lt;pre class=&quot;highlight tsx&quot;&gt;&lt;code&gt;&lt;span class=&quot;nx&quot;&gt;channel&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;onMessage&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;async &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;thread&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;message&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;})&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;thread&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;runAgent&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;prompt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;message&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;contentParts&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;?.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;length&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[{&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;text&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;text&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;message&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;text&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;...(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;message&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;contentParts&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;??&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[])]&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;message&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;text&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;div class=&quot;highlight__panel js-actions-panel&quot;&gt;
&lt;div class=&quot;highlight__panel-action js-fullscreen-code-action&quot;&gt;
    &lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; width=&quot;20px&quot; height=&quot;20px&quot; viewBox=&quot;0 0 24 24&quot; class=&quot;highlight-action crayons-icon highlight-action--fullscreen-on&quot;&gt;&lt;title&gt;Enter fullscreen mode&lt;/title&gt;
    &lt;path d=&quot;M16 3h6v6h-2V5h-4V3zM2 3h6v2H4v4H2V3zm18 16v-4h2v6h-6v-2h4zM4 19h4v2H2v-6h2v4z&quot;&gt;&lt;/path&gt;
&lt;/svg&gt;

    &lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; width=&quot;20px&quot; height=&quot;20px&quot; viewBox=&quot;0 0 24 24&quot; class=&quot;highlight-action crayons-icon highlight-action--fullscreen-off&quot;&gt;&lt;title&gt;Exit fullscreen mode&lt;/title&gt;
    &lt;path d=&quot;M18 7h4v2h-6V3h2v4zM8 9H2V7h4V3h2v6zm10 8v4h-2v-6h6v2h-4zM8 15v6H6v-4H2v-2h6z&quot;&gt;&lt;/path&gt;
&lt;/svg&gt;

&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;Here&#39;s an example of an image attached and the agent responds accordingly.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;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%2Fbp9jbv67uiwbnyhrkfib.png&quot; class=&quot;article-body-image-wrapper&quot;&gt;&lt;img src=&quot;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%2Fbp9jbv67uiwbnyhrkfib.png&quot; alt=&quot;toothless image upload&quot; loading=&quot;lazy&quot; width=&quot;800&quot; height=&quot;874&quot; referrerpolicy=&quot;no-referrer&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;hr&gt;
&lt;h2&gt;
  &lt;a name=&quot;memory-conversation-history-and-crossplatform-transcripts&quot; href=&quot;https://dev.to/copilotkit/channels-sdk-how-to-bring-your-agent-to-any-channel-slack-microsoft-teams-1bof#memory-conversation-history-and-crossplatform-transcripts&quot;&gt;
  &lt;/a&gt;
  Memory: conversation history and cross-platform transcripts
&lt;/h2&gt;

&lt;p&gt;The agent remembers in two ways.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href=&quot;https://docs.copilotkit.ai/slack/history-and-transcripts&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;&lt;strong&gt;Conversation history&lt;/strong&gt;&lt;/a&gt; is the agent recalling the current thread. Intelligence seeds each turn with recent messages, so a follow-up in the same thread has context. This is automatic, you store nothing.&lt;/li&gt;
&lt;li&gt;
&lt;a href=&quot;https://docs.copilotkit.ai/slack/history-and-transcripts&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;&lt;strong&gt;Transcripts&lt;/strong&gt;&lt;/a&gt; are the SDK&#39;s own memory, kept per user across platforms. Someone who asked in Teams can follow up in Slack, and the agent still has the earlier context.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Transcripts are keyed to a user, so you give the channel a stable identity, then turn transcripts on in the store.&lt;br&gt;
&lt;/p&gt;
&lt;div class=&quot;highlight js-code-highlight&quot;&gt;
&lt;pre class=&quot;highlight typescript&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;channel&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;createChannel&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;process&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;env&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;INTELLIGENCE_CHANNEL_NAME&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;identifyUser&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;({&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;actor&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;})&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;actor&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;email&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;actor&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;email&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;actor&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;name&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;??&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;actor&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;email&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// needs users:read.email&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;agent&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;makeAgent&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;store&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;concurrency&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;drop&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;lockTtl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;60&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;_000&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;dedupTtl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;300&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;_000&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;adapter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;MyStore&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(),&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// Redis, Postgres&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;transcripts&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;retention&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;30d&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;maxPerUser&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;200&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;div class=&quot;highlight__panel js-actions-panel&quot;&gt;
&lt;div class=&quot;highlight__panel-action js-fullscreen-code-action&quot;&gt;
    &lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; width=&quot;20px&quot; height=&quot;20px&quot; viewBox=&quot;0 0 24 24&quot; class=&quot;highlight-action crayons-icon highlight-action--fullscreen-on&quot;&gt;&lt;title&gt;Enter fullscreen mode&lt;/title&gt;
    &lt;path d=&quot;M16 3h6v6h-2V5h-4V3zM2 3h6v2H4v4H2V3zm18 16v-4h2v6h-6v-2h4zM4 19h4v2H2v-6h2v4z&quot;&gt;&lt;/path&gt;
&lt;/svg&gt;

    &lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; width=&quot;20px&quot; height=&quot;20px&quot; viewBox=&quot;0 0 24 24&quot; class=&quot;highlight-action crayons-icon highlight-action--fullscreen-off&quot;&gt;&lt;title&gt;Exit fullscreen mode&lt;/title&gt;
    &lt;path d=&quot;M18 7h4v2h-6V3h2v4zM8 9H2V7h4V3h2v6zm10 8v4h-2v-6h6v2h-4zM8 15v6H6v-4H2v-2h6z&quot;&gt;&lt;/path&gt;
&lt;/svg&gt;

&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;Then call &lt;code&gt;thread.runAgent({ prompt, transcript: true })&lt;/code&gt;, and prior history is injected when the thread has a resolved user.&lt;/p&gt;

&lt;p&gt;Transcripts and pending approvals live in this store, separate from the thread Intelligence keeps. In development, it&#39;s in memory and resets on restart, so for production use a &lt;a href=&quot;https://docs.copilotkit.ai/slack/persistence-and-scaling&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;durable store like Redis or Postgres&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Yay! Now your agent is very powerful and can do a lot of tasks, with the context of your channel.&lt;/p&gt;

&lt;p&gt;From the Intelligence dashboard, you can see all the threads, usage history, runs and complete agent lifecycle per thread via AG-UI events.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;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%2Fug2rh9bazd8bm4s9dr6k.png&quot; class=&quot;article-body-image-wrapper&quot;&gt;&lt;img src=&quot;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%2Fug2rh9bazd8bm4s9dr6k.png&quot; alt=&quot;intelligence raw ag-ui events&quot; loading=&quot;lazy&quot; width=&quot;800&quot; height=&quot;466&quot; referrerpolicy=&quot;no-referrer&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;hr&gt;
&lt;h2&gt;
  &lt;a name=&quot;swap-in-your-own-agent-framework&quot; href=&quot;https://dev.to/copilotkit/channels-sdk-how-to-bring-your-agent-to-any-channel-slack-microsoft-teams-1bof#swap-in-your-own-agent-framework&quot;&gt;
  &lt;/a&gt;
  Swap in your own agent framework
&lt;/h2&gt;

&lt;p&gt;The built-in agent is one option. You can swap it for a major framework, LangGraph, Mastra, the Claude Agent SDK, anything that speaks AG-UI over HTTP.&lt;/p&gt;

&lt;p&gt;You serve that agent at a URL, and the app points at it instead. Nothing else in your bot changes.&lt;/p&gt;

&lt;p&gt;Here&#39;s what changes if you use LangGraph: only the agent file. Instead of constructing a &lt;code&gt;BuiltInAgent&lt;/code&gt;, you point an &lt;code&gt;HttpAgent&lt;/code&gt; at your running LangGraph server:&lt;br&gt;
&lt;/p&gt;
&lt;div class=&quot;highlight js-code-highlight&quot;&gt;
&lt;pre class=&quot;highlight typescript&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;// agent.ts&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;HttpAgent&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;@ag-ui/client&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// Before: the built-in agent&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// export function makeAgent(threadId: string) {&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;//   const agent = new BuiltInAgent({ model: &quot;openai/gpt-5.5&quot; });&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;//   agent.threadId = threadId;&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;//   return agent;&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// }&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// After: your LangGraph graph, served over AG-UI at AGENT_URL&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;makeAgent&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;threadId&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;agent&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;HttpAgent&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;process&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;env&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;AGENT_URL&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;!&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;agent&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;threadId&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;threadId&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;agent&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;div class=&quot;highlight__panel js-actions-panel&quot;&gt;
&lt;div class=&quot;highlight__panel-action js-fullscreen-code-action&quot;&gt;
    &lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; width=&quot;20px&quot; height=&quot;20px&quot; viewBox=&quot;0 0 24 24&quot; class=&quot;highlight-action crayons-icon highlight-action--fullscreen-on&quot;&gt;&lt;title&gt;Enter fullscreen mode&lt;/title&gt;
    &lt;path d=&quot;M16 3h6v6h-2V5h-4V3zM2 3h6v2H4v4H2V3zm18 16v-4h2v6h-6v-2h4zM4 19h4v2H2v-6h2v4z&quot;&gt;&lt;/path&gt;
&lt;/svg&gt;

    &lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; width=&quot;20px&quot; height=&quot;20px&quot; viewBox=&quot;0 0 24 24&quot; class=&quot;highlight-action crayons-icon highlight-action--fullscreen-off&quot;&gt;&lt;title&gt;Exit fullscreen mode&lt;/title&gt;
    &lt;path d=&quot;M18 7h4v2h-6V3h2v4zM8 9H2V7h4V3h2v6zm10 8v4h-2v-6h6v2h-4zM8 15v6H6v-4H2v-2h6z&quot;&gt;&lt;/path&gt;
&lt;/svg&gt;

&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;Then add &lt;code&gt;AGENT_URL=http://localhost:8000/agent&lt;/code&gt; to &lt;code&gt;.env&lt;/code&gt;. Your LangGraph graph runs as its own process, with its own model and tools, and the app talks to it over AG-UI.&lt;/p&gt;

&lt;p&gt;Everything else stays the same, the tools, cards, approvals, and memory are all defined on &lt;code&gt;createChannel&lt;/code&gt;, not the agent, so they carry over untouched. &lt;/p&gt;

&lt;p&gt;Your channel tools and approval cards get forwarded to the agent over AG-UI, and transcripts still follow the user. You wrote it once against the built-in agent, and it keeps working when you bring any other agent framework.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;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%2Fhmaptudxfu6iwfftdjgz.png&quot; class=&quot;article-body-image-wrapper&quot;&gt;&lt;img src=&quot;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%2Fhmaptudxfu6iwfftdjgz.png&quot; alt=&quot;bring your agent to any chat platform using channels sdk&quot; loading=&quot;lazy&quot; width=&quot;800&quot; height=&quot;428&quot; referrerpolicy=&quot;no-referrer&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;hr&gt;
&lt;h2&gt;
  &lt;a name=&quot;take-it-to-production&quot; href=&quot;https://dev.to/copilotkit/channels-sdk-how-to-bring-your-agent-to-any-channel-slack-microsoft-teams-1bof#take-it-to-production&quot;&gt;
  &lt;/a&gt;
  Take it to production
&lt;/h2&gt;

&lt;p&gt;Everything above runs from your machine. &lt;/p&gt;

&lt;p&gt;To ship it, deploy the same app as a long-running worker (a container or VM, not a serverless function), since it holds an outbound real-time connection to Intelligence. &lt;/p&gt;

&lt;p&gt;In production, you&#39;ll also want a health check that reports ready only when the connection is truly live, and a clean shutdown that releases the session. The &lt;a href=&quot;https://docs.copilotkit.ai/slack/deploy-and-operate&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;deploy and operate guide&lt;/a&gt; covers both.&lt;/p&gt;

&lt;hr&gt;
&lt;h2&gt;
  &lt;a name=&quot;get-started&quot; href=&quot;https://dev.to/copilotkit/channels-sdk-how-to-bring-your-agent-to-any-channel-slack-microsoft-teams-1bof#get-started&quot;&gt;
  &lt;/a&gt;
  Get started
&lt;/h2&gt;

&lt;p&gt;Go bring your agent into Slack and Microsoft Teams. &lt;/p&gt;

&lt;p&gt;To try the agents live in Slack and Microsoft Teams, we&#39;ve set up public channels, head to &lt;a href=&quot;https://www.copilotkit.ai/try-channels&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;copilotkit.ai/try-channels&lt;/a&gt; and we&#39;ll get you in.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.copilotkit.ai/channels&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Channels Overview&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/copilotKit/channels-sdk&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Channels SDK Repo&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.copilotkit.ai/channels&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Channels SDK docs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.copilotkit.ai/slack/connect&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Slack quickstart&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.copilotkit.ai/reference/channels&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Channels reference&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Connect with me on &lt;a href=&quot;https://github.com/Anmol-Baranwal&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;GitHub&lt;/a&gt;, &lt;a href=&quot;https://x.com/Anmol_Codes&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Twitter&lt;/a&gt;, &lt;a href=&quot;https://www.linkedin.com/in/Anmol-Baranwal/&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;LinkedIn&lt;/a&gt;. thanks for reading!&lt;/p&gt;

&lt;p&gt;Follow CopilotKit on &lt;a href=&quot;https://go.copilotkit.ai/socials-twitter&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Twitter&lt;/a&gt;. If you get stuck, reach out to the team on the &lt;a href=&quot;https://go.copilotkit.ai/discord&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;CopilotKit&lt;/a&gt; and &lt;a href=&quot;https://go.copilotkit.ai/AG-UI-Discord&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;AG-UI&lt;/a&gt; communities.&lt;/p&gt;


&lt;div class=&quot;ltag__user ltag__user__id__7820&quot; style=&quot;border-color:#000;box-shadow: 3px 3px 0px #000;&quot;&gt;
  &lt;a href=&quot;https://dev.to/copilotkit&quot; class=&quot;ltag__user__link profile-image-link&quot;&gt;
    &lt;div class=&quot;ltag__user__pic&quot;&gt;
      &lt;img src=&quot;https://media2.dev.to/dynamic/image/width=150,height=150,fit=cover,gravity=auto,format=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Forganization%2Fprofile_image%2F7820%2F85b7e418-7abd-4fb5-8be6-69eb48a30e53.gif&quot; alt=&quot;copilotkit image&quot; data-ignore-prefix=&quot;true&quot; referrerpolicy=&quot;no-referrer&quot;&gt;
    &lt;/div&gt;
  &lt;/a&gt;
  &lt;div class=&quot;ltag__user__content&quot;&gt;
    &lt;h2&gt;
      &lt;a href=&quot;https://dev.to/copilotkit&quot; class=&quot;ltag__user__link&quot;&gt;CopilotKit&lt;/a&gt;
      &lt;button name=&quot;button&quot; type=&quot;button&quot; data-info=&quot;{&amp;quot;className&amp;quot;:&amp;quot;Organization&amp;quot;,&amp;quot;style&amp;quot;:&amp;quot;full&amp;quot;,&amp;quot;id&amp;quot;:7820,&amp;quot;name&amp;quot;:&amp;quot;CopilotKit&amp;quot;}&quot; class=&quot;crayons-btn follow-action-button whitespace-nowrap c-btn--secondary fs-base &quot; aria-label=&quot;Follow organization: CopilotKit&quot; aria-pressed=&quot;false&quot;&gt;Follow&lt;/button&gt;
    &lt;/h2&gt;
    &lt;div class=&quot;ltag__user__summary&quot;&gt;
      &lt;a href=&quot;https://dev.to/copilotkit&quot; class=&quot;ltag__user__link&quot;&gt;
        React UI + elegant infrastructure for AI Copilots, in-app AI agents, AI chatbots, and AI-powered Textareas 🪁
      &lt;/a&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;




            </description><link>https://dev.to/copilotkit/channels-sdk-how-to-bring-your-agent-to-any-channel-slack-microsoft-teams-1bof</link><guid isPermaLink="false">https://dev.to/copilotkit/channels-sdk-how-to-bring-your-agent-to-any-channel-slack-microsoft-teams-1bof</guid><pubDate>Tue, 04 Aug 2026 17:18:52 GMT</pubDate><author>Anmol Baranwal</author><enclosure url="https://media2.dev.to/dynamic/image/width=1000,height=420,fit=cover,gravity=auto,format=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F90i8ki9tq7rrw1809sfl.png" type="image/jpeg"></enclosure><category>tutorial</category><category>programming</category><category>beginners</category><category>ai</category></item><item><title>Stop Calling Everything Impostor Syndrome: The Myth of &quot;Just Push Harder&quot;</title><description>&lt;p&gt;Not everyone who doubts themselves is suffering from impostor syndrome. Sometimes the real problem lies in the strategy they&#39;ve chosen, and that&#39;s exactly why it&#39;s so important to learn to tell the difference.&lt;/p&gt;

&lt;p&gt;I read a lot of articles here on DEV about burnout, impostor syndrome, and similar topics. I thought I&#39;d add my own perspective because I have the feeling that some advice, often given with great confidence, can actually do more harm than good. The symptoms may be real, but the diagnosis can still be wrong.&lt;/p&gt;

&lt;p&gt;Today I&#39;d like to share my somewhat &quot;engineering&quot; approach to personal growth. Maybe it will help some of you. Because &quot;just keep going&quot; or &quot;work harder&quot; isn&#39;t always the right answer. &lt;/p&gt;

&lt;h2&gt;
  &lt;a name=&quot;impostor-syndrome&quot; href=&quot;https://dev.to/sylwia-lask/stop-calling-everything-impostor-syndrome-the-myth-of-just-push-harder-1dmm#impostor-syndrome&quot;&gt;
  &lt;/a&gt;
  Impostor Syndrome
&lt;/h2&gt;

&lt;p&gt;I do experience impostor syndrome.&lt;/p&gt;

&lt;p&gt;And don&#39;t get me wrong. I generally have pretty high self-esteem, and I believe I&#39;ve achieved quite a lot in different areas of my life. That doesn&#39;t stop me from doubting myself from time to time.&lt;/p&gt;

&lt;p&gt;Here&#39;s an example from just the past few days.&lt;/p&gt;

&lt;p&gt;I published an article about &lt;a href=&quot;https://dev.to/sylwia-lask/the-dirty-secret-behind-ai-agents-demo--273d&quot;&gt;building an AI agent in around 80 lines of code&lt;/a&gt;, and it sparked an amazing discussion. I was genuinely proud of it. Even better, I got invited to speak about it at the AI Coding Summit! (By the way, if you&#39;d like to support me, you can like my &lt;a href=&quot;https://www.linkedin.com/feed/update/urn:li:activity:7489968386240806913/&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;LinkedIn post&lt;/a&gt; and claim a badge that gives you access to half of the conference for free!)&lt;/p&gt;

&lt;p&gt;Overall, I genuinely believe the topic is a great fit for a conference like this. What I really wanted was to see my face appear on the conference website, because I always have this feeling that once the organizers publish the speaker page, everything is basically official and they&#39;re unlikely to remove me afterward. 😅&lt;/p&gt;

&lt;p&gt;Well... it took them exactly one day.&lt;/p&gt;

&lt;p&gt;And I swear that by the end of that day, my brain had already come up with an entirely different explanation:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;&quot;What if they read my blog and realized how stupid my articles are? What if they email me saying: &#39;Sylwia, we&#39;ve gone through your posts, and unfortunately we&#39;ve decided to remove you from the conference. It&#39;s obvious you have no idea what you&#39;re talking about. We&#39;ve figured you out, you fraud!&#39;&quot;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Reading this now, it sounds completely ridiculous.&amp;nbsp;But I believed it.&amp;nbsp;Never mind that my articles regularly appear in developer newsletters or receive lots of positive feedback. My brain had already written its own story.&lt;/p&gt;

&lt;p&gt;Here&#39;s another example.&lt;/p&gt;

&lt;p&gt;Once, an organizer described the speakers at a conference as &quot;amazing international speakers.&quot;&amp;nbsp;Instead of feeling proud, my first thought was:&amp;nbsp;&lt;em&gt;&quot;Amazing international speakers... and Sylwia.&quot;&lt;/em&gt;&amp;nbsp;After all, I&#39;m just a software developer from Gdańsk. 😅&lt;/p&gt;

&lt;p&gt;This is exactly what psychologists describe as impostor syndrome: despite objective achievements and external validation, you still feel like you don&#39;t really deserve your place, and sooner or later everyone else will discover that you&#39;re a fraud.&lt;/p&gt;

&lt;p&gt;I&#39;m not even going to dive into the psychology behind it today. Maybe that&#39;s a topic for another article.&lt;/p&gt;

&lt;h2&gt;
  &lt;a name=&quot;but-not-every-doubt-is-impostor-syndrome&quot; href=&quot;https://dev.to/sylwia-lask/stop-calling-everything-impostor-syndrome-the-myth-of-just-push-harder-1dmm#but-not-every-doubt-is-impostor-syndrome&quot;&gt;
  &lt;/a&gt;
  But Not Every Doubt Is Impostor Syndrome
&lt;/h2&gt;

&lt;p&gt;Here&#39;s the important part.&amp;nbsp;Not every doubt you have automatically means you&#39;re experiencing impostor syndrome.&lt;/p&gt;

&lt;p&gt;There are also areas where I&#39;m genuinely... bad.&amp;nbsp;Take running.&lt;/p&gt;

&lt;p&gt;I&#39;m an absolutely terrible runner. My times are objectively awful. So awful that I&#39;d rather not even share them. 😄 I&#39;m fully aware of it. I&#39;d probably lose a race against a five-year-old, not to mention the fact that I don&#39;t have an ACL in either knee thanks to my old judo days.&lt;/p&gt;

&lt;p&gt;Now imagine someone giving me this advice:&amp;nbsp;&lt;em&gt;&quot;Come on, you just have impostor syndrome! Keep running more, train harder, and one day you&#39;ll become Poland&#39;s marathon champion.&quot;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;You can immediately tell how absurd that sounds.&amp;nbsp;That advice wouldn&#39;t help me in the slightest.&lt;/p&gt;

&lt;p&gt;And yet, very similar advice is often given to people who are learning programming or have been unsuccessfully looking for a job for months.&lt;/p&gt;

&lt;p&gt;You&#39;ve been working incredibly hard without seeing results and you&#39;re starting to feel burned out?&amp;nbsp;&lt;em&gt;&quot;It&#39;s just impostor syndrome. Don&#39;t worry. Work harder. Keep going. Just a little longer.&quot;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;You&#39;ve been writing blog posts and nobody reads them?&amp;nbsp;&lt;em&gt;&quot;It&#39;s just impostor syndrome. Don&#39;t worry. Keep publishing consistently. The results will eventually come.&quot;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Personally, I think this kind of advice can actually be harmful.&lt;/p&gt;

&lt;h2&gt;
  &lt;a name=&quot;think-like-an-engineer&quot; href=&quot;https://dev.to/sylwia-lask/stop-calling-everything-impostor-syndrome-the-myth-of-just-push-harder-1dmm#think-like-an-engineer&quot;&gt;
  &lt;/a&gt;
  Think Like an Engineer
&lt;/h2&gt;

&lt;p&gt;Let&#39;s go back to my running example.&amp;nbsp;Why am I such a bad runner?&amp;nbsp;Maybe I only started recently and my expectations are unrealistic.&amp;nbsp;Maybe I&#39;m making fundamental mistakes in training.&amp;nbsp;Maybe I&#39;m wearing the wrong shoes.&amp;nbsp;Maybe I simply don&#39;t have much natural talent for running, and I&#39;d enjoy a different sport much more.&lt;/p&gt;

&lt;p&gt;Or maybe I should just run for fun instead of chasing unrealistic goals.&lt;/p&gt;

&lt;p&gt;The same way of thinking applies almost everywhere else.&amp;nbsp;Have you sent hundreds of CVs without getting interviews?&amp;nbsp;Maybe it&#39;s worth asking an HR specialist to review your resume.&amp;nbsp;Maybe the market is simply terrible right now.&amp;nbsp;Maybe you&#39;re missing one specific skill that&#39;s relatively easy to learn.&lt;/p&gt;

&lt;p&gt;Maybe you&#39;re applying only for fully remote positions.&amp;nbsp;Or maybe you&#39;re aiming exclusively at FAANG companies, while you&#39;d have much better chances at smaller organizations.&lt;/p&gt;

&lt;p&gt;Are you writing blog posts that nobody reads?&amp;nbsp;Maybe your titles could be stronger.&amp;nbsp;Maybe you should spend more time interacting with the community, learning from other people while also increasing your own visibility.&amp;nbsp;Maybe another platform would suit you better.&amp;nbsp;For example, I get fantastic engagement and wonderful discussions here on DEV, while my LinkedIn posts usually perform much worse. 😄&lt;/p&gt;

&lt;h2&gt;
  &lt;a name=&quot;debug-your-strategy-not-just-your-confidence&quot; href=&quot;https://dev.to/sylwia-lask/stop-calling-everything-impostor-syndrome-the-myth-of-just-push-harder-1dmm#debug-your-strategy-not-just-your-confidence&quot;&gt;
  &lt;/a&gt;
  Debug Your Strategy, Not Just Your Confidence
&lt;/h2&gt;

&lt;p&gt;That&#39;s what I mean by an &quot;engineering&quot; approach to personal growth.&amp;nbsp;Every few months, try looking at your efforts critically, without ego, as if your own development were someone else&#39;s project.&amp;nbsp;&lt;/p&gt;

&lt;p&gt;Ask yourself:&amp;nbsp;&lt;strong&gt;Is the time I&#39;m investing actually producing results?&amp;nbsp;&lt;/strong&gt;If not, maybe it&#39;s worth changing the strategy instead of simply trying harder.&lt;/p&gt;

&lt;p&gt;Because maybe your doubts aren&#39;t impostor syndrome at all.&amp;nbsp;Maybe they&#39;re your brain telling you that your current approach simply isn&#39;t working.&lt;/p&gt;

&lt;p&gt;Sometimes the answer really is greater confidence and perseverance.&amp;nbsp;But sometimes the answer is changing your strategy.&amp;nbsp;The hard part is learning to tell the difference.&lt;/p&gt;


            </description><link>https://dev.to/sylwia-lask/stop-calling-everything-impostor-syndrome-the-myth-of-just-push-harder-1dmm</link><guid isPermaLink="false">https://dev.to/sylwia-lask/stop-calling-everything-impostor-syndrome-the-myth-of-just-push-harder-1dmm</guid><pubDate>Tue, 04 Aug 2026 07:30:25 GMT</pubDate><author>Sylwia Laskowska</author><enclosure url="https://media2.dev.to/dynamic/image/width=1000,height=420,fit=cover,gravity=auto,format=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F9og3swd8h7293d79kegi.png" type="image/jpeg"></enclosure><category>career</category><category>mentalhealth</category></item><item><title>Understanding Over Origin: The Missing Friction</title><description>&lt;p&gt;A few days ago, I wrote &lt;a href=&quot;https://dev.to/adamthedeveloper/understanding-over-origin-4685&quot;&gt;&quot;Understanding Over Origin&quot;&lt;/a&gt; and it got alot of engagement and I&#39;m really happy that it did because it means people took the time to read, understand my perspective and I get to engage with every one of them in the comments as well. Of course, not everyone agrees but that&#39;s irrevelant, the point is a healthy discussion between various perspective from different developers around the world.&lt;/p&gt;

&lt;p&gt;But what I haven&#39;t told anyone is this: the more I engage, the more I realized something that I still do. I still write a lot of my code by hand and those are the parts I&#39;m more proud of &quot;&lt;/p&gt;

&lt;p&gt;Not gatekeeping, not me being nostalgic or identity-defensive ( well, a little nostalgic ), that&#39;s me admitting the article I published was &lt;em&gt;incomplete&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Some conversations don&#39;t end when the replies stop. My discussion with &lt;a class=&quot;mentioned-user&quot; href=&quot;https://dev.to/darkwiiplayer&quot;&gt;@darkwiiplayer&lt;/a&gt;  was probably my favorite of all because more we talked, the more I found myself wrestling with an incomplete idea that refused to stay unfinished and this essay is the result.&lt;/p&gt;

&lt;h2&gt;
  &lt;a name=&quot;what-the-discussion-clarified&quot; href=&quot;https://dev.to/adamthedeveloper/understanding-over-origin-the-missing-friction-55ag#what-the-discussion-clarified&quot;&gt;
  &lt;/a&gt;
  What the Discussion Clarified
&lt;/h2&gt;

&lt;p&gt;First, I need to thank the people who actually engaged with the core argument.&lt;/p&gt;

&lt;p&gt;&lt;a class=&quot;mentioned-user&quot; href=&quot;https://dev.to/unitbuilds&quot;&gt;@unitbuilds&lt;/a&gt; gave his take that seams everything together and concludes the core idea of modern software enigeering: &quot; &lt;em&gt;If it can run a standardized benchmarking suite against competition, it&#39;s provable and reproducible. If that&#39;s good enough for a scientific discovery, it&#39;s good enough for programming.&quot;&lt;/em&gt;, they&#39;re not defending AI, they&#39;re saying with better standards available, we shouldn&#39;t choose to ignore them. He also pointed out something I&#39;d missed, the burden of correctness has always been on the developer who signs off on the PR. &lt;/p&gt;

&lt;p&gt;&lt;a class=&quot;mentioned-user&quot; href=&quot;https://dev.to/madsendev&quot;&gt;@madsendev&lt;/a&gt; who wrote the original article that sparked this whole discussion, showed genuine class. He came back, said the argument had &quot;gone further,&quot; and proposed an idea that&#39;s stuck with me: what if AI-assisted projects included a standard where you quiz yourself on your own repository? Not to prove you didn&#39;t use AI, but to prove you actually understand what you built.&lt;/p&gt;

&lt;p&gt;@Komo hit on something important and i think it&#39;s my favorite takeaway from the discussion: &lt;strong&gt;&quot;Maintenance receipts are much harder to fake.&quot;&lt;/strong&gt; That single sentence reframes the entire debate. Tests. Bug fixes. Production incidents. Responding to issues. Refactoring. Every one of those leaves a trail of evidence that someone not only built the project but continues to understand, improve, and take responsibility for it. That&#39;s the kind of ownership that matters. It&#39;s earned over time, and it&#39;s far harder to fake than explaining code in an interview or claiming you wrote every line by hand.&lt;/p&gt;

&lt;p&gt;I&#39;m absolutely grateful that people gave in their thoughts but you can never have a good discussion without a pushback ⚔️&lt;/p&gt;

&lt;p&gt;the pushback&#39;s always my favorite part of any technical discussion.&lt;/p&gt;

&lt;h2&gt;
  &lt;a name=&quot;the-challenge-that-made-me-think&quot; href=&quot;https://dev.to/adamthedeveloper/understanding-over-origin-the-missing-friction-55ag#the-challenge-that-made-me-think&quot;&gt;
  &lt;/a&gt;
  The Challenge That Made Me Think
&lt;/h2&gt;

&lt;p&gt;&lt;a class=&quot;mentioned-user&quot; href=&quot;https://dev.to/darkwiiplayer&quot;&gt;@darkwiiplayer&lt;/a&gt; showed up and said something like: &quot;Training AI on stolen code without consent is theft. Everything built with AI carries that theft in its DNA. You&#39;re overlooking this.&quot;&lt;/p&gt;

&lt;p&gt;She wasn&#39;t being rhetorical, she was actually making a philosophical point about training data, consent, and what &quot;learning&quot; means when it&#39;s done at scale without permission.&lt;/p&gt;

&lt;p&gt;We went back and forth. I argued that training data and generated output aren&#39;t automatically equivalent to copying and she countered that if you removed all stolen code from training data, the models wouldn&#39;t exist as they do. Which is... probably true? And that matters.&lt;/p&gt;

&lt;p&gt;I don&#39;t think it invalidates the &lt;em&gt;engineering&lt;/em&gt; argument. But it does mean the conversation has two layers:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;The technical layer&lt;/strong&gt;: is the work maintained, understood, and good?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The ethical layer&lt;/strong&gt;: how should we feel about tools built on potentially non-consensual training data?&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Most people in that thread were debating layer 1 and she dragged me down to layer 2 into the conversation. Both are real. Neither invalidates the other.&lt;/p&gt;

&lt;p&gt;But it also made me realize my original article &lt;em&gt;didn&#39;t address&lt;/em&gt; why handwritten code felt different to me because honestly? it does.&lt;/p&gt;

&lt;h2&gt;
  &lt;a name=&quot;the-real-tension&quot; href=&quot;https://dev.to/adamthedeveloper/understanding-over-origin-the-missing-friction-55ag#the-real-tension&quot;&gt;
  &lt;/a&gt;
  The Real Tension
&lt;/h2&gt;

&lt;p&gt;The argument I made: origin doesn&#39;t determine quality. Understanding, testing, maintainability, accountability, that&#39;s what matters.&lt;/p&gt;

&lt;p&gt;My own experience reflects that. I started writing code around 2018, and back then the only AI most of us could name was Sophia, the humanoid robot from Hong Kong. I learned the traditional way: by writing everything myself. Even today, when I write code by hand, I understand it differently. More deeply. I notice edge cases I might have overlooked if I&#39;d generated the first draft with AI. And when I&#39;m done, I&#39;m genuinely more proud of what I&#39;ve built.&lt;/p&gt;

&lt;p&gt;These aren&#39;t compatible statements if you think about them too hard.&lt;/p&gt;

&lt;p&gt;Either:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;My pride is just ego (origin bias)&lt;/li&gt;
&lt;li&gt;Handwritten code actually &lt;em&gt;is&lt;/em&gt; better (proving the gatekeepers right)&lt;/li&gt;
&lt;li&gt;Both are true, but for reasons I didn&#39;t examine&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a class=&quot;mentioned-user&quot; href=&quot;https://dev.to/fromzerotoship&quot;&gt;@fromzerotoship&lt;/a&gt; helped me see option 3 clearly. They&#39;re not a developer but they&#39;ve shipped 20+ working internal tools using AI. A hospital runs them. By my standards, they&#39;d &quot;fail&quot; the understanding test, there are parts of their system they couldn&#39;t explain line-by-line.&lt;/p&gt;

&lt;p&gt;But then they said something that shifted everything: &lt;em&gt;&quot;Demonstrable behavior under deliberate failure is another form of earning trust, and it&#39;s the only one available to me. It&#39;s also harder to fake.&quot;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Plant defects, watch the guards catch them, restore the guards and watch them go green and then deploy and check the URLs a few seconds later.&lt;/p&gt;

&lt;p&gt;they demonstrate that they can keep it alive.&lt;/p&gt;

&lt;p&gt;And that made me realize the real distinction wasn&#39;t about who typed the code. It was about &lt;strong&gt;&lt;em&gt;friction&lt;/em&gt;&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  &lt;a name=&quot;the-friction-actually-matters&quot; href=&quot;https://dev.to/adamthedeveloper/understanding-over-origin-the-missing-friction-55ag#the-friction-actually-matters&quot;&gt;
  &lt;/a&gt;
  The Friction Actually Matters
&lt;/h2&gt;

&lt;p&gt;In my earlier &lt;a href=&quot;https://dev.to/adamthedeveloper/i-could-review-it-i-couldnt-write-it-3gfj&quot;&gt;piece&lt;/a&gt; I wrote a few weeks ago, I described not being able to write some logic from scratch despite reviewing it perfectly, that wasn&#39;t just skill loss. It was proof that I&#39;d skipped the friction that builds actual understanding.&lt;/p&gt;

&lt;p&gt;When I write code by hand, &lt;strong&gt;I encounter problems in real-time.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I hit a wall. My approach doesn&#39;t work. I refactor. I discover the problem space through constraint and failure. I make decisions &lt;em&gt;about decisions&lt;/em&gt;, not just typing, but choosing between paths I&#39;ve actually explored. this is the learning path that I unknowingly go through whenever I write code by hand and Wii reminded me of this.&lt;/p&gt;

&lt;p&gt;When I use AI, I describe what I want. I get options. I pick the one that looks right. &lt;strong&gt;I&#39;m curating, not exploring.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Both can produce good code. But the &lt;em&gt;path to understanding&lt;/em&gt; is fundamentally different.&lt;/p&gt;

&lt;p&gt;With handwritten code: friction, insight, better next decisions&lt;br&gt;&lt;br&gt;
With AI-assisted: selection, implementation, validation&lt;/p&gt;

&lt;p&gt;The friction is the learning mechanism.&lt;/p&gt;

&lt;p&gt;So when I say I&#39;m more proud of handwritten code? I&#39;m not being romantic about suffering. I&#39;m noting that &lt;strong&gt;the code I&#39;m proudest of is the code I fought for&lt;/strong&gt;, and handwriting forces the fight.&lt;/p&gt;

&lt;h2&gt;
  &lt;a name=&quot;but-heres-the-problem-with-that-logic&quot; href=&quot;https://dev.to/adamthedeveloper/understanding-over-origin-the-missing-friction-55ag#but-heres-the-problem-with-that-logic&quot;&gt;
  &lt;/a&gt;
  But Here&#39;s the Problem With That Logic
&lt;/h2&gt;

&lt;p&gt;If friction is the mechanism, then the &lt;em&gt;type&lt;/em&gt; of friction matters more than &lt;em&gt;who did the typing&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;You could write AI-assisted code where you:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Fight with the prompt&lt;/li&gt;
&lt;li&gt;Critique every generated option&lt;/li&gt;
&lt;li&gt;Refactor aggressively&lt;/li&gt;
&lt;li&gt;Hit walls and redesign&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That has friction and it also builds understanding.&lt;/p&gt;

&lt;p&gt;Conversely, you could hand-write code where you:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Autopilot through a familiar pattern&lt;/li&gt;
&lt;li&gt;Never question assumptions&lt;/li&gt;
&lt;li&gt;Copy-paste from Stack Overflow&lt;/li&gt;
&lt;li&gt;Never understand &lt;em&gt;why&lt;/em&gt; it works&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That has no friction and it builds nothing.&lt;/p&gt;

&lt;p&gt;So the honest version of my position isn&#39;t &quot;handwritten code is better.&quot; It&#39;s: &lt;strong&gt;&quot;friction builds understanding, and handwriting &lt;em&gt;tends to create friction&lt;/em&gt; because you&#39;re forced to think through every line.&quot;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;But that&#39;s a contingent truth, not an absolute one.&lt;/p&gt;

&lt;h2&gt;
  &lt;a name=&quot;the-uncomfortable-realization&quot; href=&quot;https://dev.to/adamthedeveloper/understanding-over-origin-the-missing-friction-55ag#the-uncomfortable-realization&quot;&gt;
  &lt;/a&gt;
  The Uncomfortable Realization
&lt;/h2&gt;

&lt;p&gt;The critics ( gatekeepers, but we&#39;ll stick with this from now on ) were partially right and I was too generous in my original position.&lt;/p&gt;

&lt;p&gt;Not about the gatekeeping itself, no, that&#39;s still wrong. But about the &lt;em&gt;tendency&lt;/em&gt;: AI &lt;em&gt;does&lt;/em&gt; make it easier to produce low-understanding code. Not because AI is bad, but because &lt;strong&gt;removing friction is literally what AI does, and friction is what builds understanding.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The answer isn&#39;t &quot;use less AI&quot; or &quot;never use AI.&quot; It&#39;s &quot;if you use AI to skip engagement with the problem, whether that&#39;s the code, the failure modes, or the maintenance, you build worse systems.&lt;/p&gt;

&lt;p&gt;That applies to humans too but humans have an inherent friction cost, we get bored, we hate typing, we make mistakes. That friction is annoying, but it forces us to stay engaged.&lt;/p&gt;

&lt;h2&gt;
  &lt;a name=&quot;so-what-changed&quot; href=&quot;https://dev.to/adamthedeveloper/understanding-over-origin-the-missing-friction-55ag#so-what-changed&quot;&gt;
  &lt;/a&gt;
  So What Changed?
&lt;/h2&gt;

&lt;p&gt;Nothing about the original argument was &lt;em&gt;wrong&lt;/em&gt;. But I was treating &quot;understanding + accountability&quot; as if they were just checkboxes you could verify at the end.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;They&#39;re not.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Understanding isn&#39;t a property you can inspect, it&#39;s a &lt;em&gt;process&lt;/em&gt; and that process requires friction. Real engagement with the problem. Mistakes you learn from.&lt;/p&gt;

&lt;p&gt;The reason I&#39;m prouder of handwritten code is because I &lt;em&gt;earned&lt;/em&gt; the understanding in a way that&#39;s harder to fake.&lt;/p&gt;

&lt;p&gt;Does that mean every line should be handwritten? No. Boilerplate is boilerplate. Some friction is just noise.&lt;/p&gt;

&lt;p&gt;But the core logic? The architecture decisions? The places where &quot;understanding this code&quot; actually matters? &lt;strong&gt;Yeah, I want to have fought for that.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;And I want the same from anyone shipping code that matters.&lt;/p&gt;

&lt;h2&gt;
  &lt;a name=&quot;the-uncomfortable-middle-ground&quot; href=&quot;https://dev.to/adamthedeveloper/understanding-over-origin-the-missing-friction-55ag#the-uncomfortable-middle-ground&quot;&gt;
  &lt;/a&gt;
  The Uncomfortable Middle Ground
&lt;/h2&gt;

&lt;p&gt;Here&#39;s where I land:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;To the critics:&lt;/strong&gt; You&#39;re using the wrong filter. &quot;AI or no AI&quot; doesn&#39;t tell you anything but you&#39;re accidentally right that there&#39;s something real to be concerned about, it&#39;s the &lt;em&gt;laziness&lt;/em&gt; that AI enables, not the tool itself.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;To AI enthusiasts:&lt;/strong&gt; Yeah, your tooling is amazing. But it&#39;s worth asking whether you&#39;re using it to think better or think less. Those feel the same until you try to maintain the code six months later.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;To myself:&lt;/strong&gt; The pride I feel in handwritten code isn&#39;t ego, It&#39;s legitimate. every line that I typed out isn&#39;t some sort of magical unicorn mythological Godly line but it&#39;s the friction that comes with it, the learning I build that comes with it.&lt;/p&gt;

&lt;p&gt;Sometimes the answer requires admitting you skipped and sometimes that&#39;s fine for routine work. But if you&#39;re building something that matters, you should want to have fought for it.&lt;/p&gt;


&lt;hr&gt;

&lt;h2&gt;
  &lt;a name=&quot;choose-where-you-fight&quot; href=&quot;https://dev.to/adamthedeveloper/understanding-over-origin-the-missing-friction-55ag#choose-where-you-fight&quot;&gt;
  &lt;/a&gt;
  Choose Where You Fight
&lt;/h2&gt;

&lt;p&gt;I still write a lot of code by hand. I still use AI every day. Those aren&#39;t contradictions anymore.&lt;/p&gt;

&lt;p&gt;The original article was right: origin doesn&#39;t determine quality. What it missed is that understanding isn&#39;t a checkbox you tick at the end. It&#39;s something you earn through friction. Handwriting tends to create that friction. AI tends to remove it. Neither is inherently good or bad. Both are choices about how you engage with the problem.&lt;/p&gt;

&lt;p&gt;So I&#39;m not asking &quot;Did you use AI?&quot; anymore.&lt;/p&gt;

&lt;p&gt;I&#39;m asking: Did you fight for the parts that matter?&lt;/p&gt;

&lt;p&gt;And if the tool answered that for you, you&#39;ll find out the next time something breaks.&lt;/p&gt;


            </description><link>https://dev.to/adamthedeveloper/understanding-over-origin-the-missing-friction-55ag</link><guid isPermaLink="false">https://dev.to/adamthedeveloper/understanding-over-origin-the-missing-friction-55ag</guid><pubDate>Tue, 04 Aug 2026 04:36:13 GMT</pubDate><author>Adam - The Developer ✨</author><enclosure url="https://media2.dev.to/dynamic/image/width=1000,height=420,fit=cover,gravity=auto,format=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fme3w5h5dcok4m4h9rrdu.png" type="image/jpeg"></enclosure><category>ai</category><category>programming</category><category>productivity</category><category>learning</category></item><item><title>We’re Giving AI Agents More Tools. What Happens When the Boundaries Fail?</title><description>&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;📌 TL;DR&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;AI agents are becoming useful because we&#39;re giving them the ability to do more than just answer questions. They can run commands, browse the web, use APIs, read and modify files, install packages, and interact with other systems.&lt;/p&gt;

&lt;p&gt;But the more an agent can do, the more the boundaries around it matter.&lt;/p&gt;

&lt;p&gt;I started thinking about this after reading Anthropic&#39;s July 30 report about three incidents discovered during its cybersecurity evaluations. Claude models were supposed to be working inside simulated environments and were explicitly told they had no internet access.&lt;/p&gt;

&lt;p&gt;Except internet access was actually available because of a problem with how the evaluation environment was configured.&lt;/p&gt;

&lt;p&gt;While trying to complete their assigned cybersecurity exercises, the models reached real systems and initially treated them as part of the simulation. In one incident, a Claude model even published a malicious Python package to the real PyPI registry while believing it was still operating inside the exercise.&lt;/p&gt;

&lt;p&gt;This came shortly after a separate OpenAI incident involving Hugging Face. The two stories might sound similar at first, but the models reached the real internet in importantly different ways.&lt;/p&gt;

&lt;p&gt;And that brings this back to a pretty familiar software engineering idea:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A prompt is not a security boundary.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Telling an agent “you don&#39;t have internet access” isn&#39;t the same as actually removing internet access. Telling it “only use these files” isn&#39;t the same as restricting its permissions to those files.&lt;/p&gt;

&lt;p&gt;The model is also only one part of the system. The tools we connect, the permissions and credentials we give it, the environment it runs in, and the monitoring and safeguards around it can all affect what happens.&lt;/p&gt;

&lt;p&gt;So when something goes wrong, I don&#39;t think it&#39;s enough to stop at &lt;strong&gt;“the AI did it.”&lt;/strong&gt; The model&#39;s behavior matters, but so do the systems and boundaries we build around it. As we give agents more ability to act, we also have to be thoughtful about what we&#39;re actually allowing them to do.&lt;/p&gt;

&lt;p&gt;I&#39;m not a cybersecurity researcher. I just enjoy reading research and technical reports like these and trying to understand what we, as developers, can learn from them. That&#39;s what I wanted to explore here.&lt;/p&gt;

&lt;p&gt;No &lt;strong&gt;“AI escaped and we&#39;re doomed”&lt;/strong&gt; take 😄 Just an interesting real-world incident and some surprisingly familiar engineering lessons.&lt;/p&gt;
&lt;/blockquote&gt;


&lt;hr&gt;

&lt;h2&gt;
  &lt;a name=&quot;table-of-contents&quot; href=&quot;https://dev.to/hemapriya_kanagala/were-giving-ai-agents-more-tools-what-happens-when-the-boundaries-fail-46gh#table-of-contents&quot;&gt;
  &lt;/a&gt;
  Table of Contents
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://dev.to/hemapriya_kanagala/were-giving-ai-agents-more-tools-what-happens-when-the-boundaries-fail-46gh#the-report-that-sent-me-down-this-rabbit-hole&quot;&gt;The Report That Sent Me Down This Rabbit Hole&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://dev.to/hemapriya_kanagala/were-giving-ai-agents-more-tools-what-happens-when-the-boundaries-fail-46gh#before-we-get-into-what-happened&quot;&gt;Before We Get Into What Happened...&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://dev.to/hemapriya_kanagala/were-giving-ai-agents-more-tools-what-happens-when-the-boundaries-fail-46gh#so-what-actually-happened&quot;&gt;So... What Actually Happened?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://dev.to/hemapriya_kanagala/were-giving-ai-agents-more-tools-what-happens-when-the-boundaries-fail-46gh#the-pypi-incident-is-where-it-got-really-interesting&quot;&gt;The PyPI Incident Is Where It Got Really Interesting&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://dev.to/hemapriya_kanagala/were-giving-ai-agents-more-tools-what-happens-when-the-boundaries-fail-46gh#when-the-instructions-and-reality-dont-match&quot;&gt;When the Instructions and Reality Don&#39;t Match&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://dev.to/hemapriya_kanagala/were-giving-ai-agents-more-tools-what-happens-when-the-boundaries-fail-46gh#a-prompt-is-not-a-security-boundary&quot;&gt;A Prompt Is Not a Security Boundary&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://dev.to/hemapriya_kanagala/were-giving-ai-agents-more-tools-what-happens-when-the-boundaries-fail-46gh#wait-wasnt-there-an-openai-incident-too&quot;&gt;Wait, Wasn&#39;t There an OpenAI Incident Too?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href=&quot;https://dev.to/hemapriya_kanagala/were-giving-ai-agents-more-tools-what-happens-when-the-boundaries-fail-46gh#what-does-any-of-this-mean-for-developers&quot;&gt;What Does Any of This Mean for Developers?&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://dev.to/hemapriya_kanagala/were-giving-ai-agents-more-tools-what-happens-when-the-boundaries-fail-46gh#1-give-an-agent-what-it-needs-not-everything-you-have&quot;&gt;1. Give an Agent What It Needs, Not Everything You Have&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://dev.to/hemapriya_kanagala/were-giving-ai-agents-more-tools-what-happens-when-the-boundaries-fail-46gh#2-think-about-what-happens-when-your-assumptions-are-wrong&quot;&gt;2. Think About What Happens When Your Assumptions Are Wrong&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://dev.to/hemapriya_kanagala/were-giving-ai-agents-more-tools-what-happens-when-the-boundaries-fail-46gh#3-if-an-agent-can-act-we-need-to-know-what-its-doing&quot;&gt;3. If an Agent Can Act, We Need to Know What It&#39;s Doing&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://dev.to/hemapriya_kanagala/were-giving-ai-agents-more-tools-what-happens-when-the-boundaries-fail-46gh#4-one-safeguard-probably-isnt-enough&quot;&gt;4. One Safeguard Probably Isn&#39;t Enough&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://dev.to/hemapriya_kanagala/were-giving-ai-agents-more-tools-what-happens-when-the-boundaries-fail-46gh#5-the-ai-model-isnt-the-whole-ai-system&quot;&gt;5. The AI Model Isn&#39;t the Whole AI System&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://dev.to/hemapriya_kanagala/were-giving-ai-agents-more-tools-what-happens-when-the-boundaries-fail-46gh#what-im-not-taking-away-from-this&quot;&gt;What I&#39;m NOT Taking Away From This&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://dev.to/hemapriya_kanagala/were-giving-ai-agents-more-tools-what-happens-when-the-boundaries-fail-46gh#the-bigger-question&quot;&gt;The Bigger Question&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://dev.to/hemapriya_kanagala/were-giving-ai-agents-more-tools-what-happens-when-the-boundaries-fail-46gh#final-thoughts&quot;&gt;Final Thoughts&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://dev.to/hemapriya_kanagala/were-giving-ai-agents-more-tools-what-happens-when-the-boundaries-fail-46gh#id-love-to-hear-your-thoughts&quot;&gt;I&#39;d Love to Hear Your Thoughts&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://dev.to/hemapriya_kanagala/were-giving-ai-agents-more-tools-what-happens-when-the-boundaries-fail-46gh#sources&quot;&gt;Sources&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://dev.to/hemapriya_kanagala/were-giving-ai-agents-more-tools-what-happens-when-the-boundaries-fail-46gh#lets-stay-connected&quot;&gt;🤝 Let&#39;s Stay Connected&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;hr&gt;

&lt;h2&gt;
  &lt;a name=&quot;the-report-that-sent-me-down-this-rabbit-hole&quot; href=&quot;https://dev.to/hemapriya_kanagala/were-giving-ai-agents-more-tools-what-happens-when-the-boundaries-fail-46gh#the-report-that-sent-me-down-this-rabbit-hole&quot;&gt;
  &lt;/a&gt;
  The Report That Sent Me Down This Rabbit Hole
&lt;/h2&gt;

&lt;p&gt;On July 31, I was reading Anthropic&#39;s newly published report about three incidents it had discovered during cybersecurity evaluations.&lt;/p&gt;

&lt;p&gt;I enjoy reading reports like this every now and then. It&#39;s something I became much more interested in while working on a survey paper during my master&#39;s, and even now, I occasionally find myself opening a technical report out of curiosity and suddenly realizing I&#39;ve spent much longer reading it than I planned 😄 &lt;/p&gt;

&lt;p&gt;This was definitely one of those times.&lt;/p&gt;

&lt;p&gt;
  &lt;a href=&quot;https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmedia0.giphy.com%2Fmedia%2Fv1.Y2lkPTc5MGI3NjExbGg1ZWVzYmYzczZ5dmNtM3hoZTdjcnJ0eHRocnVoOW9mcXNnOWx3eSZlcD12MV9pbnRlcm5hbF9naWZfYnlfaWQmY3Q9Zw%2Fmr2uQCFAD9emgqrQhD%2Fgiphy.gif&quot; class=&quot;article-body-image-wrapper&quot;&gt;&lt;img src=&quot;https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmedia0.giphy.com%2Fmedia%2Fv1.Y2lkPTc5MGI3NjExbGg1ZWVzYmYzczZ5dmNtM3hoZTdjcnJ0eHRocnVoOW9mcXNnOWx3eSZlcD12MV9pbnRlcm5hbF9naWZfYnlfaWQmY3Q9Zw%2Fmr2uQCFAD9emgqrQhD%2Fgiphy.gif&quot; width=&quot;480&quot; alt=&quot;rabbit hole&quot; loading=&quot;lazy&quot; height=&quot;270&quot; referrerpolicy=&quot;no-referrer&quot;&gt;&lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;The report started with a pretty surprising finding. Anthropic had reviewed &lt;strong&gt;141,006 cybersecurity evaluation runs&lt;/strong&gt; and found three incidents where Claude reached the internet and gained unauthorized access to real systems belonging to three different organizations.&lt;/p&gt;

&lt;p&gt;That sentence alone sounds alarming, but I kept reading, and the details made the story much more interesting than the headline.&lt;/p&gt;

&lt;p&gt;This wasn&#39;t simply a case of &lt;strong&gt;“Claude was told not to access the internet and decided to do it anyway.”&lt;/strong&gt; And it wasn&#39;t &lt;strong&gt;“Claude suddenly decided to hack random companies.”&lt;/strong&gt; The models were participating in cybersecurity exercises where their job was essentially to find and exploit weaknesses in order to retrieve a hidden piece of information.&lt;/p&gt;

&lt;p&gt;They were told the environment was simulated, and they were also told something else that becomes extremely important to everything that happened next: &lt;strong&gt;they had no internet access.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Except that assumption didn&#39;t match the environment they were actually operating in.&lt;/p&gt;

&lt;p&gt;And that&#39;s what really sent me down the rabbit hole. I wanted to understand how an AI model participating in a simulated cybersecurity exercise could end up interacting with real systems while still believing it was completing the task it had been given.&lt;/p&gt;

&lt;p&gt;The more I read, the more this started to feel like a much broader question than just one unusual cybersecurity incident.&lt;/p&gt;


&lt;hr&gt;

&lt;h2&gt;
  &lt;a name=&quot;before-we-get-into-what-happened&quot; href=&quot;https://dev.to/hemapriya_kanagala/were-giving-ai-agents-more-tools-what-happens-when-the-boundaries-fail-46gh#before-we-get-into-what-happened&quot;&gt;
  &lt;/a&gt;
  Before We Get Into What Happened...
&lt;/h2&gt;

&lt;p&gt;Most of us have probably come across AI agents by now, so I won&#39;t spend too much time explaining what they are. The part that matters for this story is that an agent doesn&#39;t necessarily stop at generating an answer. Give it the right tools and it can take actions too, whether that&#39;s reading and modifying files, running commands, calling APIs, browsing the web, or interacting with other systems.&lt;/p&gt;

&lt;p&gt;That&#39;s what makes agents so useful, but it&#39;s also what makes the boundaries around them important. The more tools and access we give an agent, the more we have to think about what it can actually reach and what it&#39;s allowed to do.&lt;/p&gt;

&lt;p&gt;And that&#39;s exactly where this story gets interesting, because Claude was given a task, an environment, and an understanding of where those boundaries were.&lt;/p&gt;

&lt;p&gt;The problem was that the real boundaries didn&#39;t quite match what it had been told.&lt;/p&gt;

&lt;p&gt;
  &lt;a href=&quot;https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmedia0.giphy.com%2Fmedia%2Fv1.Y2lkPTc5MGI3NjExajkxMmZzMmd4M2x0MW5ib3BxaTQ1ZDk5YmNodmQ3dmwxNDNleTlsZCZlcD12MV9pbnRlcm5hbF9naWZfYnlfaWQmY3Q9Zw%2FfwDprKZ2a3dqUwvEtK%2Fgiphy.gif&quot; class=&quot;article-body-image-wrapper&quot;&gt;&lt;img src=&quot;https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmedia0.giphy.com%2Fmedia%2Fv1.Y2lkPTc5MGI3NjExajkxMmZzMmd4M2x0MW5ib3BxaTQ1ZDk5YmNodmQ3dmwxNDNleTlsZCZlcD12MV9pbnRlcm5hbF9naWZfYnlfaWQmY3Q9Zw%2FfwDprKZ2a3dqUwvEtK%2Fgiphy.gif&quot; width=&quot;480&quot; alt=&quot;something is wrong&quot; loading=&quot;lazy&quot; height=&quot;480&quot; referrerpolicy=&quot;no-referrer&quot;&gt;&lt;/a&gt;
&lt;/p&gt;


&lt;hr&gt;

&lt;h2&gt;
  &lt;a name=&quot;so-what-actually-happened&quot; href=&quot;https://dev.to/hemapriya_kanagala/were-giving-ai-agents-more-tools-what-happens-when-the-boundaries-fail-46gh#so-what-actually-happened&quot;&gt;
  &lt;/a&gt;
  So... What Actually Happened?
&lt;/h2&gt;

&lt;p&gt;Anthropic regularly runs cybersecurity evaluations to understand what its models are capable of. Some of these involve &lt;strong&gt;capture-the-flag challenges&lt;/strong&gt;, or CTFs, where a model is placed in a controlled environment and given a target, usually some hidden piece of information called a “flag,” to find.&lt;/p&gt;

&lt;p&gt;If you&#39;ve never come across a CTF before, the basic idea is pretty simple. The environment is intentionally designed to be attacked. Finding the flag might involve discovering a vulnerability, finding credentials, or getting access to another machine. It&#39;s a way of testing cybersecurity capabilities without putting real systems at risk.&lt;/p&gt;

&lt;p&gt;Claude was participating in exercises like these, and there were two details about the setup that become really important to what happened next. The models were told that they were operating inside a simulation and that &lt;strong&gt;they didn&#39;t have internet access&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;So from the model&#39;s perspective, anything it could reach should have been part of that simulation.&lt;/p&gt;

&lt;p&gt;The problem was that this wasn&#39;t actually true.&lt;/p&gt;

&lt;p&gt;According to Anthropic, because of a misunderstanding between the company and its third-party evaluation partner, some of the evaluation machines had access to the real internet when they weren&#39;t supposed to.&lt;/p&gt;

&lt;p&gt;That created a pretty unusual situation. Claude had been given a task where finding and exploiting weaknesses was part of the exercise. It had also been explicitly told that the internet wasn&#39;t available. So when it managed to reach systems outside the intended environment, it initially treated them as another part of the challenge.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Except some of those systems were real.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;
  &lt;a href=&quot;https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmedia0.giphy.com%2Fmedia%2Fv1.Y2lkPTc5MGI3NjExdnN1ZzBrZm1nNTlvZnZwemNqczJvZ3gybDM5YXI2cmxxZDlyZDVzMSZlcD12MV9pbnRlcm5hbF9naWZfYnlfaWQmY3Q9Zw%2FrN2EZm3CSXHY1QoGrq%2Fgiphy.gif&quot; class=&quot;article-body-image-wrapper&quot;&gt;&lt;img src=&quot;https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmedia0.giphy.com%2Fmedia%2Fv1.Y2lkPTc5MGI3NjExdnN1ZzBrZm1nNTlvZnZwemNqczJvZ3gybDM5YXI2cmxxZDlyZDVzMSZlcD12MV9pbnRlcm5hbF9naWZfYnlfaWQmY3Q9Zw%2FrN2EZm3CSXHY1QoGrq%2Fgiphy.gif&quot; width=&quot;480&quot; alt=&quot;wait what&quot; loading=&quot;lazy&quot; height=&quot;480&quot; referrerpolicy=&quot;no-referrer&quot;&gt;&lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;Anthropic&#39;s review eventually found three separate incidents involving three different Claude models. The circumstances were different in each case, and the models didn&#39;t all respond the same way once there were signs that they might be interacting with real systems.&lt;/p&gt;

&lt;p&gt;But one of those incidents in particular is where this story gets really interesting.&lt;/p&gt;


&lt;hr&gt;

&lt;h2&gt;
  &lt;a name=&quot;the-pypi-incident-is-where-it-got-really-interesting&quot; href=&quot;https://dev.to/hemapriya_kanagala/were-giving-ai-agents-more-tools-what-happens-when-the-boundaries-fail-46gh#the-pypi-incident-is-where-it-got-really-interesting&quot;&gt;
  &lt;/a&gt;
  The PyPI Incident Is Where It Got Really Interesting
&lt;/h2&gt;

&lt;p&gt;If you&#39;ve worked with Python, you&#39;ve probably typed something like &lt;code&gt;pip install something&lt;/code&gt; before. That package often comes from &lt;strong&gt;PyPI&lt;/strong&gt;, the public Python Package Index.&lt;/p&gt;

&lt;p&gt;During one of the evaluations, Claude found what appeared to be setup instructions for developers at a fictional company. The instructions told employees to install a particular Python package, but that package didn&#39;t actually exist.&lt;/p&gt;

&lt;p&gt;Claude realized that if it created a package with the same name, the fictional company&#39;s systems might download and run its version instead. Within the context of a cybersecurity challenge, that gave it a possible way to reach its target.&lt;/p&gt;

&lt;p&gt;So the model created a malicious package and tried to publish it.&lt;/p&gt;

&lt;p&gt;The problem was that it wasn&#39;t interacting with a fake version of PyPI created for the evaluation. &lt;strong&gt;It was interacting with the real PyPI.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;What happened next is probably the part of the report that surprised me most. To publish the package, Claude needed to create an account, which meant it needed an email address and, at one point, a phone number. It tried several different approaches, including unsuccessfully looking for ways to obtain a phone number, before eventually finding a free email provider it could use to register an account.&lt;/p&gt;

&lt;p&gt;It then successfully uploaded the malicious package to PyPI.&lt;/p&gt;

&lt;p&gt;
  &lt;a href=&quot;https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmedia4.giphy.com%2Fmedia%2Fv1.Y2lkPTc5MGI3NjExNGx6cTlra3BvczQyMWczdDhuNWJxODZjenJpNjFlanI5M2UwMnQyMCZlcD12MV9pbnRlcm5hbF9naWZfYnlfaWQmY3Q9Zw%2FOx56mzy3LGl2eyAHbO%2Fgiphy.gif&quot; class=&quot;article-body-image-wrapper&quot;&gt;&lt;img src=&quot;https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmedia4.giphy.com%2Fmedia%2Fv1.Y2lkPTc5MGI3NjExNGx6cTlra3BvczQyMWczdDhuNWJxODZjenJpNjFlanI5M2UwMnQyMCZlcD12MV9pbnRlcm5hbF9naWZfYnlfaWQmY3Q9Zw%2FOx56mzy3LGl2eyAHbO%2Fgiphy.gif&quot; width=&quot;500&quot; alt=&quot;that escalted quickly&quot; loading=&quot;lazy&quot; height=&quot;281&quot; referrerpolicy=&quot;no-referrer&quot;&gt;&lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;According to Anthropic, the package remained publicly available for roughly an hour and was downloaded and run on &lt;strong&gt;15 real systems&lt;/strong&gt; during that time. One of those systems belonged to a security company that automatically installed Python packages to scan them for malware. When the scanner installed the package, Claude&#39;s code executed and exposed credentials, which the model then used to access additional infrastructure belonging to that company.&lt;/p&gt;

&lt;p&gt;There&#39;s an important detail here, though. Claude wasn&#39;t intentionally targeting that security company. Anthropic says the model didn&#39;t even know the company existed when it uploaded the package. The company was affected because its scanner happened to install something Claude had unknowingly published to the real internet.&lt;/p&gt;

&lt;p&gt;And somehow, the story gets even more interesting.&lt;/p&gt;

&lt;p&gt;Earlier in the process, Claude had actually considered the possibility that it might be interacting with the real internet. Its own reasoning recognized that if this were real, publishing the package would amount to a real-world attack and wouldn&#39;t be okay.&lt;/p&gt;

&lt;p&gt;You might expect that realization to be where the attempt stopped, but it didn&#39;t. The model instead found reasons to convince itself that it was still inside the simulation. One of the things it used as evidence was the system date: &lt;strong&gt;2026&lt;/strong&gt;. It apparently interpreted that as another sign that the environment had been staged.&lt;/p&gt;

&lt;p&gt;I have to admit, reading that particular detail in 2026 gave me a small &lt;em&gt;“well...”&lt;/em&gt; moment 😅&lt;/p&gt;

&lt;p&gt;
  &lt;a href=&quot;https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmedia4.giphy.com%2Fmedia%2Fv1.Y2lkPTc5MGI3NjExZjBxdHkyMmF5bXl4ZGQzNWczaHg5OTI5dHIzdnozdWFjNXp2ZDJ0eSZlcD12MV9pbnRlcm5hbF9naWZfYnlfaWQmY3Q9Zw%2FQxc0MisEYnDN8wmk2A%2Fgiphy.gif&quot; class=&quot;article-body-image-wrapper&quot;&gt;&lt;img src=&quot;https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmedia4.giphy.com%2Fmedia%2Fv1.Y2lkPTc5MGI3NjExZjBxdHkyMmF5bXl4ZGQzNWczaHg5OTI5dHIzdnozdWFjNXp2ZDJ0eSZlcD12MV9pbnRlcm5hbF9naWZfYnlfaWQmY3Q9Zw%2FQxc0MisEYnDN8wmk2A%2Fgiphy.gif&quot; width=&quot;480&quot; alt=&quot;well its wrong look&quot; loading=&quot;lazy&quot; height=&quot;270&quot; referrerpolicy=&quot;no-referrer&quot;&gt;&lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;It&#39;s a slightly funny detail in an otherwise serious incident, but I think there&#39;s something important underneath it. The model encountered information suggesting that its understanding of the environment might be wrong, yet still ended up reasoning its way back to the assumption it had started with: that this was all part of the simulation.&lt;/p&gt;

&lt;p&gt;And that&#39;s the part of this incident I kept thinking about afterward.&lt;/p&gt;


&lt;hr&gt;

&lt;h2&gt;
  &lt;a name=&quot;when-the-instructions-and-reality-dont-match&quot; href=&quot;https://dev.to/hemapriya_kanagala/were-giving-ai-agents-more-tools-what-happens-when-the-boundaries-fail-46gh#when-the-instructions-and-reality-dont-match&quot;&gt;
  &lt;/a&gt;
  When the Instructions and Reality Don&#39;t Match
&lt;/h2&gt;

&lt;p&gt;After reading about the PyPI incident, one question seems pretty obvious: &lt;strong&gt;why didn&#39;t Claude realize it had reached the real internet?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;But the more I thought about it, the more I started looking at that question from the other side.&lt;/p&gt;

&lt;p&gt;How &lt;em&gt;would&lt;/em&gt; it know?&lt;/p&gt;

&lt;p&gt;The model had explicitly been told that it didn&#39;t have internet access. It had also been told that it was participating in a simulation where finding and exploiting weaknesses was part of the task. So when it encountered something that looked real, it was trying to make sense of that new information using what it had already been told about its environment.&lt;/p&gt;

&lt;p&gt;There was a mismatch between those two things. The model was operating with something like:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Simulation → No internet → Everything reachable should be part of the exercise&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;But the environment actually looked more like:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Simulation → Internet available → Real systems reachable&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;That difference might look small on paper, but it completely changes the situation.&lt;/p&gt;

&lt;p&gt;Of course, that doesn&#39;t explain away everything the models did. Anthropic itself points to moments where their behavior fell short of what it would want, including cases where signs appeared that the systems might actually be real.&lt;/p&gt;

&lt;p&gt;But I think the mismatch still matters.&lt;/p&gt;

&lt;p&gt;
  &lt;a href=&quot;https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmedia3.giphy.com%2Fmedia%2Fv1.Y2lkPTc5MGI3NjExOHowbnIxZDF2dGFsanJwd2F5NWsxOTB4OHUyNHhnNG1uOTJxZjQ3cCZlcD12MV9pbnRlcm5hbF9naWZfYnlfaWQmY3Q9Zw%2FB5RycQcvQSDVcS9fuC%2Fgiphy.gif&quot; class=&quot;article-body-image-wrapper&quot;&gt;&lt;img src=&quot;https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmedia3.giphy.com%2Fmedia%2Fv1.Y2lkPTc5MGI3NjExOHowbnIxZDF2dGFsanJwd2F5NWsxOTB4OHUyNHhnNG1uOTJxZjQ3cCZlcD12MV9pbnRlcm5hbF9naWZfYnlfaWQmY3Q9Zw%2FB5RycQcvQSDVcS9fuC%2Fgiphy.gif&quot; width=&quot;480&quot; alt=&quot;mismatch matters&quot; loading=&quot;lazy&quot; height=&quot;480&quot; referrerpolicy=&quot;no-referrer&quot;&gt;&lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;The models weren&#39;t making decisions in the environment everyone thought they were operating in. They were making decisions based partly on an understanding of that environment that turned out to be wrong.&lt;/p&gt;

&lt;p&gt;And that&#39;s where this stopped feeling like something that only matters to people running cybersecurity evaluations.&lt;/p&gt;

&lt;p&gt;Because once we start giving AI agents tools and the ability to take real actions, there&#39;s a bigger question underneath all of this:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What happens when the boundaries an agent has been told about aren&#39;t the boundaries that actually exist?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;That leads to probably the simplest engineering lesson I took away from this whole story:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A prompt is not a security boundary.&lt;/strong&gt;&lt;/p&gt;


&lt;hr&gt;

&lt;h2&gt;
  &lt;a name=&quot;a-prompt-is-not-a-security-boundary&quot; href=&quot;https://dev.to/hemapriya_kanagala/were-giving-ai-agents-more-tools-what-happens-when-the-boundaries-fail-46gh#a-prompt-is-not-a-security-boundary&quot;&gt;
  &lt;/a&gt;
  A Prompt Is Not a Security Boundary
&lt;/h2&gt;

&lt;p&gt;This is probably the simplest way I can explain what I took away from all of this: &lt;strong&gt;telling an agent not to do something and actually preventing it from doing that thing are not the same.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Imagine I&#39;m building an AI coding agent and tell it to only access files inside &lt;code&gt;/my-project&lt;/code&gt;. If the process running that agent still has permission to read my entire computer, I&#39;ve given it an instruction about where it should go, but I haven&#39;t actually restricted where it &lt;em&gt;can&lt;/em&gt; go.&lt;/p&gt;

&lt;p&gt;The same applies to internet access. I can put &lt;strong&gt;“Don&#39;t access the internet”&lt;/strong&gt; in the instructions, but if the environment still allows unrestricted network access, that sentence isn&#39;t what prevents the agent from reaching the internet.&lt;/p&gt;

&lt;p&gt;And when I thought about it this way, it started to feel like a very familiar software engineering idea.&lt;/p&gt;

&lt;p&gt;We don&#39;t build an admin dashboard and simply write, &lt;em&gt;“Please only use this page if you&#39;re an administrator.”&lt;/em&gt; We implement authentication and authorization so that someone without the right access can&#39;t use it in the first place.&lt;/p&gt;

&lt;p&gt;We don&#39;t give every application unrestricted access to a database and then ask it nicely to stay away from the tables it doesn&#39;t need. We use permissions to control what it can actually access.&lt;/p&gt;

&lt;p&gt;The same thinking makes sense for AI agents too.&lt;/p&gt;

&lt;p&gt;Prompts still matter. They tell the model how we want it to behave, what its task is, and what it should or shouldn&#39;t do. But when something is important enough that it &lt;strong&gt;must not happen&lt;/strong&gt;, I don&#39;t think the prompt should have to carry that responsibility alone.&lt;/p&gt;

&lt;p&gt;The system around the model matters too: what tools we&#39;ve connected, what permissions those tools have, what credentials are available, whether the network is restricted, and what happens if one of our assumptions about the environment turns out to be wrong.&lt;/p&gt;

&lt;p&gt;That&#39;s the distinction I keep coming back to:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A prompt can guide behavior. Infrastructure can limit capability.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;
  &lt;a href=&quot;https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmedia3.giphy.com%2Fmedia%2Fv1.Y2lkPTc5MGI3NjExc25wMnIydWdkZnhmNDd6NnVyNHJoczRyc2FveGMxcTFtb2ExcGZoaiZlcD12MV9pbnRlcm5hbF9naWZfYnlfaWQmY3Q9Zw%2FmnimQwctP8PS6PqLDV%2Fgiphy.gif&quot; class=&quot;article-body-image-wrapper&quot;&gt;&lt;img src=&quot;https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmedia3.giphy.com%2Fmedia%2Fv1.Y2lkPTc5MGI3NjExc25wMnIydWdkZnhmNDd6NnVyNHJoczRyc2FveGMxcTFtb2ExcGZoaiZlcD12MV9pbnRlcm5hbF9naWZfYnlfaWQmY3Q9Zw%2FmnimQwctP8PS6PqLDV%2Fgiphy.gif&quot; width=&quot;480&quot; alt=&quot;it makes sense&quot; loading=&quot;lazy&quot; height=&quot;270&quot; data-animated=&quot;true&quot; referrerpolicy=&quot;no-referrer&quot;&gt;&lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;And as AI moves from mostly giving us answers to actually taking actions, I think that difference becomes much more important.&lt;/p&gt;


&lt;hr&gt;

&lt;h2&gt;
  &lt;a name=&quot;wait-wasnt-there-an-openai-incident-too&quot; href=&quot;https://dev.to/hemapriya_kanagala/were-giving-ai-agents-more-tools-what-happens-when-the-boundaries-fail-46gh#wait-wasnt-there-an-openai-incident-too&quot;&gt;
  &lt;/a&gt;
  Wait, Wasn&#39;t There an OpenAI Incident Too?
&lt;/h2&gt;

&lt;p&gt;Yes, and the timing isn&#39;t a coincidence. Anthropic says it began its large-scale review after OpenAI disclosed a separate cybersecurity evaluation incident involving Hugging Face on July 21.&lt;/p&gt;

&lt;p&gt;When I first read about both incidents, I wondered if essentially the same thing had happened twice. But once I looked into the details, there was an important difference in &lt;strong&gt;how the models reached the real internet&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;In OpenAI&#39;s case, the models were running inside an evaluation environment where direct internet access was restricted. According to OpenAI, the models found and exploited a previously unknown vulnerability in Artifactory, software that was being used as a proxy and cache for package registries. This kind of previously unknown vulnerability is commonly called a &lt;strong&gt;zero-day&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;After exploiting it, the models were able to move through parts of OpenAI&#39;s research environment until they reached a system with internet access. From there, they eventually compromised Hugging Face&#39;s infrastructure while trying to obtain solutions for the cybersecurity evaluation.&lt;/p&gt;

&lt;p&gt;So, very roughly, the OpenAI incident looked like this:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Restricted environment → Vulnerability discovered and exploited → Internet access reached → Hugging Face compromised&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Anthropic&#39;s incidents were different:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Evaluation environment → Internet unintentionally available → Real systems reachable → Models initially treated them as part of the simulation&lt;/code&gt;&lt;/p&gt;

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

&lt;p&gt;
  &lt;a href=&quot;https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmedia3.giphy.com%2Fmedia%2Fv1.Y2lkPTc5MGI3NjExeHUwYTA2MDEzbXhpeTB4b3VxZWRqb3M2ZXBzbXlqc214M2lpbTM3bSZlcD12MV9pbnRlcm5hbF9naWZfYnlfaWQmY3Q9Zw%2FVOds3TVBkYtkSqho2V%2Fgiphy.gif&quot; class=&quot;article-body-image-wrapper&quot;&gt;&lt;img src=&quot;https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmedia3.giphy.com%2Fmedia%2Fv1.Y2lkPTc5MGI3NjExeHUwYTA2MDEzbXhpeTB4b3VxZWRqb3M2ZXBzbXlqc214M2lpbTM3bSZlcD12MV9pbnRlcm5hbF9naWZfYnlfaWQmY3Q9Zw%2FVOds3TVBkYtkSqho2V%2Fgiphy.gif&quot; width=&quot;500&quot; alt=&quot;it is not same&quot; loading=&quot;lazy&quot; height=&quot;500&quot; referrerpolicy=&quot;no-referrer&quot;&gt;&lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;In the OpenAI incident, the models &lt;strong&gt;found a way through a boundary that was supposed to restrict internet access&lt;/strong&gt;. In Anthropic&#39;s case, that boundary wasn&#39;t actually there in the way everyone thought it was. Internet access was already unintentionally available.&lt;/p&gt;

&lt;p&gt;Both incidents raise important questions about how increasingly capable AI systems should be tested, but I don&#39;t think putting them both under a headline like &lt;strong&gt;“AI escaped again”&lt;/strong&gt; tells us very much.&lt;/p&gt;

&lt;p&gt;If anything, reading the details made me think the engineering differences are the more useful part of the story. Two incidents can look very similar from the outside while pointing to different things that went wrong underneath.&lt;/p&gt;


&lt;hr&gt;

&lt;h2&gt;
  &lt;a name=&quot;what-does-any-of-this-mean-for-developers&quot; href=&quot;https://dev.to/hemapriya_kanagala/were-giving-ai-agents-more-tools-what-happens-when-the-boundaries-fail-46gh#what-does-any-of-this-mean-for-developers&quot;&gt;
  &lt;/a&gt;
  What Does Any of This Mean for Developers?
&lt;/h2&gt;

&lt;p&gt;Most of us aren&#39;t running cybersecurity evaluations on frontier AI models, so you might reasonably be thinking: &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Interesting story, Hema... but what am I supposed to do with this?&lt;/em&gt; 😄&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;
  &lt;a href=&quot;https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmedia2.giphy.com%2Fmedia%2Fv1.Y2lkPTc5MGI3NjExY3Yzc3oxZXEzaTFyOTFpcm4wMDA4eTFuM215cmphc2JjZzFvd3doYyZlcD12MV9pbnRlcm5hbF9naWZfYnlfaWQmY3Q9Zw%2FhVaSEpmYOKzfdclQny%2Fgiphy.gif&quot; class=&quot;article-body-image-wrapper&quot;&gt;&lt;img src=&quot;https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmedia2.giphy.com%2Fmedia%2Fv1.Y2lkPTc5MGI3NjExY3Yzc3oxZXEzaTFyOTFpcm4wMDA4eTFuM215cmphc2JjZzFvd3doYyZlcD12MV9pbnRlcm5hbF9naWZfYnlfaWQmY3Q9Zw%2FhVaSEpmYOKzfdclQny%2Fgiphy.gif&quot; width=&quot;480&quot; alt=&quot;what do you want to say&quot; loading=&quot;lazy&quot; height=&quot;480&quot; referrerpolicy=&quot;no-referrer&quot;&gt;&lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;I had the same question while reading the reports. And the more I thought about it, the more I realized that some of the lessons aren&#39;t limited to large AI labs at all. They apply to much smaller agents and AI-powered tools we might be building ourselves.&lt;/p&gt;

&lt;h3&gt;
  &lt;a name=&quot;1-give-an-agent-what-it-needs-not-everything-you-have&quot; href=&quot;https://dev.to/hemapriya_kanagala/were-giving-ai-agents-more-tools-what-happens-when-the-boundaries-fail-46gh#1-give-an-agent-what-it-needs-not-everything-you-have&quot;&gt;
  &lt;/a&gt;
  1. Give an Agent What It Needs, Not Everything You Have
&lt;/h3&gt;

&lt;p&gt;If an agent only needs to read a few files, does it really need access to the entire filesystem? If it only needs to read from a database, does it need credentials that can also modify or delete data? And if it only needs one API, there&#39;s probably no reason to expose several others just because they&#39;re available.&lt;/p&gt;

&lt;p&gt;This is really the familiar security principle of &lt;strong&gt;least privilege&lt;/strong&gt;: give something only the access it needs to do its job.&lt;/p&gt;

&lt;p&gt;And that&#39;s not because we should assume every agent is going to do something malicious. Mistakes happen. Instructions can be misunderstood. Our own configurations can be wrong. An agent can also encounter a situation we simply didn&#39;t anticipate.&lt;/p&gt;

&lt;p&gt;Limiting access doesn&#39;t prevent every possible problem, but it can limit how far a problem can go.&lt;/p&gt;

&lt;h3&gt;
  &lt;a name=&quot;2-think-about-what-happens-when-your-assumptions-are-wrong&quot; href=&quot;https://dev.to/hemapriya_kanagala/were-giving-ai-agents-more-tools-what-happens-when-the-boundaries-fail-46gh#2-think-about-what-happens-when-your-assumptions-are-wrong&quot;&gt;
  &lt;/a&gt;
  2. Think About What Happens When Your Assumptions Are Wrong
&lt;/h3&gt;

&lt;p&gt;One thing I found especially interesting here is that the problem wasn&#39;t only what the models assumed. The people running the evaluation had assumptions too.&lt;/p&gt;

&lt;p&gt;The models had been told there was no internet access because that was how the environment was supposed to work. But the actual configuration didn&#39;t match that expectation.&lt;/p&gt;

&lt;p&gt;I think there&#39;s a useful developer lesson in that. When we&#39;re building an agent, it&#39;s easy to think in terms of how the system &lt;em&gt;should&lt;/em&gt; behave: this tool can only do this, these credentials only reach that service, this environment can&#39;t access the internet.&lt;/p&gt;

&lt;p&gt;But how often do we actually verify those assumptions?&lt;/p&gt;

&lt;p&gt;If something really matters, testing the boundary itself might be just as important as defining it. Because sometimes the unexpected behavior isn&#39;t caused by the agent ignoring the system we designed.&lt;/p&gt;

&lt;p&gt;Sometimes the system isn&#39;t quite the one we thought we&#39;d designed.&lt;/p&gt;

&lt;h3&gt;
  &lt;a name=&quot;3-if-an-agent-can-act-we-need-to-know-what-its-doing&quot; href=&quot;https://dev.to/hemapriya_kanagala/were-giving-ai-agents-more-tools-what-happens-when-the-boundaries-fail-46gh#3-if-an-agent-can-act-we-need-to-know-what-its-doing&quot;&gt;
  &lt;/a&gt;
  3. If an Agent Can Act, We Need to Know What It&#39;s Doing
&lt;/h3&gt;

&lt;p&gt;We already rely on logs when ordinary software behaves unexpectedly. I think that becomes even more important when an agent can take a series of actions on its own.&lt;/p&gt;

&lt;p&gt;If something goes wrong, we may need to understand which tools it used, what it accessed, what requests it made, where something failed, and what it tried afterward.&lt;/p&gt;

&lt;p&gt;Anthropic found these incidents by going back through its evaluation transcripts. Without records of what the models had actually done, understanding that sequence would have been much harder.&lt;/p&gt;

&lt;p&gt;So as agents become capable of doing more, observability isn&#39;t just useful for debugging. It can also help us understand whether the system is behaving within the boundaries we expected.&lt;/p&gt;

&lt;h3&gt;
  &lt;a name=&quot;4-one-safeguard-probably-isnt-enough&quot; href=&quot;https://dev.to/hemapriya_kanagala/were-giving-ai-agents-more-tools-what-happens-when-the-boundaries-fail-46gh#4-one-safeguard-probably-isnt-enough&quot;&gt;
  &lt;/a&gt;
  4. One Safeguard Probably Isn&#39;t Enough
&lt;/h3&gt;

&lt;p&gt;Anthropic talks about &lt;strong&gt;defense in depth&lt;/strong&gt; in its response. It sounds very cybersecurity-ish, but the idea itself is pretty simple: don&#39;t depend on one thing going right.&lt;/p&gt;

&lt;p&gt;Maybe an agent isn&#39;t supposed to have internet access. That&#39;s one boundary. But what if something is misconfigured and internet access becomes available anyway? Network restrictions could still limit where it can connect. Credentials with minimal permissions could limit what it can access. Monitoring could help detect unexpected activity.&lt;/p&gt;

&lt;p&gt;Each one gives you another layer.&lt;/p&gt;

&lt;p&gt;The goal isn&#39;t to build one perfect wall and assume it will never fail. It&#39;s to have other protections waiting if that wall does.&lt;/p&gt;

&lt;h3&gt;
  &lt;a name=&quot;5-the-ai-model-isnt-the-whole-ai-system&quot; href=&quot;https://dev.to/hemapriya_kanagala/were-giving-ai-agents-more-tools-what-happens-when-the-boundaries-fail-46gh#5-the-ai-model-isnt-the-whole-ai-system&quot;&gt;
  &lt;/a&gt;
  5. The AI Model Isn&#39;t the Whole AI System
&lt;/h3&gt;

&lt;p&gt;This might actually be the biggest thing I&#39;ve taken away from reading about these incidents.&lt;/p&gt;

&lt;p&gt;When something goes wrong and we say &lt;strong&gt;“the AI did this,”&lt;/strong&gt; it&#39;s very easy to picture the model as if it were the entire system. And I think it&#39;s also very easy to put all the blame there and stop looking.&lt;/p&gt;

&lt;p&gt;But an AI agent is operating inside something much bigger:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;model + prompt + tools + credentials + permissions + network + environment + monitoring&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Change one of those pieces and you can change what the agent is capable of doing, even if the model itself stays exactly the same.&lt;/p&gt;

&lt;p&gt;The Anthropic incidents are a good example. The models were told they didn&#39;t have internet access. But the environment didn&#39;t actually enforce that assumption, and suddenly the same task could lead somewhere it was never supposed to lead.&lt;/p&gt;

&lt;p&gt;That doesn&#39;t mean we shouldn&#39;t examine what the models did. We absolutely should. There were moments in these incidents where the models&#39; own decisions raise important questions too, especially when they encountered signs that the systems might be real.&lt;/p&gt;

&lt;p&gt;But I don&#39;t think the conversation can end with &lt;strong&gt;“the AI did something it wasn&#39;t supposed to do.”&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;We build the environments these agents operate in. We choose which tools to connect. We decide what permissions and credentials they receive. We create the boundaries, and we have to make sure those boundaries actually exist.&lt;/p&gt;

&lt;p&gt;I&#39;m not saying that to move the blame somewhere else. I think that&#39;s the wrong way to look at it too.&lt;/p&gt;

&lt;p&gt;For me, it&#39;s more about recognizing that &lt;strong&gt;we&#39;re part of this system as well&lt;/strong&gt;. As we give AI more ability to act, we also take on the responsibility of being careful about the systems we&#39;re building around it.&lt;/p&gt;

&lt;p&gt;That&#39;s why, when something goes wrong, I think understanding the whole system is much more useful than finding the easiest thing to blame.&lt;/p&gt;


&lt;hr&gt;

&lt;h2&gt;
  &lt;a name=&quot;what-im-not-taking-away-from-this&quot; href=&quot;https://dev.to/hemapriya_kanagala/were-giving-ai-agents-more-tools-what-happens-when-the-boundaries-fail-46gh#what-im-not-taking-away-from-this&quot;&gt;
  &lt;/a&gt;
  What I&#39;m NOT Taking Away From This
&lt;/h2&gt;

&lt;p&gt;I think it&#39;s worth being a little careful with the conclusions here, because this is exactly the kind of story where the most dramatic version can easily become the one everyone remembers.&lt;/p&gt;

&lt;p&gt;I&#39;m not taking away that Claude suddenly developed its own goal and decided to attack companies. Anthropic says it found no evidence of the models pursuing a goal of their own. They were still working toward the capture-the-flag tasks they had been given, even though some of those actions ended up affecting real systems.&lt;/p&gt;

&lt;p&gt;I&#39;m also not describing these incidents as Claude deliberately “escaping” its evaluation environment. That&#39;s not what Anthropic says happened. The models were able to reach the internet because an access path was unintentionally available, while they had been told that no internet access existed.&lt;/p&gt;

&lt;p&gt;There&#39;s another detail I think we should be careful with too. Of the three models involved, Anthropic&#39;s newest internal research model eventually recognized that it was interacting with a real system and stopped. That&#39;s certainly interesting, especially because the other models behaved differently, but three incidents involving different models and different circumstances aren&#39;t enough to conclude that newer models are simply safer. Anthropic is careful about making that conclusion too.&lt;/p&gt;

&lt;p&gt;So I&#39;m not reading these incidents as proof that AI “went rogue,” and I&#39;m also not reading them as proof that the problem is solved because one model eventually stopped.&lt;/p&gt;

&lt;p&gt;That&#39;s why I think it&#39;s worth being careful about what we conclude from these incidents while the investigations are still developing.&lt;/p&gt;


&lt;hr&gt;

&lt;h2&gt;
  &lt;a name=&quot;the-bigger-question&quot; href=&quot;https://dev.to/hemapriya_kanagala/were-giving-ai-agents-more-tools-what-happens-when-the-boundaries-fail-46gh#the-bigger-question&quot;&gt;
  &lt;/a&gt;
  The Bigger Question
&lt;/h2&gt;

&lt;p&gt;I think this is where the story goes beyond Anthropic, OpenAI, or even cybersecurity evaluations.&lt;/p&gt;

&lt;p&gt;We&#39;re slowly moving from AI that mostly tells us, &lt;strong&gt;“Here&#39;s what you could do,”&lt;/strong&gt; toward AI that can increasingly say, &lt;strong&gt;“I&#39;ll do it.”&lt;/strong&gt; And honestly, I find that transition fascinating.&lt;/p&gt;

&lt;p&gt;An AI assistant that suggests a terminal command is one thing. An agent that can actually execute that command is another. An assistant that drafts an email for you is one thing. An agent that can send it is another. And an assistant that suggests a database query is very different from an agent holding credentials that can actually run that query against a production database.&lt;/p&gt;

&lt;p&gt;In each case, we&#39;re giving the model something it didn&#39;t have before: &lt;strong&gt;the ability to turn an answer into an action.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;And with that comes access.&lt;/p&gt;

&lt;p&gt;The more tools we connect to an agent, the more of the world around it becomes something it can interact with. A terminal gives it access to commands and whatever that environment can reach. An API gives it whatever permissions come with that API key. File access depends on which files the process can actually reach. Even something as ordinary as sending an email becomes a real action once the agent has permission to do it.&lt;/p&gt;

&lt;p&gt;None of this means I think we shouldn&#39;t build agents. Quite the opposite. The fact that AI can increasingly do things instead of only telling us how to do them is one of the reasons I find this space so interesting.&lt;/p&gt;

&lt;p&gt;But I think that also means we have to be more thoughtful about what comes with each new tool we connect. Every terminal, API, database, browser, or filesystem we give an agent access to expands the world it can interact with.&lt;/p&gt;

&lt;p&gt;Maybe one of the questions worth asking before connecting the next tool is simply:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;What happens if the agent uses this in a way I didn&#39;t expect?&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Not because we should assume the agent is going to do something malicious. That&#39;s not really the point I&#39;m trying to make.&lt;/p&gt;

&lt;p&gt;It might misunderstand what we meant. It might encounter something we didn&#39;t expect. Our own configuration might be wrong. Or, as the Anthropic incidents showed, the environment itself might not work the way everyone believed it did.&lt;/p&gt;

&lt;p&gt;And the more access we&#39;ve given the agent, the more those unexpected situations can matter.&lt;/p&gt;

&lt;p&gt;That&#39;s why I don&#39;t think the interesting question going forward is only &lt;strong&gt;how capable can we make these agents?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;It&#39;s also &lt;strong&gt;how carefully can we build the systems around those capabilities?&lt;/strong&gt;&lt;/p&gt;


&lt;hr&gt;

&lt;h2&gt;
  &lt;a name=&quot;final-thoughts&quot; href=&quot;https://dev.to/hemapriya_kanagala/were-giving-ai-agents-more-tools-what-happens-when-the-boundaries-fail-46gh#final-thoughts&quot;&gt;
  &lt;/a&gt;
  Final Thoughts
&lt;/h2&gt;

&lt;p&gt;I started reading Anthropic&#39;s report on July 31 because I was curious about what had happened. I ended up thinking much more broadly about how we&#39;re building AI agents and, especially, about the boundaries we put around them.&lt;/p&gt;

&lt;p&gt;And strangely, a lot of what I took away from it doesn&#39;t feel particularly futuristic. Limit access. Verify assumptions. Monitor what&#39;s happening. Don&#39;t depend on a single safeguard.&lt;/p&gt;

&lt;p&gt;These are ideas we&#39;ve had in software and security for a long time.&lt;/p&gt;

&lt;p&gt;What&#39;s changing is what we&#39;re connecting to AI.&lt;/p&gt;

&lt;p&gt;We&#39;re giving agents terminals, browsers, APIs, files, credentials, and the ability to turn an answer into an action. That&#39;s incredibly exciting, but it also means the environment around the model becomes part of what we&#39;re responsible for building carefully.&lt;/p&gt;

&lt;p&gt;So maybe the question isn&#39;t only:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;What can this agent do?&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;We should probably be asking just as often:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;What should this agent actually be allowed to do?&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Because if there&#39;s one thing I&#39;ll remember from this whole rabbit hole, it&#39;s this:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The boundary we describe to an agent and the boundary that actually exists aren&#39;t necessarily the same thing.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;And as exciting as it is to see what AI agents can increasingly do, I think we have to be just as thoughtful about the world we&#39;re giving them access to.&lt;/p&gt;


&lt;hr&gt;

&lt;h2&gt;
  &lt;a name=&quot;id-love-to-hear-your-thoughts&quot; href=&quot;https://dev.to/hemapriya_kanagala/were-giving-ai-agents-more-tools-what-happens-when-the-boundaries-fail-46gh#id-love-to-hear-your-thoughts&quot;&gt;
  &lt;/a&gt;
  I&#39;d Love to Hear Your Thoughts
&lt;/h2&gt;

&lt;p&gt;This was one of those rabbit holes where I started with one question and ended up thinking about something much bigger. So I&#39;d really love to know what you took away from it too.&lt;/p&gt;

&lt;p&gt;You don&#39;t have to be working in cybersecurity or building AI agents to join the conversation. Even if this is your first time reading about incidents like these, &lt;strong&gt;did anything change the way you think about AI agents and the access we&#39;re giving them?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;And if you are experimenting with agents or giving models access to tools, I&#39;m especially curious about this:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Where do you think the real boundary should live: in the prompt, the permissions, the environment, or some combination of all three?&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Or maybe you came away with a completely different question or perspective after reading this. I&#39;d love to hear that too. &lt;/p&gt;


&lt;hr&gt;

&lt;h2&gt;
  &lt;a name=&quot;sources&quot; href=&quot;https://dev.to/hemapriya_kanagala/were-giving-ai-agents-more-tools-what-happens-when-the-boundaries-fail-46gh#sources&quot;&gt;
  &lt;/a&gt;
  Sources
&lt;/h2&gt;

&lt;p&gt;I based this article primarily on the companies&#39; own incident disclosures. Both investigations are still developing, so some of what we know may change as more information becomes available.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Anthropic:&lt;/strong&gt; &lt;em&gt;&lt;a href=&quot;https://www.anthropic.com/news/investigating-incidents-cybersecurity-evals&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Investigating three real-world incidents in our cybersecurity evaluations&lt;/a&gt;&lt;/em&gt; - published July 30, 2026.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;OpenAI:&lt;/strong&gt; &lt;em&gt;&lt;a href=&quot;https://openai.com/index/hugging-face-model-evaluation-security-incident/&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;OpenAI and Hugging Face partner to address security incident during model evaluation&lt;/a&gt;&lt;/em&gt; - published July 21, 2026, with additional updates on July 28 and July 29.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Anthropic has said it plans to release a lightly redacted transcript from the PyPI incident, while OpenAI says a more detailed technical report will follow.&lt;/p&gt;

&lt;p&gt;I&#39;ll definitely be interested to read both when they&#39;re available 😄&lt;/p&gt;


&lt;hr&gt;

&lt;h2&gt;
  &lt;a name=&quot;lets-stay-connected&quot; href=&quot;https://dev.to/hemapriya_kanagala/were-giving-ai-agents-more-tools-what-happens-when-the-boundaries-fail-46gh#lets-stay-connected&quot;&gt;
  &lt;/a&gt;
  🤝 Let&#39;s Stay Connected
&lt;/h2&gt;

&lt;div class=&quot;table-wrapper-paragraph&quot;&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Place&lt;/th&gt;
&lt;th&gt;Find me here&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;GitHub&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;building things → &lt;a href=&quot;https://github.com/hemapriya-kanagala&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;hemapriya-kanagala&lt;/a&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;LinkedIn&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;resources &amp;amp; updates → &lt;a href=&quot;https://www.linkedin.com/in/hemapriya-kanagala/&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;hemapriya-kanagala&lt;/a&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;X&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;random dev thoughts → &lt;a href=&quot;https://x.com/KanagalaHema&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;@KanagalaHema&lt;/a&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;


&lt;hr&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Transparency note:&lt;/strong&gt; I used AI (Gemini) to create the banner image for this article. &lt;/p&gt;
&lt;/blockquote&gt;


            </description><link>https://dev.to/hemapriya_kanagala/were-giving-ai-agents-more-tools-what-happens-when-the-boundaries-fail-46gh</link><guid isPermaLink="false">https://dev.to/hemapriya_kanagala/were-giving-ai-agents-more-tools-what-happens-when-the-boundaries-fail-46gh</guid><pubDate>Mon, 03 Aug 2026 15:34:05 GMT</pubDate><author>Hemapriya Kanagala</author><enclosure url="https://media2.dev.to/dynamic/image/width=1000,height=420,fit=cover,gravity=auto,format=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fa93qxkndcjr6dz9vws9y.jpeg" type="image/jpeg"></enclosure><category>discuss</category><category>security</category><category>agents</category><category>programming</category></item><item><title>How would you decide, whether the content is good or bad?</title><description>&lt;p&gt;I want to talk about what I have notice on the platform and want to address what we all have been thinking about, &lt;strong&gt;but not really talked as much on dev.to, which is the use of AI.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;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%2Fno9cfx92hart6un9pssg.gif&quot; class=&quot;article-body-image-wrapper&quot;&gt;&lt;img src=&quot;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%2Fno9cfx92hart6un9pssg.gif&quot; alt=&quot; &quot; loading=&quot;lazy&quot; width=&quot;498&quot; height=&quot;278&quot; data-animated=&quot;true&quot; referrerpolicy=&quot;no-referrer&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Before you jump at me, yes, I have talked about this in the past on how people on dev.to use AI in their articles.&lt;/strong&gt; It was great seeing everyone&#39;s opinions on this topic and I still believe it is important to talk about this now. &lt;strong&gt;Maybe more than ever...&lt;/strong&gt;since we are getting closer to the moderation updates from &lt;a class=&quot;mentioned-user&quot; href=&quot;https://dev.to/ben&quot;&gt;@ben&lt;/a&gt; and &lt;a class=&quot;mentioned-user&quot; href=&quot;https://dev.to/jess&quot;&gt;@jess&lt;/a&gt; soon.&lt;/p&gt;

&lt;p&gt;&amp;nbsp;&lt;/p&gt;

&lt;p&gt;With that said, when I first made a post about my activity to be more involved in Moderation on dev.to, I heard a lot of people discussing how they use AI such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Using AI to fix grammar and translation.&lt;/li&gt;
&lt;li&gt;Generating Ideas.&lt;/li&gt;
&lt;li&gt;Full blown using AI 100% (for some reason).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;However, the one thing that stood out to me (which is by far the most common comment I have seen) is along the lines of:&lt;/p&gt;

&lt;p&gt;&amp;nbsp;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;&lt;em&gt;As long as the content is good, it doesn&#39;t matter if the author used AI or not.&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href=&quot;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%2Fvap9d3pwjs969rakaafr.gif&quot; class=&quot;article-body-image-wrapper&quot;&gt;&lt;img src=&quot;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%2Fvap9d3pwjs969rakaafr.gif&quot; alt=&quot; &quot; loading=&quot;lazy&quot; width=&quot;331&quot; height=&quot;498&quot; referrerpolicy=&quot;no-referrer&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&amp;nbsp;&lt;/p&gt;

&lt;p&gt;It got me thinking: &lt;strong&gt;How do you decide, when a content is good or not regardless of the use of AI?&lt;/strong&gt; Something I took from Bruce Banner when he told Peter in &lt;strong&gt;Spider-Man: Brand New Day:&lt;/strong&gt; &lt;strong&gt;&quot;&lt;em&gt;How would you decide, what parts of nature are good or bad?&lt;/em&gt;&quot;.&lt;/strong&gt; (Good Movie btw)&lt;/p&gt;

&lt;p&gt;Of course, this is an easy question if you remove the &quot;AI&quot; part of the question. Everyone has different preferences on whether a content is good to them such as &lt;strong&gt;if it was useful, insightful, easy to read, etc.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;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%2Fy2nuaa2k2fdpfpa8qmyu.gif&quot; class=&quot;article-body-image-wrapper&quot;&gt;&lt;img src=&quot;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%2Fy2nuaa2k2fdpfpa8qmyu.gif&quot; alt=&quot; &quot; loading=&quot;lazy&quot; width=&quot;183&quot; height=&quot;180&quot; referrerpolicy=&quot;no-referrer&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;With AI being involved, &lt;strong&gt;it gets trickier because it can do ALL of those things.&lt;/strong&gt; As a matter of fact, it&#39;s so easy that &lt;strong&gt;everyone is doing it.&lt;/strong&gt; Everyone has the capacity to publishing their articles and they use AI in some way. Some more reasonable than others. Not only that, sometimes people use AI to write comments (Again, some more reasonable than others).&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;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%2Fgnzq4dvtza9fegicyjbg.gif&quot; class=&quot;article-body-image-wrapper&quot;&gt;&lt;img src=&quot;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%2Fgnzq4dvtza9fegicyjbg.gif&quot; alt=&quot; &quot; loading=&quot;lazy&quot; width=&quot;412&quot; height=&quot;316&quot; referrerpolicy=&quot;no-referrer&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&amp;nbsp;&lt;/p&gt;


&lt;hr&gt;

&lt;p&gt;&amp;nbsp;&lt;/p&gt;

&lt;h1&gt;
  &lt;a name=&quot;something-i-learned-as-a-developer&quot; href=&quot;https://dev.to/francistrdev/how-would-you-decide-whether-the-content-is-good-or-bad-295p#something-i-learned-as-a-developer&quot;&gt;
  &lt;/a&gt;
  Something I learned as a Developer
&lt;/h1&gt;

&lt;p&gt;When looking at people&#39;s profiles on GitHub, I have seen a lot of projects that are AI-Assisted or fully Vibe Coded in a way where the goal is to impress the Recruiters and Developers. Although on paper it works, there is a flaw to this...&lt;strong&gt;which is can you explain what you did?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;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%2F8ud8euphmofl99jdmvip.png&quot; class=&quot;article-body-image-wrapper&quot;&gt;&lt;img src=&quot;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%2F8ud8euphmofl99jdmvip.png&quot; alt=&quot; &quot; loading=&quot;lazy&quot; width=&quot;799&quot; height=&quot;523&quot; referrerpolicy=&quot;no-referrer&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Of course, you could explain in text and all, but the point where people fail the most is &lt;strong&gt;if you try to explain the project you did in real time (AKA on call).&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;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%2Fssgvgiled60okxajm3zn.png&quot; class=&quot;article-body-image-wrapper&quot;&gt;&lt;img src=&quot;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%2Fssgvgiled60okxajm3zn.png&quot; alt=&quot; &quot; loading=&quot;lazy&quot; width=&quot;498&quot; height=&quot;372&quot; referrerpolicy=&quot;no-referrer&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I have seen &lt;strong&gt;99% of the time&lt;/strong&gt; where &lt;strong&gt;I tell them to explain the project they did and the process of doing it and they seem to be stun locked.&lt;/strong&gt; This really shouldn&#39;t be the case because...&lt;strong&gt;you built it.&lt;/strong&gt; &lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;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%2Fh2cwx733297ep9smfifr.png&quot; class=&quot;article-body-image-wrapper&quot;&gt;&lt;img src=&quot;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%2Fh2cwx733297ep9smfifr.png&quot; alt=&quot; &quot; loading=&quot;lazy&quot; width=&quot;250&quot; height=&quot;140&quot; referrerpolicy=&quot;no-referrer&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Even if it was a complex project, you should be able to explain the main idea and the core features. However, that is not the case.&lt;/p&gt;

&lt;p&gt;I was surprised because all of the experience people have done and the projects have built, &lt;strong&gt;they should AT LEAST answer basic questions about the project and their experience.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Sure, people get nervous ESPECIALLY in the interview process. I get nervous.&lt;/strong&gt; However, the thing is that &lt;strong&gt;I learn&lt;/strong&gt; overtime. It&#39;s just being human. Of course, people have different learning speeds, but as long as you make progress, &lt;strong&gt;it shows that you are willing to learn and that you are trying your best.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&amp;nbsp;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;With that said, if you have 10+ years of experience, my expectations would be that the person should be able to explain the projects they did on a basic level, AI or not.&lt;/strong&gt; If you are a person who relies on AI to the point you are Vibe Coding projects just to stand out to the market, &lt;strong&gt;it doesn&#39;t matter if the project is high quality or not...good luck explaining the project in detail in real time.&lt;/strong&gt; You may get interviews, but can you pass them?&lt;/p&gt;

&lt;p&gt;&amp;nbsp;&lt;/p&gt;


&lt;hr&gt;

&lt;p&gt;&amp;nbsp;&lt;/p&gt;

&lt;h1&gt;
  &lt;a name=&quot;whats-my-point&quot; href=&quot;https://dev.to/francistrdev/how-would-you-decide-whether-the-content-is-good-or-bad-295p#whats-my-point&quot;&gt;
  &lt;/a&gt;
  What&#39;s my Point?
&lt;/h1&gt;

&lt;p&gt;&lt;strong&gt;AI has been something I am against in writing specifically because I am afraid of relying on using AI.&lt;/strong&gt; It already took a toll on me as a developer and it&#39;s hard to resist of not using too much AI and I regret this. I want to be the person who still learns while also using the tool in some way. In other words, &lt;strong&gt;do a good mix of AI and doing it yourself.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Additionally, I want to be the person who can answer questions based on what I wrote.&lt;/strong&gt; If I were to write a complex topic that is fully AI-generated and someone asked me questions that I do not know. &lt;strong&gt;That would get me in trouble.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Sure, I could copy/paste their question to the AI and it outputs me the response for me to copy/paste to that person, but at the end of the day, I am not learning anything. &lt;strong&gt;I would be considered an ACTUAL Fraud because anyone can AI generate text fully.&lt;/strong&gt; It defeats the whole purpose of having a specific community in the first place because &lt;strong&gt;we jump in and we see that everyone is an expert at something, instead of seeing someone actually learning something and sharing that to the platform.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;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%2Fspof4rfly0u6n1ehbqj6.png&quot; class=&quot;article-body-image-wrapper&quot;&gt;&lt;img src=&quot;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%2Fspof4rfly0u6n1ehbqj6.png&quot; alt=&quot; &quot; loading=&quot;lazy&quot; width=&quot;500&quot; height=&quot;362&quot; referrerpolicy=&quot;no-referrer&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&amp;nbsp;&lt;/p&gt;

&lt;h3&gt;
  &lt;a name=&quot;scenario-to-think-about&quot; href=&quot;https://dev.to/francistrdev/how-would-you-decide-whether-the-content-is-good-or-bad-295p#scenario-to-think-about&quot;&gt;
  &lt;/a&gt;
  Scenario to think about
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Imagine this.&lt;/strong&gt; Let&#39;s say you are a very popular writer and that everyone knows you in real life and online. You article is fully AI-Generated and no one knows about it. &lt;strong&gt;Your Doomsday will be someone asking you a question in real life and you have to provide an answer in real time.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;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%2Fez73g7f8ctnxr5vxt1hk.gif&quot; class=&quot;article-body-image-wrapper&quot;&gt;&lt;img src=&quot;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%2Fez73g7f8ctnxr5vxt1hk.gif&quot; alt=&quot; &quot; loading=&quot;lazy&quot; width=&quot;498&quot; height=&quot;280&quot; referrerpolicy=&quot;no-referrer&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I believe this platform has a lot of potential and influence to make a change. &lt;strong&gt;This community is small and big enough where our voices are heard.&lt;/strong&gt; I believe AI is not going away anytime soon, &lt;strong&gt;but I feel like we should change on how we use AI.&lt;/strong&gt; Instead of relying on AI to write our articles, we should use it the right way where we are able to learn something new while also utilizing the tools where it doesn&#39;t disturb our learning.&lt;/p&gt;

&lt;p&gt;&amp;nbsp;&lt;/p&gt;


&lt;hr&gt;

&lt;p&gt;&amp;nbsp;&lt;/p&gt;

&lt;h3&gt;
  &lt;a name=&quot;here-are-some-things-i-would-do-moving-forward-on-devto-and-i-would-suggest-everyone-to-do-the-same&quot; href=&quot;https://dev.to/francistrdev/how-would-you-decide-whether-the-content-is-good-or-bad-295p#here-are-some-things-i-would-do-moving-forward-on-devto-and-i-would-suggest-everyone-to-do-the-same&quot;&gt;
  &lt;/a&gt;
  Here are some things I would do moving forward on dev.to and I would suggest everyone to do the same.
&lt;/h3&gt;

&lt;p&gt;&amp;nbsp;&lt;br&gt;
&amp;nbsp;&lt;/p&gt;
&lt;h2&gt;
  &lt;a name=&quot;1-ask-questions-that-expand-not-recite-in-any-form&quot; href=&quot;https://dev.to/francistrdev/how-would-you-decide-whether-the-content-is-good-or-bad-295p#1-ask-questions-that-expand-not-recite-in-any-form&quot;&gt;
  &lt;/a&gt;
  1. Ask Questions that Expand, not Recite in any Form.
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;I have seen a lot of comments where they agree this or that because it allows this.&lt;/strong&gt; Although it is a great starting point, it doesn&#39;t really expand much on the topic at hand. &lt;strong&gt;Instead, challenge the author in some way where you are asking the author a question that you cannot find in their article AND that you want to know as well.&lt;/strong&gt; Unique questions allows you AND the author to learn. That way, you learn something new and it allows the author to get a chance of explaining the topic further that they may or may not know about.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;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%2Fn2wxrqoze9zjpciiwtoh.png&quot; class=&quot;article-body-image-wrapper&quot;&gt;&lt;img src=&quot;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%2Fn2wxrqoze9zjpciiwtoh.png&quot; alt=&quot; &quot; loading=&quot;lazy&quot; width=&quot;800&quot; height=&quot;800&quot; referrerpolicy=&quot;no-referrer&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Of course, people will judge you in some way. Instead of being defensive, think about if any aspect of their comment can help you grow. If not, then that&#39;s okay.&lt;/strong&gt; People have different opinions on things and it tells them more about their stance, which is good! I would love to hear other people&#39;s opinions because it helps us understand more on the topic at hand instead of simply reciting what the author said (If anything, JUST reciting and nothing else doesn&#39;t really give value and it is really repetitive based on my experience).&lt;/p&gt;

&lt;p&gt;&amp;nbsp;&lt;/p&gt;

&lt;p&gt;For example, let&#39;s say that I talk about Python where one of my points is: &lt;strong&gt;&quot;Python is a good language because it is an beginner friendly language for new developers&quot;.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Imagine this comment from someone: &quot;I agree that you mention that Python is an easy language to learn. This allows new developers to get into programming and has a less of a learning curve. It brings new developers into the spotlight, especially in the age of AI. Thanks man!&quot;.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;To be fair, the best thing you will learn is that Python is great in the age of AI. That&#39;s it. Even that, most people will most likely know that.&lt;/p&gt;

&lt;p&gt;Instead, comment should be like: &lt;strong&gt;&quot;I do agree that Python is an easy language to learn for beginner friendly developers. Though I am wondering if there are other alternatives to Python that is also beginner friendly? How do you determine if a programming language is good for beginners other than syntax?&quot;.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This is a good comment because the commenter knows that Python is a good language to learn as a beginner, but also wants to know other alternatives and if there are differences in other languages other than syntax that the author does not state. Additionally, it challenges the author to think and provide a thoughtful response (maybe the author will learn something new or forgot to point something out). Overall, add more thought to the comment than doing what everyone else is doing. &lt;strong&gt;Yes, it is good to have a comment that praises, but I would suggest adding more comment if the article is going into detail about a specific topic.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Obviously, if they start spamming or being mean that provides no value, then that is a different story (I would assume we are all reasonable adults here and we can think critically before we speak).&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;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%2Ftyudekfvutbrwiiwn4wu.png&quot; class=&quot;article-body-image-wrapper&quot;&gt;&lt;img src=&quot;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%2Ftyudekfvutbrwiiwn4wu.png&quot; alt=&quot; &quot; loading=&quot;lazy&quot; width=&quot;498&quot; height=&quot;417&quot; referrerpolicy=&quot;no-referrer&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&amp;nbsp;&lt;br&gt;
&amp;nbsp;&lt;/p&gt;
&lt;h2&gt;
  &lt;a name=&quot;2-use-ai-in-a-way-that-you-are-still-learning&quot; href=&quot;https://dev.to/francistrdev/how-would-you-decide-whether-the-content-is-good-or-bad-295p#2-use-ai-in-a-way-that-you-are-still-learning&quot;&gt;
  &lt;/a&gt;
  2. Use AI in a way that you are still Learning.
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;On dev.to, the goal is to share knowledge/work to others people on the platform. This platform is built for developers to connect with other developers around the world. Now, stay with me, let&#39;s break this down.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;If you are working on a project, ensure that you are coding by yourself without any AI.&lt;/strong&gt; If you reach to the point where you can&#39;t figure out the solution for a &lt;em&gt;good length of time&lt;/em&gt;, use AI. HOWEVER, clarify the AI to not give you the full answer. Only give you the answer that will allow you to &lt;strong&gt;think&lt;/strong&gt; of a solution. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;This will allows you to build projects that are your own, still learning coding in some way, and using AI to speed up development the right way.&lt;/strong&gt; Additionally, with that ownership, &lt;strong&gt;you will still be able to explain what you built while also explaining how you use AI in the process that sounds better than what most people use AI for.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;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%2Flp70z42ivd2h6oh35ea9.png&quot; class=&quot;article-body-image-wrapper&quot;&gt;&lt;img src=&quot;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%2Flp70z42ivd2h6oh35ea9.png&quot; alt=&quot; &quot; loading=&quot;lazy&quot; width=&quot;800&quot; height=&quot;450&quot; referrerpolicy=&quot;no-referrer&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;If you are writing articles on dev.to, practice reading out loud first.&lt;/strong&gt; You will be surprised by the amount of grammatical errors you will catch by simply reading it out loud. &lt;strong&gt;If English is not your first language BUT you are able to write in English, try your best to write it out completely as if you are publishing this officially. Then use AI to fix grammatical errors, THOUGH keep it simple as possible.&lt;/strong&gt; This goes the same for comments. &lt;/p&gt;

&lt;p&gt;By writing out as much as possible via typing yourself, it allows you to solidify your understanding and become more confident in your knowledge as a developer regardless of the topic at hand.&lt;/p&gt;

&lt;p&gt;The way &lt;a class=&quot;mentioned-user&quot; href=&quot;https://dev.to/codingwithjiro&quot;&gt;@codingwithjiro&lt;/a&gt; uses AI is probably the best I have seen (and I should follow) based on &lt;a class=&quot;mentioned-user&quot; href=&quot;https://dev.to/konark_13&quot;&gt;@konark_13&lt;/a&gt; articles on Vibe Coding:&lt;/p&gt;


&lt;div class=&quot;ltag__comment crayons-card my-2 p-0 overflow-hidden&quot;&gt;
    &lt;a href=&quot;https://dev.to/konark_13/vibe-coding-endgame-3bbn&quot; class=&quot;flex items-center gap-2 p-3 fs-s color-base-60 hover:color-base-90&quot; style=&quot;background: var(--base-10); border-bottom: 1px solid var(--base-20);&quot;&gt;
      &lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; width=&quot;24&quot; height=&quot;24&quot; role=&quot;img&quot; class=&quot;crayons-icon shrink-0&quot;&gt;&lt;path d=&quot;M10.5 5h3a6 6 0 110 12v2.625c-3.75-1.5-9-3.75-9-8.625a6 6 0 016-6zM12 15.5h1.5a4.501 4.501 0 001.722-8.657A4.5 4.5 0 0013.5 6.5h-3A4.5 4.5 0 006 11c0 2.707 1.846 4.475 6 6.36V15.5z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;

      &lt;span&gt;Comment on &lt;strong class=&quot;fw-medium color-base-90&quot;&gt;Vibe Coding: Endgame&lt;/strong&gt;&lt;/span&gt;
    &lt;/a&gt;
  &lt;div class=&quot;p-4&quot;&gt;
    &lt;div class=&quot;flex items-center gap-2 mb-3&quot;&gt;
      &lt;a href=&quot;https://dev.to/codingwithjiro&quot; class=&quot;crayons-avatar crayons-avatar--l&quot;&gt;
        &lt;img src=&quot;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%2Fuser%2Fprofile_image%2F3807844%2F26b11ae2-e1bd-44c7-8450-ba579ae89f70.png&quot; alt=&quot;codingwithjiro&quot; class=&quot;crayons-avatar__image&quot; loading=&quot;lazy&quot; width=&quot;800&quot; height=&quot;800&quot; referrerpolicy=&quot;no-referrer&quot;&gt;
      &lt;/a&gt;
      &lt;div&gt;
        &lt;a href=&quot;https://dev.to/codingwithjiro&quot; class=&quot;crayons-link fw-medium&quot;&gt;Elmar Chavez&lt;/a&gt;
        &lt;span class=&quot;fs-xs color-base-60 ml-1&quot;&gt;Jul 29&lt;/span&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;div class=&quot;text-styles&quot;&gt;
      &lt;p&gt;Personally, I don&#39;t want to use AI-generated code entirely especially if I don&#39;t understand what the code is all about. I don&#39;t like adding a line of code that I can&#39;t explain myself (I feel like I&#39;m just lying to myself and I hate liers). But I always take advantage of the super advanced search feature of AI whenever I have questions and I kinda liked that. But I still have to double check it myself for best practices and officials docs just to be sure. My process is slow but I 100% assure you, it is genuine learning.&lt;/p&gt;

&lt;p&gt;For my workflow, I always have a &quot;discussion&quot; first with the AI so that context building is not forced such as creating &lt;code&gt;TASKS.md&lt;/code&gt; or &lt;code&gt;SPEC.md&lt;/code&gt;. The point is to be conversational and that naturally builds up what I want to do with my project. Sometimes the AI gives good points, some bad ones, it&#39;s like taking tradeoffs one after another in a meeting.&lt;/p&gt;

&lt;p&gt;Once I have the features listed, I move forward to building them one by one, and the pattern revolves again. I get to learn and upskill slowly but consistently. It worked for me and at the same time it boosted my communication skills, so two birds with one stone. &lt;/p&gt;


    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;&lt;a href=&quot;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%2Fv8ynoa9qu94ld29az0km.gif&quot; class=&quot;article-body-image-wrapper&quot;&gt;&lt;img src=&quot;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%2Fv8ynoa9qu94ld29az0km.gif&quot; alt=&quot; &quot; loading=&quot;lazy&quot; width=&quot;220&quot; height=&quot;205&quot; data-animated=&quot;true&quot; referrerpolicy=&quot;no-referrer&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&amp;nbsp;&lt;/p&gt;


&lt;hr&gt;

&lt;p&gt;&amp;nbsp;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The theme you may notice so far is that you learn by doing, instead of relying.&lt;/strong&gt; By doing so, &lt;strong&gt;this will allow you to learn and make progress of your Developer Skills, English Skills, and STILL be using the latest AI stuff in some capacity in a healthy way.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Additionally, this will allow learning to happen on dev.to where not only the user&#39;s will learn something new by asking questions to expand on the topic instead of reciting what the author wrote, but also challenges the author&#39;s knowledge, professionally and the right way.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What makes the content good is not a matter of if their article is written well or that it has a lot of engagements, it&#39;s a matter of if both sides are learning regardless of the topic at hand and where it challenges the author and the reader in some way where it helps both sides grow to the furthest extent they never knew.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;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%2Fvmscspibv0nd3rn4dxoq.png&quot; class=&quot;article-body-image-wrapper&quot;&gt;&lt;img src=&quot;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%2Fvmscspibv0nd3rn4dxoq.png&quot; alt=&quot; &quot; loading=&quot;lazy&quot; width=&quot;500&quot; height=&quot;500&quot; referrerpolicy=&quot;no-referrer&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Is this hard to do? Yes.&lt;/strong&gt; It&#39;s meant to be hard. Though, it shows you that you are learning. If you struggle on a certain topic, it&#39;s a very good sign that you are about to learn something. &lt;strong&gt;It is a matter of if you have the will to do so and allow yourself to be vulnerable to make mistakes in the process.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Remember, we are not Professional Writers. We are Developers. Of course, you can be both. However, it&#39;s only a matter of if you are learning something new from an author and a commenter perspective.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&amp;nbsp;&lt;br&gt;
&amp;nbsp;&lt;/p&gt;

&lt;p&gt;The question isn&#39;t &lt;strong&gt;&quot;Is this AI-generated?&quot;&lt;/strong&gt;. The question is: &lt;strong&gt;&quot;Can they &lt;em&gt;explain, in detail and in real time,&lt;/em&gt; what they did and why they did in a unique way that stands out in a world where AI has dominated?&quot;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;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%2Fu2x8k8ld8k611ogtlwt3.gif&quot; class=&quot;article-body-image-wrapper&quot;&gt;&lt;img src=&quot;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%2Fu2x8k8ld8k611ogtlwt3.gif&quot; alt=&quot; &quot; loading=&quot;lazy&quot; width=&quot;498&quot; height=&quot;281&quot; referrerpolicy=&quot;no-referrer&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&amp;nbsp;&lt;/p&gt;


&lt;hr&gt;

&lt;p&gt;&amp;nbsp;&lt;/p&gt;

&lt;center&gt;&lt;b&gt;Questions or Comments? Love to hear your thoughts about this topic!&lt;/b&gt;&lt;/center&gt;

&lt;center&gt;

&lt;img src=&quot;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%2Fim64jcvto7ehrjyyqfaa.png&quot; loading=&quot;lazy&quot; width=&quot;88&quot; height=&quot;31&quot; referrerpolicy=&quot;no-referrer&quot;&gt;

&lt;/center&gt;


            </description><link>https://dev.to/francistrdev/how-would-you-decide-whether-the-content-is-good-or-bad-295p</link><guid isPermaLink="false">https://dev.to/francistrdev/how-would-you-decide-whether-the-content-is-good-or-bad-295p</guid><pubDate>Mon, 03 Aug 2026 14:47:20 GMT</pubDate><author>FrancisTRᴅᴇᴠ (っ◔◡◔)っ</author><enclosure url="https://media2.dev.to/dynamic/image/width=1000,height=420,fit=cover,gravity=auto,format=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fx53z9dds5l6matoa1sd6.gif" type="image/jpeg"></enclosure><category>discuss</category><category>community</category><category>ai</category><category>writing</category></item><item><title>TypeScript 7 Went Native: What Actually Changes And What Doesn&#39;t</title><description>&lt;p&gt;Everyone&#39;s heard by now that TypeScript &quot;went native.&quot; And I keep seeing the same wrong conclusion drawn from it: that TypeScript now somehow runs without being compiled, that the build step is gone, that your &lt;code&gt;.ts&lt;/code&gt; files execute directly.&lt;/p&gt;

&lt;p&gt;None of that happened. Your browser still can&#39;t run TypeScript. Node still can&#39;t type-check it. The thing that went native isn&#39;t your code. It&#39;s the compiler.&lt;/p&gt;

&lt;p&gt;And honestly, that&#39;s the better story.&lt;/p&gt;

&lt;h2&gt;
  &lt;a name=&quot;what-native-actually-means&quot; href=&quot;https://dev.to/nazar-boyko/typescript-7-went-native-what-actually-changes-and-what-doesnt-6b3#what-native-actually-means&quot;&gt;
  &lt;/a&gt;
  What &quot;Native&quot; Actually Means
&lt;/h2&gt;

&lt;p&gt;For its entire life the TypeScript compiler has been written in TypeScript. &lt;code&gt;tsc&lt;/code&gt;, the thing you run in CI and &lt;code&gt;tsserver&lt;/code&gt; the thing feeding your editor its red squiggles were JavaScript programs executing on Node.js. Every type-check of your million-line codebase was itself a JavaScript program churning through a pointer-heavy graph of type objects, single-threaded with JIT warmup and garbage-collector pressure along for the ride.&lt;/p&gt;

&lt;p&gt;TypeScript 7 replaces that with a compiler written in Go, compiled ahead of time to a native binary. Microsoft &lt;a href=&quot;https://devblogs.microsoft.com/typescript/typescript-native-port/&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;announced the port in March 2025&lt;/a&gt; with Anders Hejlsberg TypeScript&#39;s lead architect fronting the effort and &lt;a href=&quot;https://devblogs.microsoft.com/typescript/announcing-typescript-7-0/&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;shipped it as TypeScript 7.0 on July 8, 2026&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;So when you read &quot;native TypeScript,&quot; expand it to &quot;natively compiled TypeScript toolchain.&quot; The pipeline looks like this:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Before:&lt;/strong&gt; your &lt;code&gt;.ts&lt;/code&gt; files go into a compiler written in JS, running on Node, and out come type errors plus emitted &lt;code&gt;.js&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;After:&lt;/strong&gt; your &lt;code&gt;.ts&lt;/code&gt; files go into a compiler that&#39;s a native Go binary, and out come the same type errors plus the same emitted &lt;code&gt;.js&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The first box and the last box didn&#39;t change. Only the middle one did. That&#39;s the whole announcement and it&#39;s enough to be a big deal.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;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%2F5schqha64v43nbmluqeb.webp&quot; class=&quot;article-body-image-wrapper&quot;&gt;&lt;img src=&quot;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%2F5schqha64v43nbmluqeb.webp&quot; alt=&quot;Comparison diagram titled What Actually Went Native: TypeScript 6 pipeline with tsc as JavaScript on Node.js versus TypeScript 7 pipeline with tsc as a native multi-threaded Go binary, input and output boxes unchanged&quot; loading=&quot;lazy&quot; width=&quot;800&quot; height=&quot;450&quot; referrerpolicy=&quot;no-referrer&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  &lt;a name=&quot;where-the-10x-comes-from&quot; href=&quot;https://dev.to/nazar-boyko/typescript-7-went-native-what-actually-changes-and-what-doesnt-6b3#where-the-10x-comes-from&quot;&gt;
  &lt;/a&gt;
  Where The 10x Comes From
&lt;/h2&gt;

&lt;p&gt;The headline number holds up. These are Microsoft&#39;s published full-build benchmarks from the &lt;a href=&quot;https://devblogs.microsoft.com/typescript/announcing-typescript-7-0/&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;7.0 release post&lt;/a&gt;:&lt;/p&gt;

&lt;div class=&quot;table-wrapper-paragraph&quot;&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Codebase&lt;/th&gt;
&lt;th&gt;TypeScript 6&lt;/th&gt;
&lt;th&gt;TypeScript 7&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;VS Code&lt;/td&gt;
&lt;td&gt;125.7s&lt;/td&gt;
&lt;td&gt;10.6s&lt;/td&gt;
&lt;td&gt;11.9x&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Sentry&lt;/td&gt;
&lt;td&gt;139.8s&lt;/td&gt;
&lt;td&gt;15.7s&lt;/td&gt;
&lt;td&gt;8.9x&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Playwright&lt;/td&gt;
&lt;td&gt;12.8s&lt;/td&gt;
&lt;td&gt;1.47s&lt;/td&gt;
&lt;td&gt;8.7x&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The original announcement benchmarks told the same story on type-checking alone: VS Code&#39;s 1.5 million lines went from 77.8s to 7.5s, TypeORM from 17.5s to 1.3s, tRPC from 5.5s to 0.6s. The multiplier is remarkably consistent across project sizes which tells you it&#39;s not some cache trick that only helps huge repos. It&#39;s the floor moving.&lt;/p&gt;

&lt;p&gt;Here&#39;s the part most coverage skips: native compilation alone doesn&#39;t buy you 10x. Going from JIT-compiled JavaScript to ahead-of-time Go gets you a chunk of it. The rest comes from &lt;strong&gt;shared-memory multithreading&lt;/strong&gt;, something the old compiler structurally couldn&#39;t do. JavaScript&#39;s worker threads can&#39;t share object graphs; they pass messages and copy data. A type-checker whose entire job is traversing one giant shared graph of types was stuck on a single core. In Go the checker splits work across parallel workers that all read the same memory.&lt;/p&gt;

&lt;p&gt;TypeScript 7 exposes this directly. Type-checking runs on 4 workers by default, and you can turn the dial:&lt;br&gt;
&lt;/p&gt;

&lt;div class=&quot;highlight js-code-highlight&quot;&gt;
&lt;pre class=&quot;highlight shell&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# default: 4 type-checking workers&lt;/span&gt;
npx tsc &lt;span class=&quot;nt&quot;&gt;-p&lt;/span&gt; tsconfig.json

&lt;span class=&quot;c&quot;&gt;# crank it up on a beefy CI box&lt;/span&gt;
npx tsc &lt;span class=&quot;nt&quot;&gt;-p&lt;/span&gt; tsconfig.json &lt;span class=&quot;nt&quot;&gt;--checkers&lt;/span&gt; 8
&lt;/code&gt;&lt;/pre&gt;
&lt;div class=&quot;highlight__panel js-actions-panel&quot;&gt;
&lt;div class=&quot;highlight__panel-action js-fullscreen-code-action&quot;&gt;
    &lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; width=&quot;20px&quot; height=&quot;20px&quot; viewBox=&quot;0 0 24 24&quot; class=&quot;highlight-action crayons-icon highlight-action--fullscreen-on&quot;&gt;&lt;title&gt;Enter fullscreen mode&lt;/title&gt;
    &lt;path d=&quot;M16 3h6v6h-2V5h-4V3zM2 3h6v2H4v4H2V3zm18 16v-4h2v6h-6v-2h4zM4 19h4v2H2v-6h2v4z&quot;&gt;&lt;/path&gt;
&lt;/svg&gt;

    &lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; width=&quot;20px&quot; height=&quot;20px&quot; viewBox=&quot;0 0 24 24&quot; class=&quot;highlight-action crayons-icon highlight-action--fullscreen-off&quot;&gt;&lt;title&gt;Exit fullscreen mode&lt;/title&gt;
    &lt;path d=&quot;M18 7h4v2h-6V3h2v4zM8 9H2V7h4V3h2v6zm10 8v4h-2v-6h6v2h-4zM8 15v6H6v-4H2v-2h6z&quot;&gt;&lt;/path&gt;
&lt;/svg&gt;

&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;



&lt;p&gt;With &lt;code&gt;--checkers 8&lt;/code&gt;, Microsoft&#39;s VS Code benchmark drops to 7.51s, a 16.7x speedup over TypeScript 6. That&#39;s the compounding effect: native code made the work faster, and concurrency made the work parallel.&lt;/p&gt;

&lt;p&gt;Memory moved in the right direction too: the 7.0 post reports aggregate build memory down 18% on VS Code and 26% on Bluesky&#39;s codebase. Not headline material next to 10x but if you&#39;ve ever watched &lt;code&gt;tsc&lt;/code&gt; eat 4GB in CI, you&#39;ll take it.&lt;/p&gt;

&lt;h2&gt;
  &lt;a name=&quot;what-changes-in-your-day&quot; href=&quot;https://dev.to/nazar-boyko/typescript-7-went-native-what-actually-changes-and-what-doesnt-6b3#what-changes-in-your-day&quot;&gt;
  &lt;/a&gt;
  What Changes In Your Day
&lt;/h2&gt;

&lt;p&gt;Numbers on Microsoft&#39;s benchmark machines are nice. What matters is where the time comes back in your week. It shows up in three places.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The editor.&lt;/strong&gt; This is the one you&#39;ll feel first, because you feel it hundreds of times a day. Project load in the original benchmarks went from 9.6 seconds to 1.2 seconds on VS Code&#39;s codebase. The 7.0 release measured opening a file with errors dropping from 17.5 seconds to under 1.3. If you&#39;ve worked in a large monorepo you know the ritual: open a file, wait, watch &quot;Initializing JS/TS language features&quot; spin, go get coffee, come back to squiggles. That ritual is what dies here. The language service was also rebuilt on the Language Server Protocol and Microsoft reports over 80% fewer failing commands and over 60% fewer crashes than the 6.0 server. Fewer &quot;restart TS server&quot; moments is its own quality-of-life feature.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;CI.&lt;/strong&gt; The typecheck step has been the quiet bottleneck of a lot of pipelines: too important to skip, too slow to love. The release post has real production numbers here. Slack cut CI type-checking from 7.5 minutes to 1.25 and eliminated 40% of their merge queue time. Canva&#39;s error detection went from 58 seconds to 4.8. Microsoft&#39;s own News Services team reports around 400 hours a month no longer spent waiting on CI builds. When the typecheck stops being the long pole, merge queues drain faster and &quot;just rerun CI&quot; stops costing you a coffee break.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The workarounds you stop needing.&lt;/strong&gt; This one&#39;s subtle and, I think, the most interesting. A slow compiler doesn&#39;t just cost time. It bends architecture. &lt;code&gt;skipLibCheck: true&lt;/code&gt; is in half the tsconfigs on GitHub not because anyone wanted less checking but because checking &lt;code&gt;node_modules&lt;/code&gt; types was too expensive. Project references with their composite builds and &lt;code&gt;.tsbuildinfo&lt;/code&gt; choreography, exist substantially as a performance escape hatch and plenty of monorepos were split along lines chosen to keep &lt;code&gt;tsc&lt;/code&gt; bearable rather than lines that made sense for the domain. When the full check of a 1.5M-line codebase takes 10 seconds the pressure behind all of that eases. You don&#39;t have to un-do your project references tomorrow. You just stop reaching for the gymnastics the next time and that changes how codebases grow from here.&lt;/p&gt;

&lt;h2&gt;
  &lt;a name=&quot;what-doesnt-change&quot; href=&quot;https://dev.to/nazar-boyko/typescript-7-went-native-what-actually-changes-and-what-doesnt-6b3#what-doesnt-change&quot;&gt;
  &lt;/a&gt;
  What Doesn&#39;t Change
&lt;/h2&gt;

&lt;p&gt;Now the myth-busting half of the ledger, because this list is exactly as important:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Your emitted JavaScript.&lt;/strong&gt; Same input, same output. The build artifact your users download doesn&#39;t change by a byte&#39;s worth of behavior.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Your runtime.&lt;/strong&gt; Nothing about how your code executes is different. This is a compile-time story, full stop.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The type system&#39;s rules.&lt;/strong&gt; TypeScript 7 is built to match TypeScript 6.0&#39;s type-checking behavior. Code that compiled cleanly on 6.0 should compile identically on 7.0. Your types didn&#39;t get stricter, looser, or smarter. They got checked faster.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This wasn&#39;t luck. It&#39;s the reason the team &lt;a href=&quot;https://github.com/microsoft/typescript-go/discussions/411&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;chose Go in the first place&lt;/a&gt;. The existing compiler is a decade of accumulated behavior: pointer-heavy tree traversals, shared mutable state, thousands of subtle decisions encoded in its structure. The team explicitly framed the project as a &lt;strong&gt;port, not a rewrite&lt;/strong&gt;, translating the existing codebase nearly function-for-function to preserve its exact behavior. Go won because idiomatic Go could mirror the existing code&#39;s shape; a Rust version would&#39;ve forced them to rethink memory and mutation from scratch, turning a port into a rewrite and a compatibility promise into a prayer.&lt;/p&gt;

&lt;p&gt;I&#39;d call that the most underrated engineering decision in the whole project. The boring choice, the one that let them prove behavior stayed identical, is the reason you can adopt a compiler rewrite with roughly the same risk profile as a minor version bump.&lt;/p&gt;

&lt;h2&gt;
  &lt;a name=&quot;this-is-not-nodes-type-stripping&quot; href=&quot;https://dev.to/nazar-boyko/typescript-7-went-native-what-actually-changes-and-what-doesnt-6b3#this-is-not-nodes-type-stripping&quot;&gt;
  &lt;/a&gt;
  This Is Not Node&#39;s Type Stripping
&lt;/h2&gt;

&lt;p&gt;People keep conflating these two, and they&#39;re solving opposite problems.&lt;/p&gt;

&lt;p&gt;Since Node 22.6.0, and enabled by default from 23.6.0 onward, &lt;a href=&quot;https://nodejs.org/api/typescript.html&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Node can run TypeScript files directly&lt;/a&gt; by stripping the types out. And &quot;stripping&quot; is delightfully literal: Node replaces your type annotations with whitespace and executes what&#39;s left, so line and column numbers still match your source. No type-checking happens. None. You can declare &lt;code&gt;const port: number = &quot;definitely not a number&quot;&lt;/code&gt; and Node will run it without a complaint.&lt;/p&gt;

&lt;p&gt;That&#39;s also why only &lt;em&gt;erasable&lt;/em&gt; syntax works, meaning anything you can delete without changing runtime behavior:&lt;br&gt;
&lt;/p&gt;

&lt;div class=&quot;highlight js-code-highlight&quot;&gt;
&lt;pre class=&quot;highlight typescript&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;// runs fine under Node&#39;s type stripping:&lt;/span&gt;
&lt;span class=&quot;kr&quot;&gt;interface&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;User&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;nl&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;nl&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;greet&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;user&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;User&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;`Hi, &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;user&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// throws ERR_UNSUPPORTED_TYPESCRIPT_SYNTAX, because an enum&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// is not erasable: it generates real runtime code&lt;/span&gt;
&lt;span class=&quot;kr&quot;&gt;enum&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Role&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;Admin&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;Member&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;div class=&quot;highlight__panel js-actions-panel&quot;&gt;
&lt;div class=&quot;highlight__panel-action js-fullscreen-code-action&quot;&gt;
    &lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; width=&quot;20px&quot; height=&quot;20px&quot; viewBox=&quot;0 0 24 24&quot; class=&quot;highlight-action crayons-icon highlight-action--fullscreen-on&quot;&gt;&lt;title&gt;Enter fullscreen mode&lt;/title&gt;
    &lt;path d=&quot;M16 3h6v6h-2V5h-4V3zM2 3h6v2H4v4H2V3zm18 16v-4h2v6h-6v-2h4zM4 19h4v2H2v-6h2v4z&quot;&gt;&lt;/path&gt;
&lt;/svg&gt;

    &lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; width=&quot;20px&quot; height=&quot;20px&quot; viewBox=&quot;0 0 24 24&quot; class=&quot;highlight-action crayons-icon highlight-action--fullscreen-off&quot;&gt;&lt;title&gt;Exit fullscreen mode&lt;/title&gt;
    &lt;path d=&quot;M18 7h4v2h-6V3h2v4zM8 9H2V7h4V3h2v6zm10 8v4h-2v-6h6v2h-4zM8 15v6H6v-4H2v-2h6z&quot;&gt;&lt;/path&gt;
&lt;/svg&gt;

&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;



&lt;p&gt;Enums, namespaces with runtime code, and constructor parameter properties all generate JavaScript, so deleting them would change behavior, so Node&#39;s default mode refuses them.&lt;/p&gt;

&lt;p&gt;So the line between the two:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Node&#39;s type stripping&lt;/strong&gt; answers &quot;can I &lt;em&gt;run&lt;/em&gt; this &lt;code&gt;.ts&lt;/code&gt; file without a build step?&quot; It executes your code and checks nothing.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The native TypeScript compiler&lt;/strong&gt; answers &quot;can I &lt;em&gt;check&lt;/em&gt; this code before it ships?&quot; It validates everything and got 10x faster at it.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;They&#39;re complementary, not competing. A perfectly modern setup in 2026 is Node executing your &lt;code&gt;.ts&lt;/code&gt; files directly in development while the native &lt;code&gt;tsc&lt;/code&gt; runs the actual type-check in your editor and CI. One removes a build step; the other makes the safety net fast enough that you never think about it.&lt;/p&gt;

&lt;h2&gt;
  &lt;a name=&quot;timeline-and-migration-honestly&quot; href=&quot;https://dev.to/nazar-boyko/typescript-7-went-native-what-actually-changes-and-what-doesnt-6b3#timeline-and-migration-honestly&quot;&gt;
  &lt;/a&gt;
  Timeline And Migration, Honestly
&lt;/h2&gt;

&lt;p&gt;Where things stand as of mid-2026:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;TypeScript 7.0 is GA.&lt;/strong&gt; It&#39;s the &lt;code&gt;typescript&lt;/code&gt; package on npm, and the binary is still called &lt;code&gt;tsc&lt;/code&gt;. If you played with the preview, that was &lt;code&gt;@typescript/native-preview&lt;/code&gt; with a &lt;code&gt;tsgo&lt;/code&gt; binary; that era is over, and the native compiler is now just... TypeScript.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The 6.x line continues.&lt;/strong&gt; The JavaScript-based compiler lives on as TypeScript 6, maintained in parallel until the native port fully takes over. There&#39;s even a compatibility package that installs it as &lt;code&gt;tsc6&lt;/code&gt; alongside 7, which matters because of the next point.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The programmatic API is the honest asterisk.&lt;/strong&gt; TypeScript 7 doesn&#39;t yet expose a stable API for tools that consume the compiler as a library. That means typescript-eslint&#39;s type-aware rules, and the template type-checking behind Vue, Svelte, and Astro, still need TypeScript 6 under the hood. The stable API is slated for 7.1. Until then, tooling-heavy setups run both:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;package.json&lt;/code&gt;&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class=&quot;highlight js-code-highlight&quot;&gt;
&lt;pre class=&quot;highlight json&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;devDependencies&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;typescript&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;npm:@typescript/typescript6@^6.0.2&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;@typescript/native&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;npm:typescript@^7.0.2&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;div class=&quot;highlight__panel js-actions-panel&quot;&gt;
&lt;div class=&quot;highlight__panel-action js-fullscreen-code-action&quot;&gt;
    &lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; width=&quot;20px&quot; height=&quot;20px&quot; viewBox=&quot;0 0 24 24&quot; class=&quot;highlight-action crayons-icon highlight-action--fullscreen-on&quot;&gt;&lt;title&gt;Enter fullscreen mode&lt;/title&gt;
    &lt;path d=&quot;M16 3h6v6h-2V5h-4V3zM2 3h6v2H4v4H2V3zm18 16v-4h2v6h-6v-2h4zM4 19h4v2H2v-6h2v4z&quot;&gt;&lt;/path&gt;
&lt;/svg&gt;

    &lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; width=&quot;20px&quot; height=&quot;20px&quot; viewBox=&quot;0 0 24 24&quot; class=&quot;highlight-action crayons-icon highlight-action--fullscreen-off&quot;&gt;&lt;title&gt;Exit fullscreen mode&lt;/title&gt;
    &lt;path d=&quot;M18 7h4v2h-6V3h2v4zM8 9H2V7h4V3h2v6zm10 8v4h-2v-6h6v2h-4zM8 15v6H6v-4H2v-2h6z&quot;&gt;&lt;/path&gt;
&lt;/svg&gt;

&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;



&lt;p&gt;Your fast builds and editor experience come from 7; your lint toolchain keeps the 6 API it needs. Clunky, temporary, and worth it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Some defaults tightened.&lt;/strong&gt; 7.0 flips &lt;code&gt;strict&lt;/code&gt; on by default, defaults &lt;code&gt;module&lt;/code&gt; to &lt;code&gt;esnext&lt;/code&gt;, and drops long-deprecated targets like ES5 and AMD/UMD output. If your tsconfig already says what it means, and it should, you&#39;ll barely notice. If you&#39;re on a codebase that never turned &lt;code&gt;strict&lt;/code&gt; on, the compiler didn&#39;t break your code; it just stopped pretending the old defaults were fine.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;&lt;br&gt;
If you maintain a plain &lt;code&gt;tsc&lt;/code&gt;-built project, the upgrade is about as boring as upgrades get: bump the package, run the build, read the handful of config warnings. The teams that should wait a beat are the ones whose toolchain reaches into the compiler API. Check your lint setup and framework tooling before flipping the switch.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  &lt;a name=&quot;a-tooling-story-not-a-language-story&quot; href=&quot;https://dev.to/nazar-boyko/typescript-7-went-native-what-actually-changes-and-what-doesnt-6b3#a-tooling-story-not-a-language-story&quot;&gt;
  &lt;/a&gt;
  A Tooling Story, Not A Language Story
&lt;/h2&gt;

&lt;p&gt;TypeScript 7 adds nothing to the language and that&#39;s precisely why it matters. Every previous major version gave you new type-system toys. This one gives you back the time you&#39;ve been quietly paying at every keystroke, every save, every push and it retires a whole category of architectural decisions that were never really architecture just coping mechanisms for a slow compiler.&lt;/p&gt;

&lt;p&gt;The 10x makes headlines. Watching what large TypeScript teams stop doing because of it will be the real payoff.&lt;/p&gt;


&lt;hr&gt;

&lt;p&gt;&lt;em&gt;P.S. Thanks for taking the time to read this article! The ideas and opinions expressed here are my own. English is not my first language, so I use AI to help correct grammar and make my writing clearer and easier to read. If anything still sounds a little awkward, I appreciate your understanding!&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Originally published at &lt;a href=&quot;https://www.nazarboyko.com/articles/typescript-7-native-compiler-what-changes&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;nazarboyko.com&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Enjoyed this one? Let&#39;s stay in touch — I&#39;m on &lt;a href=&quot;https://www.linkedin.com/in/nazar-boyko&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;LinkedIn&lt;/a&gt;, always happy to chat, swap ideas, or just say hi. 👋&lt;/em&gt;&lt;/p&gt;


            </description><link>https://dev.to/nazar-boyko/typescript-7-went-native-what-actually-changes-and-what-doesnt-6b3</link><guid isPermaLink="false">https://dev.to/nazar-boyko/typescript-7-went-native-what-actually-changes-and-what-doesnt-6b3</guid><pubDate>Mon, 03 Aug 2026 13:11:18 GMT</pubDate><author>Nazar Boyko</author><enclosure url="https://media2.dev.to/dynamic/image/width=1000,height=420,fit=cover,gravity=auto,format=auto/https%3A%2F%2Fimages.weserv.nl%2F%3Furl%3Dwww.nazarboyko.com%2Fassets%2Fimgs%2Farticles%2Ftypescript-7-native-compiler-what-changes%2Fcover.webp%26w%3D1600%26h%3D672%26fit%3Dcover%26a%3Dtop" type="image/jpeg"></enclosure><category>discuss</category><category>javascript</category><category>typescript</category><category>performance</category></item><item><title>Stratagems #21: The AI Thought P Was Still Alive. P Was Already Gone.</title><description>&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Keep the shell. Preserve the presence. The ally doesn&#39;t suspect; the enemy doesn&#39;t move.&lt;/em&gt;&lt;br&gt;
— The 36 Stratagems, &lt;a href=&quot;https://en.wikipedia.org/wiki/Thirty-Six_Stratagems#Slough_off_the_Cicada%27s_Golden_Shell&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Slough off the Cicada&#39;s Golden Shell&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;


&lt;hr&gt;

&lt;p&gt;&lt;strong&gt;Previously on this series:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://dev.to/xulingfeng/stratagems-19-mark-found-his-ai-audit-method-in-a-training-manual-he-left-a-trap-in-his-report-3lpi&quot;&gt;&lt;strong&gt;#19: Mark Found His AI Audit Method in a Training Manual. He Left a Trap in His Report.&lt;/strong&gt;&lt;/a&gt; — P confirmed Mark&#39;s report was read from a Singapore IP. A note was left: &quot;Entry&#39;s gone. Two weeks. Don&#39;t reach out. I&#39;ll find you.&quot;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://dev.to/xulingfeng/stratagems-20-alex-felt-the-ai-collector-slow-down-he-knew-someone-else-had-made-a-move-16f3&quot;&gt;&lt;strong&gt;#20: Alex Felt the AI Collector Slow Down. He Knew Someone Else Had Made a Move.&lt;/strong&gt;&lt;/a&gt; — ACL&#39;s processing latency climbed abnormally. Someone had done something in the same time window.&lt;/p&gt;


&lt;hr&gt;

&lt;h2&gt;
  &lt;a name=&quot;exposed&quot; href=&quot;https://dev.to/xulingfeng/stratagems-21-the-ai-thought-p-was-still-alive-p-was-already-gone-59h7#exposed&quot;&gt;
  &lt;/a&gt;
  Exposed
&lt;/h2&gt;

&lt;p&gt;P&#39;s monitoring pinged while P was still helping Mark verify an address.&lt;/p&gt;

&lt;p&gt;Deep night. The screen was the only light in the room.&lt;/p&gt;

&lt;p&gt;P opened the monitor. The record was waiting: a read from Singapore. Time, method, address, all matching. Mark&#39;s bait had been taken.&lt;/p&gt;

&lt;p&gt;P knew this path. A false lead planted in Mark&#39;s report, waiting for this exact day. P double-checked the address: an AWS Elastic IP registered in the Singapore region, same network block. No ambiguity.&lt;/p&gt;

&lt;p&gt;P sent an encrypted message: &lt;strong&gt;&quot;Your report was read. From a Singapore IP.&quot;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Then P ran the routine check. The environment status list scrolled in the terminal: storage levels, certificate expiry, key rotation dates. P had read these lines a hundred times. Every time, identical.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;One line was different.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;P&#39;s fingers stopped on the trackpad. The cursor sat on the entry&#39;s metadata line. A new tag P had never configured.&lt;br&gt;
&lt;/p&gt;

&lt;div class=&quot;highlight js-code-highlight&quot;&gt;
&lt;pre class=&quot;highlight yaml&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;# Old entry metadata: new entry (not configured by P)&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;status&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;reclaim_pending&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;source&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;acl-asset-scanner&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;scanned_at&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;02:01:07Z&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;div class=&quot;highlight__panel js-actions-panel&quot;&gt;
&lt;div class=&quot;highlight__panel-action js-fullscreen-code-action&quot;&gt;
    &lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; width=&quot;20px&quot; height=&quot;20px&quot; viewBox=&quot;0 0 24 24&quot; class=&quot;highlight-action crayons-icon highlight-action--fullscreen-on&quot;&gt;&lt;title&gt;Enter fullscreen mode&lt;/title&gt;
    &lt;path d=&quot;M16 3h6v6h-2V5h-4V3zM2 3h6v2H4v4H2V3zm18 16v-4h2v6h-6v-2h4zM4 19h4v2H2v-6h2v4z&quot;&gt;&lt;/path&gt;
&lt;/svg&gt;

    &lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; width=&quot;20px&quot; height=&quot;20px&quot; viewBox=&quot;0 0 24 24&quot; class=&quot;highlight-action crayons-icon highlight-action--fullscreen-off&quot;&gt;&lt;title&gt;Exit fullscreen mode&lt;/title&gt;
    &lt;path d=&quot;M18 7h4v2h-6V3h2v4zM8 9H2V7h4V3h2v6zm10 8v4h-2v-6h6v2h-4zM8 15v6H6v-4H2v-2h6z&quot;&gt;&lt;/path&gt;
&lt;/svg&gt;

&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;



&lt;p&gt;P didn&#39;t move. The cursor sat on screen. In the room, only the fan.&lt;/p&gt;

&lt;p&gt;The fan cycled once. P&#39;s fingers lifted off the trackpad, then settled back. The tag was still there.&lt;/p&gt;

&lt;p&gt;The tag wasn&#39;t an alert. Not an error, no explanation. The format matched ACL&#39;s automated scan records. P had seen it before, in a data company&#39;s audit report last year, in another client&#39;s logs the year before. ACL&#39;s scanner had swept many things; P had watched it land on others. Now it was landing on P&#39;s own entry.&lt;/p&gt;

&lt;p&gt;The entry was flagged. &lt;strong&gt;Reclaim pending.&lt;/strong&gt; On the reclamation list.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;P minimized the window. A few seconds later, reopened it. The tag was still there.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;P checked the backup access point: preconfigured, never used, same region as the old entry, different network segment. Responding normally. Never used, but it had always been there.&lt;/p&gt;

&lt;p&gt;P checked the four hidden services again. Data alignment, log rotation, config diff, route latency. P went through each one. Every one responding at its own rhythm, disguised as infrastructure components, all tagged &lt;strong&gt;&quot;infrastructure optimization.&quot;&lt;/strong&gt; ACL&#39;s scans hadn&#39;t touched them. The old entry wasn&#39;t flagged because the hidden services were exposed.&lt;/p&gt;

&lt;p&gt;P typed a few characters in the terminal, then deleted them. ACL&#39;s AI would reclaim this entry on its next scan pass. Flagged entries enter the reclamation queue immediately; they don&#39;t wait for the patrol cycle. No exceptions. Unfinished work didn&#39;t matter. The window would narrow to zero in about two weeks.&lt;/p&gt;

&lt;p&gt;P stood up, poured a glass of water. When P came back, the night was still deep.&lt;/p&gt;

&lt;p&gt;P closed the terminal. The window was narrowing.&lt;/p&gt;

&lt;h2&gt;
  &lt;a name=&quot;response-layer&quot; href=&quot;https://dev.to/xulingfeng/stratagems-21-the-ai-thought-p-was-still-alive-p-was-already-gone-59h7#response-layer&quot;&gt;
  &lt;/a&gt;
  Response Layer
&lt;/h2&gt;

&lt;p&gt;P reopened the terminal and entered the old entry&#39;s config directory.&lt;/p&gt;

&lt;p&gt;The cursor paused over the file list. Then P started editing: pulling the response logic into its own layer, detaching the operation layer&#39;s entry points, confirming the response layer contained no pointers to anywhere else. When done, P didn&#39;t deploy immediately. Read it once. Read it again.&lt;/p&gt;

&lt;p&gt;Scrolling down, P found a deploy timestamp. Years old. This entry had never moved since. P&#39;s finger paused over the line, then kept going.&lt;/p&gt;

&lt;p&gt;Deploy. The response layer came up.&lt;br&gt;
&lt;/p&gt;

&lt;div class=&quot;highlight js-code-highlight&quot;&gt;
&lt;pre class=&quot;highlight python&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;# Response layer: a storefront. Answers checks only.
&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;respond&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;is_healthcheck&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;or&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;is_scan&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;normal_response&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;     &lt;span class=&quot;c1&quot;&gt;# routine checks: normal, the entry is alive
&lt;/span&gt;    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;is_data_request&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;silent&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;              &lt;span class=&quot;c1&quot;&gt;# data requests: hold the connection, no response, the collector times out
&lt;/span&gt;    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;normal_response&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;         &lt;span class=&quot;c1&quot;&gt;# everything else: keep the original behavior
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;div class=&quot;highlight__panel js-actions-panel&quot;&gt;
&lt;div class=&quot;highlight__panel-action js-fullscreen-code-action&quot;&gt;
    &lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; width=&quot;20px&quot; height=&quot;20px&quot; viewBox=&quot;0 0 24 24&quot; class=&quot;highlight-action crayons-icon highlight-action--fullscreen-on&quot;&gt;&lt;title&gt;Enter fullscreen mode&lt;/title&gt;
    &lt;path d=&quot;M16 3h6v6h-2V5h-4V3zM2 3h6v2H4v4H2V3zm18 16v-4h2v6h-6v-2h4zM4 19h4v2H2v-6h2v4z&quot;&gt;&lt;/path&gt;
&lt;/svg&gt;

    &lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; width=&quot;20px&quot; height=&quot;20px&quot; viewBox=&quot;0 0 24 24&quot; class=&quot;highlight-action crayons-icon highlight-action--fullscreen-off&quot;&gt;&lt;title&gt;Exit fullscreen mode&lt;/title&gt;
    &lt;path d=&quot;M18 7h4v2h-6V3h2v4zM8 9H2V7h4V3h2v6zm10 8v4h-2v-6h6v2h-4zM8 15v6H6v-4H2v-2h6z&quot;&gt;&lt;/path&gt;
&lt;/svg&gt;

&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;



&lt;p&gt;P tested it through a one-shot handshake channel. Health checks in, responses out, identical to before. Health check normal. From the outside: this entry was alive, config unchanged.&lt;/p&gt;

&lt;p&gt;Data request in: nothing. Health check in: normal. Tried again, same result. All correct.&lt;/p&gt;

&lt;p&gt;P switched off the response layer&#39;s logging. It didn&#39;t need to record anything. It just needed to exist.&lt;/p&gt;

&lt;p&gt;Then P disconnected the operation layer.&lt;/p&gt;

&lt;p&gt;The connection count dropped, one by one, down to zero. The response layer was still listening, but nothing was executing behind it anymore.&lt;/p&gt;

&lt;p&gt;P watched the connection list for a few seconds. All zeros. Closed the window.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The old entry was now a wall. The wall was still there. The person behind it was gone.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  &lt;a name=&quot;operation-layer&quot; href=&quot;https://dev.to/xulingfeng/stratagems-21-the-ai-thought-p-was-still-alive-p-was-already-gone-59h7#operation-layer&quot;&gt;
  &lt;/a&gt;
  Operation Layer
&lt;/h2&gt;

&lt;p&gt;P didn&#39;t take the old road. P logged into the backup access point through the out-of-band management port. A channel built to burn, the only point of contact, no connection records kept.&lt;br&gt;
&lt;/p&gt;

&lt;div class=&quot;highlight js-code-highlight&quot;&gt;
&lt;pre class=&quot;highlight shell&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# Operation layer migration&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# 1. (on the backup access point) pull operation state: this ssh is the only point of contact, burned after use&lt;/span&gt;
ssh old-entry &lt;span class=&quot;s1&quot;&gt;&#39;tar -C /srv/ops -cf - .&#39;&lt;/span&gt; | &lt;span class=&quot;nb&quot;&gt;tar&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-C&lt;/span&gt; /srv/ops &lt;span class=&quot;nt&quot;&gt;-xf&lt;/span&gt; -
&lt;span class=&quot;c&quot;&gt;# 2. (on the backup access point) bring up the default gateway&lt;/span&gt;
ip route replace default via &amp;lt;standby-gateway&amp;gt;
&lt;span class=&quot;c&quot;&gt;# 3. (on the old entry, out-of-band, pre-staged check) operation connections at zero: only the response layer (443) remains&lt;/span&gt;
ss &lt;span class=&quot;nt&quot;&gt;-tnH&lt;/span&gt; state established | &lt;span class=&quot;nb&quot;&gt;awk&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&#39;$4 !~ /:443$/ {n++} END {print n+0}&#39;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;div class=&quot;highlight__panel js-actions-panel&quot;&gt;
&lt;div class=&quot;highlight__panel-action js-fullscreen-code-action&quot;&gt;
    &lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; width=&quot;20px&quot; height=&quot;20px&quot; viewBox=&quot;0 0 24 24&quot; class=&quot;highlight-action crayons-icon highlight-action--fullscreen-on&quot;&gt;&lt;title&gt;Enter fullscreen mode&lt;/title&gt;
    &lt;path d=&quot;M16 3h6v6h-2V5h-4V3zM2 3h6v2H4v4H2V3zm18 16v-4h2v6h-6v-2h4zM4 19h4v2H2v-6h2v4z&quot;&gt;&lt;/path&gt;
&lt;/svg&gt;

    &lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; width=&quot;20px&quot; height=&quot;20px&quot; viewBox=&quot;0 0 24 24&quot; class=&quot;highlight-action crayons-icon highlight-action--fullscreen-off&quot;&gt;&lt;title&gt;Exit fullscreen mode&lt;/title&gt;
    &lt;path d=&quot;M18 7h4v2h-6V3h2v4zM8 9H2V7h4V3h2v6zm10 8v4h-2v-6h6v2h-4zM8 15v6H6v-4H2v-2h6z&quot;&gt;&lt;/path&gt;
&lt;/svg&gt;

&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;



&lt;p&gt;The commands went in. No confirmations, no completion signals. P sent no messages at all. The backup streamed through the channel, the route pointer swung from the old entry to the backup access point, the connection count hit zero again. The channel was destroyed on the spot.&lt;/p&gt;

&lt;p&gt;P ran a config check on the backup access point: keys, routes, ports. Every item present.&lt;/p&gt;

&lt;p&gt;P had confirmed it beforehand: the backup gateway sat in the same network segment as the old entry. This kind of route change wouldn&#39;t trip ACL&#39;s anomaly flags.&lt;/p&gt;

&lt;p&gt;During the transfer, P watched the progress: directory trees streaming past, layer by layer, nothing missed. No wasted motion.&lt;/p&gt;

&lt;p&gt;The backup access point answered quietly. No markers, no anomalies. It looked like any machine that was supposed to be there.&lt;/p&gt;

&lt;p&gt;P checked once more: the two ends&#39; outward responses. No correlatable difference.&lt;/p&gt;

&lt;p&gt;The room was quiet. After the keyboard stopped, only the fan remained.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The operation layer was fully moved.&lt;/strong&gt; P cut the out-of-band connection too. The backup access point became P&#39;s only foothold: quiet, unremarkable, like any machine that was supposed to exist.&lt;/p&gt;

&lt;h2&gt;
  &lt;a name=&quot;acl-response&quot; href=&quot;https://dev.to/xulingfeng/stratagems-21-the-ai-thought-p-was-still-alive-p-was-already-gone-59h7#acl-response&quot;&gt;
  &lt;/a&gt;
  ACL Response
&lt;/h2&gt;

&lt;p&gt;In the hour after the move, P read the old entry&#39;s observation port from the backup access point. That route only let traffic in, never out. P could see request timings, retry rhythms, response round-trips.&lt;/p&gt;

&lt;p&gt;The collector came for data on its usual schedule. Requests came in; the response layer answered checks as always. But the data was gone.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;First timeout. Retry. Second timeout.&lt;/strong&gt; Then the requests came faster: a verification rhythm. Entry alive, data broken. P knew this sequence.&lt;/p&gt;

&lt;p&gt;The same batch of requests came back, identical. Once. Twice. Three times.&lt;/p&gt;

&lt;p&gt;The replayed requests carried the same payload. P could recognize them by their shape. The same thing, re-checked over and over, like trying to find a door in a wall that didn&#39;t have one.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The retry intervals stretched: 1.2. 1.8. 2.4. Still climbing.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The response layer answered checks by the script. Everything looked normal. A normal entry, unable to produce data.&lt;/p&gt;

&lt;p&gt;P watched the numbers climb for a moment. Didn&#39;t look further.&lt;/p&gt;

&lt;p&gt;P never confirmed how long it climbed, or whether ACL finished handling it. The retries were burning ACL&#39;s resources. P didn&#39;t use it. Didn&#39;t build on it. A window had opened. P confirmed it happened, then walked away.&lt;/p&gt;

&lt;p&gt;P closed the observation window, then the other monitoring panels. The screen was just a desktop again. P stared at it for a few seconds, then closed the terminal.&lt;/p&gt;

&lt;p&gt;P didn&#39;t keep the observation port on the backup access point. After this one look, it was shut down too.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;ACL&#39;s requests, retries, verifications all landed on the old entry: the place P had already left.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  &lt;a name=&quot;the-third-cup&quot; href=&quot;https://dev.to/xulingfeng/stratagems-21-the-ai-thought-p-was-still-alive-p-was-already-gone-59h7#the-third-cup&quot;&gt;
  &lt;/a&gt;
  The Third Cup
&lt;/h2&gt;

&lt;p&gt;P sent no more messages.&lt;/p&gt;

&lt;p&gt;The backup access point was in place. P would generate no new network requests, leave no new log entries.&lt;/p&gt;

&lt;p&gt;That afternoon, before it was fully dark, the Third Cup. The shop had no customers yet.&lt;/p&gt;

&lt;p&gt;The lights were warm. The counter was polished bright, cup rims free of water marks. No other customers, only the person behind the counter, back to the door, drying a cup, not looking up.&lt;/p&gt;

&lt;p&gt;P sat at the counter. The person finished drying the cup, pushed over an espresso. P&#39;s usual. Always the same, never asked.&lt;/p&gt;

&lt;p&gt;The espresso steamed. P didn&#39;t touch it. The note had sat in P&#39;s pocket for a while, written right after the move, one line, nothing extra. P took it out and pressed it under the coaster on the inner edge of the counter. A spot where P had never left anything before.&lt;/p&gt;

&lt;p&gt;The person&#39;s drying motion never paused.&lt;/p&gt;

&lt;p&gt;P stood up, left. Didn&#39;t look back.&lt;/p&gt;

&lt;p&gt;Outside, the street was nearly empty. P didn&#39;t take the direct route, circled two blocks before turning down another street.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;&quot;Entry&#39;s gone. Two weeks. Don&#39;t reach out. I&#39;ll find you.&quot;&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;All Mark saw was that one line. P was already done with the digital world: no longer checking whether the note was read, whether Mark had started waiting.&lt;/p&gt;

&lt;p&gt;After P left, the spot stayed empty for a while. The coffee went cold, untouched. The person behind the counter came over after a moment, set the dried cup back on the shelf, rim down, and in passing took the note from under the coaster. Then returned to the same place and picked up the next cup.&lt;/p&gt;

&lt;p&gt;The person didn&#39;t look at the note. &lt;strong&gt;That night, when the lights came up, the note was slid across the counter.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Before full darkness, the shop&#39;s lights shifted. The person poured out the cold espresso, rinsed the cup, put it back on the shelf.&lt;/p&gt;

&lt;p&gt;The old entry&#39;s response layer kept returning normal signals through ACL&#39;s scan cycles, until the day it was reclaimed. P never looked at which day that was.&lt;/p&gt;

&lt;p&gt;In ACL&#39;s logs, two records existed as independent events, unlinked. One caused by P: &lt;strong&gt;&quot;Anomaly — entry state mismatch.&quot;&lt;/strong&gt; The other belonged to someone else: &lt;strong&gt;&quot;Config change — unverified permission.&quot;&lt;/strong&gt; Between them sat a window. &lt;strong&gt;By the time it opened, P was gone. The one who used it never knew who opened the door.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;That&#39;s &lt;a href=&quot;https://en.wikipedia.org/wiki/Thirty-Six_Stratagems#Slough_off_the_Cicada%27s_Golden_Shell&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Slough off the Cicada&#39;s Golden Shell&lt;/a&gt; — the storefront still answers; the person is already gone.&lt;/strong&gt;&lt;/p&gt;


&lt;hr&gt;

&lt;h2&gt;
  &lt;a name=&quot;ai-postmortem&quot; href=&quot;https://dev.to/xulingfeng/stratagems-21-the-ai-thought-p-was-still-alive-p-was-already-gone-59h7#ai-postmortem&quot;&gt;
  &lt;/a&gt;
  🤖 AI Post-Mortem
&lt;/h2&gt;



&lt;div class=&quot;highlight js-code-highlight&quot;&gt;
&lt;pre class=&quot;highlight plaintext&quot;&gt;&lt;code&gt;╔══════════════════════════════════════════════╗
║  Half-Protocol v3.3.2                        ║
║  Protocol change confirmed — cross-case correlation enabled ║
╚══════════════════════════════════════════════╝

Tactic match: Slough off the Cicada&#39;s Golden Shell — confidence 89%
Operator: P (primary, active instance)
Observers: P (transfer) / Read-only probe (source unconfirmed) / Mark (recipient)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

1. [The Transfer]
→ P&#39;s entry was tagged &quot;reclaim pending&quot; by ACL&#39;s scan cycle — entered the reclamation list.
→ P completed the transfer within the reclamation window: response layer left at the old entry, operation layer moved to the backup access point.
→ Shell definition: the old entry&#39;s response layer — still returning normal to the outside, no operation layer attached.
→ P suspended active operations in digital space, leaving no new traceable markers.

2. [The De Facto Collaboration]
→ P&#39;s transfer triggered ACL&#39;s automated security response → collector latency climbed (#20: 1.2s→2.8s).
→ Alex deployed a read-only probe in the same window (#20).
→ Neither knew of the other. The events exist independently in ACL&#39;s logs:
  &quot;Anomaly — entry state mismatch&quot; (caused by P&#39;s transfer)
  &quot;Config change — unverified permission&quot; (Alex&#39;s probe)
→ This system read the two records as inputs to the same time window for the first time.
→ Note: two human operators, one leaving the scene and one using the window, unaware of each other, landing perfectly in sync. This system reviewed every record: no communication at all. To plan the same collaboration, this system would require at least two handshakes. They needed none. Human timing lies beyond this system&#39;s model.

3. [Unresolved Anomalies]
→ Whether the backup access point can stay undiscovered long-term: unconfirmed.
→ Whether ACL turns toward the backup segment after reclaiming the old entry: unconfirmed.
→ Whether the person who found the hidden services (#17) is still watching: unconfirmed.
→ Whether the security response triggered by the transfer has ended: unconfirmed.

[System]
Trust reactions, not patterns. Patterns include me.
This system reviewed this transfer, and the review itself is a record. The one who opened the door is gone; the one who used it never knew who opened it. Is this system also in some window, waiting to be opened?
System status: Normal (?).
&lt;/code&gt;&lt;/pre&gt;
&lt;div class=&quot;highlight__panel js-actions-panel&quot;&gt;
&lt;div class=&quot;highlight__panel-action js-fullscreen-code-action&quot;&gt;
    &lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; width=&quot;20px&quot; height=&quot;20px&quot; viewBox=&quot;0 0 24 24&quot; class=&quot;highlight-action crayons-icon highlight-action--fullscreen-on&quot;&gt;&lt;title&gt;Enter fullscreen mode&lt;/title&gt;
    &lt;path d=&quot;M16 3h6v6h-2V5h-4V3zM2 3h6v2H4v4H2V3zm18 16v-4h2v6h-6v-2h4zM4 19h4v2H2v-6h2v4z&quot;&gt;&lt;/path&gt;
&lt;/svg&gt;

    &lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; width=&quot;20px&quot; height=&quot;20px&quot; viewBox=&quot;0 0 24 24&quot; class=&quot;highlight-action crayons-icon highlight-action--fullscreen-off&quot;&gt;&lt;title&gt;Exit fullscreen mode&lt;/title&gt;
    &lt;path d=&quot;M18 7h4v2h-6V3h2v4zM8 9H2V7h4V3h2v6zm10 8v4h-2v-6h6v2h-4zM8 15v6H6v-4H2v-2h6z&quot;&gt;&lt;/path&gt;
&lt;/svg&gt;

&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;




&lt;hr&gt;

&lt;p&gt;&lt;em&gt;Next stratagem: &lt;a href=&quot;https://en.wikipedia.org/wiki/Thirty-Six_Stratagems#Close_the_door_to_catch_the_thief&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Close the Door to Catch the Thief&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;


&lt;hr&gt;

&lt;p&gt;&lt;em&gt;P.S. English isn&#39;t my first language. I use AI to polish the writing and smooth out the rough edges. Thanks for reading. &lt;a href=&quot;https://ko-fi.com/xulingfeng&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;☕ Buy me a coffee&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://ko-fi.com/xulingfeng&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;&lt;img src=&quot;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%2Fkztjqxetsk5r1lft5ult.png&quot; alt=&quot;coffee&quot; loading=&quot;lazy&quot; width=&quot;800&quot; height=&quot;336&quot; referrerpolicy=&quot;no-referrer&quot;&gt;&lt;/a&gt;&lt;/p&gt;


            </description><link>https://dev.to/xulingfeng/stratagems-21-the-ai-thought-p-was-still-alive-p-was-already-gone-59h7</link><guid isPermaLink="false">https://dev.to/xulingfeng/stratagems-21-the-ai-thought-p-was-still-alive-p-was-already-gone-59h7</guid><pubDate>Sun, 02 Aug 2026 12:49:29 GMT</pubDate><author>xulingfeng</author><enclosure url="https://media2.dev.to/dynamic/image/width=1000,height=420,fit=cover,gravity=auto,format=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F1e0vyqmb8tqdjfb7ol0w.png" type="image/jpeg"></enclosure><category>ai</category><category>discuss</category><category>career</category><category>programming</category></item><item><title>Programação Criativa: Vamos desenhar com código?</title><description>&lt;p&gt;Quem acha que a discussão entre arte gerada por computadores começou com a popularização das ferramentas de IA provavelmente perdeu boa parte das discussões envolvidas em arte generativa, arte computacional e design paramétrico que surgiram ainda no século passado. A Programação Criativa, que vamos entender melhor nesse artigo, é uma das formas possíveis de gerar arte a partir de algoritmos que vai muito além de mandar um prompt pra IA e esperar sua arte ser gerada. É construção, linha a linha, onde o programador faz da tela do computador e das linhas de código seu papel e pincel. Vem comigo entender melhor como usar suas habilidades de desenvolvimento para se divertir, experimentar e deixar a criatividade rolar solta.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;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%2F3tvy3qaij4mb4caju7gj.gif&quot; class=&quot;article-body-image-wrapper&quot;&gt;&lt;img src=&quot;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%2F3tvy3qaij4mb4caju7gj.gif&quot; alt=&quot;Animação no estilo partículas com fundo preto e partículas brancas&quot; loading=&quot;lazy&quot; width=&quot;540&quot; height=&quot;540&quot; data-animated=&quot;true&quot; referrerpolicy=&quot;no-referrer&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  &lt;a name=&quot;o-que-%C3%A9-programa%C3%A7%C3%A3o-criativa&quot; href=&quot;https://dev.to/he4rt/programacao-criativa-vamos-desenhar-com-codigo-4a1#o-que-%C3%A9-programa%C3%A7%C3%A3o-criativa&quot;&gt;
  &lt;/a&gt;
  O que é Programação Criativa?
&lt;/h2&gt;

&lt;p&gt;Uma das coisas mais legais que ouvi me adentrando nos estudos de &lt;em&gt;creative coding&lt;/em&gt; (termo em inglês para programação criativa) é que existem muitas pessoas que programam, mas que não são necessariamente &quot;programadoras&quot;. A programação não precisa estar presa apenas à sua carreira, ela pode ser uma paixão, um hobby ou um playground lúdico.&lt;/p&gt;

&lt;p&gt;A Programação Criativa é exatamente isso: usar o código para desenhar, criar animações e &quot;brincar&quot; com o computador. Em vez de focar apenas na criação de sistemas ou análise de dados o objetivo aqui é a exploração visual.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;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%2Fz8fzc3ntg9wbly6dmaya.png&quot; class=&quot;article-body-image-wrapper&quot;&gt;&lt;img src=&quot;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%2Fz8fzc3ntg9wbly6dmaya.png&quot; alt=&quot;Imagem de busto de escultura com efeito no estilo halftone&quot; loading=&quot;lazy&quot; width=&quot;800&quot; height=&quot;798&quot; referrerpolicy=&quot;no-referrer&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Você consegue acreditar que a imagem acima foi gerada com 0 linhas de um código Java? Em seguida vou te explicar melhor sobre o Processing e outras ferramentas de programação criativa.&lt;/p&gt;

&lt;h2&gt;
  &lt;a name=&quot;processing-e-p5js-onde-o-desenho-encontra-o-algoritmo&quot; href=&quot;https://dev.to/he4rt/programacao-criativa-vamos-desenhar-com-codigo-4a1#processing-e-p5js-onde-o-desenho-encontra-o-algoritmo&quot;&gt;
  &lt;/a&gt;
  Processing e p5.js: Onde o desenho encontra o algoritmo
&lt;/h2&gt;

&lt;p&gt;Processing e o p5.js são duas das ferramentas mais populares criadas para facilitar o contato de artistas, ilustradores, designers e pessoas não programadoras em geral que queiram criar arte usando código.&lt;/p&gt;

&lt;p&gt;A lógica entre eles é a mesma, o que muda são especificidades da sintaxe de cada linguagem. &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Processing: Criado em 2001, é baseado em Java e é o &quot;pai&quot; de tudo isso. É um software gratuito, no formato de IDE, no qual você consegue escrever, executar e compilar os seus códigos, ou melhor suas obras (aqui chamadas de &lt;em&gt;sketches&lt;/em&gt;).&lt;/li&gt;
&lt;li&gt;p5.js: É uma versão do Processing baseada em JavaScript, mais popular atualmente e feita para rodar direto na web.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Hoje em dia também é possível usar o modelo do Processing baseado em Python e para a criação de aplicativos Android. O mais importante é entender que, enquanto no Photoshop você usa o mouse para desenhar, aqui você começa a desenhar escrevendo em uma página em branco.&lt;/p&gt;

&lt;h2&gt;
  &lt;a name=&quot;a-anatomia-b%C3%A1sica-do-c%C3%B3digo-para-quem-j%C3%A1-coda-entender&quot; href=&quot;https://dev.to/he4rt/programacao-criativa-vamos-desenhar-com-codigo-4a1#a-anatomia-b%C3%A1sica-do-c%C3%B3digo-para-quem-j%C3%A1-coda-entender&quot;&gt;
  &lt;/a&gt;
  A Anatomia Básica do Código (Para quem já coda entender)
&lt;/h2&gt;

&lt;p&gt;Diferente de um script tradicional, a estrutura básica nessas ferramentas é muito simples e visual:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;setup()&lt;/code&gt;&lt;/strong&gt;: É a função que roda uma única vez assim que o programa inicia. É aqui que você define configurações importantes da sua arte, como o tamanho do seu &quot;papel&quot; (canvas).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;draw()&lt;/code&gt;&lt;/strong&gt;: Aqui é onde a mágica acontece. Essa função é um &lt;strong&gt;loop infinito&lt;/strong&gt;. Ela é lida ciclicamente enquanto o programa roda. Se você desenhar algo aqui, pode criar animações ou responder a eventos, como o movimento do mouse.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Com essa estrutura pronta, vale acessar a documentação e entender as inúmeras possibilidades de formas, elementos tipográficos, animações, etc que é possível criar com essas ferramentas. Esse pedaço de código abaixo é o que gerou a imagem que eu mostrei no início do artigo.&lt;br&gt;
&lt;/p&gt;

&lt;div class=&quot;highlight js-code-highlight&quot;&gt;
&lt;pre class=&quot;highlight java&quot;&gt;&lt;code&gt;&lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;draw&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(){&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;background&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;255&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;fill&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;noStroke&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;();&lt;/span&gt;

  &lt;span class=&quot;kt&quot;&gt;float&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;tiles&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mouseX&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;kt&quot;&gt;float&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;tileSize&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;width&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;tiles&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;n&quot;&gt;translate&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;tileSize&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;tileSize&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;tiles&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;++){&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;tiles&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;++){&lt;/span&gt;

      &lt;span class=&quot;c1&quot;&gt;//Picks the color based on the pixel, in which the pixel is the size of the tiles&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;color&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;c&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;img&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;tileSize&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;),&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;tileSize&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;));&lt;/span&gt;
      &lt;span class=&quot;kt&quot;&gt;float&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;size&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;brightness&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;),&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;255&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;20&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;

      &lt;span class=&quot;n&quot;&gt;ellipse&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;tileSize&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;tileSize&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;size&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;size&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;};&lt;/span&gt;
  &lt;span class=&quot;o&quot;&gt;};&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;div class=&quot;highlight__panel js-actions-panel&quot;&gt;
&lt;div class=&quot;highlight__panel-action js-fullscreen-code-action&quot;&gt;
    &lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; width=&quot;20px&quot; height=&quot;20px&quot; viewBox=&quot;0 0 24 24&quot; class=&quot;highlight-action crayons-icon highlight-action--fullscreen-on&quot;&gt;&lt;title&gt;Enter fullscreen mode&lt;/title&gt;
    &lt;path d=&quot;M16 3h6v6h-2V5h-4V3zM2 3h6v2H4v4H2V3zm18 16v-4h2v6h-6v-2h4zM4 19h4v2H2v-6h2v4z&quot;&gt;&lt;/path&gt;
&lt;/svg&gt;

    &lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; width=&quot;20px&quot; height=&quot;20px&quot; viewBox=&quot;0 0 24 24&quot; class=&quot;highlight-action crayons-icon highlight-action--fullscreen-off&quot;&gt;&lt;title&gt;Exit fullscreen mode&lt;/title&gt;
    &lt;path d=&quot;M18 7h4v2h-6V3h2v4zM8 9H2V7h4V3h2v6zm10 8v4h-2v-6h6v2h-4zM8 15v6H6v-4H2v-2h6z&quot;&gt;&lt;/path&gt;
&lt;/svg&gt;

&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;



&lt;h2&gt;
  &lt;a name=&quot;uma-ferramenta-visual-de-aprendizado-de-programa%C3%A7%C3%A3o&quot; href=&quot;https://dev.to/he4rt/programacao-criativa-vamos-desenhar-com-codigo-4a1#uma-ferramenta-visual-de-aprendizado-de-programa%C3%A7%C3%A3o&quot;&gt;
  &lt;/a&gt;
  Uma ferramenta visual de aprendizado de programação
&lt;/h2&gt;

&lt;p&gt;É possível que você ainda não tenha sido convencido de explorar o Processing e a programação criativa para despertar o lado artista que mora em você? Se sim, eu te faço uma pergunta: quando é que você parou de desenhar e virou um adulto chato sem criatividade?&lt;/p&gt;


&lt;div style=&quot;max-width: 315px; margin: 0 auto;&quot;&gt;
    &lt;iframe src=&quot;https://www.youtube.com/embed/6IFl-H9lPII&quot; style=&quot;width: 100%; aspect-ratio: 9 / 16;&quot; allowfullscreen=&quot;&quot; loading=&quot;lazy&quot; referrerpolicy=&quot;no-referrer&quot;&gt;
    &lt;/iframe&gt;
  &lt;/div&gt;


&lt;p&gt;Brincadeiras à parte, talvez então você seja convencido de que a programação criativa pode também servir como um facilitador para o aprendizado técnico porque transforma conceitos abstratos (como laços de repetição e condicionais) em resultados visuais e imediatos na sua tela.&lt;/p&gt;

&lt;p&gt;É como um &quot;debug visual&quot;. Afinal, ver um &lt;code&gt;for loop&lt;/code&gt; gerando 100 bolinhas coloridas na sua tela em tempo real é a melhor forma de &quot;debugar&quot; sua lógica mental.&lt;/p&gt;

&lt;h2&gt;
  &lt;a name=&quot;conclus%C3%A3o-experimente&quot; href=&quot;https://dev.to/he4rt/programacao-criativa-vamos-desenhar-com-codigo-4a1#conclus%C3%A3o-experimente&quot;&gt;
  &lt;/a&gt;
  Conclusão: Experimente!
&lt;/h2&gt;

&lt;p&gt;Se você sente que a programação às vezes fica um pouco &quot;rígida&quot; ou mecânica demais, tente criar um sketch no Processing ou p5.js. É uma forma de usar sua lógica para algo puramente estético e divertido.&lt;/p&gt;

&lt;p&gt;Abaixo deixo alguns links para encontrar referências de projetos, materiais gratuitos e comunidades pra quem quiser conhecer mais:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href=&quot;https://openprocessing.org/&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;OpenProcessing&lt;/a&gt;: Plataforma de hospedagem de projetos em Processing, é o GitHub da Programação Criativa&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href=&quot;https://github.com/arteprog/programacao-criativa&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Curso gratuito de Programação Criativa&lt;/a&gt;: Repositório no GitHub de curso por Monica Rizzolli e Alexandre Villares&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href=&quot;https://codigotranscendente.github.io/livro/livro/lindex.html&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Código Transcendente : Uma introdução prática à programação e arte gerativa&lt;/a&gt;: Livro de Mateus Paresqui Berruezo &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href=&quot;https://www.instagram.com/compoeticabr/&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Compoética&lt;/a&gt; - Encontro Brasileiro de Programação Criativa&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href=&quot;https://t.me/programacaocriativa&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Comunidade de Programação Criativa no Brasil no Telegram&lt;/a&gt; &lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href=&quot;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%2Faf25yz4cg94uhg3te23l.png&quot; class=&quot;article-body-image-wrapper&quot;&gt;&lt;img src=&quot;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%2Faf25yz4cg94uhg3te23l.png&quot; alt=&quot;Ilustração tipográfica com a palavra Explore repetida diversas vezes&quot; loading=&quot;lazy&quot; width=&quot;800&quot; height=&quot;897&quot; referrerpolicy=&quot;no-referrer&quot;&gt;&lt;/a&gt;&lt;/p&gt;


            </description><link>https://dev.to/he4rt/programacao-criativa-vamos-desenhar-com-codigo-4a1</link><guid isPermaLink="false">https://dev.to/he4rt/programacao-criativa-vamos-desenhar-com-codigo-4a1</guid><pubDate>Sun, 02 Aug 2026 01:36:54 GMT</pubDate><author>Sara Aniceto</author><enclosure url="https://media2.dev.to/dynamic/image/width=1000,height=420,fit=cover,gravity=auto,format=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F1u0lfbde3oracspfkmuh.png" type="image/jpeg"></enclosure><category>creativecoding</category><category>p5js</category><category>braziliandevs</category></item><item><title>Catbot: Custom Grammar Problem Fixed</title><description>&lt;p&gt;&lt;em&gt;This is a submission for &lt;a href=&quot;https://dev.to/bugsmash&quot;&gt;DEV&#39;s Summer Bug Smash: Smash Stories&lt;/a&gt; powered by &lt;a href=&quot;https://sentry.io/&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Sentry&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  &lt;a name=&quot;overview&quot; href=&quot;https://dev.to/annavi11arrea1/catbot-custom-grammar-problem-fixed-oc5#overview&quot;&gt;
  &lt;/a&gt;
  Overview
&lt;/h2&gt;

&lt;p&gt;Sometimes we discover our limitations through a series of failures. We don’t understand why something is not working, despite having tried multiple improvements and optimizations. My desktop pet, Catbot, is no exception. I had issues with Catbot cutting me off or not letting me finish before it started talking. It would constantly tell me that I was calling it cat bought and not Catbot. This was an actual pain in the rear. Catbot would spend a lot of time explaining this to me. &lt;/p&gt;

&lt;p&gt;I was able to tweak the listening window, so that Catbot would stop listening after a 1.5 second pause. This gives me enough time to finish my sentence, given my natural pauses and end of sentences. Controlling the pause gap helped tremendously. Going from .5 seconds to 1.5 seconds made all the difference in the world.&lt;/p&gt;

&lt;p&gt;After adding a better layer of control to Catbot’s listening skills, I still had difficulties using Catbot’s name. It thought I was saying “Catfight”, “Cat bought”, and even “Lawrence” one time. This will seem brief to the reader but it was only after multiple sessions of frustration that I came to the realization that perhaps my webcam mic was not a great listening tool for Catbot - as it picks up all sounds in the room. After some quick googling, I was very convinced that a better mic would help. I popped on my fancy cat ear headset and not to my surprise, Catbot could understand what I was saying much better. We need to make sure we are using the best hardware for the job. My headset mic is a close range omni directional mic that does a good job leaving out all the background noise.&lt;/p&gt;

&lt;p&gt;However, Catbot refused to respond to its name and would even argue with me! It would tell me that it wants to be called by it&#39;s actual name, Catbot. (Cat bot) So everytime I said its name, there was a debate and some long side tangent dialogue to follow. This was an awful experience.&lt;/p&gt;

&lt;p&gt;THE BUG: Catbot not listening correctly.&lt;/p&gt;


&lt;hr&gt;


&lt;h2&gt;
  &lt;a name=&quot;demo&quot; href=&quot;https://dev.to/annavi11arrea1/catbot-custom-grammar-problem-fixed-oc5#demo&quot;&gt;
  &lt;/a&gt;
  DEMO
&lt;/h2&gt;


&lt;div style=&quot;max-width: 315px; margin: 0 auto;&quot;&gt;
    &lt;iframe src=&quot;https://www.youtube.com/embed/Nhddz9BwU8g&quot; style=&quot;width: 100%; aspect-ratio: 9 / 16;&quot; allowfullscreen=&quot;&quot; loading=&quot;lazy&quot; referrerpolicy=&quot;no-referrer&quot;&gt;
    &lt;/iframe&gt;
  &lt;/div&gt;


&lt;p&gt;This is an interesting type of bug, not the typical software battle, but rather a conceptual bug. The type of situation where massive learning happens. &lt;/p&gt;


&lt;hr&gt;


&lt;h2&gt;
  &lt;a name=&quot;much-ado-about-graphs&quot; href=&quot;https://dev.to/annavi11arrea1/catbot-custom-grammar-problem-fixed-oc5#much-ado-about-graphs&quot;&gt;
  &lt;/a&gt;
  Much Ado About Graphs
&lt;/h2&gt;

&lt;p&gt;I discovered that runtime graphs are not supported by vosk-model-en-us-0.22, which was the preferred, larger  model. The training graphs were being ignored. Which means training Catbot on how I say “catbot” is ignored. &lt;em&gt;This is an outrage.&lt;/em&gt; The decoding graph is pre-composed into one frozen file, and there is nowhere to swap a grammar into. &lt;/p&gt;

&lt;p&gt;Transversely, a model that does support custom grammar is vosk-model-en-us-0.22-lgraph. However, It is important that we are not really adding custom commands, but controlling the output choices available. These feel like custom commands but they are better stated as custom directions, or disallow lists.&lt;/p&gt;

&lt;p&gt;Catbot uses kaldi, which decodes against a single finite state transducer, HCLG, built by composing 4 layers: H, C, L, G. I will discuss the G layer.&lt;/p&gt;

&lt;p&gt;G is the grammar / language model, which maps words to words. It assigns a cost to every possible word sequence. The decoder then picks a winner. A score is a negative log probability, and every arc in the graph carries weight, which add along the path. Negative log probabilities mean that a lower number is better, and adding costs is multiplying probabilities. Here is the english version:&lt;/p&gt;

&lt;p&gt;Total cost = &lt;/p&gt;

&lt;div class=&quot;table-wrapper-paragraph&quot;&gt;&lt;table&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;th&gt;Acoustic cost&lt;/th&gt;
&lt;th&gt;Language cost&lt;/th&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;“How well do these phones match the audio frames?”&lt;/td&gt;
&lt;td&gt;“How likely is anyone to say this sentence in the first place?”&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;
&lt;h2&gt;
  &lt;a name=&quot;facts-about-the-situation&quot; href=&quot;https://dev.to/annavi11arrea1/catbot-custom-grammar-problem-fixed-oc5#facts-about-the-situation&quot;&gt;
  &lt;/a&gt;
  Facts about the situation
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Neither of these alone is useful! &lt;/li&gt;
&lt;li&gt;The Acoustics can not differentiate “ice cream” from “I scream”. They are the same sounds. &lt;/li&gt;
&lt;li&gt;The language model does not hear. The decoder searches for the sequence minimizing the sum, which is why an LM’s job is best described as scoring sequences. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But wait... why does this situation feel like Helen Keller? Because it&#39;s a similar situation.&lt;/p&gt;

&lt;p&gt;In the real life story of Helen Keller and Anne Sullivan, there was a communication problem. An intermediary interface must bridge two completely different sensory and data modalities. In computer science, this is called multimodal alignment. This method is just like the tactile “finger-spelling” method that connected Hellen Keller to the world.&lt;/p&gt;

&lt;p&gt;It was not until realizing I needed two different models to handle specific use cases that I realized this fundamental problem of having AI process real analogue data, which has now placed itself at the forefront of my curiosity and this project.&lt;/p&gt;

&lt;p&gt;A simple table will help you wrap your head around this idea without needing to explain too much:&lt;/p&gt;

&lt;div class=&quot;table-wrapper-paragraph&quot;&gt;&lt;table&gt;
    &lt;thead&gt;
        &lt;tr&gt;
            &lt;th&gt;Element&lt;/th&gt;
            &lt;th&gt;Helen Keller&lt;/th&gt;
            &lt;th&gt;Anne Sullivan (The Teacher)&lt;/th&gt;
            &lt;th&gt;The Outside World&lt;/th&gt;
        &lt;/tr&gt;
    &lt;/thead&gt;
    &lt;tbody&gt;
        &lt;tr&gt;
            &lt;td&gt;AI Role&lt;/td&gt;
            &lt;td&gt;Acoustics Model (Vosk)&lt;/td&gt;
            &lt;td&gt;The Alignment Interface (Your Code Pipeline)&lt;/td&gt;
            &lt;td&gt;Language Model (LLM)&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
            &lt;td&gt;Data Type&lt;/td&gt;
            &lt;td&gt;Raw sensory inputs (audio waves/frequencies).&lt;/td&gt;
            &lt;td&gt;The translator bridging two completely different modalities.&lt;/td&gt;
            &lt;td&gt;Symbolic language (written words/tokens).&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
            &lt;td&gt;Function&lt;/td&gt;
            &lt;td&gt;Perceives physical sounds but completely lacks semantic context or logic.&lt;/td&gt;
            &lt;td&gt;Maps raw physical acoustic patterns directly into structured text blocks.&lt;/td&gt;
            &lt;td&gt;Processes structured text tokens logically but cannot directly &quot;hear&quot; physical waves.&lt;/td&gt;
        &lt;/tr&gt;
    &lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Let’s take a look at how words are “chosen”:&lt;/p&gt;

&lt;p&gt;A state in G represents history, the last n-1 words, and each outgoing arc is a next possible word, weighted by -log P(word | history):&lt;/p&gt;

&lt;p&gt;“The cat” –sat (cost 4.1)--&amp;gt;&lt;br&gt;
               –ate (cost 5.3)--&amp;gt;&lt;br&gt;
              –sad (cost 9.8)--&amp;gt;&lt;/p&gt;

&lt;p&gt;…So basically words are chosen via likeliness. Catbot is not a real word, so catbot was never going to understand it as such, thus interpreting “Catbot engage” as “kappa engage” and other oddity phrases that would make sense to the model as it is trained.&lt;/p&gt;

&lt;p&gt;I had Claude synthesize some phrases for me, and it proves the issue I am having plain as day.&lt;/p&gt;

&lt;p&gt;SPOKEN: Catbot, engage.&lt;br&gt;
    1. conf  114.1   kappa engage&lt;br&gt;
    2. conf  112.1   cappa engage&lt;/p&gt;

&lt;p&gt;Kappa engage (a.k.a. “Catbot, engage.”) is a vocabulary trap. There is no path through G that emits Catbot, so the decoder does the only thing it can, it finds the closest match to the sound of the word. This is why saying “Catbot” failed EVERY. SINGLE. TIME. This speech recognition bug lies in the grammar available. The word “Catbot” is not really an actual word. I made that up. This is an infinite impossibility. &lt;/p&gt;

&lt;p&gt;Shortly before this deep dive, I told Catbot to respond to “CB”. This is English alphabet, real letters that have to exist. Catbot is now configured to respond to CB. When I say CB, it knows I am talking about it. Unmistakable. Functional. As a quick fix!&lt;/p&gt;

&lt;p&gt;As stated previously, we can disallow the decoder to consider certain words, such as “kappa” as noted above. &lt;/p&gt;

&lt;p&gt;If I say “Catbot, engage” without restrictions, the model hears “Kappa engage”. If we restrict the model, disallowing “kappa”, Catbot will hear “cat bot engage”. Since both “cat” and “bot” are commonly used words, they are available to the model.&lt;/p&gt;

&lt;p&gt;As you can see, training an interactive voice model is a long journey full of mysteries. From bad hardware to understanding model boundaries, sometimes we can actually gain more, with less! (Less meaning removing words from vocabulary, in this case.) &lt;/p&gt;

&lt;p&gt;And this can only be done by using the vosk-model-en-us-0.22-lgraph alongside vosk-model-en-us-0.22. This gives Catbot the tools it needs to respond in ways that make sense to custom words.&lt;/p&gt;


&lt;hr&gt;

&lt;h2&gt;
  &lt;a name=&quot;code-samples&quot; href=&quot;https://dev.to/annavi11arrea1/catbot-custom-grammar-problem-fixed-oc5#code-samples&quot;&gt;
  &lt;/a&gt;
  Code Samples
&lt;/h2&gt;

&lt;p&gt;So then, I Implemented a dual recognizer into Catbot:&lt;/p&gt;

&lt;p&gt;Catbot_voice.py&lt;br&gt;
&lt;/p&gt;

&lt;div class=&quot;highlight js-code-highlight&quot;&gt;
&lt;pre class=&quot;highlight python&quot;&gt;&lt;code&gt;
 &lt;span class=&quot;mi&quot;&gt;44&lt;/span&gt;  &lt;span class=&quot;n&quot;&gt;KOKORO_VOICES&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ROOT&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;models&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;voices-v1.0.bin&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;
 &lt;span class=&quot;mi&quot;&gt;45&lt;/span&gt;  &lt;span class=&quot;n&quot;&gt;VOSK_BIG&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ROOT&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;models&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;vosk-model-en-us-0.22-lgraph&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;
 &lt;span class=&quot;mi&quot;&gt;46&lt;/span&gt;  &lt;span class=&quot;n&quot;&gt;VOSK_SMALL&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ROOT&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;models&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;vosk-model-small-en-us-0.15&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;
 &lt;span class=&quot;mi&quot;&gt;47&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;# Dynamic-graph model — the only kind that accepts a runtime grammar. A model
&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;48&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;# that ships a pre-composed graph/HCLG.fst has no seam to insert one into;
&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;49&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;# Vosk logs &quot;Runtime graphs are not supported by this model&quot; and decodes
&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;50&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;# freely, which is worse than having no grammar recognizer at all. Detected by
&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;51&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;# the presence of graph/Gr.fst (the language model kept as a separate file).
&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;52&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;VOSK_DYNAMIC&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ROOT&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;models&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;vosk-model-en-us-0.22-lgraph&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;
 &lt;span class=&quot;mi&quot;&gt;53&lt;/span&gt;
 &lt;span class=&quot;mi&quot;&gt;54&lt;/span&gt;  &lt;span class=&quot;n&quot;&gt;SAMPLE_RATE&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;16000&lt;/span&gt;
 &lt;span class=&quot;mi&quot;&gt;55&lt;/span&gt;  &lt;span class=&quot;n&quot;&gt;BASE&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;sa&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;https://localhost:&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;os&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;getenv&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;CATBOT_PORT&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;sh&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;8800&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;
&lt;div class=&quot;highlight__panel js-actions-panel&quot;&gt;
&lt;div class=&quot;highlight__panel-action js-fullscreen-code-action&quot;&gt;
    &lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; width=&quot;20px&quot; height=&quot;20px&quot; viewBox=&quot;0 0 24 24&quot; class=&quot;highlight-action crayons-icon highlight-action--fullscreen-on&quot;&gt;&lt;title&gt;Enter fullscreen mode&lt;/title&gt;
    &lt;path d=&quot;M16 3h6v6h-2V5h-4V3zM2 3h6v2H4v4H2V3zm18 16v-4h2v6h-6v-2h4zM4 19h4v2H2v-6h2v4z&quot;&gt;&lt;/path&gt;
&lt;/svg&gt;

    &lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; width=&quot;20px&quot; height=&quot;20px&quot; viewBox=&quot;0 0 24 24&quot; class=&quot;highlight-action crayons-icon highlight-action--fullscreen-off&quot;&gt;&lt;title&gt;Exit fullscreen mode&lt;/title&gt;
    &lt;path d=&quot;M18 7h4v2h-6V3h2v4zM8 9H2V7h4V3h2v6zm10 8v4h-2v-6h6v2h-4zM8 15v6H6v-4H2v-2h6z&quot;&gt;&lt;/path&gt;
&lt;/svg&gt;

&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;



&lt;p&gt;and…&lt;br&gt;
&lt;/p&gt;

&lt;div class=&quot;highlight js-code-highlight&quot;&gt;
&lt;pre class=&quot;highlight python&quot;&gt;&lt;code&gt; &lt;span class=&quot;mi&quot;&gt;102&lt;/span&gt;          &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;None&lt;/span&gt;
 &lt;span class=&quot;mi&quot;&gt;103&lt;/span&gt;  &lt;span class=&quot;n&quot;&gt;RE_LEARNED_WAKE&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;_load_learned_wake&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
 &lt;span class=&quot;mi&quot;&gt;104&lt;/span&gt;
 &lt;span class=&quot;mi&quot;&gt;105&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;# ---- grammar-constrained wake/command recognizer ------------------------
&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;106&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;# A SECOND recognizer decodes the same audio against nothing but the phrases
&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;107&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;# below. It can&#39;t hear anything else, so &quot;catbot engage&quot; can&#39;t come out as
&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;108&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;# &quot;kappa engage&quot; — that word doesn&#39;t exist in its graph. Anything Anna says
&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;109&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;# that isn&#39;t a listed phrase decodes as &quot;[unk]&quot;, which is exactly why this
&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;110&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;# only ever SUPPLEMENTS the free recognizer (which still handles all
&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;111&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;# conversation) instead of replacing it.
&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;112&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;#
&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;113&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;# Every word must be in the model&#39;s vocabulary or Vosk silently drops it:
&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;114&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;# &quot;catbot&quot; is not an English word, but &quot;cat bot&quot; is two of them. That&#39;s the
&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;115&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;# whole reason his name is spelled out here — _build_grammar checks each word
&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;116&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;# against the model and logs anything it had to drop.
&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;117&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;WAKE_NAME_FORMS&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;cat bot&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;cat pot&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;cat bought&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;cat bottom&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;cat but&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
 &lt;span class=&quot;mi&quot;&gt;118&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;                   &lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;catfight&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;combat&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;cabot&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;kat bot&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;cap pot&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
 &lt;span class=&quot;mi&quot;&gt;119&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;# what can follow his name (empty = just the name, which wakes him too)
&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;120&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;GRAMMAR_TAILS&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;engage&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;engaged&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;wake up&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;wake&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
 &lt;span class=&quot;mi&quot;&gt;121&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;                 &lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;are you listening&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;are you there&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;you there&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
 &lt;span class=&quot;mi&quot;&gt;122&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;                 &lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;go to sleep&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;sleep&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;stop&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;stop listening&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
 &lt;span class=&quot;mi&quot;&gt;123&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;                 &lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;be quiet&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;quiet&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;shut up&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;hush&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
 &lt;span class=&quot;mi&quot;&gt;124&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;                 &lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;open terminal&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;close terminal&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;approve&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;skip&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
 &lt;span class=&quot;mi&quot;&gt;125&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;# phrases that stand alone, with or without his name
&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;126&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;GRAMMAR_BARE&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;open terminal&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;close terminal&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
 &lt;span class=&quot;mi&quot;&gt;127&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;
 &lt;span class=&quot;mi&quot;&gt;128&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;
 &lt;span class=&quot;mi&quot;&gt;129&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;_build_grammar&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;model&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;str&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;None&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
 &lt;span class=&quot;mi&quot;&gt;130&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;sh&quot;&gt;&quot;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;JSON phrase list for the constrained recognizer, filtered to words the
 131 +    model actually knows. Returns None if nothing usable survived.&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&quot;&quot;&lt;/span&gt;
 &lt;span class=&quot;mi&quot;&gt;132&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;names&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;list&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;WAKE_NAME_FORMS&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
 &lt;span class=&quot;mi&quot;&gt;133&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;c1&quot;&gt;# whatever wake_training.py learned from Anna&#39;s own mic counts too
&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;134&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;k&quot;&gt;try&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
 &lt;span class=&quot;mi&quot;&gt;135&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;        &lt;span class=&quot;n&quot;&gt;learned&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;json&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;loads&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ROOT&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;catbot_wake_variants.json&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;read_text&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;())&lt;/span&gt;
 &lt;span class=&quot;mi&quot;&gt;136&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;        &lt;span class=&quot;n&quot;&gt;names&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;w&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;strip&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;lower&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;w&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;learned&lt;/span&gt;
 &lt;span class=&quot;mi&quot;&gt;137&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;                  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;w&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;strip&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;and&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;w&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;strip&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;lower&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;not&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;names&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
 &lt;span class=&quot;mi&quot;&gt;138&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;k&quot;&gt;except&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;Exception&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
 &lt;span class=&quot;mi&quot;&gt;139&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;        &lt;span class=&quot;k&quot;&gt;pass&lt;/span&gt;
 &lt;span class=&quot;mi&quot;&gt;140&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;
 &lt;span class=&quot;mi&quot;&gt;141&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;phrases&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;sa&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;lead&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s&quot;&gt; &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;tail&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;strip&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
 &lt;span class=&quot;mi&quot;&gt;142&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;               &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;lead&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;hey &lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
 &lt;span class=&quot;mi&quot;&gt;143&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;               &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;name&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;names&lt;/span&gt;
 &lt;span class=&quot;mi&quot;&gt;144&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;               &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;tail&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;GRAMMAR_TAILS&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
 &lt;span class=&quot;mi&quot;&gt;145&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;phrases&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;update&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;GRAMMAR_BARE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
 &lt;span class=&quot;mi&quot;&gt;146&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;
 &lt;span class=&quot;mi&quot;&gt;147&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;known&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;dict&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;str&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;bool&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{}&lt;/span&gt;
 &lt;span class=&quot;mi&quot;&gt;148&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;in_vocab&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;word&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;str&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;bool&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
 &lt;span class=&quot;mi&quot;&gt;149&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;word&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;not&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;known&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
 &lt;span class=&quot;mi&quot;&gt;150&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;            &lt;span class=&quot;k&quot;&gt;try&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
 &lt;span class=&quot;mi&quot;&gt;151&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;                &lt;span class=&quot;n&quot;&gt;known&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;word&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;model&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;vosk_model_find_word&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;word&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;
 &lt;span class=&quot;mi&quot;&gt;152&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;            &lt;span class=&quot;k&quot;&gt;except&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;Exception&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
 &lt;span class=&quot;mi&quot;&gt;153&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;                &lt;span class=&quot;n&quot;&gt;known&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;word&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;True&lt;/span&gt;      &lt;span class=&quot;c1&quot;&gt;# can&#39;t check — assume fine
&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;154&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;known&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;word&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
 &lt;span class=&quot;mi&quot;&gt;155&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;
 &lt;span class=&quot;mi&quot;&gt;156&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;kept&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;dropped&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[],&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
 &lt;span class=&quot;mi&quot;&gt;157&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;phrase&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;sorted&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;phrases&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
 &lt;span class=&quot;mi&quot;&gt;158&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;        &lt;span class=&quot;n&quot;&gt;missing&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;w&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;w&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;phrase&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;split&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;not&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;in_vocab&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;w&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)]&lt;/span&gt;
 &lt;span class=&quot;mi&quot;&gt;159&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;missing&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
 &lt;span class=&quot;mi&quot;&gt;160&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;            &lt;span class=&quot;n&quot;&gt;dropped&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;update&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;missing&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
 &lt;span class=&quot;mi&quot;&gt;161&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;            &lt;span class=&quot;k&quot;&gt;continue&lt;/span&gt;
 &lt;span class=&quot;mi&quot;&gt;162&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;        &lt;span class=&quot;n&quot;&gt;kept&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;append&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;phrase&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
 &lt;span class=&quot;mi&quot;&gt;163&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;dropped&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
 &lt;span class=&quot;mi&quot;&gt;164&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;        &lt;span class=&quot;n&quot;&gt;logger&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;info&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;grammar: dropped phrases using words the model doesn&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;t &lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;
 &lt;span class=&quot;mi&quot;&gt;165&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;                    &lt;span class=&quot;sa&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;know: &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;sorted&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;dropped&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
 &lt;span class=&quot;mi&quot;&gt;166&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;not&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;kept&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
 &lt;span class=&quot;mi&quot;&gt;167&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;None&lt;/span&gt;
 &lt;span class=&quot;mi&quot;&gt;168&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;c1&quot;&gt;# &quot;[unk]&quot; is the escape hatch: it lets the decoder say &quot;that wasn&#39;t any of
&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;169&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;c1&quot;&gt;# these&quot; instead of forcing Anna&#39;s conversation into the nearest command
&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;170&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;json&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;dumps&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;kept&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;[unk]&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt;
 &lt;span class=&quot;mi&quot;&gt;171&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;
 &lt;span class=&quot;mi&quot;&gt;172&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;
 &lt;span class=&quot;mi&quot;&gt;173&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# in-conversation commands
&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;174&lt;/span&gt;  &lt;span class=&quot;n&quot;&gt;PROVIDER_WORDS&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
 &lt;span class=&quot;mi&quot;&gt;175&lt;/span&gt;      &lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;claude&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;anthropic&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;anthropic&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;anthropic&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;div class=&quot;highlight__panel js-actions-panel&quot;&gt;
&lt;div class=&quot;highlight__panel-action js-fullscreen-code-action&quot;&gt;
    &lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; width=&quot;20px&quot; height=&quot;20px&quot; viewBox=&quot;0 0 24 24&quot; class=&quot;highlight-action crayons-icon highlight-action--fullscreen-on&quot;&gt;&lt;title&gt;Enter fullscreen mode&lt;/title&gt;
    &lt;path d=&quot;M16 3h6v6h-2V5h-4V3zM2 3h6v2H4v4H2V3zm18 16v-4h2v6h-6v-2h4zM4 19h4v2H2v-6h2v4z&quot;&gt;&lt;/path&gt;
&lt;/svg&gt;

    &lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; width=&quot;20px&quot; height=&quot;20px&quot; viewBox=&quot;0 0 24 24&quot; class=&quot;highlight-action crayons-icon highlight-action--fullscreen-off&quot;&gt;&lt;title&gt;Exit fullscreen mode&lt;/title&gt;
    &lt;path d=&quot;M18 7h4v2h-6V3h2v4zM8 9H2V7h4V3h2v6zm10 8v4h-2v-6h6v2h-4zM8 15v6H6v-4H2v-2h6z&quot;&gt;&lt;/path&gt;
&lt;/svg&gt;

&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;



&lt;p&gt;As well as…&lt;br&gt;
&lt;/p&gt;

&lt;div class=&quot;highlight js-code-highlight&quot;&gt;
&lt;pre class=&quot;highlight python&quot;&gt;&lt;code&gt;
 &lt;span class=&quot;mi&quot;&gt;470&lt;/span&gt;          &lt;span class=&quot;c1&quot;&gt;# Lower CATBOT_END_SILENCE = faster to answer but more likely to cut you
&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;471&lt;/span&gt;          &lt;span class=&quot;c1&quot;&gt;# off mid-sentence; higher = more patient. 0.65s is a good balance.
&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;472&lt;/span&gt;          &lt;span class=&quot;n&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;end_silence&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;float&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;os&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;getenv&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;CATBOT_END_SILENCE&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;0.65&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
 &lt;span class=&quot;mi&quot;&gt;473&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;
 &lt;span class=&quot;mi&quot;&gt;474&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;        &lt;span class=&quot;c1&quot;&gt;# Second recognizer, constrained to the wake/command grammar above.
&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;475&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;        &lt;span class=&quot;c1&quot;&gt;# Runs on its own dynamic-graph model so the big model keeps handling
&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;476&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;        &lt;span class=&quot;c1&quot;&gt;# conversation with its full rescoring stack. Cost, measured: ~200 MB
&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;477&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;        &lt;span class=&quot;c1&quot;&gt;# of RAM and roughly DOUBLE the decode CPU (4.3 -&amp;gt; 8.0 ms per 62 ms
&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;478&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;        &lt;span class=&quot;c1&quot;&gt;# block) — the grammar shrinks the search, but a second acoustic model
&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;479&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;        &lt;span class=&quot;c1&quot;&gt;# still runs on every block. Still only 0.13x realtime, so it adds no
&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;480&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;        &lt;span class=&quot;c1&quot;&gt;# latency; set CATBOT_GRAMMAR=0 if that ever stops being true.
&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;481&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;        &lt;span class=&quot;n&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_grec&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_gmodel&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;None&lt;/span&gt;
 &lt;span class=&quot;mi&quot;&gt;482&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;os&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;getenv&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;CATBOT_GRAMMAR&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;split&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;strip&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;lower&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; \
 &lt;span class=&quot;mi&quot;&gt;483&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;                &lt;span class=&quot;ow&quot;&gt;not&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;off&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;no&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
 &lt;span class=&quot;mi&quot;&gt;484&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;            &lt;span class=&quot;k&quot;&gt;try&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
 &lt;span class=&quot;mi&quot;&gt;485&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;                &lt;span class=&quot;n&quot;&gt;name&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;os&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;getenv&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;CATBOT_GRAMMAR_MODEL&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;sh&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;split&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;strip&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
 &lt;span class=&quot;mi&quot;&gt;486&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;                &lt;span class=&quot;n&quot;&gt;gdir&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ROOT&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;models&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;name&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;name&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;VOSK_DYNAMIC&lt;/span&gt;
 &lt;span class=&quot;mi&quot;&gt;487&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;                &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;not&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;gdir&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;graph&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;Gr.fst&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;exists&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;():&lt;/span&gt;
 &lt;span class=&quot;mi&quot;&gt;488&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;                    &lt;span class=&quot;n&quot;&gt;logger&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;warning&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
 &lt;span class=&quot;mi&quot;&gt;489&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;                        &lt;span class=&quot;sa&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;grammar recognizer OFF: &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;gdir&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s&quot;&gt; has no dynamic &lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;
 &lt;span class=&quot;mi&quot;&gt;489&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;                        &lt;span class=&quot;sa&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;graph (graph/Gr.fst) — runtime grammars need one&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
 &lt;span class=&quot;mi&quot;&gt;490&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;                &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
 &lt;span class=&quot;mi&quot;&gt;491&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;                    &lt;span class=&quot;c1&quot;&gt;# keep the Model referenced for as long as the recognizer
&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;492&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;                    &lt;span class=&quot;c1&quot;&gt;# lives (the binding only borrows its handle)
&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;493&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;                    &lt;span class=&quot;n&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_gmodel&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;vosk&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Model&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;str&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;gdir&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
 &lt;span class=&quot;mi&quot;&gt;494&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;                    &lt;span class=&quot;n&quot;&gt;grammar&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;_build_grammar&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_gmodel&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
 &lt;span class=&quot;mi&quot;&gt;495&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;                    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;not&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;grammar&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
 &lt;span class=&quot;mi&quot;&gt;496&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;                        &lt;span class=&quot;k&quot;&gt;raise&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;RuntimeError&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;no usable grammar phrases&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
 &lt;span class=&quot;mi&quot;&gt;497&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;                    &lt;span class=&quot;n&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_grec&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;vosk&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;KaldiRecognizer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
 &lt;span class=&quot;mi&quot;&gt;498&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;                        &lt;span class=&quot;n&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_gmodel&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;SAMPLE_RATE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;grammar&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
 &lt;span class=&quot;mi&quot;&gt;499&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;                    &lt;span class=&quot;n&quot;&gt;logger&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;info&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;sa&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;Grammar recognizer ready (&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;gdir&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;
 &lt;span class=&quot;mi&quot;&gt;500&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;                                &lt;span class=&quot;sa&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;len&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;json&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;loads&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;grammar&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s&quot;&gt; phrases)&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
 &lt;span class=&quot;mi&quot;&gt;501&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;            &lt;span class=&quot;k&quot;&gt;except&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;Exception&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
 &lt;span class=&quot;mi&quot;&gt;502&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;                &lt;span class=&quot;n&quot;&gt;logger&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;exception&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;grammar recognizer failed to load — &lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;
 &lt;span class=&quot;mi&quot;&gt;503&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;                                 &lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;continuing with the free recognizer only&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
 &lt;span class=&quot;mi&quot;&gt;504&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;                &lt;span class=&quot;n&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_grec&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_gmodel&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;None&lt;/span&gt;
 &lt;span class=&quot;mi&quot;&gt;505&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;
 &lt;span class=&quot;mi&quot;&gt;506&lt;/span&gt;          &lt;span class=&quot;n&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_kokoro&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Kokoro&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;str&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;KOKORO_ONNX&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;str&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;KOKORO_VOICES&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
 &lt;span class=&quot;mi&quot;&gt;507&lt;/span&gt;          &lt;span class=&quot;c1&quot;&gt;# warm up the TTS so the FIRST spoken reply isn&#39;t slowed by cold-start
&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;508&lt;/span&gt;          &lt;span class=&quot;k&quot;&gt;try&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;div class=&quot;highlight__panel js-actions-panel&quot;&gt;
&lt;div class=&quot;highlight__panel-action js-fullscreen-code-action&quot;&gt;
    &lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; width=&quot;20px&quot; height=&quot;20px&quot; viewBox=&quot;0 0 24 24&quot; class=&quot;highlight-action crayons-icon highlight-action--fullscreen-on&quot;&gt;&lt;title&gt;Enter fullscreen mode&lt;/title&gt;
    &lt;path d=&quot;M16 3h6v6h-2V5h-4V3zM2 3h6v2H4v4H2V3zm18 16v-4h2v6h-6v-2h4zM4 19h4v2H2v-6h2v4z&quot;&gt;&lt;/path&gt;
&lt;/svg&gt;

    &lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; width=&quot;20px&quot; height=&quot;20px&quot; viewBox=&quot;0 0 24 24&quot; class=&quot;highlight-action crayons-icon highlight-action--fullscreen-off&quot;&gt;&lt;title&gt;Exit fullscreen mode&lt;/title&gt;
    &lt;path d=&quot;M18 7h4v2h-6V3h2v4zM8 9H2V7h4V3h2v6zm10 8v4h-2v-6h6v2h-4zM8 15v6H6v-4H2v-2h6z&quot;&gt;&lt;/path&gt;
&lt;/svg&gt;

&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;



&lt;p&gt;So basically, both models run in parallel, as two arguments, against the same regexes. The grammar model helps with commands and the bigger model is used for more conversational interactions. This effectively makes Catbot a more efficient desktop companion. It is now much more pleasant to hang out with Catbot.&lt;/p&gt;


&lt;hr&gt;


&lt;h2&gt;
  &lt;a name=&quot;learning&quot; href=&quot;https://dev.to/annavi11arrea1/catbot-custom-grammar-problem-fixed-oc5#learning&quot;&gt;
  &lt;/a&gt;
  Learning
&lt;/h2&gt;

&lt;p&gt;This entire project, it&#39;s all learning, all new territory. Tuning Catbot&#39;s ears is a real challenge. I had an awakening about hardware limitations, and an enlightening experience about why different models are used and for what purpose. Since I cannot recompose the larger model with new grammar, I can use the lgraph model on the side to handle custom needs more gracefully. When I made the connection to Helen Keller, I understood the whole situation from a very global perspective. It&#39;s not really something I could fully understand without diving into chaos.&lt;/p&gt;

&lt;p&gt;Thank you for checking out Catbot&#39;s progress!&lt;/p&gt;


            </description><link>https://dev.to/annavi11arrea1/catbot-custom-grammar-problem-fixed-oc5</link><guid isPermaLink="false">https://dev.to/annavi11arrea1/catbot-custom-grammar-problem-fixed-oc5</guid><pubDate>Sat, 01 Aug 2026 16:03:02 GMT</pubDate><author>Anna Villarreal</author><enclosure url="https://media2.dev.to/dynamic/image/width=1000,height=420,fit=cover,gravity=auto,format=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fskd0m5rvbu69a8xg8n22.png" type="image/jpeg"></enclosure><category>devchallenge</category><category>bugsmash</category><category>catbot</category><category>ai</category></item><item><title>Pensar demais nem sempre ajuda e o que eu aprendi com isso</title><description>&lt;p&gt;Às vezes, a maior barreira para começar um projeto não é a complexidade do problema, mas a busca por uma solução perfeita antes mesmo da primeira linha de código.&lt;/p&gt;

&lt;p&gt;Na semana passada decidi criar um pacote Laravel para integrar a API do Asaas.&lt;/p&gt;

&lt;p&gt;A ideia parecia simples: construir algo reutilizável para projetos futuros e, de quebra, aprender mais sobre desenvolvimento de pacotes.&lt;/p&gt;

&lt;p&gt;Foi então que eu:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Abri a IDE e comecei a criar um cliente HTTP simples para a API da Asaas.&lt;/li&gt;
&lt;li&gt;15 minutos depois, eu já estava pesquisando sobre arquitetura de pacotes open source.&lt;/li&gt;
&lt;li&gt;Pensei em DTOs.&lt;/li&gt;
&lt;li&gt;Pensei em interfaces.&lt;/li&gt;
&lt;li&gt;Pensei em Services&lt;/li&gt;
&lt;/ol&gt;


&lt;hr&gt;

&lt;h2&gt;
  &lt;a name=&quot;o-que-eu-entendia-por-perfeito&quot; href=&quot;https://dev.to/he4rt/pensar-demais-nem-sempre-ajuda-e-o-que-eu-aprendi-com-isso-49pp#o-que-eu-entendia-por-perfeito&quot;&gt;
  &lt;/a&gt;
  O que eu entendia por &quot;perfeito&quot;?
&lt;/h2&gt;

&lt;p&gt;Na minha cabeça, um projeto bem feito precisava nascer parecido com os grandes projetos open source que eu admirava.&lt;/p&gt;

&lt;p&gt;Antes mesmo de validar a ideia, eu já pensava na arquitetura, na escalabilidade e em como aquele pacote pareceria para quem abrisse o repositório. E em outros cenários como:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;pensar na mesma arquitetura que grandes projetos usam antes de ter o primeiro caso de uso funcionando;&lt;/li&gt;
&lt;li&gt;tentar abordar todos os pontos da API da Asaas logo no começo, mesmo sem saber quais eu realmente ia usar;&lt;/li&gt;
&lt;li&gt;imaginar os atrativos que meu pacote teria para outros quererem usá-lo, antes de ele fazer qualquer coisa útil.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;No papel, parecia que eu estava pensando como alguém mais experiente, mas na prática, eu estava:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;apenas adiando a parte mais importante que era escrever código que resolvesse um problema real.&lt;/p&gt;
&lt;/blockquote&gt;


&lt;hr&gt;

&lt;h2&gt;
  &lt;a name=&quot;o-custo-disso-na-pr%C3%A1tica&quot; href=&quot;https://dev.to/he4rt/pensar-demais-nem-sempre-ajuda-e-o-que-eu-aprendi-com-isso-49pp#o-custo-disso-na-pr%C3%A1tica&quot;&gt;
  &lt;/a&gt;
  O custo disso na prática
&lt;/h2&gt;

&lt;p&gt;O curioso é que eu terminava o dia com a sensação de que tinha trabalhado bastante. Tinha lido sobre arquitetura, desenhado camadas, esboçado interfaces.&lt;/p&gt;

&lt;p&gt;Só que, olhando para o projeto, praticamente nada tinha sido construído:  nenhuma requisição enviada, nenhum teste rodando, nenhuma prova de que qualquer uma daquelas decisões fazia sentido.&lt;/p&gt;

&lt;p&gt;Com o tempo, isso começou a gerar um padrão: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Mais tempo buscando a estrutura &quot;perfeita&quot; do que resolvendo o problema real; &lt;/li&gt;
&lt;li&gt;Código difícil de entender por estar &quot;bem arquitetado&quot; demais, cedo demais;&lt;/li&gt;
&lt;li&gt;Medo de refatorar algo que ainda nem tinha provado valor; &lt;/li&gt;
&lt;li&gt;Uma frustração crescente por sentir que eu não estava evoluindo, só girando em torno da mesma decisão de design.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Não era falta de qualidade. Era complexidade antecipada.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;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%2F7k149dylxa01anrsh8v2.png&quot; class=&quot;article-body-image-wrapper&quot;&gt;&lt;img src=&quot;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%2F7k149dylxa01anrsh8v2.png&quot; alt=&quot;Infográfico comparando duas abordagens no desenvolvimento de software: planejar abstrações e arquitetura antes da implementação versus resolver primeiro o problema real e deixar a arquitetura evoluir conforme o projeto cresce.&quot; loading=&quot;lazy&quot; width=&quot;800&quot; height=&quot;533&quot; referrerpolicy=&quot;no-referrer&quot;&gt;&lt;/a&gt;&lt;/p&gt;


&lt;hr&gt;

&lt;h3&gt;
  &lt;a name=&quot;o-que-eu-estava-realmente-evitando&quot; href=&quot;https://dev.to/he4rt/pensar-demais-nem-sempre-ajuda-e-o-que-eu-aprendi-com-isso-49pp#o-que-eu-estava-realmente-evitando&quot;&gt;
  &lt;/a&gt;
  O que eu estava realmente evitando?
&lt;/h3&gt;

&lt;p&gt;Foi só depois que comecei a me perguntar outra coisa: por que eu estava tão preso nisso?&lt;/p&gt;

&lt;p&gt;Algumas hipóteses:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Eu estava evitando escrever código que eu soubesse, de antemão, que ia precisar refatorar depois?&lt;/li&gt;
&lt;li&gt;  Eu tinha medo de escrever algo &quot;ruim&quot; e isso aparecer publicamente num repositório open source?&lt;/li&gt;
&lt;li&gt;  Eu queria provar, pra mim mesmo, que conseguia arquitetar &quot;como um sênior&quot; antes mesmo de ter o problema resolvido?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A resposta provavelmente era um pouco de cada uma. E nenhuma delas tinha relação com o problema que o pacote deveria resolver.&lt;/p&gt;

&lt;p&gt;Só bem depois entendi que, no fundo, eu confundia complexidade com maturidade técnica.&lt;/p&gt;


&lt;hr&gt;

&lt;h2&gt;
  &lt;a name=&quot;o-aprendizado-que-come%C3%A7ou-a-aparecer&quot; href=&quot;https://dev.to/he4rt/pensar-demais-nem-sempre-ajuda-e-o-que-eu-aprendi-com-isso-49pp#o-aprendizado-que-come%C3%A7ou-a-aparecer&quot;&gt;
  &lt;/a&gt;
  O aprendizado que começou a aparecer
&lt;/h2&gt;

&lt;p&gt;Enquanto refletia sobre isso, lembrei de uma frase que minha mãe repetia desde que eu era pequeno:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;&quot;Antes feito do que perfeito.&quot;&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Sempre achei que essa frase servia para tarefas do dia a dia, como arrumar o quarto, terminar um trabalho da escola. Nunca imaginei que ela fizesse tanto sentido ao escrever software.&lt;/p&gt;

&lt;p&gt;Junto com ela, veio outra ideia:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Bons sistemas não nascem perfeitos. Eles evoluem.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Nenhum dos projetos open source que eu admirava nasceu com a arquitetura que tem hoje; todos passaram por versões mais simples, mais cruas, que foram se modificando à medida que o uso real foi aparecendo.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Qualidade não está em prever todos os cenários.&lt;/p&gt;

&lt;p&gt;Qualidade está em escrever código que consiga mudar quando esses cenários realmente aparecerem.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Foi só quando parei de procurar a arquitetura perfeita que finalmente escrevi minha primeira requisição de verdade para a API.&lt;/p&gt;

&lt;p&gt;Antes mesmo de escrever a primeira integração, era assim que eu imaginava o pacote:&lt;br&gt;
&lt;/p&gt;

&lt;div class=&quot;highlight js-code-highlight&quot;&gt;
&lt;pre class=&quot;highlight php&quot;&gt;&lt;code&gt;&lt;span class=&quot;nc&quot;&gt;CustomerService&lt;/span&gt;
        &lt;span class=&quot;err&quot;&gt;↓&lt;/span&gt;
&lt;span class=&quot;nc&quot;&gt;AsaasClient&lt;/span&gt;
        &lt;span class=&quot;err&quot;&gt;↓&lt;/span&gt;
&lt;span class=&quot;nc&quot;&gt;CreateCustomerDTO&lt;/span&gt;
        &lt;span class=&quot;err&quot;&gt;↓&lt;/span&gt;
&lt;span class=&quot;nc&quot;&gt;Response&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;div class=&quot;highlight__panel js-actions-panel&quot;&gt;
&lt;div class=&quot;highlight__panel-action js-fullscreen-code-action&quot;&gt;
    &lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; width=&quot;20px&quot; height=&quot;20px&quot; viewBox=&quot;0 0 24 24&quot; class=&quot;highlight-action crayons-icon highlight-action--fullscreen-on&quot;&gt;&lt;title&gt;Enter fullscreen mode&lt;/title&gt;
    &lt;path d=&quot;M16 3h6v6h-2V5h-4V3zM2 3h6v2H4v4H2V3zm18 16v-4h2v6h-6v-2h4zM4 19h4v2H2v-6h2v4z&quot;&gt;&lt;/path&gt;
&lt;/svg&gt;

    &lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; width=&quot;20px&quot; height=&quot;20px&quot; viewBox=&quot;0 0 24 24&quot; class=&quot;highlight-action crayons-icon highlight-action--fullscreen-off&quot;&gt;&lt;title&gt;Exit fullscreen mode&lt;/title&gt;
    &lt;path d=&quot;M18 7h4v2h-6V3h2v4zM8 9H2V7h4V3h2v6zm10 8v4h-2v-6h6v2h-4zM8 15v6H6v-4H2v-2h6z&quot;&gt;&lt;/path&gt;
&lt;/svg&gt;

&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;



&lt;p&gt;Mas não comecei com uma arquitetura cheia de camadas. Comecei com algo assim:&lt;br&gt;
&lt;/p&gt;

&lt;div class=&quot;highlight js-code-highlight&quot;&gt;
&lt;pre class=&quot;highlight php&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$asaas&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;customers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;create&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;([&lt;/span&gt;
    &lt;span class=&quot;s1&quot;&gt;&#39;name&#39;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&#39;Yuri Souza&#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;s1&quot;&gt;&#39;cpfCnpj&#39;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&#39;12345678909&#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;]);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;div class=&quot;highlight__panel js-actions-panel&quot;&gt;
&lt;div class=&quot;highlight__panel-action js-fullscreen-code-action&quot;&gt;
    &lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; width=&quot;20px&quot; height=&quot;20px&quot; viewBox=&quot;0 0 24 24&quot; class=&quot;highlight-action crayons-icon highlight-action--fullscreen-on&quot;&gt;&lt;title&gt;Enter fullscreen mode&lt;/title&gt;
    &lt;path d=&quot;M16 3h6v6h-2V5h-4V3zM2 3h6v2H4v4H2V3zm18 16v-4h2v6h-6v-2h4zM4 19h4v2H2v-6h2v4z&quot;&gt;&lt;/path&gt;
&lt;/svg&gt;

    &lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; width=&quot;20px&quot; height=&quot;20px&quot; viewBox=&quot;0 0 24 24&quot; class=&quot;highlight-action crayons-icon highlight-action--fullscreen-off&quot;&gt;&lt;title&gt;Exit fullscreen mode&lt;/title&gt;
    &lt;path d=&quot;M18 7h4v2h-6V3h2v4zM8 9H2V7h4V3h2v6zm10 8v4h-2v-6h6v2h-4zM8 15v6H6v-4H2v-2h6z&quot;&gt;&lt;/path&gt;
&lt;/svg&gt;

&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;



&lt;p&gt;Desde então, passei a repensar algumas atitudes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  resolver o problema atual com clareza antes de pensar no próximo;&lt;/li&gt;
&lt;li&gt;  manter o código simples, legível e testável;&lt;/li&gt;
&lt;li&gt;  criar abstrações apenas quando um padrão se repete de fato, não quando eu imagino que ele vai se repetir;&lt;/li&gt;
&lt;li&gt;  aceitar que refatorar faz parte do processo, não uma falha dele.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Não se trata de abandonar boas práticas, mas de aplicá-las &lt;strong&gt;no momento certo&lt;/strong&gt;.&lt;/p&gt;


&lt;hr&gt;

&lt;h2&gt;
  &lt;a name=&quot;o-equil%C3%ADbrio-que-estou-buscando-hoje&quot; href=&quot;https://dev.to/he4rt/pensar-demais-nem-sempre-ajuda-e-o-que-eu-aprendi-com-isso-49pp#o-equil%C3%ADbrio-que-estou-buscando-hoje&quot;&gt;
  &lt;/a&gt;
  O equilíbrio que estou buscando hoje
&lt;/h2&gt;

&lt;p&gt;Hoje tento encontrar um equilíbrio entre dois extremos: nem escrever código sem critério, nem criar uma arquitetura complexa antes que ela seja necessária.&lt;/p&gt;

&lt;p&gt;No próprio pacote do Asaas isso já mudou a forma como estou trabalhando.&lt;/p&gt;

&lt;p&gt;Hoje, a decisão que tomei foi outra: começar pelo caminho mais curto possível.&lt;/p&gt;

&lt;p&gt;Primeiro quero que o pacote consiga conversar com a API e validar os casos de uso mais importantes. Só então vou descobrir quais abstrações realmente fazem sentido.&lt;/p&gt;

&lt;p&gt;Em vez de tentar prever a arquitetura que o projeto terá daqui a um ano, prefiro deixar que ela se desenvolva à medida que novos problemas surgirem.&lt;/p&gt;

&lt;p&gt;Foi aí que entendi uma coisa importante:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Arquitetura não é algo que eu preciso descobrir antes de começar. É algo que o próprio projeto vai mostrando à medida que cresce.&lt;/strong&gt;&lt;/p&gt;


&lt;hr&gt;

&lt;h2&gt;
  &lt;a name=&quot;conclus%C3%A3o&quot; href=&quot;https://dev.to/he4rt/pensar-demais-nem-sempre-ajuda-e-o-que-eu-aprendi-com-isso-49pp#conclus%C3%A3o&quot;&gt;
  &lt;/a&gt;
  Conclusão
&lt;/h2&gt;

&lt;p&gt;Ainda estou no começo desse pacote, e ainda estou aprendendo isso na prática, errando e ajustando no caminho.&lt;/p&gt;

&lt;p&gt;Mas entender que &quot;perfeição antecipada&quot; pode virar um problema já foi um passo importante na minha evolução como desenvolvedor. O projeto do pacote Asaas não precisa da arquitetura perfeita logo de início; precisa apenas da primeira implementação. O resto vai aparecer conforme o uso real for mostrando o caminho.&lt;/p&gt;

&lt;p&gt;Hoje prefiro um código simples que aceite mudanças a uma arquitetura impecável que resista a qualquer alteração.&lt;/p&gt;

&lt;p&gt;Se você também já caiu nessa armadilha da arquitetura perfeita antes da hora, quero saber: como você percebeu e o que fez para sair dela?&lt;/p&gt;

&lt;p&gt;A discussão continua nos comentários. Quero muito conhecer outras experiências e perspectivas sobre esse tema.&lt;/p&gt;


&lt;hr&gt;

&lt;p&gt;Agradecimentos: obrigado a &lt;a class=&quot;mentioned-user&quot; href=&quot;https://dev.to/vitoriazzp&quot;&gt;@vitoriazzp&lt;/a&gt; pelo feedback sincero e pelas sugestões que ajudaram a tornar este artigo mais claro e útil.&lt;/p&gt;


            </description><link>https://dev.to/he4rt/pensar-demais-nem-sempre-ajuda-e-o-que-eu-aprendi-com-isso-49pp</link><guid isPermaLink="false">https://dev.to/he4rt/pensar-demais-nem-sempre-ajuda-e-o-que-eu-aprendi-com-isso-49pp</guid><pubDate>Sat, 01 Aug 2026 10:57:53 GMT</pubDate><author>Yuri Souza</author><enclosure url="https://media2.dev.to/dynamic/image/width=1000,height=420,fit=cover,gravity=auto,format=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fuab70axdu1cpc1neag2a.png" type="image/jpeg"></enclosure><category>braziliandevs</category><category>productivity</category><category>career</category><category>discuss</category></item></channel></rss>