<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Herrington Darkholme</title>
    <description>The latest articles on Forem by Herrington Darkholme (@herrington_darkholme).</description>
    <link>https://forem.com/herrington_darkholme</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F928561%2F965fd4c8-81f5-4ea7-932f-55d613b55092.jpeg</url>
      <title>Forem: Herrington Darkholme</title>
      <link>https://forem.com/herrington_darkholme</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/herrington_darkholme"/>
    <language>en</language>
    <item>
      <title>ast-grep 0.42: The Answer to Code Searching</title>
      <dc:creator>Herrington Darkholme</dc:creator>
      <pubDate>Mon, 16 Mar 2026 22:18:30 +0000</pubDate>
      <link>https://forem.com/herrington_darkholme/ast-grep-042-the-answer-to-code-searching-270</link>
      <guid>https://forem.com/herrington_darkholme/ast-grep-042-the-answer-to-code-searching-270</guid>
      <description>&lt;p&gt;After a long journey through the galaxy of AST manipulation, ast-grep has arrived at &lt;strong&gt;version 0.42&lt;/strong&gt; — the answer to the ultimate question of code searching, linting, and rewriting.&lt;/p&gt;

&lt;p&gt;If &lt;a href="https://en.wikipedia.org/wiki/The_Hitchhiker%27s_Guide_to_the_Galaxy" rel="noopener noreferrer"&gt;Douglas Adams&lt;/a&gt; taught us anything, it's that the answer to life, the universe, and everything is &lt;strong&gt;42&lt;/strong&gt;. We'd like to think ast-grep 0.42 lives up to its number: this release packs powerful new features that answer some of the most requested questions from our community.&lt;/p&gt;

&lt;p&gt;Don't panic — let's dive in.&lt;/p&gt;

&lt;h2&gt;
  
  
  Parameterized Utilities (Experimental)
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;Parameterized utilities are &lt;strong&gt;experimental&lt;/strong&gt;. The current implementation is hacky, dirty, and quick — a prototype to gather real-world feedback. The API, behavior, and semantics &lt;strong&gt;may change, break, or even be removed entirely&lt;/strong&gt; in future releases. That said, we encourage adventurous users to try it out! Please report bugs and share your feedback at &lt;a href="https://github.com/ast-grep/ast-grep" rel="noopener noreferrer"&gt;ast-grep/ast-grep&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The biggest feature in this release has landed: &lt;a href="https://github.com/ast-grep/ast-grep/issues/1298" rel="noopener noreferrer"&gt;parameterized utilities&lt;/a&gt;. &lt;a href="///guide/rule-config/utility-rule.html#global-utility-rules"&gt;Global utility rules&lt;/a&gt; in ast-grep let you define reusable rule components shared across your project, but previously they were static — you couldn't customize them for different contexts. Now, global utilities can accept arguments, making them far more flexible and reducing duplication in your rule configurations.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Problem
&lt;/h3&gt;

&lt;p&gt;Global utilities are reusable across files, but they couldn't be customized — you'd copy-paste the same structure over and over, changing only a name or a pattern.&lt;/p&gt;

&lt;p&gt;Say you want to audit logging calls that pass a string literal as an argument. One rule bans &lt;code&gt;console.log&lt;/code&gt; with string literals in production code, another flags &lt;code&gt;logger.error&lt;/code&gt; with hardcoded messages. They have different severities and messages, so they must be separate rules — but without parameterization, each duplicates the entire rule structure:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# rules/audit-logging.yml&lt;/span&gt;
&lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;no-console-string&lt;/span&gt;
&lt;span class="na"&gt;language&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;TypeScript&lt;/span&gt;
&lt;span class="na"&gt;rule&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;pattern&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;$OBJ.$METHOD($$$ARGS)&lt;/span&gt;
  &lt;span class="na"&gt;all&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;has&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;member_expression&lt;/span&gt;
        &lt;span class="na"&gt;has&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;field&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;object&lt;/span&gt;
          &lt;span class="na"&gt;regex&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;^console$&lt;/span&gt;     &lt;span class="c1"&gt;# &amp;lt;--- console&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;has&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;field&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;arguments&lt;/span&gt;
        &lt;span class="na"&gt;has&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;string&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;no-hardcoded-logger&lt;/span&gt;
&lt;span class="na"&gt;language&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;TypeScript&lt;/span&gt;
&lt;span class="na"&gt;rule&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;pattern&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;$OBJ.$METHOD($$$ARGS)&lt;/span&gt;
  &lt;span class="na"&gt;all&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;has&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;member_expression&lt;/span&gt;
        &lt;span class="na"&gt;has&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;field&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;object&lt;/span&gt;
          &lt;span class="na"&gt;regex&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;^logger$&lt;/span&gt;      &lt;span class="c1"&gt;# &amp;lt;--- logger&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;has&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;field&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;arguments&lt;/span&gt;
        &lt;span class="na"&gt;has&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;string&lt;/span&gt;
&lt;span class="c1"&gt;# the entire rule body is identical — only this one line differs!&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;On top of that, there was no way to export matched meta-variables from a global utility back to its caller. This caused inability to share captured meta-variables across files (&lt;a href="https://github.com/ast-grep/ast-grep/issues/1297" rel="noopener noreferrer"&gt;#1297&lt;/a&gt;), parse errors when using global util variables in &lt;code&gt;fix&lt;/code&gt; (&lt;a href="https://github.com/ast-grep/ast-grep/issues/1766" rel="noopener noreferrer"&gt;#1766&lt;/a&gt;), and confusion about why global utils couldn't provide variables like local ones could (&lt;a href="https://github.com/ast-grep/ast-grep/issues/1994" rel="noopener noreferrer"&gt;#1994&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;Parameterized utilities solve both problems: they eliminate duplication and provide a well-defined interface for passing rules in and getting meta-variables back.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Solution
&lt;/h3&gt;

&lt;p&gt;Think of parameterized utilities as &lt;strong&gt;functions for your rules&lt;/strong&gt;. You declare parameters in the utility name, and then pass arguments when you call it with &lt;code&gt;matches&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;Define a parameterized &lt;a href="///guide/rule-config/utility-rule.html#global-utility-rules"&gt;global utility&lt;/a&gt; in a file under your &lt;code&gt;utils/&lt;/code&gt; directory:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# utils/audit-log-call.yml&lt;/span&gt;
&lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;audit-log-call&lt;/span&gt;
&lt;span class="na"&gt;arguments&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;logger-rule&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;          &lt;span class="c1"&gt;# declare parameters&lt;/span&gt;
&lt;span class="na"&gt;language&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;TypeScript&lt;/span&gt;
&lt;span class="na"&gt;rule&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;pattern&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;$OBJ.$METHOD($$$ARGS)&lt;/span&gt;
  &lt;span class="na"&gt;all&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;has&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;member_expression&lt;/span&gt;
        &lt;span class="na"&gt;has&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;field&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;object&lt;/span&gt;
          &lt;span class="na"&gt;matches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;logger-rule&lt;/span&gt;    &lt;span class="c1"&gt;# use the parameter as a rule&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;has&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;field&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;arguments&lt;/span&gt;
        &lt;span class="na"&gt;has&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;string&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then call it from any rule by passing arguments via &lt;code&gt;matches&lt;/code&gt;. Each argument is itself a &lt;strong&gt;rule&lt;/strong&gt;, not just a string — so you can pass patterns, regex, or any composite rule:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# rules/audit-logging.yml&lt;/span&gt;
&lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;no-console-string&lt;/span&gt;
&lt;span class="na"&gt;language&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;TypeScript&lt;/span&gt;
&lt;span class="na"&gt;rule&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;matches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;audit-log-call&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;logger-rule&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;regex&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;^console$&lt;/span&gt; &lt;span class="pi"&gt;}&lt;/span&gt; &lt;span class="c1"&gt;# pass rule as arg&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;no-hardcoded-logger&lt;/span&gt;
&lt;span class="na"&gt;language&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;TypeScript&lt;/span&gt;
&lt;span class="na"&gt;rule&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;matches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;audit-log-call&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;logger-rule&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;regex&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;^logger$&lt;/span&gt; &lt;span class="pi"&gt;}&lt;/span&gt; &lt;span class="c1"&gt;# pass rule as arg&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The entire deep rule structure is defined once in the utility. Each rule only specifies what differs — the logger object name.&lt;/p&gt;

&lt;p&gt;Crucially, meta-variables captured inside argument rules are &lt;strong&gt;exported back to the caller&lt;/strong&gt;. This solves the long-standing problem of global utilities not being able to provide meta-variables for &lt;code&gt;fix&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Here's an example: the &lt;code&gt;named-import&lt;/code&gt; utility matches an import statement and delegates source validation to an argument rule. The &lt;code&gt;ban-lodash&lt;/code&gt; rule uses it to find lodash imports and rewrite them to &lt;code&gt;lodash-es&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The highlighted lines show where arguments are declared and where they are used as &lt;code&gt;matches&lt;/code&gt; targets inside the utility body:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# utils/named-import.yml — reusable utility for matching named imports&lt;/span&gt;
&lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;named-import&lt;/span&gt;
&lt;span class="na"&gt;arguments&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;source-rule&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;binding-rule&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;   &lt;span class="c1"&gt;# declare two param rule&lt;/span&gt;
&lt;span class="na"&gt;language&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;TypeScript&lt;/span&gt;
&lt;span class="na"&gt;rule&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;pattern&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;import { $BINDING } from "$SOURCE"&lt;/span&gt;
  &lt;span class="na"&gt;all&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;has&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;field&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;source&lt;/span&gt;
        &lt;span class="na"&gt;has&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;string_fragment&lt;/span&gt;
          &lt;span class="na"&gt;matches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;source-rule&lt;/span&gt;           &lt;span class="c1"&gt;# filter source with param&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;has&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;stopBy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;end&lt;/span&gt;
        &lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;identifier&lt;/span&gt;
        &lt;span class="na"&gt;matches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;binding-rule&lt;/span&gt;            &lt;span class="c1"&gt;# export $BINDING&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The highlighted lines below show the caller passing concrete rules as arguments. Meta-variable &lt;code&gt;$IMPORT_NAME&lt;/code&gt; defined here is exported back and usable in &lt;code&gt;fix&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# rules/ban-lodash.yml — rewrites lodash imports to lodash-es&lt;/span&gt;
&lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ban-lodash&lt;/span&gt;
&lt;span class="na"&gt;language&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;TypeScript&lt;/span&gt;
&lt;span class="na"&gt;rule&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;matches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;named-import&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;source-rule&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;regex&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;^lodash$&lt;/span&gt; &lt;span class="pi"&gt;}&lt;/span&gt;         &lt;span class="c1"&gt;# only match lodash import&lt;/span&gt;
      &lt;span class="na"&gt;binding-rule&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;pattern&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;$IMPORT_NAME&lt;/span&gt; &lt;span class="pi"&gt;}&lt;/span&gt;  &lt;span class="c1"&gt;# capture import in metavar&lt;/span&gt;
&lt;span class="na"&gt;fix&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;import { $IMPORT_NAME } from "lodash-es"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When matching &lt;code&gt;import { map } from "lodash"&lt;/code&gt;, the utility's pattern captures &lt;code&gt;$BINDING = map&lt;/code&gt; and &lt;code&gt;$SOURCE = lodash&lt;/code&gt; internally, in a separate environment. Note that &lt;code&gt;matches: binding-rule&lt;/code&gt; is called on the AST node corresponding to &lt;code&gt;$BINDING&lt;/code&gt; (the identifier &lt;code&gt;map&lt;/code&gt;), so the caller's argument &lt;code&gt;pattern: $IMPORT_NAME&lt;/code&gt; matches that same node and captures &lt;code&gt;$IMPORT_NAME = map&lt;/code&gt; — effectively exporting &lt;code&gt;$BINDING&lt;/code&gt; under a new name.&lt;/p&gt;

&lt;p&gt;The utility's own meta-variables stay &lt;strong&gt;isolated&lt;/strong&gt;. Only meta-variables from &lt;strong&gt;argument rules&lt;/strong&gt; are exported to the caller:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Meta-variable&lt;/th&gt;
&lt;th&gt;Captured by&lt;/th&gt;
&lt;th&gt;Visible in &lt;code&gt;ban-lodash&lt;/code&gt;?&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;$IMPORT_NAME&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;argument rule (&lt;code&gt;binding-rule&lt;/code&gt;)&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;Yes&lt;/strong&gt; — available in &lt;code&gt;fix&lt;/code&gt;, &lt;code&gt;constraints&lt;/code&gt;, etc.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;$BINDING&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;utility's internal pattern&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;No&lt;/strong&gt; — isolated inside the utility&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;$SOURCE&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;utility's internal pattern&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;No&lt;/strong&gt; — isolated inside the utility&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;code&gt;$IMPORT_NAME&lt;/code&gt; is available in &lt;code&gt;fix&lt;/code&gt; because it was captured by a caller-supplied argument rule. Without parameterized utilities, there was no mechanism to get any meta-variables out of a global utility at all.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The rule of thumb here is that a meta-variable like &lt;code&gt;$IMPORT_NAME&lt;/code&gt; is only available if it appears &lt;strong&gt;in the same YAML file&lt;/strong&gt; where you define it. Meta-variables defined in a different file (like &lt;code&gt;$BINDING&lt;/code&gt;) are never visible to the caller.&lt;br&gt;
If you can't see the &lt;code&gt;$&lt;/code&gt; definition in your rule file, you can't use it.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Key Usage Rules
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Only &lt;a href="///guide/rule-config/utility-rule.html#global-utility-rules"&gt;global utility rules&lt;/a&gt;&lt;/strong&gt; (separate YAML files in the &lt;code&gt;utils/&lt;/code&gt; directory with &lt;code&gt;id&lt;/code&gt;, &lt;code&gt;language&lt;/code&gt;, and &lt;code&gt;rule&lt;/code&gt;) can declare parameters. Local &lt;code&gt;utils:&lt;/code&gt; entries in rule config files remain zero-argument helpers.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;All declared arguments must be provided&lt;/strong&gt; at the call site — no optional parameters.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Arguments are rules&lt;/strong&gt;, not strings. Each argument value is a full ast-grep rule object.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Meta-variable isolation&lt;/strong&gt;: argument rules match in their own isolated scope. They don't read or write the caller's meta-variables during matching — exports happen only after the entire parameterized rule matches successfully.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Advanced: How It Works Under the Hood
&lt;/h3&gt;

&lt;p&gt;Implementation details for the curious&lt;/p&gt;

&lt;p&gt;Parameterized utilities are implemented with &lt;strong&gt;runtime binding frames&lt;/strong&gt; rather than template expansion. The binding frames are stored in a thread-local variable and use &lt;code&gt;unsafe&lt;/code&gt; code internally — the implementation is pragmatic rather than polished, which is part of why this feature is marked experimental. Performance may be suboptimal, especially with deeply nested parameterized calls. When a parameterized rule is called:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The &lt;code&gt;matches&lt;/code&gt; reference pushes &lt;code&gt;name -&amp;gt; rule&lt;/code&gt; bindings into a thread-local frame.&lt;/li&gt;
&lt;li&gt;The stored rule body is matched directly against the target code.&lt;/li&gt;
&lt;li&gt;When a bare &lt;code&gt;matches: PARAM&lt;/code&gt; is encountered inside the body, it looks up the binding frame and matches the bound rule.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Name resolution&lt;/strong&gt; for bare &lt;code&gt;matches: NAME&lt;/code&gt; follows lexical scoping:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Current parameter binding (innermost scope)&lt;/li&gt;
&lt;li&gt;Local utility&lt;/li&gt;
&lt;li&gt;Global zero-argument rule&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;A parameter name shadows any same-named local or global utility.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Meta-variable isolation&lt;/strong&gt; is a deliberate design choice. Argument rules match in a temporary, isolated &lt;code&gt;MetaVarEnv&lt;/code&gt;. Any meta-variables they define are accumulated and exported back to the caller &lt;em&gt;only after the entire parameterized rule matches&lt;/em&gt;. If exporting conflicts with the caller's existing bindings (e.g., the caller already bound &lt;code&gt;$A&lt;/code&gt; to a different value), the whole parameterized call fails. Importantly, this failure does &lt;strong&gt;not&lt;/strong&gt; trigger backtracking inside the parameterized rule — an &lt;code&gt;any&lt;/code&gt; branch won't be retried just because a late export failed.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Kind inference&lt;/strong&gt; is conservative. Internally, ast-grep computes a set of &lt;code&gt;potential_kinds&lt;/code&gt; for each rule as a performance optimization — if a rule can only ever match &lt;code&gt;call_expression&lt;/code&gt; nodes, ast-grep skips all other node kinds entirely. However, when kind inference reaches a &lt;code&gt;matches: PARAM&lt;/code&gt; reference, it cannot know what kinds the caller will pass, so it returns &lt;code&gt;None&lt;/code&gt; (meaning "any kind is possible"). This disables kind-based pruning for that rule. If you need precise pruning, add an explicit &lt;code&gt;kind&lt;/code&gt; guard in the utility body or at the call site.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Cycle detection&lt;/strong&gt; remains syntactic. ast-grep detects circular dependencies between utility rules at parse time — if rule A &lt;code&gt;matches&lt;/code&gt; rule B and rule B &lt;code&gt;matches&lt;/code&gt; rule A, ast-grep will report an error before any scanning happens, helping you catch buggy rules early. For parameterized utilities, parameter names are excluded from dependency edges during topological sorting. A utility cannot call itself through its argument rules, either directly or transitively.&lt;/p&gt;

&lt;h2&gt;
  
  
  More ESQuery-Style Selectors
&lt;/h2&gt;

&lt;p&gt;In ast-grep 0.39, we introduced ESQuery-style &lt;code&gt;kind&lt;/code&gt; selectors with combinators like &lt;code&gt;&amp;gt;&lt;/code&gt;, &lt;code&gt;+&lt;/code&gt;, and &lt;code&gt;~&lt;/code&gt;. In 0.42, we're expanding this with &lt;strong&gt;new pseudo-selectors&lt;/strong&gt; that bring even more expressive power to your queries. See the &lt;a href="https://github.com/ast-grep/ast-grep/issues/2127" rel="noopener noreferrer"&gt;tracking issue&lt;/a&gt; for the full ESQuery roadmap.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;:has(selector)&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Select nodes that contain descendants matching a given selector. &lt;code&gt;:has&lt;/code&gt; also supports the &lt;code&gt;&amp;gt;&lt;/code&gt; combinator to match only direct children.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;function_declaration:has(return_statement)'&lt;/span&gt;
&lt;span class="c1"&gt;# is equivalent to&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;function_declaration&lt;/span&gt;
&lt;span class="na"&gt;has&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;return_statement&lt;/span&gt;
  &lt;span class="na"&gt;stopBy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;call_expression:has(&amp;gt;&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;identifier)'&lt;/span&gt;
&lt;span class="c1"&gt;# is equivalent to&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;call_expression&lt;/span&gt;
&lt;span class="na"&gt;has&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;identifier&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  &lt;code&gt;:not(selector)&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Exclude nodes matching a selector. Perfect for filtering out unwanted matches.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# match expression statements that don't contain a call&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;expression_statement:not(:has(&amp;gt;&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;call_expression))'&lt;/span&gt;
&lt;span class="c1"&gt;# is equivalent to&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;expression_statement&lt;/span&gt;
&lt;span class="na"&gt;not&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;has&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;call_expression&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  &lt;code&gt;:is(selector, moreSelector, ...)&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Match nodes against any one of several selectors — a concise way to express "or" logic. Previously, the comma operator (e.g. &lt;code&gt;function_declaration, arrow_function&lt;/code&gt;) could only be used at the top level of a selector. &lt;code&gt;:is&lt;/code&gt; lifts that restriction: you can now express "or" anywhere inside a compound selector.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# match return statements or variable declarations inside a block&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;statement_block&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;:is(return_statement,&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;lexical_declaration)'&lt;/span&gt;
&lt;span class="c1"&gt;# is equivalent to&lt;/span&gt;
&lt;span class="na"&gt;any&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;return_statement&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;lexical_declaration&lt;/span&gt;
&lt;span class="na"&gt;inside&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;statement_block&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  &lt;code&gt;:nth-child(An+B)&lt;/code&gt; and &lt;code&gt;:nth-child(An+B of selector)&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Select nodes by their position among siblings, using the familiar &lt;code&gt;An+B&lt;/code&gt; syntax. You can even combine it with an &lt;code&gt;of selector&lt;/code&gt; clause to filter which siblings count. Both &lt;code&gt;An+B&lt;/code&gt; and &lt;code&gt;An+B of selector&lt;/code&gt; are supported.&lt;/p&gt;

&lt;p&gt;These are equivalent to ast-grep's &lt;a href="///reference/rule.html#nthchild"&gt;&lt;code&gt;nthChild&lt;/code&gt; rule&lt;/a&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# match odd-positioned numbers: [①, 2, ③, 4, ⑤]&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;array&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;number:nth-child(2n+1)'&lt;/span&gt;
&lt;span class="c1"&gt;# is equivalent to&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;number&lt;/span&gt;
&lt;span class="na"&gt;nthChild&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;2n+1&lt;/span&gt;
&lt;span class="na"&gt;inside&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;array&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# match the first number, skipping non-numbers: [a, ①, 2, 3]&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;array&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;:nth-child(1&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;of&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;number)'&lt;/span&gt;
&lt;span class="c1"&gt;# is equivalent to&lt;/span&gt;
&lt;span class="na"&gt;nthChild&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;position&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;
  &lt;span class="na"&gt;ofRule&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;number&lt;/span&gt;
&lt;span class="na"&gt;inside&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;array&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These pseudo-selectors compose naturally with the existing combinators. Together, they bring ast-grep's ESQuery support much closer to a full selector system, making complex structural queries concise and readable.&lt;/p&gt;

&lt;h2&gt;
  
  
  LSP: Diagnostics for Injected Languages
&lt;/h2&gt;

&lt;p&gt;A subtle but important fix: the ast-grep Language Server now correctly &lt;a href="https://github.com/ast-grep/ast-grep/issues/2522" rel="noopener noreferrer"&gt;scans injected languages for diagnostics&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Injected languages are code embedded within other code — for example, Sassdoc comments inside SCSS files, or SQL within template strings. The ast-grep CLI has supported scanning these injected sections for a while, but the LSP wasn't reporting diagnostics for them. This created a frustrating inconsistency: rules that worked perfectly on the command line would show no results in your editor.&lt;/p&gt;

&lt;p&gt;With this fix, your editor integration (VSCode, Zed, Neovim, etc.) now surfaces diagnostics for injected language rules, just like the CLI does. No more switching to the terminal to catch violations in embedded code.&lt;/p&gt;

&lt;h2&gt;
  
  
  Next Steps
&lt;/h2&gt;

&lt;p&gt;As the Hitchhiker's Guide reminds us, the hard part was never finding the answer — it was knowing the right question to ask. We hope ast-grep 0.42 helps you ask better questions about your code.&lt;/p&gt;

&lt;p&gt;Thanks for reading! If you are interested in the new features, please try them out and let us know your feedback.&lt;/p&gt;

&lt;p&gt;Happy Grepping, and don't forget your towel! 🚀&lt;/p&gt;

</description>
      <category>ai</category>
      <category>programming</category>
      <category>productivity</category>
      <category>tooling</category>
    </item>
    <item>
      <title>Agent Calculus: A Unified Framework for AI Agent Design</title>
      <dc:creator>Herrington Darkholme</dc:creator>
      <pubDate>Fri, 16 Jan 2026 03:11:38 +0000</pubDate>
      <link>https://forem.com/herrington_darkholme/agent-calculus-a-unified-framework-for-ai-agent-design-32d8</link>
      <guid>https://forem.com/herrington_darkholme/agent-calculus-a-unified-framework-for-ai-agent-design-32d8</guid>
      <description>&lt;h2&gt;
  
  
  Abstract
&lt;/h2&gt;

&lt;p&gt;This document presents a unified formal framework for understanding AI agents through a calculus-like model. We introduce the concept of &lt;strong&gt;entities&lt;/strong&gt; as the fundamental unit of agent computation, and define a &lt;strong&gt;harness&lt;/strong&gt; that manages the flow of entities between the LLM's context and the external world. This framework elegantly unifies disparate concepts such as skills, tools, memory, subagents, and dynamic context loading under a single coherent model.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Introduction &amp;amp; Motivation
&lt;/h2&gt;

&lt;h3&gt;
  
  
  The Problem
&lt;/h3&gt;

&lt;p&gt;Modern AI agent systems involve numerous distinct concepts:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Tools&lt;/strong&gt;: Functions the agent can call to interact with the world&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Skills&lt;/strong&gt;: Reusable prompt templates and workflows&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Memory&lt;/strong&gt;: Persistent state from previous interactions&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Subagents&lt;/strong&gt;: Spawned agents for subtasks&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Dynamic context loading&lt;/strong&gt;: Just-in-time injection of relevant information&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;System prompts&lt;/strong&gt;: Static instructions and behavior definitions&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These concepts are typically treated as separate mechanisms, leading to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Conceptual fragmentation in agent design&lt;/li&gt;
&lt;li&gt;Difficulty reasoning about agent behavior holistically&lt;/li&gt;
&lt;li&gt;Lack of composability between different agent patterns&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  The Solution
&lt;/h3&gt;

&lt;p&gt;We propose treating all inputs to an agent as &lt;strong&gt;entities&lt;/strong&gt; that flow through a &lt;strong&gt;harness&lt;/strong&gt; which manages:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Loading&lt;/strong&gt;: Filtering and packing entities into the LLM's limited context&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Execution&lt;/strong&gt;: Handling LLM actions and returning new entities&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This abstraction enables:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Unified reasoning about agent behavior&lt;/li&gt;
&lt;li&gt;Compositional design patterns&lt;/li&gt;
&lt;li&gt;Systematic approaches to context management&lt;/li&gt;
&lt;li&gt;Formal analysis of multi-agent systems&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  2. Core Assumptions
&lt;/h2&gt;

&lt;p&gt;To simplify our calculus, we make three foundational assumptions:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Assumption 1: Limited Context&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;LLM context windows are finite and constrained. Context is the primary scarce resource in agent systems.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Note: LLM's context window can be larger in future. For example,&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;a conditional memory lookup can spare more attention to longer context &lt;a href="https://github.com/deepseek-ai/Engram?tab=readme-ov-file" rel="noopener noreferrer"&gt;https://github.com/deepseek-ai/Engram?tab=readme-ov-file&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Extending the Context of Pretrained LLMs by Dropping their Positional Embeddings (DroPE) &lt;a href="https://pub.sakana.ai/DroPE/" rel="noopener noreferrer"&gt;https://pub.sakana.ai/DroPE/&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Assumption 2: Static Capabilities&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;LLMs do not perform continual learning during inference. Their capabilities are fixed at deployment.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Note: this can be changed in future. So some routine context loading can be done by updating model weights&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;see Nested Learning: The Illusion of Deep Learning Architecture. &lt;a href="https://abehrouz.github.io/files/NL.pdf" rel="noopener noreferrer"&gt;https://abehrouz.github.io/files/NL.pdf&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Assumption 3: LLM Homogeneity&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;For the purposes of this calculus, we treat different LLMs as interchangeable.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Note: In practice they differ, but this simplifies our model.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Fundamental Definitions
&lt;/h2&gt;

&lt;h3&gt;
  
  
  3.1 LLM as Pure Function
&lt;/h3&gt;

&lt;p&gt;We model an LLM as a pure function:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;LLM: Context → (Reasoning, Actions)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;Context&lt;/code&gt;: The text and structured data directly accessible to the LLM&lt;/li&gt;
&lt;/ul&gt;

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

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;Reasoning&lt;/code&gt;: Internal thought process, chain-of-thought, analysis&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Actions&lt;/code&gt;: Structured requests to interact with the world (tool calls, responses, queries)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The LLM has no direct access to anything outside its context. It cannot see files, networks, databases, or any other state unless that information is explicitly loaded into its context.&lt;/p&gt;

&lt;h3&gt;
  
  
  3.2 Context vs World
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Context&lt;/strong&gt;: The observable, directly accessible information within the LLM's attention window.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Limited in size (e.g., 128K tokens)&lt;/li&gt;
&lt;li&gt;Directly influences LLM outputs&lt;/li&gt;
&lt;li&gt;Managed by the harness&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;World&lt;/strong&gt;: Everything outside the context that the agent might need.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;File systems&lt;/li&gt;
&lt;li&gt;Databases&lt;/li&gt;
&lt;li&gt;APIs&lt;/li&gt;
&lt;li&gt;Previous conversation history (not currently in context)&lt;/li&gt;
&lt;li&gt;External knowledge bases&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The harness acts as the bridge between Context and World.&lt;/p&gt;

&lt;h3&gt;
  
  
  3.3 Agent Decomposition
&lt;/h3&gt;

&lt;p&gt;An agent is the composition of two components:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Agent = LLM + Harness
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;strong&gt;LLM&lt;/strong&gt; performs reasoning and generates actions.&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;Harness&lt;/strong&gt; manages the agent loop:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Loads entities into context&lt;/li&gt;
&lt;li&gt;Executes actions in the world&lt;/li&gt;
&lt;li&gt;Handles context window constraints&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  4. The Entity Abstraction
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Core Insight&lt;/strong&gt;: Everything that can be loaded into an LLM's context is an &lt;strong&gt;entity&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  4.1 Entity Definition
&lt;/h3&gt;

&lt;p&gt;An entity is a unit of information with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Content&lt;/strong&gt;: The actual data or text&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Metadata&lt;/strong&gt;: How it should be loaded, when it's relevant, its size&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  4.2 Entity Types by Loading Strategy
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Entity Type&lt;/th&gt;
&lt;th&gt;Content Nature&lt;/th&gt;
&lt;th&gt;Loading Strategy&lt;/th&gt;
&lt;th&gt;Example&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;System Prompt&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Static&lt;/td&gt;
&lt;td&gt;Preloaded&lt;/td&gt;
&lt;td&gt;Agent role definition, rules&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Tool Description&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Static&lt;/td&gt;
&lt;td&gt;Dynamic or preloaded&lt;/td&gt;
&lt;td&gt;Function signature, usage docs&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Skill&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Static&lt;/td&gt;
&lt;td&gt;Dynamic&lt;/td&gt;
&lt;td&gt;Reusable prompt templates&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Memory&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Dynamic&lt;/td&gt;
&lt;td&gt;Preloaded&lt;/td&gt;
&lt;td&gt;Conversation summaries&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;User Input&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Dynamic&lt;/td&gt;
&lt;td&gt;Preloaded&lt;/td&gt;
&lt;td&gt;Current user message&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Tool Result&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Dynamic&lt;/td&gt;
&lt;td&gt;Dynamic&lt;/td&gt;
&lt;td&gt;Data returned from actions&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  4.3 Entity Dimensions
&lt;/h3&gt;

&lt;p&gt;Entities can be characterized along multiple dimensions:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Content Mutability&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Static&lt;/strong&gt;: Content doesn't change (tool definitions, skills)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Dynamic&lt;/strong&gt;: Content changes during execution (memory, tool results)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;2. Loading Time&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Preloaded&lt;/strong&gt;: Always in context (system prompt, current memory)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Dynamic&lt;/strong&gt;: Loaded on-demand (skills when invoked, tool descriptions when relevant)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;3. Verbosity Levels&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Full&lt;/strong&gt;: Complete content loaded&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Summary&lt;/strong&gt;: Condensed version (e.g., skill titles only)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Digest&lt;/strong&gt;: Compressed representation (e.g., large tool results summarized)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reference&lt;/strong&gt;: Pointer only (content remains in world, accessed via actions)&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  4.4 Examples
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Example: Tool as Entity&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Entity: FileReadTool
  Content (full):
    Name: read_file
    Description: Reads contents of a file from disk
    Parameters:
      - path: string (absolute path)
      - offset: int (optional, start line)
      - limit: int (optional, number of lines)
    Returns: string (file contents)

  Content (summary):
    read_file: Read file contents

  Metadata:
    type: tool_description
    static: true
    loading: dynamic (loaded when file operations relevant)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Example: Memory as Entity&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Entity: ConversationMemory
  Content (full):
    [Last 50 conversation turns with full context]

  Content (digest):
    Summary: User is implementing auth system for web app.
    Currently debugging JWT token validation.
    Tech stack: Node.js, Express, PostgreSQL.

  Metadata:
    type: memory
    static: false (updated after each turn)
    loading: preloaded
    compression: digest after 10 turns
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Example: Skill as Entity&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Entity: GitCommitSkill
  Content (full):
    # Git Commit Workflow
    1. Run git status to see changes
    2. Review git diff for staged changes
    3. Draft commit message following repo conventions
    4. Execute git commit with message
    5. Verify with git log

  Content (summary):
    GitCommitSkill: Create git commits following best practices

  Metadata:
    type: skill
    static: true
    loading: dynamic (loaded when user requests git commit)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  5. The Harness
&lt;/h2&gt;

&lt;p&gt;The harness is the orchestration layer that manages the agent loop. It has two core responsibilities:&lt;/p&gt;

&lt;h3&gt;
  
  
  5.1 Load Function
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;load: (Context, Entity, List[Entity]) → Context'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Purpose&lt;/strong&gt;: Intelligently pack entities into the limited context window.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;Context&lt;/code&gt;: Current context state&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Entity&lt;/code&gt;: New entity to incorporate (e.g., fresh user input, tool result)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;List[Entity]&lt;/code&gt;: Available entities that could be loaded&lt;/li&gt;
&lt;/ul&gt;

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

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;Context'&lt;/code&gt;: Updated context ready for LLM consumption&lt;/li&gt;
&lt;/ul&gt;

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

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Filtering&lt;/strong&gt;: Select only relevant entities from available pool&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Compression&lt;/strong&gt;: Choose appropriate verbosity level for each entity&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ordering&lt;/strong&gt;: Arrange entities for optimal LLM performance&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Eviction&lt;/strong&gt;: Remove or compress old entities if context is full&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  5.2 Execute Function
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;execute: (Action, World) → (Entity, World')
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Purpose&lt;/strong&gt;: Perform actions in the world and return results as entities.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;Action&lt;/code&gt;: LLM-generated action (tool call, query, response)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;World&lt;/code&gt;: Current world state&lt;/li&gt;
&lt;/ul&gt;

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

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;Entity&lt;/code&gt;: Result data packaged as an entity&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;World'&lt;/code&gt;: Updated world state after action&lt;/li&gt;
&lt;/ul&gt;

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

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;Action = read_file("config.json")&lt;/code&gt; → &lt;code&gt;Entity = {type: "tool_result", content: "{...json...}"}&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Action = spawn_subagent("research task")&lt;/code&gt; → &lt;code&gt;Entity = {type: "subagent_result", content: "..."}&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Action = respond("Done!")&lt;/code&gt; → &lt;code&gt;Entity = {type: "agent_response", content: "Done!"}&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  5.3 Context Window Management
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;load&lt;/code&gt; function implements sophisticated strategies to handle context constraints:&lt;/p&gt;

&lt;h4&gt;
  
  
  Strategy 1: Relevance Filtering
&lt;/h4&gt;

&lt;p&gt;Only load entities relevant to current task:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;if task involves file operations:
  load file-related tool descriptions
else:
  omit file tools (even if available)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Strategy 2: Progressive Compression
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Fresh tool result: load full content
load(entity=tool_result, verbosity=full)

# After LLM reasoning: compress it
load(entity=tool_result, verbosity=digest)

# After several turns: remove entirely if no longer relevant
omit(entity=tool_result)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Strategy 3: Hierarchical Summarization
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# If 50 tools available:
Group into categories: [file_ops, network, database, ...]
Load only category summaries initially
Load full descriptions only when category selected
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Strategy 4: Swap Full↔Digest
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Context before LLM call:
  [system_prompt] [memory_digest] [tool_result_FULL] [user_input]

Context after LLM reasoning:
  [system_prompt] [memory_digest] [tool_result_DIGEST] [llm_reasoning] [new_action]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  5.4 Atomic Load Operations
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;load&lt;/code&gt; function is composed of atomic operations:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Operation&lt;/th&gt;
&lt;th&gt;Purpose&lt;/th&gt;
&lt;th&gt;Example&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;summarize&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Reduce entity size&lt;/td&gt;
&lt;td&gt;Compress 50 messages → 1 paragraph&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;elaborate&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Add more context&lt;/td&gt;
&lt;td&gt;Expand terse user input with clarifications&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;omit&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Remove entity completely&lt;/td&gt;
&lt;td&gt;Drop tool result from 10 turns ago&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;paraphrase&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Rewrite for clarity&lt;/td&gt;
&lt;td&gt;Standardize user input phrasing&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;group&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Combine related entities&lt;/td&gt;
&lt;td&gt;Bundle related tool descriptions&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  6. The Agent Loop
&lt;/h2&gt;

&lt;p&gt;Now we can express the complete agent execution as a simple loop:&lt;/p&gt;

&lt;h3&gt;
  
  
  6.1 Pseudocode
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;agent_loop&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user_input&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;world&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;ctx&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;entity&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Entity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;content&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;user_input&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;user_input&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;entities&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;discover_available_entities&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;world&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;# tools, skills, memory, etc.
&lt;/span&gt;
    &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="nf"&gt;should_stop&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="c1"&gt;# LOAD PHASE
&lt;/span&gt;        &lt;span class="c1"&gt;# Pack relevant entities into context
&lt;/span&gt;        &lt;span class="n"&gt;ctx&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;harness&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;load&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;entity&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;entities&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="c1"&gt;# REASONING PHASE
&lt;/span&gt;        &lt;span class="c1"&gt;# LLM processes context and generates action
&lt;/span&gt;        &lt;span class="n"&gt;reasoning&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;action&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;llm&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="c1"&gt;# Add reasoning to context for continuity
&lt;/span&gt;        &lt;span class="n"&gt;ctx&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;reasoning&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="c1"&gt;# EXECUTION PHASE
&lt;/span&gt;        &lt;span class="c1"&gt;# Execute action in world, get result as new entity
&lt;/span&gt;        &lt;span class="n"&gt;entity&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;world&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;harness&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;action&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;world&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="c1"&gt;# New entity becomes input for next iteration
&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;world&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  6.2 Example Execution Trace
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;User&lt;/strong&gt;: "Read config.json and fix the database port"&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Turn 1&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Load Phase:
  ctx = [system_prompt, memory_summary, file_tools, user_input]

LLM Phase:
  reasoning: "Need to read config.json first"
  action: read_file("config.json")

Execute Phase:
  entity: {type: "tool_result", content: "{\n  \"db_port\": 3306\n  ...\n}"}
  world: unchanged
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Turn 2&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Load Phase:
  ctx = [system_prompt, memory_summary, file_tools,
         tool_result_FULL, previous_reasoning, edit_tools]
  # Note: file tool result loaded in full for LLM to analyze

LLM Phase:
  reasoning: "Database port is 3306 but should be 5432 for PostgreSQL"
  action: edit_file("config.json", old="3306", new="5432")

Execute Phase:
  entity: {type: "tool_result", content: "Successfully edited config.json"}
  world: config.json modified
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Turn 3&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Load Phase:
  ctx = [system_prompt, memory_summary,
         previous_tool_result_DIGEST,  # compressed now!
         current_tool_result,
         previous_reasoning]
  # Note: first tool result compressed to save space

LLM Phase:
  reasoning: "Task complete. Config fixed."
  action: respond("Fixed! Changed database port from 3306 to 5432")

Execute Phase:
  entity: {type: "agent_response"}
  should_stop: true
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  7. Multi-Agent Design Patterns
&lt;/h2&gt;

&lt;p&gt;Using the entity calculus, we can formally describe common agent patterns.&lt;/p&gt;

&lt;h3&gt;
  
  
  7.1 Pattern: Tool-Use Agent
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Description&lt;/strong&gt;: Agent with access to external tools.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Implementation&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;entities&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="nc"&gt;Entity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;system_prompt&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="nc"&gt;Entity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;memory&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="nc"&gt;Entity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user_input&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nc"&gt;Entity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tool_desc&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;tool&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;available_tools&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="c1"&gt;# Tools are just entities with:
# 1. Description (for LLM to understand)
# 2. Execution handler (for harness.execute)
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Key Insight&lt;/strong&gt;: Tools are simultaneously entities (their descriptions load into context) and actions (their implementations execute in world).&lt;/p&gt;

&lt;h3&gt;
  
  
  7.2 Pattern: Skill-Enhanced Agent
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Description&lt;/strong&gt;: Agent that can load predefined workflows on-demand.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Implementation&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Skills available but not preloaded
&lt;/span&gt;&lt;span class="n"&gt;skill_entities&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="nc"&gt;Entity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;GitCommitSkill&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;loading&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;dynamic&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="nc"&gt;Entity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;DebugWorkflow&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;loading&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;dynamic&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="nc"&gt;Entity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;RefactorPattern&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;loading&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;dynamic&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="c1"&gt;# Harness.load uses semantic search:
&lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;user_input&lt;/span&gt; &lt;span class="n"&gt;mentions&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;commit&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;git&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nf"&gt;load&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;GitCommitSkill&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;verbosity&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;full&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nf"&gt;load&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;GitCommitSkill&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;verbosity&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;summary&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;# just title
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Key Insight&lt;/strong&gt;: Skills are entities loaded at different verbosity levels based on relevance.&lt;/p&gt;

&lt;h3&gt;
  
  
  7.3 Pattern: Subagent Spawning
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Description&lt;/strong&gt;: Agent delegates subtasks to other agents.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Implementation&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Define subagent spawn as a tool
&lt;/span&gt;&lt;span class="n"&gt;SubAgentTool&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Tool&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;spawn_subagent&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Create a new agent for a subtask&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;execute&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;lambda&lt;/span&gt; &lt;span class="n"&gt;prompt&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;world&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;# Create new agent with fresh context
&lt;/span&gt;        &lt;span class="n"&gt;subagent_ctx&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="n"&gt;system_prompt&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Entity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;prompt&lt;/span&gt;&lt;span class="p"&gt;)])&lt;/span&gt;

        &lt;span class="c1"&gt;# Run subagent loop until completion
&lt;/span&gt;        &lt;span class="n"&gt;result_ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;world&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt; = agent_loop(prompt, world)

        # Return subagent&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;entity&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;Entity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="nb"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;subagent_result&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;content&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nf"&gt;extract_result&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result_ctx&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;world&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;
    }
)
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Key Insight&lt;/strong&gt;: Subagents are just recursive invocations of the agent loop. The result is returned as an entity to the parent agent.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Example Flow&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Parent Agent:
  User: "Research React hooks and write a summary"

  Turn 1:
    action: spawn_subagent("Research React hooks from documentation")

    Subagent Loop:
      Turn 1: search("React hooks documentation")
      Turn 2: read(url)
      Turn 3: summarize(content)
      Turn 4: respond(summary)

    entity: {type: "subagent_result", content: "React hooks are..."}

  Turn 2:
    Context: [subagent_result, user_input]
    action: write_file("react-hooks-summary.md", content=subagent_result)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  7.4 Pattern: RAG (Retrieval-Augmented Generation)
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Description&lt;/strong&gt;: Agent retrieves relevant documents before generating responses.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Implementation&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# RAG is just a special load strategy
&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;rag_load&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;entity&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;entities&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="c1"&gt;# Extract query from latest entity (user input or reasoning)
&lt;/span&gt;    &lt;span class="n"&gt;query&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;extract_query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;entity&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# Search knowledge base (world operation)
&lt;/span&gt;    &lt;span class="n"&gt;relevant_docs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;semantic_search&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;world&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;knowledge_base&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;top_k&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# Convert docs to entities
&lt;/span&gt;    &lt;span class="n"&gt;doc_entities&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nc"&gt;Entity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;doc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;retrieved_doc&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;doc&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;relevant_docs&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

    &lt;span class="c1"&gt;# Standard load with doc entities included
&lt;/span&gt;    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;load&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;entity&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;entities&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;doc_entities&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Key Insight&lt;/strong&gt;: RAG is just a sophisticated entity discovery mechanism. Retrieved documents are entities loaded into context.&lt;/p&gt;

&lt;h3&gt;
  
  
  7.5 Pattern: ReAct (Reasoning + Acting)
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Description&lt;/strong&gt;: Agent alternates between reasoning and tool use.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Implementation&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# ReAct is the default agent loop!
# The loop naturally alternates:
&lt;/span&gt;
&lt;span class="n"&gt;Turn&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
  &lt;span class="n"&gt;LLM&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;reasoning&lt;/span&gt; &lt;span class="err"&gt;→&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Need to check database status&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
  &lt;span class="n"&gt;Action&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;check_db_status&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;Turn&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
  &lt;span class="n"&gt;LLM&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;reasoning&lt;/span&gt; &lt;span class="err"&gt;→&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Database is down, need to restart&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
  &lt;span class="n"&gt;Action&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;restart_db&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;Turn&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
  &lt;span class="n"&gt;LLM&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;reasoning&lt;/span&gt; &lt;span class="err"&gt;→&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Restart successful, task complete&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
  &lt;span class="n"&gt;Action&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;respond&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Done!&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Key Insight&lt;/strong&gt;: ReAct emerges naturally from the agent loop structure. No special implementation needed.&lt;/p&gt;

&lt;h3&gt;
  
  
  7.6 Pattern: Reflection
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Description&lt;/strong&gt;: Agent reviews and critiques its own work.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Implementation&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Reflection as a tool that spawns a critic subagent
&lt;/span&gt;&lt;span class="n"&gt;ReflectionTool&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Tool&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;reflect&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Review your work for errors and improvements&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;execute&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;lambda&lt;/span&gt; &lt;span class="n"&gt;work&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;world&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;critique_prompt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
        Review this work: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;work&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;

        Identify:
        1. Errors or bugs
        2. Missed requirements
        3. Potential improvements
        &lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;

        &lt;span class="c1"&gt;# Spawn critic agent with different system prompt
&lt;/span&gt;        &lt;span class="n"&gt;critic_ctx&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="n"&gt;critic_system_prompt&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Entity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;critique_prompt&lt;/span&gt;&lt;span class="p"&gt;)])&lt;/span&gt;
        &lt;span class="n"&gt;result_ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;world&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt; = agent_loop(critique_prompt, world)

        return Entity(type=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;reflection&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;, content=extract_result(result_ctx)), world&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Usage&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Agent:
  Turn 1: write_code(feature)
  Turn 2: reflect(code)
  Turn 3: revise(code, based_on=reflection)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Key Insight&lt;/strong&gt;: Reflection is subagent spawning with a specialized critic prompt.&lt;/p&gt;

&lt;h3&gt;
  
  
  7.7 Pattern: Multi-Agent Collaboration
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Description&lt;/strong&gt;: Multiple agents work in parallel on different aspects of a task.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Implementation&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;parallel_agents&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;task&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;world&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="c1"&gt;# Decompose task
&lt;/span&gt;    &lt;span class="n"&gt;subtasks&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;decompose&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;task&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# Spawn agent for each subtask
&lt;/span&gt;    &lt;span class="n"&gt;results&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;subtask&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;subtasks&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="c1"&gt;# Each agent runs independently
&lt;/span&gt;        &lt;span class="n"&gt;result_ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;world&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;agent_loop&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;subtask&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;world&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;results&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;extract_result&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result_ctx&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

    &lt;span class="c1"&gt;# Coordinator agent synthesizes results
&lt;/span&gt;    &lt;span class="n"&gt;synthesis_prompt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Combine these results: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;results&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="n"&gt;final_ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;world&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;agent_loop&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;synthesis_prompt&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;world&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;final_ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;world&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Key Insight&lt;/strong&gt;: Multi-agent systems are orchestrated by spawning multiple independent agent loops and synthesizing their results.&lt;/p&gt;

&lt;h2&gt;
  
  
  8. Advanced Topics
&lt;/h2&gt;

&lt;h3&gt;
  
  
  8.1 Dynamic Tool Loading
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Problem&lt;/strong&gt;: Loading descriptions of 100+ tools wastes context on irrelevant tools.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Solution&lt;/strong&gt;: Treat tool discovery as a two-phase load.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Implementation&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Phase 1: Load tool categories only
&lt;/span&gt;&lt;span class="n"&gt;tool_categories&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="nc"&gt;Entity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;File Operations: read, write, delete, ...&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="nc"&gt;Entity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Network Operations: fetch, post, websocket, ...&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="nc"&gt;Entity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Database Operations: query, insert, update, ...&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="n"&gt;ctx&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;load&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;user_input&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;tool_categories&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;reasoning&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;action&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;llm&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;# LLM might say "I need file operations"
&lt;/span&gt;
&lt;span class="c1"&gt;# Phase 2: Load full tool descriptions only for selected category
&lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;file&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;reasoning&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;lower&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;file_tools&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nc"&gt;Entity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;read_tool&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nc"&gt;Entity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;write_tool&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;...]&lt;/span&gt;
    &lt;span class="n"&gt;ctx&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;load&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Entity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;reasoning&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;file_tools&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Result&lt;/strong&gt;: Context usage reduced from O(all_tools) to O(relevant_tools).&lt;/p&gt;

&lt;h3&gt;
  
  
  8.2 Entity Discovery Mechanisms
&lt;/h3&gt;

&lt;p&gt;Entities can specify how they should be discovered:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;Entity&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;metadata&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;discovery&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;keywords&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;git&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;commit&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;version control&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;  &lt;span class="c1"&gt;# Keyword match
&lt;/span&gt;        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;semantic&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Create version control commits&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;      &lt;span class="c1"&gt;# Semantic search
&lt;/span&gt;        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;dependencies&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;read_file&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;write_file&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;       &lt;span class="c1"&gt;# Linked entities
&lt;/span&gt;        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;context_requirements&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;user_in_git_repo&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;      &lt;span class="c1"&gt;# Conditional
&lt;/span&gt;    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Use case&lt;/strong&gt;: GitCommitSkill specifies it should be loaded when:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;User mentions "commit" or "git" (keyword)&lt;/li&gt;
&lt;li&gt;Current directory is a git repo (context requirement)&lt;/li&gt;
&lt;li&gt;If loaded, also load file reading tools (dependencies)&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  8.3 Tool Data Handling Strategies
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Problem&lt;/strong&gt;: Tool returns 10MB JSON response. Loading fully into context is wasteful.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Strategy 1: Digest on Return&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;entity&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;world&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;action&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# Immediate digest
&lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;entity&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="n"&gt;KB&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;entity&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;content_full&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;entity&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;content&lt;/span&gt;
    &lt;span class="n"&gt;entity&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;content&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;llm_summarize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;entity&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;content&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;max_tokens&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;entity&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;verbosity&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;digest&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

    &lt;span class="c1"&gt;# Store full content in world for re-access if needed
&lt;/span&gt;    &lt;span class="n"&gt;world&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;store&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;entity&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;entity&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;content_full&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Strategy 2: Streaming / Pagination&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Don't load entire result
&lt;/span&gt;&lt;span class="n"&gt;entity&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Entity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nb"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;tool_result&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;content&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Large file detected. Use read_file(offset=N, limit=M) to page through.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;metadata&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;file_size&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;10MB&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;total_lines&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;50000&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Strategy 3: Structured Filtering&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Tool returns structured data with filtering instructions
&lt;/span&gt;&lt;span class="n"&gt;entity&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Entity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nb"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;tool_result&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;content&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;users&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[...]},&lt;/span&gt;  &lt;span class="c1"&gt;# 1000 users
&lt;/span&gt;    &lt;span class="n"&gt;filter_instructions&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Use filter_tool_result(key=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;users&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;, condition=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;age &amp;gt; 30&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;) to refine&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  8.4 Context Compression Strategies
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;load&lt;/code&gt; function can employ LLM-based compression:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Summarization Compression&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# When context is 80% full
&lt;/span&gt;&lt;span class="n"&gt;old_messages&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;[:&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;  &lt;span class="c1"&gt;# All but last 10
&lt;/span&gt;&lt;span class="n"&gt;summary&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;llm_summarize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;old_messages&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;messages&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;summary&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;:]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Semantic Deduplication&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Remove redundant information
&lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nf"&gt;semantic_similarity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;new_entity&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;existing_entity&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mf"&gt;0.9&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="c1"&gt;# Information already in context
&lt;/span&gt;    &lt;span class="nf"&gt;omit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;new_entity&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Importance-Based Eviction&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Score each entity by relevance to current task
&lt;/span&gt;&lt;span class="n"&gt;scores&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;score_relevance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;current_task&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;entities&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="c1"&gt;# Remove lowest-scored entities when context is full
&lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;is_full&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;entities&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;sorted&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;zip&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;entities&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;scores&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;lambda&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;])][:&lt;/span&gt;&lt;span class="n"&gt;max_entities&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  8.5 JIT (Just-In-Time) Context Loading
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Concept&lt;/strong&gt;: Tool results can include instructions for processing their data.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Example&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Tool execution
&lt;/span&gt;&lt;span class="n"&gt;entity&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;search_codebase&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;authentication&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

&lt;span class="c1"&gt;# Entity includes loading instructions
&lt;/span&gt;&lt;span class="n"&gt;entity&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;content&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;results&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;file&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;auth.py&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;line&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;45&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;snippet&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;...&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;file&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;login.py&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;line&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;12&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;snippet&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;...&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="c1"&gt;# ... 50 more results
&lt;/span&gt;    &lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;loading_instructions&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;default_verbosity&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;summary&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="c1"&gt;# Show only file names + line counts
&lt;/span&gt;        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;expand_on_request&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;       &lt;span class="c1"&gt;# Allow LLM to request full snippets
&lt;/span&gt;        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;expansion_tool&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;expand_search_result(index=N)&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;# Initial load: summary only
&lt;/span&gt;&lt;span class="nf"&gt;load&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;entity&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;verbosity&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;summary&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;# Context: "Found authentication code in 52 files. Use expand_search_result(index=N) for details."
&lt;/span&gt;
&lt;span class="c1"&gt;# LLM can then selectively expand:
&lt;/span&gt;&lt;span class="n"&gt;action&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;expand_search_result&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;# Returns full snippet from auth.py
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Benefit&lt;/strong&gt;: LLM gets overview first, then drills down only where needed.&lt;/p&gt;

&lt;h3&gt;
  
  
  8.6 Multi-Level Tool Descriptions
&lt;/h3&gt;

&lt;p&gt;Tools can define descriptions at multiple granularities:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;Tool&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;descriptions&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;title&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;read_file&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;

    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;one_liner&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Read file contents&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;

    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;summary&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
        read_file(path) → string
        Reads and returns file contents from disk.
    &lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;

    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;detailed&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
        read_file(path, offset=0, limit=None) → string

        Reads file contents from the filesystem.

        Parameters:
        - path: Absolute path to file
        - offset: Starting line number (0-indexed)
        - limit: Maximum number of lines to read

        Returns: File contents as string

        Errors: FileNotFoundError, PermissionError

        Example:
            content = read_file(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/home/user/config.json&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;)
    &lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Load Strategy&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# When context is spacious: load detailed
# When context is tight: load summary
# When very tight: load one_liner only
# When nearly full: load title only (just function name)
&lt;/span&gt;
&lt;span class="n"&gt;verbosity&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;choose_verbosity_level&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;available_space&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;tool_entity&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;content&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;tool&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;descriptions&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;verbosity&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  9. Integration with Existing Systems
&lt;/h2&gt;

&lt;h3&gt;
  
  
  9.1 Mapping to Real Agent Frameworks
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;LangChain&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# LangChain concepts → Entity Calculus
&lt;/span&gt;&lt;span class="n"&gt;Agent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;LLM&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;Harness&lt;/span&gt;
&lt;span class="n"&gt;Tools&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nc"&gt;Entity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tool_description&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;execute&lt;/span&gt; &lt;span class="n"&gt;handlers&lt;/span&gt;
&lt;span class="n"&gt;Memory&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Entity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;conversation_buffer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;memory&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;loading&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;preloaded&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;Chains&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Predefined&lt;/span&gt; &lt;span class="n"&gt;entity&lt;/span&gt; &lt;span class="n"&gt;sequences&lt;/span&gt;
&lt;span class="n"&gt;Callbacks&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Instrumentation&lt;/span&gt; &lt;span class="n"&gt;hooks&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;harness&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;load&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;harness&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;execute&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;AutoGen&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# AutoGen concepts → Entity Calculus
&lt;/span&gt;&lt;span class="n"&gt;ConversableAgent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Agent &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;LLM&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;Harness&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;UserProxyAgent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Agent&lt;/span&gt; &lt;span class="nf"&gt;with &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;no&lt;/span&gt; &lt;span class="n"&gt;LLM&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;execute&lt;/span&gt; &lt;span class="n"&gt;only&lt;/span&gt; &lt;span class="n"&gt;harness&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;GroupChat&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Multi&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;agent&lt;/span&gt; &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;shared&lt;/span&gt; &lt;span class="n"&gt;entity&lt;/span&gt; &lt;span class="n"&gt;pool&lt;/span&gt;
&lt;span class="n"&gt;Human&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="ow"&gt;in&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;loop&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;User&lt;/span&gt; &lt;span class="nb"&gt;input&lt;/span&gt; &lt;span class="n"&gt;injected&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;entity&lt;/span&gt; &lt;span class="n"&gt;during&lt;/span&gt; &lt;span class="n"&gt;loop&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Cursor / Copilot&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# IDE agent concepts → Entity Calculus
&lt;/span&gt;&lt;span class="n"&gt;Codebase&lt;/span&gt; &lt;span class="n"&gt;Context&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Entity&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="n"&gt;semantic&lt;/span&gt; &lt;span class="n"&gt;search&lt;/span&gt; &lt;span class="n"&gt;over&lt;/span&gt; &lt;span class="n"&gt;code&lt;/span&gt;
&lt;span class="n"&gt;Active&lt;/span&gt; &lt;span class="n"&gt;File&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Entity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;current_file&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;loading&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;preloaded&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;verbosity&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;full&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;Related&lt;/span&gt; &lt;span class="n"&gt;Files&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nc"&gt;Entity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;file&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;loading&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;dynamic&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;verbosity&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;summary&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
&lt;span class="n"&gt;LSP&lt;/span&gt; &lt;span class="n"&gt;Information&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Entity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;type_info&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;references&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;loading&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;on-demand&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  9.2 RAG Systems
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Traditional RAG&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;query&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;user_input&lt;/span&gt;
&lt;span class="n"&gt;docs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;vector_db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;search&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;context&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;system_prompt&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;docs&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;llm&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Entity Calculus RAG&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Documents are just entities!
&lt;/span&gt;&lt;span class="n"&gt;entities&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="nc"&gt;Entity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;system_prompt&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;loading&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;preloaded&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="nc"&gt;Entity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user_input&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;loading&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;preloaded&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nc"&gt;Entity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;doc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;loading&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;dynamic&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;discovered_by&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;semantic_search&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;doc&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;vector_db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;search&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user_input&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="c1"&gt;# Standard agent loop
&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;harness&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;load&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;entities&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;reasoning&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;action&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;llm&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Key Insight&lt;/strong&gt;: RAG is entity discovery via semantic search.&lt;/p&gt;

&lt;h2&gt;
  
  
  10. Future Directions &amp;amp; Open Questions
&lt;/h2&gt;

&lt;h3&gt;
  
  
  10.1 Entity Discovery as a Graph
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Idea&lt;/strong&gt;: Entities can link to related entities, forming a graph.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nc"&gt;Entity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;GitCommitSkill&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;links&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="nc"&gt;Link&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Entity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ReadFileTool&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;relation&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;requires&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="nc"&gt;Link&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Entity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;WriteFileTool&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;relation&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;requires&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="nc"&gt;Link&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Entity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;GitStatusTool&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;relation&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;uses&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="nc"&gt;Link&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Entity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;PRCreationSkill&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;relation&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;related_to&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Use Case&lt;/strong&gt;: When GitCommitSkill is loaded, harness can automatically load linked tools.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Question&lt;/strong&gt;: How to prevent exponential blow-up of linked entities?&lt;/p&gt;

&lt;h3&gt;
  
  
  10.2 Entity-Provided Processing Instructions
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Idea&lt;/strong&gt;: Entities specify how they should be processed after use.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nc"&gt;Entity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tool_result&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;processing_hints&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;after_llm_reads&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;compress_to_digest&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;after_N_turns&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;omit_if_not_referenced&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;if_context_full&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;move_to_world_storage&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Benefit&lt;/strong&gt;: Declarative context management instead of imperative harness logic.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Question&lt;/strong&gt;: How to balance entity autonomy with global context optimization?&lt;/p&gt;

&lt;h3&gt;
  
  
  10.3 Learned Context Management
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Idea&lt;/strong&gt;: Use ML to learn optimal loading strategies.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Train a model to predict:
# - Which entities to load given task
# - What verbosity level to use
# - When to compress/omit entities
&lt;/span&gt;
&lt;span class="n"&gt;load_policy&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;train&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;inputs&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;task_embedding&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;available_entities&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;context_state&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="n"&gt;outputs&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;entities_to_load&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;verbosity_levels&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="n"&gt;objective&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nf"&gt;maximize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;task_success_rate&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nf"&gt;penalize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context_usage&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Question&lt;/strong&gt;: How to collect training data? What are the right features?&lt;/p&gt;

&lt;h3&gt;
  
  
  10.4 Hierarchical Entities
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Idea&lt;/strong&gt;: Entities can contain sub-entities.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nc"&gt;Entity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Codebase&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;collection&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;children&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="nc"&gt;Entity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Module1&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="nc"&gt;Entity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Module2&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="bp"&gt;...&lt;/span&gt;
    &lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;# Load strategy:
# - Initially load: Entity(Codebase, verbosity="summary")
#   → "Codebase contains 50 modules in 3 categories"
# - On demand: Entity(Module1, verbosity="full")
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Use Case&lt;/strong&gt;: Representing complex structured knowledge (codebases, documentation sites, databases).&lt;/p&gt;

&lt;h3&gt;
  
  
  10.5 Entity Lifecycle Hooks
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Idea&lt;/strong&gt;: Entities can define callbacks for lifecycle events.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;Entity&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;hooks&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;on_load&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;lambda&lt;/span&gt; &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;validate_dependencies&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;on_compress&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;lambda&lt;/span&gt; &lt;span class="n"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;custom_summarize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;content&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;on_evict&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;lambda&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;persist_to_world&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;on_access&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;lambda&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;log_usage_analytics&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Benefit&lt;/strong&gt;: Entities become active components, not passive data.&lt;/p&gt;

&lt;h3&gt;
  
  
  10.6 Cross-Agent Entity Sharing
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Idea&lt;/strong&gt;: Multiple agents share a common entity pool.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Shared world with entity store
&lt;/span&gt;&lt;span class="n"&gt;world&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;entity_store&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;current_task&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Entity&lt;/span&gt;&lt;span class="p"&gt;(...),&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;research_results&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Entity&lt;/span&gt;&lt;span class="p"&gt;(...),&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;code_changes&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Entity&lt;/span&gt;&lt;span class="p"&gt;(...),&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;# Agent A updates entity
&lt;/span&gt;&lt;span class="n"&gt;agent_a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;update_entity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;research_results&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

&lt;span class="c1"&gt;# Agent B reads updated entity
&lt;/span&gt;&lt;span class="n"&gt;ctx_b&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;load&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx_b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;world&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;entity_store&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;research_results&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Use Case&lt;/strong&gt;: Multi-agent collaboration with shared knowledge.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Question&lt;/strong&gt;: How to handle conflicts? Consistency guarantees?&lt;/p&gt;

&lt;h3&gt;
  
  
  10.7 Speculative Entity Loading
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Idea&lt;/strong&gt;: Preemptively load entities the LLM might need.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Predict future entity needs
&lt;/span&gt;&lt;span class="n"&gt;predicted_entities&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;predict_next_entities&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;current_state&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;llm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;recent_actions&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# Load them in background (if context space available)
&lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;predicted_entities&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;has_space&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
        &lt;span class="n"&gt;ctx&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;load&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;verbosity&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;summary&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Benefit&lt;/strong&gt;: Reduced latency for multi-turn interactions.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Question&lt;/strong&gt;: How to predict accurately without wasting context?&lt;/p&gt;

&lt;h3&gt;
  
  
  10.8 Differential Context Updates
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Idea&lt;/strong&gt;: Instead of reloading full context, send only diffs.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Current approach: send full context every turn
&lt;/span&gt;&lt;span class="nf"&gt;llm&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;full_context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="err"&gt;→&lt;/span&gt; &lt;span class="n"&gt;action&lt;/span&gt;

&lt;span class="c1"&gt;# Differential approach:
&lt;/span&gt;&lt;span class="n"&gt;llm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;add&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;new_entity&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="n"&gt;remove&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;old_entity_id&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="n"&gt;modify&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;entity_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;new_content&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Benefit&lt;/strong&gt;: Reduced token usage, faster inference.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Challenge&lt;/strong&gt;: Requires stateful LLM API (not common yet).&lt;/p&gt;

&lt;h3&gt;
  
  
  10.9 Entity Versioning
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Idea&lt;/strong&gt;: Track entity changes over time.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;Entity&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;versions&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;timestamp&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;content&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Initial user query&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;timestamp&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;content&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Elaborated with clarifications&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;timestamp&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;content&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Further refined based on context&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="c1"&gt;# Load appropriate version based on temporal context
&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;load&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;entity&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;version_at&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Use Case&lt;/strong&gt;: Understanding how agent's understanding evolved. Debugging. Time-travel debugging.&lt;/p&gt;

&lt;h3&gt;
  
  
  10.10 Meta-Entities
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Idea&lt;/strong&gt;: Entities that describe other entities.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nc"&gt;MetaEntity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;target&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nc"&gt;Entity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;large_tool_result&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="n"&gt;metadata&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;summary&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Database query returned 10K rows&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;schema&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;columns&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[...],&lt;/span&gt; &lt;span class="n"&gt;types&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[...]},&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;relevance_to_task&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;0.85&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;recommended_verbosity&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;digest&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Benefit&lt;/strong&gt;: Richer metadata for smarter loading decisions.&lt;/p&gt;

&lt;h2&gt;
  
  
  11. Conclusion
&lt;/h2&gt;

&lt;p&gt;The &lt;strong&gt;Entity Calculus&lt;/strong&gt; provides a unified lens for understanding AI agents:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Everything is an entity&lt;/strong&gt;: Skills, tools, memory, data—all flow through the same abstraction.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Harness manages entity flow&lt;/strong&gt;: The &lt;code&gt;load&lt;/code&gt; and &lt;code&gt;execute&lt;/code&gt; functions orchestrate entity movement between context and world.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Context is the bottleneck&lt;/strong&gt;: All optimizations revolve around the limited context window.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Patterns emerge naturally&lt;/strong&gt;: Common agent patterns (ReAct, RAG, multi-agent) are special cases of entity flow.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Composability&lt;/strong&gt;: Because everything is an entity, components compose cleanly.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Key Insights
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Agent = LLM + Harness&lt;/strong&gt; cleanly separates reasoning (LLM) from orchestration (harness).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Entity abstraction&lt;/strong&gt; unifies disparate concepts under one model.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Load/Execute duality&lt;/strong&gt; captures the full agent loop: load entities into context, execute actions in world.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Multi-agent systems&lt;/strong&gt; are recursive applications of the same calculus.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Practical Value
&lt;/h3&gt;

&lt;p&gt;For &lt;strong&gt;researchers&lt;/strong&gt;, this framework provides:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Formal vocabulary for discussing agent architectures&lt;/li&gt;
&lt;li&gt;Basis for systematic analysis of agent behaviors&lt;/li&gt;
&lt;li&gt;Foundation for developing new context management techniques&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For &lt;strong&gt;engineers&lt;/strong&gt;, this framework provides:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Clear mental model for designing agents&lt;/li&gt;
&lt;li&gt;Reusable patterns for common agent tasks&lt;/li&gt;
&lt;li&gt;Principled approach to context optimization&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Next Steps
&lt;/h3&gt;

&lt;p&gt;We invite the community to:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Implement reference harnesses following this calculus&lt;/li&gt;
&lt;li&gt;Develop benchmarks for entity loading strategies&lt;/li&gt;
&lt;li&gt;Explore the open questions outlined in Section 10&lt;/li&gt;
&lt;li&gt;Extend the calculus to new domains (e.g., multimodal agents, embodied agents)&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://cursor.com/blog/dynamic-context-discovery" rel="noopener noreferrer"&gt;Cursor: Dynamic Context Discovery&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://x.com/trq212/status/2011523109871108570" rel="noopener noreferrer"&gt;Twitter Discussion on Agent Abstractions&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Appendix: Notation Reference
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Symbol&lt;/th&gt;
&lt;th&gt;Meaning&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;LLM: Context → (Reasoning, Actions)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;LLM as pure function&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Agent = LLM + Harness&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Agent decomposition&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;load: (Context, Entity, List[Entity]) → Context'&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Harness load function&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;execute: (Action, World) → (Entity, World')&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Harness execute function&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Entity&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Unit of information loadable into context&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Context&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;LLM's directly accessible information&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;World&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;External state outside context&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;verbosity ∈ {full, summary, digest, reference}&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Entity loading granularity&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;loading ∈ {preloaded, dynamic}&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Entity loading strategy&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;p&gt;&lt;em&gt;Document Version: 1.0&lt;/em&gt;&lt;br&gt;
&lt;em&gt;Last Updated: January 15, 2026&lt;/em&gt;&lt;/p&gt;

</description>
      <category>agents</category>
      <category>ai</category>
      <category>architecture</category>
      <category>llm</category>
    </item>
    <item>
      <title>Koka.py: Type-Checked Dependency Injection and Error Handling in Python</title>
      <dc:creator>Herrington Darkholme</dc:creator>
      <pubDate>Mon, 15 Dec 2025 01:56:04 +0000</pubDate>
      <link>https://forem.com/herrington_darkholme/kokapy-type-checked-dependency-injection-and-error-handling-in-python-1beg</link>
      <guid>https://forem.com/herrington_darkholme/kokapy-type-checked-dependency-injection-and-error-handling-in-python-1beg</guid>
      <description>&lt;p&gt;&lt;em&gt;Exploring algebraic effects inspired by Effect-TS, ZIO, and the Koka language&lt;/em&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  The Problem: Python's Hidden Dependencies and Exceptions
&lt;/h2&gt;

&lt;p&gt;Every developer encounters two questions when reading unfamiliar code:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;"What does this function need to work?"&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;"What can go wrong when I call this?"&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Consider a typical Python function:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_user_profile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;UserProfile&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;token&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Authorization&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;auth_service&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;verify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;token&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;cached&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;cache&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;user:&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;user_id&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;cached&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;cached&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;database&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find_user&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To answer our two questions, you must read the entire implementation. Where does &lt;code&gt;auth_service&lt;/code&gt; come from? What happens if &lt;code&gt;verify()&lt;/code&gt; fails? Can &lt;code&gt;find_user()&lt;/code&gt; return &lt;code&gt;None&lt;/code&gt;? The type signature &lt;code&gt;(str) -&amp;gt; UserProfile&lt;/code&gt; tells you almost nothing.&lt;/p&gt;

&lt;p&gt;This problem compounds in real applications with layered architectures:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;handle_request() 
 → get_user_profile() 
  → authenticate() 
   → check_cache() 
    → query_db()
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each layer can have its own dependencies and failure modes. Traditional Python keeps dependencies implicit and errors unchecked. The result: runtime surprises, missing error handling, and unclear contracts.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What if the type signature told you everything?&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_user_profile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Eff&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="n"&gt;Dep&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;AuthService&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;Dep&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Database&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;Dep&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;CacheService&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;AuthError&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;NotFoundError&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;UserProfile&lt;/span&gt;
&lt;span class="p"&gt;]:&lt;/span&gt;
    &lt;span class="bp"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now you &lt;strong&gt;know&lt;/strong&gt;: this function needs &lt;code&gt;AuthService&lt;/code&gt;, &lt;code&gt;CacheService&lt;/code&gt; and &lt;code&gt;Database&lt;/code&gt;, might fail with &lt;code&gt;AuthError&lt;/code&gt; or &lt;code&gt;NotFoundError&lt;/code&gt;, and returns &lt;code&gt;UserProfile&lt;/code&gt;. All without reading a single line of implementation.&lt;/p&gt;

&lt;p&gt;This is what the &lt;code&gt;koka&lt;/code&gt; library enables.&lt;/p&gt;




&lt;h2&gt;
  
  
  What Are Algebraic Effects? (A Practical Take)
&lt;/h2&gt;

&lt;p&gt;Skip the academic theory. Here's the practical framing:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Effects are declared capabilities&lt;/strong&gt;—what a function needs to run and how it can fail. Think of it as making the implicit explicit, and letting the type checker verify it.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;koka&lt;/code&gt; library provides two key effects:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;Dep[T]&lt;/code&gt;&lt;/strong&gt; — "I need an instance of type T to run"&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;Err[E]&lt;/code&gt;&lt;/strong&gt; — "I might fail with error E"&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The key insight: &lt;strong&gt;effects compose automatically&lt;/strong&gt;. If function A needs &lt;code&gt;Dep[Database]&lt;/code&gt; and function B needs &lt;code&gt;Dep[Cache]&lt;/code&gt;, and function C calls both A and B, then C's type automatically includes &lt;code&gt;Dep[Database] | Dep[Cache]&lt;/code&gt;. The type checker infers this—no manual annotation needed.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Inspiration Chain
&lt;/h3&gt;

&lt;p&gt;This pattern didn't emerge from nowhere. It follows a lineage of innovation:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Academic research&lt;/strong&gt; on algebraic effects and handlers (Plotkin, Pretnar, et al.)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Koka language&lt;/strong&gt; — a research language that pioneered practical algebraic effects&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;ZIO&lt;/strong&gt; (Scala) — brought effect systems to mainstream functional programming at &lt;a href="https://zio.dev/" rel="noopener noreferrer"&gt;zio.dev&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Effect-TS&lt;/strong&gt; (TypeScript) — made effects accessible to the JavaScript ecosystem&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;koka&lt;/strong&gt; (Python) — brings these ideas to Python, leveraging Python 3.13's type system&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This library is an exploration of whether Python's type system and generators can express the same patterns that have proven valuable in other ecosystems.&lt;/p&gt;




&lt;h2&gt;
  
  
  Real-World Example: User Lookup Service
&lt;/h2&gt;

&lt;p&gt;Let's build a realistic scenario with multiple failure modes that map to different HTTP responses.&lt;/p&gt;

&lt;h3&gt;
  
  
  Layer 1: Authentication
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;AuthError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;Exception&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Invalid or missing authentication. Maps to HTTP 401 Unauthorized.&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="k"&gt;pass&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;AuthService&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;verify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;token&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;User&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="bp"&gt;...&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;authenticate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;token&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Eff&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Dep&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;AuthService&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;AuthError&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;User&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
    &lt;span class="n"&gt;auth&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;AuthService&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;yield&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="nc"&gt;Dep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;AuthService&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;User&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;auth&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;verify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;token&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="nf"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;yield&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="nc"&gt;Err&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;AuthError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Invalid token&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The type signature &lt;code&gt;Eff[Dep[AuthService] | AuthError, User]&lt;/code&gt; tells you:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Needs&lt;/strong&gt;: &lt;code&gt;AuthService&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Can fail with&lt;/strong&gt;: &lt;code&gt;AuthError&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Returns&lt;/strong&gt;: &lt;code&gt;User&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Layer 2: Cache Lookup
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;CacheMiss&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;Exception&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Internal signal—don&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;t expose to HTTP clients.&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="k"&gt;pass&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;CacheService&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;UserProfile&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="bp"&gt;...&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_from_cache&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Eff&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Dep&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;CacheService&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;CacheMiss&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;UserProfile&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
    &lt;span class="n"&gt;cache&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;CacheService&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;yield&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="nc"&gt;Dep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;CacheService&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;UserProfile&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;cache&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;user:&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;user_id&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="nf"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;yield&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="nc"&gt;Err&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;CacheMiss&lt;/span&gt;&lt;span class="p"&gt;()))&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Layer 3: Database Lookup
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;NotFoundError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;Exception&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;User doesn&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;t exist. Maps to HTTP 404 Not Found.&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="k"&gt;pass&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Database&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;find_user&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;user_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;UserProfile&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="bp"&gt;...&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_from_db&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Eff&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Dep&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Database&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;NotFoundError&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;UserProfile&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
    &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Database&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;yield&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="nc"&gt;Dep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Database&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;UserProfile&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find_user&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="nf"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;yield&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="nc"&gt;Err&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;NotFoundError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;User &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;user_id&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; not found&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Layer 4: Composed Handler
&lt;/h3&gt;

&lt;p&gt;Now we compose these layers into a single handler:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_user_profile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;token&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;user_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Eff&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="n"&gt;Dep&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;AuthService&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;Dep&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;CacheService&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;Dep&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Database&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;AuthError&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;NotFoundError&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;UserProfile&lt;/span&gt;
&lt;span class="p"&gt;]:&lt;/span&gt;
    &lt;span class="c1"&gt;# First authenticate (can fail with AuthError → 401)
&lt;/span&gt;    &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;User&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;yield&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="nf"&gt;authenticate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;token&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# Try cache first (handle CacheMiss internally)
&lt;/span&gt;    &lt;span class="n"&gt;cache&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;CacheService&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;yield&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="nc"&gt;Dep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;CacheService&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;cached&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;UserProfile&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;cache&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;user:&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;user_id&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;cached&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;cached&lt;/span&gt;

    &lt;span class="c1"&gt;# Fall back to database (can fail with NotFoundError → 404)
&lt;/span&gt;    &lt;span class="nf"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;yield&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="nf"&gt;get_from_db&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user_id&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;The type signature reveals everything&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Dependencies&lt;/strong&gt;: &lt;code&gt;AuthService&lt;/code&gt;, &lt;code&gt;CacheService&lt;/code&gt;, &lt;code&gt;Database&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Possible errors&lt;/strong&gt;: &lt;code&gt;AuthError&lt;/code&gt; (→ 401), &lt;code&gt;NotFoundError&lt;/code&gt; (→ 404)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Return type&lt;/strong&gt;: &lt;code&gt;UserProfile&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Note that &lt;code&gt;CacheMiss&lt;/code&gt; doesn't appear in the final signature—we handled it internally by falling back to the database.&lt;/p&gt;

&lt;h3&gt;
  
  
  Running the Effect
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;UserProfile&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;AuthError&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;NotFoundError&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nc"&gt;Koka&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;provide&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;AuthService&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;provide&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;CacheService&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;provide&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Database&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;get_user_profile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;token-123&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;user-456&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# Pattern match to HTTP responses
&lt;/span&gt;&lt;span class="n"&gt;match&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;case&lt;/span&gt; &lt;span class="nc"&gt;AuthError&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;HttpResponse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;401&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Unauthorized: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;case&lt;/span&gt; &lt;span class="nc"&gt;NotFoundError&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;HttpResponse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;404&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Not Found: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;case&lt;/span&gt; &lt;span class="nc"&gt;UserProfile&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;profile&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;HttpResponse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;profile&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;to_json&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;Koka&lt;/code&gt; runtime ensures all dependencies are provided. If you forget to &lt;code&gt;.provide(Database())&lt;/code&gt;, you get a &lt;strong&gt;type error&lt;/strong&gt;—not a runtime &lt;code&gt;AttributeError&lt;/code&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  How &lt;code&gt;yield from&lt;/code&gt; Achieves This
&lt;/h2&gt;

&lt;p&gt;The magic happens through Python's generator protocol. Here's how it works.&lt;/p&gt;

&lt;h3&gt;
  
  
  The &lt;code&gt;Eff&lt;/code&gt; Type
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nb"&gt;type&lt;/span&gt; &lt;span class="n"&gt;Eff&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;K&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;R&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Generator&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;K&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Never&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;R&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;K&lt;/code&gt; — the effects yielded (union of &lt;code&gt;Dep[T]&lt;/code&gt; types and exception types)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;R&lt;/code&gt; — the return type&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  How &lt;code&gt;Dep[T]&lt;/code&gt; Works
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Dep&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;tpe&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;type&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tpe&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;tpe&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;__iter__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Generator&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
        &lt;span class="nf"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;yield&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;# Yield the request, receive the instance
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When you write &lt;code&gt;db = yield from Dep(Database)&lt;/code&gt;:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The generator yields &lt;code&gt;Dep(Database)&lt;/code&gt; — a request for a &lt;code&gt;Database&lt;/code&gt; instance&lt;/li&gt;
&lt;li&gt;The runtime receives this request and looks up the handler&lt;/li&gt;
&lt;li&gt;The runtime sends the &lt;code&gt;Database&lt;/code&gt; instance back into the generator&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;db&lt;/code&gt; receives the &lt;code&gt;Database&lt;/code&gt; instance&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The type checker sees:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You're yielding &lt;code&gt;Dep[Database]&lt;/code&gt; (adds to effect set K)&lt;/li&gt;
&lt;li&gt;You're receiving &lt;code&gt;Database&lt;/code&gt; (the return type)&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  How &lt;code&gt;Err[E]&lt;/code&gt; Works
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Err&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;E&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Exception&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;E&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;error&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;__iter__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Generator&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;E&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Never&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Never&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
        &lt;span class="k"&gt;yield&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;error&lt;/span&gt;  &lt;span class="c1"&gt;# Yield the error, never resume
&lt;/span&gt;        &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;RuntimeError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Unreachable&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;# Type: Never
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When you write &lt;code&gt;return (yield from Err(NotFoundError(...)))&lt;/code&gt;:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The generator yields the &lt;code&gt;NotFoundError&lt;/code&gt; exception&lt;/li&gt;
&lt;li&gt;The runtime receives it and returns it as the final result&lt;/li&gt;
&lt;li&gt;The generator never resumes (hence &lt;code&gt;Never&lt;/code&gt; return type)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The type checker sees:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You're yielding &lt;code&gt;NotFoundError&lt;/code&gt; (adds to effect set K)&lt;/li&gt;
&lt;li&gt;The expression type is &lt;code&gt;Never&lt;/code&gt; (computation doesn't continue)&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Effect Composition
&lt;/h3&gt;

&lt;p&gt;When you &lt;code&gt;yield from authenticate(token)&lt;/code&gt; inside &lt;code&gt;get_user_profile&lt;/code&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;authenticate&lt;/code&gt; has effects &lt;code&gt;Dep[AuthService] | AuthError&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;These get added to &lt;code&gt;get_user_profile&lt;/code&gt;'s effect set&lt;/li&gt;
&lt;li&gt;The type checker automatically computes the union:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  Dep[AuthService] | AuthError | Dep[CacheService] | Dep[Database] | NotFoundError
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is why you don't need to manually declare the effect types—&lt;strong&gt;the type checker infers them from usage&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Alternative: Manual Return Types
&lt;/h2&gt;

&lt;p&gt;Can we achieve the same type safety without generators? Let's try using explicit return types.&lt;/p&gt;

&lt;h3&gt;
  
  
  Attempt: Pass Dependencies, Return Union Types
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;authenticate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;auth&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;AuthService&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;token&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;User&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;AuthError&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;User&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;auth&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;verify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;token&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;AuthError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Invalid token&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_from_db&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Database&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;user_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;UserProfile&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;NotFoundError&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;UserProfile&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find_user&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;NotFoundError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;User &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;user_id&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; not found&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_user_profile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;auth&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;AuthService&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;cache&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;CacheService&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Database&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;token&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;user_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;UserProfile&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;AuthError&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;NotFoundError&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="c1"&gt;# Check auth
&lt;/span&gt;    &lt;span class="n"&gt;auth_result&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;User&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;AuthError&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;authenticate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;auth&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;token&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nf"&gt;isinstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;auth_result&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;AuthError&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;auth_result&lt;/span&gt;
    &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;User&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;auth_result&lt;/span&gt;

    &lt;span class="c1"&gt;# Try cache
&lt;/span&gt;    &lt;span class="n"&gt;cached&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;UserProfile&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;cache&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;user:&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;user_id&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;cached&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;cached&lt;/span&gt;

    &lt;span class="c1"&gt;# Try database
&lt;/span&gt;    &lt;span class="n"&gt;db_result&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;UserProfile&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;NotFoundError&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;get_from_db&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;user_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nf"&gt;isinstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;db_result&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;NotFoundError&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;db_result&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;db_result&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  The Problems
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;1. Dependency Threading&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Every function must explicitly accept and pass through all dependencies. &lt;code&gt;get_user_profile&lt;/code&gt; takes 5 parameters—3 of which are just dependency plumbing. In deep call stacks, this becomes unmanageable:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;handle_request&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;auth&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;AuthService&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;cache&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;CacheService&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Database&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;EmailService&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Logger&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;metrics&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;MetricsService&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;token&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;user_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;...:&lt;/span&gt;
    &lt;span class="c1"&gt;# Every layer needs all these parameters
&lt;/span&gt;    &lt;span class="bp"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;2. Manual Error Type Union&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;You must manually declare &lt;code&gt;-&amp;gt; UserProfile | AuthError | NotFoundError&lt;/code&gt;. Forget one, and callers get type errors—or worse, the type checker misses a case. As you add more error types, the union grows unwieldy:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;complex_operation&lt;/span&gt;&lt;span class="p"&gt;(...)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Result&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;ErrorA&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;ErrorB&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;ErrorC&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;ErrorD&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;ErrorE&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="bp"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;3. Nested &lt;code&gt;isinstance&lt;/code&gt; Checks Destroy Readability&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;result1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;step1&lt;/span&gt;&lt;span class="p"&gt;(...)&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nf"&gt;isinstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Error1&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;result1&lt;/span&gt;

&lt;span class="n"&gt;result2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;step2&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...)&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nf"&gt;isinstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Error2&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;result2&lt;/span&gt;

&lt;span class="n"&gt;result3&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;step3&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...)&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nf"&gt;isinstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Error3&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;result3&lt;/span&gt;

&lt;span class="c1"&gt;# This continues for EVERY call that can fail
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Linear code becomes a staircase of error checks, obscuring the happy path.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. No Automatic Inference&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The type checker can't infer what dependencies or errors are needed—you must declare everything manually. Add a new error case deep in the call stack? Update every function signature up to the top.&lt;/p&gt;

&lt;h3&gt;
  
  
  Comparison Table
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Aspect&lt;/th&gt;
&lt;th&gt;
&lt;code&gt;yield from&lt;/code&gt; (koka)&lt;/th&gt;
&lt;th&gt;Return types&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Dependencies&lt;/td&gt;
&lt;td&gt;Inferred from usage&lt;/td&gt;
&lt;td&gt;Explicit parameters&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Error types&lt;/td&gt;
&lt;td&gt;Inferred from &lt;code&gt;Err()&lt;/code&gt; calls&lt;/td&gt;
&lt;td&gt;Manual union annotation&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Control flow&lt;/td&gt;
&lt;td&gt;Linear, readable&lt;/td&gt;
&lt;td&gt;Nested &lt;code&gt;isinstance&lt;/code&gt; checks&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Composition&lt;/td&gt;
&lt;td&gt;Automatic&lt;/td&gt;
&lt;td&gt;Manual threading&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Adding new dependency&lt;/td&gt;
&lt;td&gt;Just use it&lt;/td&gt;
&lt;td&gt;Update all callers&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Adding new error type&lt;/td&gt;
&lt;td&gt;Just yield it&lt;/td&gt;
&lt;td&gt;Update all signatures&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  The &lt;code&gt;yield from&lt;/code&gt; Version (For Contrast)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_user_profile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;token&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;user_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Eff&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="n"&gt;Dep&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;AuthService&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;Dep&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;CacheService&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;Dep&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Database&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;AuthError&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;NotFoundError&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;UserProfile&lt;/span&gt;
&lt;span class="p"&gt;]:&lt;/span&gt;
    &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;User&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;yield&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="nf"&gt;authenticate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;token&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;cache&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;CacheService&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;yield&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="nc"&gt;Dep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;CacheService&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;cached&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;UserProfile&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;cache&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;user:&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;user_id&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;cached&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;cached&lt;/span&gt;

    &lt;span class="nf"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;yield&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="nf"&gt;get_from_db&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user_id&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Two parameters. Linear flow. Types inferred automatically.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why Not &lt;code&gt;async/await&lt;/code&gt;?
&lt;/h2&gt;

&lt;p&gt;A natural question: Python already has &lt;code&gt;async/await&lt;/code&gt; for suspending and resuming functions. Why not use that?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Different problem domains.&lt;/strong&gt; &lt;code&gt;async/await&lt;/code&gt; solves I/O scheduling—letting the event loop run other tasks while waiting for network or disk. It doesn't track "what capabilities a function needs."&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_user&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;User&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="p"&gt;...&lt;/span&gt;  &lt;span class="c1"&gt;# What dependencies? What errors? The signature doesn't say.
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There's no mechanism to declare "this async function needs a Database" in a way the type checker can verify.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Function coloring.&lt;/strong&gt; Async functions can only be called from async contexts. This "colors" your entire codebase—one async function forces async up the call stack. Generators don't have this problem; they're just values you can compose and run synchronously.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;No custom interpretation.&lt;/strong&gt; With &lt;code&gt;async/await&lt;/code&gt;, the event loop is the only interpreter. With generators, we can write custom runtimes that handle effects differently—inject mocks for testing, swap implementations for different environments, etc.&lt;/p&gt;




&lt;h2&gt;
  
  
  An Experiment Worth Exploring
&lt;/h2&gt;

&lt;p&gt;Let's be clear: &lt;code&gt;koka&lt;/code&gt; is experimental. It's a proof of concept exploring whether Python can express the effect patterns that have proven valuable in TypeScript (Effect-TS), Scala (ZIO), and research languages (Koka).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What makes this possible now?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Python 3.13 introduced new type syntax (PEP 695) that makes generic types more ergonomic. Combined with mature type checkers like pyright, we can finally express complex type relationships that would have been impossibly verbose before.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What's the value for Python developers?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This library demonstrates that type-checked effect systems are possible in Python—today, with zero runtime dependencies beyond standard generators. It shows a path toward code where:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Dependencies are explicit and verified at type-check time&lt;/li&gt;
&lt;li&gt;Errors are tracked and exhaustively handled&lt;/li&gt;
&lt;li&gt;Function signatures serve as reliable documentation&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;This invites a question for the Python community&lt;/strong&gt;: Should we have better support for this pattern? Could future Python versions make effect tracking even more ergonomic?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Try it yourself:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;The goal: answer "what does this function need?" and "what can go wrong?" at a glance. Let your type checker become your documentation.&lt;/p&gt;

</description>
      <category>tooling</category>
      <category>softwareengineering</category>
      <category>architecture</category>
      <category>python</category>
    </item>
    <item>
      <title>Beyond the Platform: Is Vercel Designing the Future of Programming Languages?</title>
      <dc:creator>Herrington Darkholme</dc:creator>
      <pubDate>Wed, 29 Oct 2025 04:54:43 +0000</pubDate>
      <link>https://forem.com/herrington_darkholme/the-new-programming-frontier-why-vercel-is-redefining-the-language-2ij0</link>
      <guid>https://forem.com/herrington_darkholme/the-new-programming-frontier-why-vercel-is-redefining-the-language-2ij0</guid>
      <description>&lt;p&gt;Vercel has recently rolled out features that do more than just enhance its platform—they challenge the very semantics of JavaScript and offer a glimpse into a new era of programming. While these changes have sparked debate, they hint at a broader, more ambitious vision.&lt;/p&gt;

&lt;p&gt;Vercel is championing the idea that the next generation of programming languages should natively manage the complexities of modern applications, including heterogeneous runtimes, transparent networks, multi-layer caching, and task durability.&lt;/p&gt;

&lt;p&gt;This article explores how programming languages might be evolving to manage not just logic, but the entire lifecycle of data and computation in distributed systems. This evolution is being quietly prototyped through three core language concepts: &lt;strong&gt;serializable closures&lt;/strong&gt;, &lt;strong&gt;algebraic effects&lt;/strong&gt;, and &lt;strong&gt;incremental computation&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Vercel's New Primitives for a Distributed World
&lt;/h2&gt;

&lt;p&gt;To understand this future, we must first look at the problems Vercel is solving today. Modern web applications are becoming more complex, featuring:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Multiple Runtimes:&lt;/strong&gt; Code executes on the client (browser), the server (Node.js), and the edge (WebAssembly).&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Dispersed Data:&lt;/strong&gt; State lives in memory, on CDNs, in databases, and across file storage.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To tame this complexity, Vercel, together with the React team, have introduced powerful new features that feel less like library additions and more like new language constructs.&lt;/p&gt;

&lt;h3&gt;
  
  
  Server Actions: Unifying Client and Server Logic
&lt;/h3&gt;

&lt;p&gt;Server Actions allow client-side components to directly call asynchronous functions that execute on the server, effectively erasing the boundary between client and server code.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// server.ts&lt;/span&gt;
&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;use server&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;createNote&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;notes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// client.ts&lt;/span&gt;
&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;use client&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="c1"&gt;// The import is transformed by the compiler into a reference:&lt;/span&gt;
&lt;span class="c1"&gt;// {$$typeof: Symbol.for("react.server.reference"), $$id: 'createNote'}&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;createNote&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./server&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;EmptyNote&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt; &lt;span class="na"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;createNote&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Create Note&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Without Server Actions, this would require manually setting up API endpoints, writing &lt;code&gt;fetch&lt;/code&gt; requests, and handling data serialization and deserialization. Server Actions abstract all of this away, making remote procedure calls (RPCs) feel like simple function calls.&lt;/p&gt;

&lt;h3&gt;
  
  
  The 'use cache' Directive: Language-Level Caching
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;'use cache'&lt;/code&gt; directive is a powerful tool for memoizing functions and caching their results. The cache key is automatically generated from the function's arguments and its &lt;em&gt;closed-over values&lt;/em&gt;—the variables from its surrounding scope that it "remembers."&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Bookings&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;haircut&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}:&lt;/span&gt; &lt;span class="nx"&gt;BookingsProps&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;use cache&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
  &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getBookingsData&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`/api/bookings?type=&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nf"&gt;encodeURIComponent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="c1"&gt;//...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is a true language-level feature. Because it needs to inspect the function's closure, it cannot be implemented as a simple library API without forcing developers to manually declare all dependencies.&lt;/p&gt;

&lt;h3&gt;
  
  
  The 'use workflow' Directive: Durable, Resumable Functions
&lt;/h3&gt;

&lt;p&gt;Making asynchronous tasks reliable typically requires a complex stack of message queues, retry logic, and persistence layers. The &lt;code&gt;'use workflow'&lt;/code&gt; directive aims to make durability a native language concept.&lt;/p&gt;

&lt;p&gt;A workflow is a function that can maintain its execution state across restarts, failures, or long pauses. It can resume exactly where it left off, whether it was paused for seconds or months.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;aiAgentWorkflow&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;use workflow&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;generateResponse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;facts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;researchFacts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;refined&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;refineWithFacts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;facts&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;response&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;refined&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;sources&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;facts&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Key Characteristics of Workflows:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Durable:&lt;/strong&gt; They survive deployments and crashes through deterministic replays from an event log.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Resumable:&lt;/strong&gt; Execution can be paused and resumed at any &lt;code&gt;await&lt;/code&gt; point.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Deterministic:&lt;/strong&gt; They run in a sandboxed environment where non-deterministic APIs (like &lt;code&gt;Math.random&lt;/code&gt; or &lt;code&gt;Date.now&lt;/code&gt;) are controlled to ensure replayability.&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;

&lt;p&gt;By baking durability into the language with a simple directive, &lt;code&gt;'use workflow'&lt;/code&gt; abstracts away immense infrastructural complexity.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Historical Arc of Programming Languages
&lt;/h2&gt;

&lt;p&gt;You may feel uneasy about these changes to JavaScript. After all, they alter the language's semantics in significant ways. &lt;br&gt;
However, if we look at the history of programming languages, we see a consistent pattern of evolution aimed at managing increasing complexity.&lt;/p&gt;

&lt;p&gt;Programming languages have always evolved to manage new layers of abstraction and complexity:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Assembly&lt;/strong&gt; managed raw CPU instructions.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;C&lt;/strong&gt; abstracted away registers and control flow.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Java&lt;/strong&gt; automated memory management.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Go&lt;/strong&gt; simplified concurrency for multi-core processors.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The next logical step in this evolution is to manage the complexities of &lt;strong&gt;data management&lt;/strong&gt;. The challenge is no longer just managing memory or threads, but managing where computation happens, how data moves, and how to ensure that access is fast, persistent, and reliable.&lt;/p&gt;

&lt;p&gt;Currently, these are problems solved by frameworks, libraries, and external systems. A developer needs a deep understanding of serialization, RPCs, caching strategies, and message queues. Vercel's new features suggest a future where these are concerns of the language itself.&lt;/p&gt;
&lt;h2&gt;
  
  
  The Language Features Powering This Vision
&lt;/h2&gt;

&lt;p&gt;Vercel's new directives have been controversial precisely because they alter JavaScript's semantics. Instead, if we see from another perspective, they can be built on powerful concepts from computer science that could form the foundation of a new kind of programming language.&lt;/p&gt;
&lt;h3&gt;
  
  
  Serializable Closures
&lt;/h3&gt;

&lt;p&gt;A closure is a function that "remembers" the environment in which it was created. A &lt;em&gt;serializable closure&lt;/em&gt; is one that can be packaged up—its code and its remembered environment—and sent across a network, stored in a database, or executed at a later time. This effectively allows us to move &lt;em&gt;computation&lt;/em&gt;, not just data, across system boundaries.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;serlializeClosure&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;closureData&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;fnCode&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;extractClosedOverVariables&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;code&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;fnCode&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;closure&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;closureData&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Server Actions&lt;/strong&gt; are a prime example. The &lt;code&gt;createNote&lt;/code&gt; function is serialized, sent to the client as a reference, and when invoked, its execution is triggered back on the server.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Simplified Concept:&lt;/span&gt;
&lt;span class="c1"&gt;// 1. On the server, the function and its closure are captured.&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;closure&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;code&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;serializeClosure&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;createNote&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;fnId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;storeCodeOnServer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;code&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// 2. A reference is sent to the client.&lt;/span&gt;
&lt;span class="nf"&gt;sendToClient&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;fnId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;closure&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="c1"&gt;// 3. The client uses the reference to invoke the function on the server.&lt;/span&gt;
&lt;span class="nf"&gt;invokeServerFunction&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;fnId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;closure&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;fnArgs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[...]&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;'use cache'&lt;/strong&gt; relies on serialization to create a unique cache key. The function's code, its closed-over values, and its arguments are hashed together.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getCacheKey&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;closure&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;code&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;serializeClosure&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;createNote&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;hash&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;fnCode&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;closureData&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Workflows&lt;/strong&gt; can be seen as serializable closures that are paused at each &lt;code&gt;await&lt;/code&gt; point. The state of the function and its continuation (the "rest" of the function) is serialized and persisted, ready to be resumed later.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For example, the &lt;code&gt;aiAgentWorkflow&lt;/code&gt; function can be visualized as a series of serialized closures at each step:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;aiAgentWorkflow&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;generateResponse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// serialize closure 1&lt;/span&gt;
    &lt;span class="nf"&gt;researchFacts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;facts&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="c1"&gt;// serialize closure 2&lt;/span&gt;
      &lt;span class="nf"&gt;refineWithFacts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;facts&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;refined&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// serialize closure 3&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;response&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;refined&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;sources&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;facts&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
      &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;   
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Algebraic Effects
&lt;/h3&gt;

&lt;p&gt;Serializable closures are powerful, but they introduce a critical challenge: how do you safely execute a piece of code in a different environment? A function designed to run on the server can't access a database if it's moved to a browser.&lt;/p&gt;

&lt;p&gt;This is where algebraic effects come in. Algebraic effects are a programming language feature that separates &lt;em&gt;what&lt;/em&gt; a function does (its side effects, like accessing a database or generating a random number) from &lt;em&gt;how&lt;/em&gt; those effects are implemented.&lt;/p&gt;

&lt;p&gt;An "effect" is performed, and an "effect handler" somewhere up the call stack decides how to interpret it.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;'use workflow'&lt;/code&gt; environment is a perfect example. APIs like &lt;code&gt;Math.random&lt;/code&gt; and &lt;code&gt;Date.now&lt;/code&gt; must behave deterministically. An effect handler could intercept a call to &lt;code&gt;Date.now&lt;/code&gt; and, instead of returning the system time, return a timestamp from the workflow's event log to ensure replayability.&lt;/p&gt;

&lt;p&gt;Another example in a hypothetical language with first-class effects, you could define different handlers for client and server contexts:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Define an effect for database access&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;dbAccessEffect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;userQuery&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
    &lt;span class="k"&gt;yield&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;fetchEffect&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;User&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;ServerContext&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;userQuery&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// On the server, the handler provides the database context&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;serverHandler&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;runEffect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;dbAccessEffect&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// OK&lt;/span&gt;

&lt;span class="c1"&gt;// On the client, the handler would throw an error, as no db is available&lt;/span&gt;
&lt;span class="c1"&gt;// clientHandler.runEffect(dbAccessEffect, query); // Throws Error&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This provides a secure and reliable way to control what resources a movable closure can access.&lt;/p&gt;

&lt;p&gt;The idea is not something new to the JavaScript world. Library like &lt;a href="https://effect.website/" rel="noopener noreferrer"&gt;Effect&lt;/a&gt; and languages like &lt;a href="https://koka-lang.github.io/" rel="noopener noreferrer"&gt;Koka&lt;/a&gt; have explored algebraic effects for years. But using effect to manage different execution environments and resource access is a novel and powerful application of the concept.&lt;/p&gt;

&lt;h3&gt;
  
  
  Incremental Computation
&lt;/h3&gt;

&lt;p&gt;In a distributed system, caching isn't just an optimization—it's essential for performance. Incremental computation is the principle of only recomputing outputs that are affected by a change in data, rather than recomputing everything from scratch.&lt;/p&gt;

&lt;p&gt;This concept is already widespread:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  React's Virtual DOM diffing is a form of incremental computation.&lt;/li&gt;
&lt;li&gt;  Memoization and directives like &lt;code&gt;'use cache'&lt;/code&gt; are explicit forms of it.&lt;/li&gt;
&lt;li&gt;  Build systems like Turbopack and Bazel use it to avoid re-building unchanged code.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;By making incremental computation a first-class language concept, a future language could automatically manage caching and data dependencies across different rendering strategies (CSR, SSR, SSG, ISR), build systems, and data layers, dramatically improving efficiency.&lt;/p&gt;

&lt;p&gt;In fact, &lt;code&gt;"use cache"&lt;/code&gt; can be seen as a simple form of incremental computation. A more advanced system could track dependencies at a finer granularity, allowing for partial recomputation when only some data changes. This idea has been explored in JavaScript world, exemplified by projects like &lt;a href="https://skiplabs.io/" rel="noopener noreferrer"&gt;skiplabs&lt;/a&gt; and &lt;a href="https://skiplang.com/" rel="noopener noreferrer"&gt;Skip langs&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Dawn of a "Vercel Lang"?
&lt;/h2&gt;

&lt;p&gt;Vercel is not just building a platform; it is embedding a powerful programming model directly into the developer experience. By introducing language-level constructs for distributed systems, they are pushing the boundaries of what developers can build and how easily they can build it.&lt;/p&gt;

&lt;p&gt;Is this a good thing? The debate is ongoing, but the direction is clear. This paradigm could be pushed even further. Imagine a language where:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Error monitoring is managed by the platform.&lt;/strong&gt; A function could declare its potential errors, and the language and platform could automatically provide monitoring and alerting.&lt;br&gt;
&lt;strong&gt;Data privacy and security are compiler-enforced.&lt;/strong&gt; By tracking data flow through an effect system, the language could enforce access controls and prevent sensitive data leaks.&lt;br&gt;
&lt;strong&gt;Observability is built-in.&lt;/strong&gt; An effect system could manage access to resources like databases, providing deep insights into performance without manual instrumentation.&lt;/p&gt;

&lt;p&gt;The next-era programming language itself understands and manages the distributed nature of modern applications, freeing developers to focus on logic, not infrastructure.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>programming</category>
      <category>vercel</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Trying Out Biome v2's Type Inference and Knowing Its Limits</title>
      <dc:creator>Herrington Darkholme</dc:creator>
      <pubDate>Wed, 25 Jun 2025 03:53:38 +0000</pubDate>
      <link>https://forem.com/herrington_darkholme/trying-out-biome-v2s-type-inference-and-knowing-its-limits-1j36</link>
      <guid>https://forem.com/herrington_darkholme/trying-out-biome-v2s-type-inference-and-knowing-its-limits-1j36</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;This article is the English translation of the article &lt;a href="https://zenn.dev/uhyo/articles/biome-v2-type-inference" rel="noopener noreferrer"&gt;"Biome v2の型推論を試して限界を知る" from Zenn&lt;/a&gt;. Thank the original author &lt;a href="https://x.com/uhyo_" rel="noopener noreferrer"&gt;Uhyo&lt;/a&gt; for their write-up!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Hello everyone. The other day, Biome v2 was released and became a hot topic. One of the new features in Biome v2 is type inference.&lt;/p&gt;

&lt;p&gt;Until now, type-aware linting for TypeScript code has been provided by TypeScript-ESLint. This has the disadvantage of being heavy because it uses the actual TypeScript compiler to obtain type information. While TypeScript itself is working on performance improvements through porting to Go and other measures, Biome has taken a different approach to this problem. That is, to perform type inference independently without relying on the official TypeScript compiler.&lt;/p&gt;

&lt;p&gt;However, the TypeScript compiler is an extremely complex system, and it is almost impossible to completely reproduce its type inference results with a separate implementation. Therefore, Biome's type inference also cannot perfectly replicate the behavior of the TypeScript compiler. The Biome v2 release notes state that, using the &lt;code&gt;noFloatingPromises&lt;/code&gt; rule as an example, it can detect about 75% of the cases compared to using the actual TypeScript compiler.&lt;/p&gt;

&lt;p&gt;Therefore, in this article, I will try out the type inference feature of Biome v2 and examine how well it can infer types compared to the real TypeScript compiler.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; This article examines the version at the time of writing (2.0.4). Biome has announced that it will improve type inference in future versions.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Simple Example
&lt;/h3&gt;

&lt;p&gt;This time, I will investigate using the &lt;code&gt;noFloatingPromises&lt;/code&gt; rule. This rule detects code where a Promise is not &lt;code&gt;await&lt;/code&gt;ed. First, let's look at a simple example.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;foo&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mf"&gt;3.14&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;foo&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this code, the &lt;code&gt;foo&lt;/code&gt; function returns a Promise, but the &lt;code&gt;main&lt;/code&gt; function does not &lt;code&gt;await&lt;/code&gt; its result. Therefore, a lint error is expected.&lt;/p&gt;

&lt;p&gt;Running &lt;code&gt;biome lint&lt;/code&gt; on this code produces the following error:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;index.ts:6:3 lint/nursery/noFloatingPromises FIXABLE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

ℹ A "floating" Promise was found, meaning it is not properly handled and could lead to ignored errors or unexpected behavior.

  5 │ export async function main() {
&amp;gt; 6 │   foo();
    │   ^^^^^^
  7 │ }

ℹ This happens when a Promise is not awaited, lacks a `.catch` or `.then` rejection handler, or is not explicitly ignored using the `void` operator.

ℹ Unsafe fix: Add await operator.

  6 │ ··await·foo();
    │ ++++++
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It detects that the return value of &lt;code&gt;foo()&lt;/code&gt; is a Promise and points out that &lt;code&gt;await&lt;/code&gt; is necessary. Although &lt;code&gt;foo()&lt;/code&gt; has no explicit type annotation, Biome infers the function's return value and determines that it is a Promise.&lt;/p&gt;

&lt;p&gt;From here, we will gradually make the inference more difficult.&lt;/p&gt;

&lt;h3&gt;
  
  
  Using &lt;code&gt;new Promise&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;In the example above, because &lt;code&gt;foo&lt;/code&gt; was defined as an &lt;code&gt;async function&lt;/code&gt;, it was very clear that the return value was a Promise. Next, let's try using &lt;code&gt;new Promise&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;foo&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;setTimeout&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nf"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;3.14&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;foo&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this example, the return value of the &lt;code&gt;foo&lt;/code&gt; function is still a Promise. However, it uses &lt;code&gt;new Promise&lt;/code&gt; without the &lt;code&gt;async&lt;/code&gt; keyword.&lt;/p&gt;

&lt;p&gt;Running &lt;code&gt;biome lint&lt;/code&gt; on this code did not detect any lint errors.&lt;/p&gt;

&lt;p&gt;Unfortunately, in this case, it seems that Biome cannot recognize that the function's return value is a Promise. In this case, since there is no type annotation for the return value of &lt;code&gt;foo&lt;/code&gt;, to find the type of &lt;code&gt;foo&lt;/code&gt;, it is necessary to look for the &lt;code&gt;return&lt;/code&gt; statement inside &lt;code&gt;foo&lt;/code&gt;, confirm that its value is &lt;code&gt;new Promise&lt;/code&gt;, and then check that the type of this expression is a Promise. However, it seems that Biome cannot perform this kind of type inference.&lt;/p&gt;

&lt;h3&gt;
  
  
  Explicitly Adding a Type Annotation
&lt;/h3&gt;

&lt;p&gt;Now, let's add a type annotation to the function's return value.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;foo&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;setTimeout&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nf"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;3.14&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;foo&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With this, Biome was able to detect the lint error.&lt;/p&gt;

&lt;p&gt;Although I haven't looked at the internal implementation of Biome's type inference, it seems that it does not examine the content of a function to determine its return type. To utilize Biome's type inference, it is important to explicitly state the return type of functions.&lt;/p&gt;

&lt;h3&gt;
  
  
  Trying Out &lt;code&gt;Promise&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Now, let's go back to using &lt;code&gt;async&lt;/code&gt; functions for clarity and try various things.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;foo&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mf"&gt;3.14&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;foo&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When running &lt;code&gt;biome lint&lt;/code&gt; on this example, surprisingly, no error was detected. I was personally a bit surprised by this.&lt;/p&gt;

&lt;p&gt;However, the official documentation for the &lt;code&gt;noFloatingPromises&lt;/code&gt; rule states the following about its behavior:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;This rule will report Promise-valued statements that are not treated in one of the following ways:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Calling its &lt;code&gt;.then()&lt;/code&gt; method with two arguments&lt;/li&gt;
&lt;li&gt;  Calling its &lt;code&gt;.catch()&lt;/code&gt; method with one argument&lt;/li&gt;
&lt;li&gt;  &lt;code&gt;await&lt;/code&gt;ing it&lt;/li&gt;
&lt;li&gt;  &lt;code&gt;return&lt;/code&gt;ing it&lt;/li&gt;
&lt;li&gt;  &lt;code&gt;void&lt;/code&gt;ing it&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;

&lt;p&gt;Since it refers to "Promise-valued &lt;em&gt;statements&lt;/em&gt;", it can be interpreted that when a Promise is used as an expression in something, it is not a target, and the detection is limited to cases where a Promise is left alone, like &lt;code&gt;foo();&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Perhaps for this reason, even when a Promise is assigned to a variable as shown below, no lint error was detected.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;foo&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mf"&gt;3.14&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;p&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;foo&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Through an Object
&lt;/h3&gt;

&lt;p&gt;I also tried the case of an object method instead of a function.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;obj&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;foo&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mf"&gt;3.14&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;foo&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this case, a lint error was detected. It seems that through some inference, it understood that &lt;code&gt;obj.foo&lt;/code&gt; is a function that returns a Promise.&lt;/p&gt;

&lt;p&gt;By the way, the lint error disappears as shown below (although an error for using &lt;code&gt;any&lt;/code&gt; appears instead).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;foo&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;foo&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mf"&gt;3.14&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;foo&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;From this, it can be seen that it properly infers the "type of obj" and through that, infers the type of the return value of &lt;code&gt;obj.foo&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Trying Difficult Types
&lt;/h3&gt;

&lt;p&gt;Now, let's be mean and try some of TypeScript's difficult types.&lt;/p&gt;

&lt;h4&gt;
  
  
  Generics
&lt;/h4&gt;

&lt;p&gt;First, here is an example using generics.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;id&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;foo&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mf"&gt;3.14&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;id&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;foo&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this example, the return value of &lt;code&gt;id(foo())&lt;/code&gt; will be a Promise, but without performing generic type inference, it cannot understand that.&lt;/p&gt;

&lt;p&gt;I was most surprised by the result here, but surprisingly, Biome detected a lint error for this example. This means it was able to recognize that the return value of &lt;code&gt;id(foo())&lt;/code&gt; is a Promise. The lint error is correctly detected for &lt;code&gt;id&lt;/code&gt; and not &lt;code&gt;foo()&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The inference rules for generics in TypeScript are very complex, so I don't think Biome can reproduce all of them, but it seems that in simple cases like this example, it can perform type inference using generics.&lt;/p&gt;

&lt;h4&gt;
  
  
  Lookup Types
&lt;/h4&gt;

&lt;p&gt;A lookup type is a type with a syntax like &lt;code&gt;T[K]&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;Obj&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;noPromise&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;yesPromise&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Obj&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;noPromise&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;3.14&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;yesPromise&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;3.14&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;foo&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;K&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="kr"&gt;keyof&lt;/span&gt; &lt;span class="nx"&gt;Obj&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;K&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;Obj&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;K&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;foo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;noPromise&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nf"&gt;foo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;yesPromise&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this case, the return value of &lt;code&gt;foo('noPromise')&lt;/code&gt; is of type &lt;code&gt;number&lt;/code&gt;, but the return value of &lt;code&gt;foo('yesPromise')&lt;/code&gt; is of type &lt;code&gt;Promise&amp;lt;number&amp;gt;&lt;/code&gt;. Can Biome figure this out?&lt;/p&gt;

&lt;p&gt;The answer is, unfortunately, no lint error was detected for &lt;code&gt;foo('yesPromise')&lt;/code&gt;. It seems that it does not support calculations of lookup types.&lt;/p&gt;

&lt;p&gt;By the way, even a simple case like the one below without generics was not possible.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;Obj&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;noPromise&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;yesPromise&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;foo&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="nx"&gt;Obj&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;yesPromise&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mf"&gt;3.14&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;foo&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Mapped Types and Conditional Types
&lt;/h4&gt;

&lt;p&gt;Since lookup types were not possible, I thought the rest would be impossible too, but I tried them anyway. As expected, it was not possible.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Mapped Type&lt;/span&gt;
&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Raw&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;noPromise&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;yesPromise&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Obj&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;K&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="kr"&gt;keyof&lt;/span&gt; &lt;span class="nx"&gt;Raw&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;Raw&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;K&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Obj&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;noPromise&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;42&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;yesPromise&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;3.14&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;yesPromise&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Conditional Type&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;foo&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;K&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;K&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;K&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;string&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;42&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;42&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;foo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;123&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Union and Intersection Types
&lt;/h4&gt;

&lt;p&gt;Union types are important in practical TypeScript. Let's try a case involving them.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;foo&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;random&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mf"&gt;0.5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;42&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;setTimeout&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;42&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;foo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;123&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this case, &lt;code&gt;foo(123)&lt;/code&gt; may or may not be a Promise.&lt;/p&gt;

&lt;p&gt;For this example, Biome detected a lint error. This means it can recognize the possibility of a Promise as part of a union type.&lt;/p&gt;

&lt;p&gt;Now, let's also try an intersection type.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;foo&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;abort&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// omitted&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;foo&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For this one, no lint error was detected. It seems that it cannot recognize the presence of a Promise as part of an intersection type. However, whether this should be a detection target may be a matter of judgment. Also, since there is no essential difficulty in detection, it seems that it could be supported relatively easily.&lt;/p&gt;

&lt;h4&gt;
  
  
  Using a Type Alias
&lt;/h4&gt;

&lt;p&gt;Will it be detected if a type alias is used for the &lt;code&gt;Promise&lt;/code&gt; type?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;PromiseNumber&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;foo&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="nx"&gt;PromiseNumber&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;setTimeout&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;42&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;foo&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this example, it was detected. It seems that while complex type calculations are not possible, type aliases can be recognized.&lt;/p&gt;

&lt;h3&gt;
  
  
  Summary
&lt;/h3&gt;

&lt;p&gt;In this article, I investigated the performance of Biome v2's "type inference" at the time of writing.&lt;/p&gt;

&lt;p&gt;As a result, it was found that the performance is quite modest compared to type inference by a type checker, such as the inability to perform type inference in the &lt;code&gt;return new Promise&lt;/code&gt; example, requiring a type annotation.&lt;/p&gt;

&lt;p&gt;Still, there were behaviors that could be called inference, such as the internal handling of object and function types, the ability to handle generics, and the recognition that the return value of an &lt;code&gt;async&lt;/code&gt; function is a &lt;code&gt;Promise&lt;/code&gt; type even without a type annotation. It feels like it was created by properly facing the concept of "type" rather than something else disguised as type inference.&lt;/p&gt;

&lt;p&gt;However, even when type annotations are explicitly stated, there seem to be limits to the calculation of types. It seemed impossible to calculate things like lookup types and conditional types.&lt;/p&gt;

&lt;p&gt;It is surprising that even with such modest performance, it is sufficient to detect 75% of cases, as stated in the official blog.&lt;/p&gt;

&lt;p&gt;I had a concern about Biome and other TypeScript-independent "type inference" features. That is, that a coding rule that does not fully utilize TypeScript's type system and only uses descriptions that Biome and others can understand might become widespread. If that happens, TypeScript's type system will essentially be forked.&lt;/p&gt;

&lt;p&gt;Although Biome is still in the process of evolution, what do you think after seeing the results of this verification? Did it make you want to change your TypeScript practices to match Biome?&lt;/p&gt;

&lt;p&gt;As for me, I would like to continue to watch how things will develop.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Biome's GritQL Plugin vs. ast-grep: Your Guide to AST-Based Code Transformation for JS/TS Devs</title>
      <dc:creator>Herrington Darkholme</dc:creator>
      <pubDate>Fri, 06 Jun 2025 05:05:10 +0000</pubDate>
      <link>https://forem.com/herrington_darkholme/biomes-gritql-plugin-vs-ast-grep-your-guide-to-ast-based-code-transformation-for-jsts-devs-29j2</link>
      <guid>https://forem.com/herrington_darkholme/biomes-gritql-plugin-vs-ast-grep-your-guide-to-ast-based-code-transformation-for-jsts-devs-29j2</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2lfqdy6775ie24ar1qvc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2lfqdy6775ie24ar1qvc.png" alt="Comparison" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Introduction – Why AST Tools Matter for Native Linters
&lt;/h2&gt;

&lt;p&gt;Maintaining consistent, high-quality code in large projects presents a significant challenge. While modern Rust-based linting tools deliver impressive performance for enforcing basic coding standards, they frequently fall short when developers require highly custom, project-specific patterns or automated, large-scale refactors across a codebase. This is where AST-based tools, particularly with the development of &lt;a href="https://speakerdeck.com/unvalley/typescript-linters" rel="noopener noreferrer"&gt;plugin systems in native linters&lt;/a&gt;, become essential. &lt;/p&gt;

&lt;p&gt;In this report, we will delve into two prominent AST-based tools: Biome's new GritQL plugin and the established ast-grep. We will compare their syntax, performance, features, and more, providing a comprehensive guide to help developers choose the most suitable tool for their specific needs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Meet the Contenders: A Quick Overview
&lt;/h2&gt;

&lt;p&gt;Before diving into a head-to-head comparison, let's get acquainted with each tool individually, understanding their core functionalities and design philosophies.&lt;/p&gt;

&lt;h3&gt;
  
  
  Biome's GritQL Plugin: The New Kid on the Biome Block
&lt;/h3&gt;

&lt;p&gt;Biome is a fast formatter and linter designed for web projects, intended to serve as a comprehensive replacement for tools like Prettier and ESLint. With its 2.0 beta release, Biome &lt;a href="https://next.biomejs.dev/linter/plugins/" rel="noopener noreferrer"&gt;introduced a plugin system&lt;/a&gt;, initially supporting GritQL for defining custom lint rules.&lt;/p&gt;

&lt;p&gt;The plugin operates by utilizing &lt;code&gt;.grit&lt;/code&gt; files, which contain patterns written in GritQL. GritQL itself is a specialized query language designed for searching and transforming syntax trees. These &lt;code&gt;.grit&lt;/code&gt; files are used to define custom diagnostic rules that Biome can then apply to a codebase. Configuration is straightforward: developers enable the plugin by adding the path to their &lt;code&gt;.grit&lt;/code&gt; file within the &lt;code&gt;plugins&lt;/code&gt; array in their &lt;code&gt;biome.json&lt;/code&gt; configuration file.&lt;/p&gt;

&lt;p&gt;As of the Biome 2.0 beta, the GritQL plugin is &lt;a href="https://github.com/biomejs/biome/issues/5687" rel="noopener noreferrer"&gt;currently diagnostic-only&lt;/a&gt;. This means it excels at identifying and reporting specific code patterns, but it does not yet offer the capability to automatically fix them. However, the implementation of fixable rules, which will leverage GritQL's rewrite operator (=&amp;gt;), is a planned feature, indicating an ongoing development towards more comprehensive capabilities.&lt;/p&gt;

&lt;h3&gt;
  
  
  ast-grep: The Established AST Powerhouse
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://ast-grep.github.io/guide/introduction.html" rel="noopener noreferrer"&gt;ast-grep&lt;/a&gt; stands as a mature and robust command-line tool, built on the high-performance Rust programming language. Its operational mechanism involves defining rules for searching, linting, and rewriting code using YAML files. ast-grep leverages &lt;a href="https://tree-sitter.github.io/tree-sitter/" rel="noopener noreferrer"&gt;tree-sitter&lt;/a&gt;, a powerful parsing library, to construct its Abstract Syntax Trees, enabling deep code understanding.&lt;/p&gt;

&lt;p&gt;A significant advantage of ast-grep is its comprehensive set of capabilities, offering full fix and rewrite functionalities directly out of the box. This makes it a versatile tool for automated code modifications, ranging from simple linting autofixes to complex large-scale refactors. Its reliance on tree-sitter also provides extensive language support beyond just JavaScript, TypeScript, JSX, TSX, HTML, and CSS. It supports a wide array of programming languages including Python, Java, Go, Rust, and etc, making it a truly polyglot tool.&lt;/p&gt;

&lt;p&gt;Biome's GritQL plugin extends Biome's existing linter primarily for custom diagnostics, whereas ast-grep is a foundational and versatile AST manipulation tool with a broader scope, including robust rewriting capabilities.&lt;/p&gt;

&lt;h2&gt;
  
  
  Head-to-Head: A Deep Dive into Comparison
&lt;/h2&gt;

&lt;p&gt;Now that we've had a quick introduction to both tools, let's put them side-by-side and explore their differences across key aspects that matter to developers.&lt;/p&gt;

&lt;h3&gt;
  
  
  Syntax Showdown: How Rules Are Written
&lt;/h3&gt;

&lt;p&gt;Understanding how to write rules is fundamental to using any AST-based tool. Let's examine equivalent examples in both Biome's GritQL plugin and ast-grep to compare their pattern languages and rule definition approaches.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Example 1: Detect &lt;code&gt;console.log()&lt;/code&gt; Statements&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Our goal here is to find all instances where &lt;code&gt;console.log(...)&lt;/code&gt; is used, typically to identify debugging statements.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Biome GritQL Plugin (detect-console-log.grit):&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;For more detailed setup instructions, please kindly refer to the &lt;a href="https://zenn.dev/timetree/articles/1f5f56780aee7b" rel="noopener noreferrer"&gt;Isco's article&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;language&lt;/span&gt; &lt;span class="nf"&gt;js &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;typescript&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;jsx&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Pattern to match any call to console.log and register a warning&lt;/span&gt;
&lt;span class="s2"&gt;`console.log($$$arguments)`&lt;/span&gt; &lt;span class="nx"&gt;where&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;register_diagnostic&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nx"&gt;span&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;$$$arguments&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// Highlight the arguments of the call&lt;/span&gt;
    &lt;span class="nx"&gt;message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Avoid using console.log. Consider a dedicated logger or removing it for production.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;severity&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;warn&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To enable this rule, add the path to your &lt;code&gt;.grit&lt;/code&gt; file in your &lt;code&gt;biome.json&lt;/code&gt; configuration:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"linter"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"enabled"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"rules"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"all"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"plugins"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"./detect-console-log.grit"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Explanation of Biome GritQL Rule:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This GritQL rule precisely targets &lt;code&gt;console.log&lt;/code&gt; calls.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; &lt;strong&gt;&lt;code&gt;language js (typescript, jsx);&lt;/code&gt;&lt;/strong&gt;: Sets the parser for JavaScript, TypeScript, and JSX.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;&lt;code&gt;`console.log($$$arguments)`&lt;/code&gt;&lt;/strong&gt;: This is the literal code pattern. &lt;code&gt;$$$arguments&lt;/code&gt; is a &lt;em&gt;spread metavariable&lt;/em&gt; that matches any number of arguments passed to &lt;code&gt;console.log()&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;&lt;code&gt;where { register_diagnostic(...) }&lt;/code&gt;&lt;/strong&gt;: When the pattern matches, &lt;code&gt;register_diagnostic()&lt;/code&gt; is called to report an issue. It highlights the &lt;code&gt;$$$arguments&lt;/code&gt; part of the code, provides a custom &lt;code&gt;message&lt;/code&gt;, and sets the &lt;code&gt;severity&lt;/code&gt; to "warn".&lt;/li&gt;
&lt;/ol&gt;




&lt;p&gt;&lt;strong&gt;ast-grep (rules/no-console-log.yml):&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;For more detailed setup instructions, please kindly refer to &lt;a href="https://zenn.dev/makotot/articles/ea823805582e5c" rel="noopener noreferrer"&gt;makotot's article&lt;/a&gt; or the &lt;a href="https://ast-grep.github.io/guide/scan-project.html" rel="noopener noreferrer"&gt;official site&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# rules/no-console-log.yml&lt;/span&gt;
&lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;no-console-log&lt;/span&gt;
&lt;span class="na"&gt;language&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;TypeScript&lt;/span&gt; &lt;span class="c1"&gt;# or JavaScript&lt;/span&gt;
&lt;span class="na"&gt;severity&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;warn&lt;/span&gt;
&lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Avoid&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;using&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;console.log.&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Consider&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;a&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;dedicated&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;logger&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;or&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;removing&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;it&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;for&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;production."&lt;/span&gt;
&lt;span class="na"&gt;rule&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;pattern&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;console.log($$$ARGS)&lt;/span&gt;
    &lt;span class="c1"&gt;# fix: "" # Uncomment to automatically remove the console.log call&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Explanation of ast-grep Rule:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This ast-grep rule similarly detects &lt;code&gt;console.log&lt;/code&gt; statements using a declarative YAML structure.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; &lt;strong&gt;&lt;code&gt;id&lt;/code&gt;, &lt;code&gt;language&lt;/code&gt;, &lt;code&gt;severity&lt;/code&gt;, &lt;code&gt;message&lt;/code&gt;&lt;/strong&gt;: Standard fields providing rule identification, target language, warning level, and a descriptive message.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;&lt;code&gt;rule: pattern: console.log($$$ARGS)&lt;/code&gt;&lt;/strong&gt;: This defines the code pattern to match. &lt;code&gt;$$$ARGS&lt;/code&gt; is a &lt;em&gt;spread metavariable&lt;/em&gt; that captures any number of arguments to &lt;code&gt;console.log()&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;&lt;code&gt;# fix: ""&lt;/code&gt;&lt;/strong&gt;: A commented-out &lt;code&gt;fix&lt;/code&gt; field demonstrates ast-grep's auto-rewriting capability; uncommenting it would remove the matched &lt;code&gt;console.log()&lt;/code&gt; statement.&lt;/li&gt;
&lt;/ol&gt;




&lt;p&gt;&lt;strong&gt;Syntax Takeaways for Example 1:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Pattern Matching:&lt;/strong&gt; Both tools use a similar, intuitive pattern syntax (&lt;code&gt;console.log($$$args)&lt;/code&gt;) with spread metavariables to match function calls irrespective of their arguments.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Diagnostic Reporting:&lt;/strong&gt; GritQL uses a &lt;code&gt;register_diagnostic()&lt;/code&gt; function within a &lt;code&gt;where&lt;/code&gt; clause, while ast-grep uses direct YAML fields (&lt;code&gt;message&lt;/code&gt;, &lt;code&gt;severity&lt;/code&gt;) for rule metadata.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Rewrite Capability:&lt;/strong&gt; ast-grep includes an explicit &lt;code&gt;fix&lt;/code&gt; field for automated code transformations, a feature still planned for GritQL's direct rewrite operator.&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;strong&gt;Example 2: Detect React Components in &lt;code&gt;createFileRoute&lt;/code&gt; Files&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This rule aims to enforce a common architectural pattern in frameworks like TanStack Router: route files should primarily define routes and their data loaders, not React UI components. We want to flag any React component definitions (function or arrow function, named or default export) within files that import &lt;code&gt;createFileRoute&lt;/code&gt; from &lt;code&gt;@tanstack/react-router&lt;/code&gt;. This demonstrates a more complex, multi-step rule involving checking for an import and then searching for specific patterns conditionally.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Biome GritQL Plugin (no-components-in-route-file.grit):&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Code snippet&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// First check if this file imports createFileRoute from @tanstack/react-router&lt;/span&gt;
&lt;span class="nf"&gt;file&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nx"&gt;$program&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nx"&gt;where&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// Check for the specific import within the entire file's AST&lt;/span&gt;
  &lt;span class="nx"&gt;$program&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;contains&lt;/span&gt; &lt;span class="nx"&gt;bubble&lt;/span&gt; &lt;span class="s2"&gt;`import { $imports } from "@tanstack/react-router"`&lt;/span&gt; &lt;span class="nx"&gt;where&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;$imports&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;contains&lt;/span&gt; &lt;span class="s2"&gt;`createFileRoute`&lt;/span&gt; &lt;span class="c1"&gt;// Ensure 'createFileRoute' is among the imported identifiers&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="c1"&gt;// If the import exists, proceed to find component definitions anywhere within the file&lt;/span&gt;
  &lt;span class="nx"&gt;$program&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;contains&lt;/span&gt; &lt;span class="nx"&gt;bubble&lt;/span&gt; &lt;span class="nx"&gt;or&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// 1. Function declaration components (e.g., function MyComponent() { ... })&lt;/span&gt;
    &lt;span class="s2"&gt;`function $ComponentName($props) {
      $body
    }`&lt;/span&gt; &lt;span class="nx"&gt;where&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;$ComponentName&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;^[A-Z][a-zA-Z0-9]*$&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// Regex constraint: ensures it's a PascalCase identifier&lt;/span&gt;
      &lt;span class="nf"&gt;register_diagnostic&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;span&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nx"&gt;$ComponentName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;`Component should not be defined directly in a route file. Move it to a separate UI component file.`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;severity&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;error&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="c1"&gt;// 2. Arrow function components assigned to a variable (e.g., const MyComponent = () =&amp;gt; { ... })&lt;/span&gt;
    &lt;span class="s2"&gt;`const $ComponentName = ($props) =&amp;gt; {
      $body
    }`&lt;/span&gt; &lt;span class="nx"&gt;where&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;$ComponentName&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;^[A-Z][a-zA-Z0-9]*$&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// Regex constraint: ensures it's a PascalCase identifier&lt;/span&gt;
      &lt;span class="nf"&gt;register_diagnostic&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;span&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nx"&gt;$ComponentName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;`Component should not be defined directly in a route file. Move it to a separate UI component file.`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;severity&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;error&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="c1"&gt;// 3. Default exported function components (e.g., export default function MyComponent() { ... })&lt;/span&gt;
    &lt;span class="s2"&gt;`export default function $ComponentName($props) {
      $body
    }`&lt;/span&gt; &lt;span class="nx"&gt;where&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nf"&gt;register_diagnostic&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;span&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nx"&gt;$ComponentName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Default exported function components should not be defined in route files. Move it to a separate UI component file.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;severity&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;error&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="c1"&gt;// 4. Default exported anonymous arrow function components (e.g., export default () =&amp;gt; { ... })&lt;/span&gt;
    &lt;span class="s2"&gt;`export default ($props) =&amp;gt; {
      $body
    }`&lt;/span&gt; &lt;span class="nx"&gt;where&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nf"&gt;register_diagnostic&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;span&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nx"&gt;$props&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Default exported arrow functions should not be defined in route files. Move it to a separate UI component file.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;severity&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;error&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="c1"&gt;// 5. Named exported function components (e.g., export function MyComponent() { ... })&lt;/span&gt;
    &lt;span class="s2"&gt;`export function $ComponentName($props) {
      $body
    }`&lt;/span&gt; &lt;span class="nx"&gt;where&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;$ComponentName&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;^[A-Z][a-zA-Z0-9]*$&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nf"&gt;register_diagnostic&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;span&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nx"&gt;$ComponentName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;`Exported component should not be defined directly in a route file. Move it to a separate UI component file.`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;severity&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;error&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Explanation of Biome GritQL Rule:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This GritQL rule uses a powerful combination of top-level file matching, recursive searching (&lt;code&gt;contains&lt;/code&gt; with &lt;code&gt;bubble&lt;/code&gt;), and logical grouping (&lt;code&gt;or&lt;/code&gt; and &lt;code&gt;where&lt;/code&gt;) to implement the complex architectural check.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;file(body=$program) where { ... }&lt;/code&gt;&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;&lt;code&gt;file()&lt;/code&gt;&lt;/strong&gt;: This is a GritQL function that signifies the entire source file being analyzed. It's the highest-level entry point for pattern matching, ensuring the rule considers the full context of the code.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;&lt;code&gt;body=$program&lt;/code&gt;&lt;/strong&gt;: This captures the &lt;em&gt;entire Abstract Syntax Tree (AST) of the file&lt;/em&gt; into a metavariable named &lt;code&gt;$program&lt;/code&gt;. This &lt;code&gt;$program&lt;/code&gt; metavariable effectively becomes the root node for all subsequent searches and conditions within this rule.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;&lt;code&gt;where { ... }&lt;/code&gt;&lt;/strong&gt;: This clause introduces conditions that must all be met for the &lt;code&gt;file()&lt;/code&gt; pattern to be considered a match and for any diagnostics within to be registered.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;$program &amp;lt;: contains bubble \&lt;/code&gt;import { $imports } from "@tanstack/react-router"&lt;code&gt;where { $imports &amp;lt;: contains \&lt;/code&gt;createFileRoute&lt;code&gt;}&lt;/code&gt;&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  This is the &lt;strong&gt;first primary condition&lt;/strong&gt; within the &lt;code&gt;file()&lt;/code&gt;'s &lt;code&gt;where&lt;/code&gt; clause. Its purpose is to check if the current file contains the specific import &lt;code&gt;createFileRoute&lt;/code&gt; from &lt;code&gt;@tanstack/react-router&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;&lt;code&gt;$program &amp;lt;:&lt;/code&gt;&lt;/strong&gt;: This syntax indicates that &lt;code&gt;$program&lt;/code&gt; (the entire file's AST) must &lt;em&gt;contain&lt;/em&gt; or &lt;em&gt;match&lt;/em&gt; the pattern that follows.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;&lt;code&gt;contains&lt;/code&gt;&lt;/strong&gt;: This is a GritQL predicate that performs a &lt;em&gt;search&lt;/em&gt; for the specified pattern within the given AST node (&lt;code&gt;$program&lt;/code&gt; in this case). It only searches the immediate children of program. This is crucial for excluding elements that are not be at the top level of the file.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;&lt;code&gt;bubble&lt;/code&gt;&lt;/strong&gt;: When used with &lt;code&gt;contains&lt;/code&gt;, the &lt;a href="https://docs.grit.io/language/bubble" rel="noopener noreferrer"&gt;&lt;code&gt;bubble&lt;/code&gt; clause creates a &lt;em&gt;new, isolated scope&lt;/em&gt;&lt;/a&gt; for metavariables defined within the pattern it's applied to. In this specific pattern (&lt;code&gt;`import { $imports } ...`&lt;/code&gt;), the metavariable is &lt;code&gt;$imports&lt;/code&gt;. By using &lt;code&gt;bubble&lt;/code&gt;, the &lt;code&gt;$imports&lt;/code&gt; metavariable and its value are confined to this particular &lt;code&gt;contains&lt;/code&gt; clause. This ensures that:

&lt;ul&gt;
&lt;li&gt;  If there were other metavariables named &lt;code&gt;$imports&lt;/code&gt; elsewhere in the rule, their values would not conflict with the &lt;code&gt;$imports&lt;/code&gt; captured by &lt;em&gt;this specific import statement match&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;  The subsequent &lt;code&gt;where { $imports &amp;lt;: contains&lt;/code&gt;createFileRoute&lt;code&gt;}&lt;/code&gt; clause can directly refer to the &lt;code&gt;$imports&lt;/code&gt; captured by &lt;em&gt;this specific &lt;code&gt;import&lt;/code&gt; pattern&lt;/em&gt; and apply a further condition to it, without ambiguity. It allows for modular reasoning about nested matches.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;&lt;code&gt;`import { $imports } from "@tanstack/react-router"`&lt;/code&gt;&lt;/strong&gt;: This is the literal code pattern GritQL searches for. The &lt;code&gt;$imports&lt;/code&gt; metavariable captures the destructured part of the import statement (e.g., &lt;code&gt;createFileRoute&lt;/code&gt;, &lt;code&gt;createLoader&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;&lt;code&gt;where { $imports &amp;lt;: contains&lt;/code&gt;createFileRoute&lt;code&gt;}&lt;/code&gt;&lt;/strong&gt;: This is a &lt;em&gt;nested condition&lt;/em&gt; applied specifically to the &lt;code&gt;$imports&lt;/code&gt; metavariable captured by the import pattern. It uses &lt;code&gt;contains&lt;/code&gt; again to verify that the string &lt;code&gt;createFileRoute&lt;/code&gt; is present within the identifiers captured by &lt;code&gt;$imports&lt;/code&gt;. This ensures we are only targeting files specifically using &lt;code&gt;createFileRoute&lt;/code&gt; from the router library.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;$program &amp;lt;: contains bubble or { ... }&lt;/code&gt;&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  This is the &lt;strong&gt;second primary condition&lt;/strong&gt; in the &lt;code&gt;file()&lt;/code&gt;'s &lt;code&gt;where&lt;/code&gt; clause. This condition is only evaluated if the first condition (the import check) is met. Its purpose is to find any React component definitions within the file.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;&lt;code&gt;contains bubble&lt;/code&gt;&lt;/strong&gt;: Similar to the first condition, this performs a recursive search throughout the entire file's AST (&lt;code&gt;$program&lt;/code&gt;) for any of the patterns defined within the &lt;code&gt;or&lt;/code&gt; block. The &lt;code&gt;bubble&lt;/code&gt; again ensures that any metavariables (like &lt;code&gt;$ComponentName&lt;/code&gt;, &lt;code&gt;$props&lt;/code&gt;, &lt;code&gt;$body&lt;/code&gt;) captured within each individual component pattern are scoped locally to that specific pattern match. This means, for example, if there's a &lt;code&gt;function MyComponent&lt;/code&gt; and later &lt;code&gt;const MyOtherComponent&lt;/code&gt;, the &lt;code&gt;$ComponentName&lt;/code&gt; metavariable will correctly capture "MyComponent" for the first match and "MyOtherComponent" for the second, without conflict.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;&lt;code&gt;or { ... }&lt;/code&gt;&lt;/strong&gt;: This is a logical OR operator. It means that if &lt;em&gt;any&lt;/em&gt; of the patterns listed inside its curly braces match, this entire &lt;code&gt;contains&lt;/code&gt; condition is satisfied. This is essential for detecting the various ways a React component can be defined (function declaration, arrow function, default export, named export).&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Individual Component Patterns (e.g., &lt;code&gt;`function $ComponentName($props) { $body }`&lt;/code&gt;)&lt;/strong&gt;: Each block defines a common React component structure using GritQL's pattern syntax.

&lt;ul&gt;
&lt;li&gt;  &lt;code&gt;$ComponentName&lt;/code&gt;, &lt;code&gt;$props&lt;/code&gt;, &lt;code&gt;$body&lt;/code&gt;: These are metavariables capturing the component's name, props, and body respectively.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;&lt;code&gt;$ComponentName &amp;lt;: r"^[A-Z][a-zA-Z0-9]*$"&lt;/code&gt;&lt;/strong&gt;: This applies a regular expression predicate to the &lt;code&gt;$ComponentName&lt;/code&gt; metavariable, ensuring the captured component name follows the PascalCase convention typical for React components (starts with an uppercase letter, followed by alphanumeric characters). &lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;&lt;code&gt;register_diagnostic(span=$ComponentName, message=..., severity="error")&lt;/code&gt;&lt;/strong&gt;: This is the action that occurs when a component pattern successfully matches &lt;em&gt;and&lt;/em&gt; all preceding &lt;code&gt;where&lt;/code&gt; conditions (including the &lt;code&gt;createFileRoute&lt;/code&gt; import check) are satisfied.

&lt;ul&gt;
&lt;li&gt;  &lt;code&gt;span=$ComponentName&lt;/code&gt;: Directs Biome to highlight the AST node corresponding to the component's name when reporting the issue.&lt;/li&gt;
&lt;li&gt;  &lt;code&gt;message&lt;/code&gt;: The informative error message displayed to the developer.&lt;/li&gt;
&lt;li&gt;  &lt;code&gt;severity&lt;/code&gt;: Sets the diagnostic level (e.g., "error", "warn").&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;In Summary for GritQL:&lt;/strong&gt; The rule operates by first establishing that the file is a "route file" (by finding the &lt;code&gt;createFileRoute&lt;/code&gt; import). Only if that condition holds true does it then proceed to recursively scan the same file for any common React component definitions. The &lt;code&gt;bubble&lt;/code&gt; clause is critical for isolating the scope of metavariables within the &lt;code&gt;contains&lt;/code&gt; patterns, ensuring that complex, multi-part rules can be built without unintended variable collisions or ambiguities across different matched sub-patterns.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;ast-grep (rules/no-components-in-route-file.yml):&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;YAML&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# rules/no-components-in-route-file.yml&lt;/span&gt;
&lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;no-components-in-route-file&lt;/span&gt;
&lt;span class="na"&gt;language&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;TypeScript&lt;/span&gt; &lt;span class="c1"&gt;# or JavaScript, JSX, TSX&lt;/span&gt;
&lt;span class="na"&gt;severity&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;error&lt;/span&gt;
&lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;React&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;components&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;should&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;not&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;be&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;defined&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;directly&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;in&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;files&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;that&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;import&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;createFileRoute.&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Move&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;them&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;to&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;a&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;separate&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;UI&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;component&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;file."&lt;/span&gt;
&lt;span class="na"&gt;rule&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;program&lt;/span&gt;
  &lt;span class="na"&gt;all&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="c1"&gt;# Both conditions must be true for the rule to apply&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;has&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="c1"&gt;# Condition 1: Check for the createFileRoute import&lt;/span&gt;
      &lt;span class="na"&gt;pattern&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;import $$$IMP from "@tanstack/react-router"&lt;/span&gt;
      &lt;span class="na"&gt;regex&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;createFileRoute&lt;/span&gt; &lt;span class="c1"&gt;# Ensure 'createFileRoute' is part of the imported identifiers&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;has&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="c1"&gt;# Condition 2: Check for the presence of a React component pattern&lt;/span&gt;
      &lt;span class="na"&gt;any&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="c1"&gt;# Match any of these component definitions&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;pattern&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;function $COMPONENT($$$ARGS) { $$$ }&lt;/span&gt; &lt;span class="c1"&gt;# Function declaration&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;pattern&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;const $COMPONENT = ($$$ARGS) =&amp;gt; $$$&lt;/span&gt; &lt;span class="c1"&gt;# Arrow function assigned to a variable&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;pattern&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;export default ($$$PROPS) =&amp;gt; $$$&lt;/span&gt; &lt;span class="c1"&gt;# Default exported anonymous arrow function&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;pattern&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;export default function $COMPONENT($$$ARGS) { $$$ }&lt;/span&gt; &lt;span class="c1"&gt;# Default exported function&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;pattern&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;export function $COMPONENT($$$ARGS) { $$$ }&lt;/span&gt; &lt;span class="c1"&gt;# Named exported function&lt;/span&gt;
&lt;span class="na"&gt;constraints&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="c1"&gt;# Ensure PascalCase naming convention&lt;/span&gt;
  &lt;span class="na"&gt;COMPONENT&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;regex&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;^[A-Z][a-zA-Z0-9]*"&lt;/span&gt; &lt;span class="pi"&gt;}&lt;/span&gt; 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Explanation of ast-grep Rule:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This ast-grep rule utilizes YAML's declarative structure with &lt;code&gt;kind&lt;/code&gt;, &lt;code&gt;all&lt;/code&gt;, &lt;code&gt;has&lt;/code&gt;, and &lt;code&gt;any&lt;/code&gt; to define the same complex logical checks.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;code&gt;id&lt;/code&gt;, &lt;code&gt;language&lt;/code&gt;, &lt;code&gt;severity&lt;/code&gt;, &lt;code&gt;message&lt;/code&gt;&lt;/strong&gt;: These are standard metadata fields for an ast-grep rule, providing a unique identifier for the rule, specifying the programming language(s) it applies to, defining its diagnostic severity level (e.g., "error"), and providing the human-readable message that will be displayed when the rule is triggered.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;rule: kind: program&lt;/code&gt;&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;&lt;code&gt;kind: program&lt;/code&gt;&lt;/strong&gt;: This specifies the &lt;a href="https://dev.toTODO"&gt;target AST node type&lt;/a&gt; that the rule should be applied to. &lt;code&gt;program&lt;/code&gt; typically represents the entire source file or compilation unit. This ensures the rule examines the complete code context, similar to GritQL's &lt;code&gt;file()&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;code&gt;all: [...]&lt;/code&gt;&lt;/strong&gt;: This is a logical AND operator in ast-grep. It means that &lt;em&gt;all&lt;/em&gt; of the sub-rules listed within its array must successfully match for the overall rule to be considered true. In this example, it enforces that &lt;em&gt;both&lt;/em&gt; the import condition &lt;em&gt;and&lt;/em&gt; the component presence condition must be met simultaneously.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;First sub-rule: &lt;code&gt;- has: pattern: import $$$IMP from "@tanstack/react-router"&lt;/code&gt; and &lt;code&gt;regex: createFileRoute&lt;/code&gt;&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  This is the &lt;strong&gt;first condition&lt;/strong&gt; under the &lt;code&gt;all&lt;/code&gt; clause. It is designed to verify the presence of the &lt;code&gt;createFileRoute&lt;/code&gt; import statement.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;&lt;code&gt;has&lt;/code&gt;&lt;/strong&gt;: This ast-grep rule field indicates that the current node (&lt;code&gt;program&lt;/code&gt; in this context) &lt;em&gt;must contain&lt;/em&gt; (as a descendant anywhere in its subtree) the specified &lt;code&gt;pattern&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;&lt;code&gt;pattern: import $$$IMP from "@tanstack/react-router"&lt;/code&gt;&lt;/strong&gt;: This is the structural pattern for the import statement. &lt;code&gt;$$$IMP&lt;/code&gt; is a metavariable that captures the entire list of destructured identifiers within the curly braces (e.g., &lt;code&gt;{ createFileRoute, anotherImport }&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;&lt;code&gt;regex: createFileRoute&lt;/code&gt;&lt;/strong&gt;: This field applies a regular expression specifically to the &lt;em&gt;text captured by the &lt;code&gt;$$$IMP&lt;/code&gt; metavariable&lt;/em&gt;. It ensures that the exact string &lt;code&gt;createFileRoute&lt;/code&gt; is present within that captured text.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Second sub-rule: &lt;code&gt;- has: any: [...]&lt;/code&gt;&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  This is the &lt;strong&gt;second condition&lt;/strong&gt; under the &lt;code&gt;all&lt;/code&gt; clause. It is responsible for detecting various forms of React component definitions. This condition is only evaluated if the first condition (the &lt;code&gt;createFileRoute&lt;/code&gt; import check) has passed.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;&lt;code&gt;has&lt;/code&gt;&lt;/strong&gt;: Similar to the first &lt;code&gt;has&lt;/code&gt; rule, this performs a recursive search within the &lt;code&gt;program&lt;/code&gt; node for any of the patterns defined within the nested &lt;code&gt;any&lt;/code&gt; block.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;&lt;code&gt;any: [...]&lt;/code&gt;&lt;/strong&gt;: This is a logical OR operator in ast-grep. If &lt;em&gt;any&lt;/em&gt; of the &lt;code&gt;pattern&lt;/code&gt; rules listed in this array match within the &lt;code&gt;program&lt;/code&gt;'s AST, this &lt;code&gt;has&lt;/code&gt; condition is satisfied. This flexibility allows the rule to catch all common ways React components are structured.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Individual Component Patterns (e.g., &lt;code&gt;- pattern: function $COMPONENT($$$ARGS) { $$$ }&lt;/code&gt;)&lt;/strong&gt;: Each item in the &lt;code&gt;any&lt;/code&gt; array defines a specific structural pattern for a React component.

&lt;ul&gt;
&lt;li&gt;  &lt;code&gt;$COMPONENT&lt;/code&gt;, &lt;code&gt;$$$ARGS&lt;/code&gt;, &lt;code&gt;$$$&lt;/code&gt; (wildcard for body): These are ast-grep's metavariables. &lt;code&gt;$COMPONENT&lt;/code&gt; captures a single AST node (like a function name), &lt;code&gt;$$$ARGS&lt;/code&gt; captures a sequence of nodes (like function arguments), and &lt;code&gt;$$$&lt;/code&gt; is a generic wildcard that matches any sequence of nodes (often used for a function body or statement block).&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;constraints&lt;/strong&gt;: &lt;code&gt;constraints&lt;/code&gt; field adds a check that &lt;code&gt;$COMPONENT&lt;/code&gt; meta variable passes a PascalCase validation on component names.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;In Summary for ast-grep:&lt;/strong&gt; The rule is structured to apply to the entire file. It then uses an "AND" (&lt;code&gt;all&lt;/code&gt;) condition to combine two primary "contains" (&lt;code&gt;has&lt;/code&gt;) checks: one to confirm the presence of the &lt;code&gt;createFileRoute&lt;/code&gt; import (with a regex to verify the specific identifier), and another to confirm the presence of any common React component patterns. If both checks pass, the rule triggers, reporting the architectural violation.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Syntax Takeaways for Example 2:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Complex Conditional Logic:&lt;/strong&gt; This example highlights how both tools can implement rules requiring multiple conditions. GritQL uses chained &lt;code&gt;where&lt;/code&gt; clauses with &lt;code&gt;contains&lt;/code&gt; and &lt;code&gt;bubble&lt;/code&gt; for deep searches and &lt;code&gt;or&lt;/code&gt; for multiple alternatives. ast-grep uses &lt;code&gt;all&lt;/code&gt; to combine necessary conditions and &lt;code&gt;has&lt;/code&gt; with nested &lt;code&gt;any&lt;/code&gt; to match a variety of component patterns.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Targeted Matching:&lt;/strong&gt; Both tools can precisely target specific code constructs (imports, function declarations, arrow functions) and even apply additional constraints (like the PascalCase regex in GritQL for named components, which would require an additional &lt;code&gt;regex&lt;/code&gt; or &lt;code&gt;matches&lt;/code&gt; sub-rule in ast-grep for full parity).&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Rule Scope:&lt;/strong&gt; Both &lt;code&gt;file(body=$program)&lt;/code&gt; in GritQL and &lt;code&gt;kind: program&lt;/code&gt; in ast-grep indicate that the rule operates on the entire file's Abstract Syntax Tree.&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  Performance: Speed Matters
&lt;/h3&gt;

&lt;p&gt;Performance is a critical factor for any code analysis tool, especially those integrated into linters that run frequently during development or within continuous integration/continuous deployment (CI/CD) pipelines. After all, linting speed is why we migrate from the &lt;a href="https://www.youtube.com/watch?v=m9Oo_hI4EjI" rel="noopener noreferrer"&gt;more customizable eslint&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Real-World Case Study:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A real-world case study, documented in GitHub issue &lt;a href="https://github.com/biomejs/biome/issues/6210" rel="noopener noreferrer"&gt;biomejs/biome#6210&lt;/a&gt;, highlighted a significant performance discrepancy between the two tools. In this scenario, a user created a custom Biome GritQL plugin rule designed to enforce specific conventions related to component definitions in files importing &lt;code&gt;createFileRoute&lt;/code&gt; from &lt;code&gt;@tanstack/react-router&lt;/code&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Original Biome GritQL rule performance:&lt;/strong&gt; The initial version of this custom rule took a staggering &lt;strong&gt;70 seconds&lt;/strong&gt; to execute on the VS Code repository.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Biome performance without the rule:&lt;/strong&gt; For context, Biome's base performance without this custom rule was remarkably fast, completing the same task in &lt;strong&gt;less than 2 seconds&lt;/strong&gt;. This stark contrast clearly indicated that the custom GritQL rule was the primary bottleneck.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Equivalent ast-grep rule performance:&lt;/strong&gt; An equivalent rule implemented in ast-grep performed significantly better, completing the same task on the same repository in a mere &lt;strong&gt;0.5 seconds&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Optimized Biome GritQL rule performance:&lt;/strong&gt; The Biome team and GritQL developers identified that the performance issue stemmed from unoptimized GritQL patterns. After optimization, which involved using more specific patterns like &lt;code&gt;file(body=$program)&lt;/code&gt; and &lt;code&gt;bubble&lt;/code&gt;, the Biome GritQL rule showed substantial improvement, adding only about &lt;strong&gt;1 second&lt;/strong&gt; of overhead to Biome's base performance.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Key Performance Takeaways:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;ast-grep's general high performance:&lt;/strong&gt; ast-grep consistently demonstrates superior performance. Its Rust core and optimized AST traversal mechanisms contribute to its speed, offering reliable and impressive performance across various scenarios.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Potential performance pitfalls with Biome's GritQL plugin (beta):&lt;/strong&gt; As a newer tool still in beta, the initial implementation or the use of certain broad GritQL patterns (such as &lt;code&gt;$program&lt;/code&gt; and &lt;code&gt;contains&lt;/code&gt; without careful scoping) can lead to significant slowdowns. This indicates that while the tool is powerful, its current state requires careful consideration in rule design.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Importance of optimized patterns:&lt;/strong&gt; The case study vividly illustrates that the way a GritQL rule is authored can drastically impact its performance within Biome. The Biome team and GritQL developers are actively aware of these considerations and are working on further optimizations and providing guidance for writing efficient patterns.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Conclusion on Performance:&lt;/strong&gt; ast-grep currently offers superior and more consistent performance, especially for complex rules. Biome's GritQL plugin, being newer and in beta, shows promise but currently requires careful pattern authoring to avoid performance bottlenecks. However, performance is expected to improve as Biome and its GritQL integration continue to mature.&lt;/p&gt;

&lt;p&gt;The stark contrast in initial performance (70 seconds for an unoptimized Biome GritQL rule versus 0.5 seconds for ast-grep) followed by Biome's optimization to 1 second overhead reveals a critical distinction. ast-grep delivers high performance as an inherent feature, largely out-of-the-box, due to its Rust core and optimized traversal. For Biome's GritQL plugin, however, achieving optimal performance is currently a challenge that the rule author must actively manage through careful pattern design and optimization. This means that the learning curve for Biome's GritQL isn't just about understanding its syntax, but also about mastering its performance characteristics and best practices for writing efficient rules. This can add a significant burden to developers, especially for complex or frequently run rules, potentially negating some of the benefits of integrating within the Biome ecosystem if not managed effectively.&lt;/p&gt;

&lt;h3&gt;
  
  
  Documentation &amp;amp; Learning Curve: Getting Started
&lt;/h3&gt;

&lt;p&gt;The quality and accessibility of documentation, along with the overall learning curve, significantly impact a developer's ability to adopt and effectively use a new tool.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Biome GritQL Plugin Documentation:&lt;/strong&gt;&lt;br&gt;
Biome's official website provides documentation for its plugin system, covering how to enable plugins and the basic usage of the &lt;code&gt;register_diagnostic()&lt;/code&gt; function. However, for the intricate details of the GritQL syntax itself—the language used to write the patterns—users need to refer to a separate official GritQL documentation, which is hosted on &lt;a href="https://docs.grit.io/" rel="noopener noreferrer"&gt;docs.grit.io&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Biome GritQL Plugin Learning Curve:&lt;/strong&gt;&lt;br&gt;
The learning curve for Biome's GritQL Plugin involves understanding two distinct systems. While Biome's plugin system is relatively straightforward to grasp, the GritQL language itself is more complex. GritQL has its own unique syntax and concepts, including patterns, predicates, &lt;code&gt;where&lt;/code&gt; clauses, and specific built-in functions like &lt;code&gt;contains&lt;/code&gt; and &lt;code&gt;bubble&lt;/code&gt;. Furthermore, as demonstrated in the performance section, the need to write performant GritQL rules adds another layer of complexity to the learning curve. Currently, there isn't an interactive playground specifically integrated for Biome's GritQL plugin within the Biome ecosystem, although Grit.io does offer a general interactive playground for the GritQL language.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;ast-grep Documentation:&lt;/strong&gt;&lt;br&gt;
ast-grep boasts comprehensive documentation available directly on its website, &lt;a href="https://ast-grep.github.io/" rel="noopener noreferrer"&gt;ast-grep.github.io&lt;/a&gt;. This includes detailed guides on its pattern syntax, rule configuration using YAML, advanced features, and API usage. A significant advantage for learning and testing patterns is the availability of an excellent interactive playground directly on its website (&lt;a href="https://ast-grep.github.io/playground.html" rel="noopener noreferrer"&gt;ast-grep.github.io/playground.html&lt;/a&gt;), which is invaluable for experimentation and rapid prototyping of rules.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;ast-grep Learning Curve:&lt;/strong&gt;&lt;br&gt;
The YAML-based rule configuration of ast-grep is generally considered straightforward for developers to pick up. Its pattern syntax, which employs &lt;code&gt;$META_VAR&lt;/code&gt; for single AST nodes and &lt;code&gt;$$$VAR&lt;/code&gt; for sequences of nodes, is described as relatively intuitive for developers already familiar with code manipulation concepts. While understanding AST node kinds (derived from tree-sitter) can be beneficial for crafting more advanced rules, it is not strictly necessary for many common use cases. The tool also offers powerful relational (e.g., &lt;code&gt;has&lt;/code&gt;, &lt;code&gt;inside&lt;/code&gt;) and composite (e.g., &lt;code&gt;all&lt;/code&gt;, &lt;code&gt;any&lt;/code&gt;, &lt;code&gt;not&lt;/code&gt;) rule fields, which may require some time to master for complex scenarios but provide significant flexibility.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Conclusion on Documentation &amp;amp; Learning:&lt;/strong&gt;&lt;br&gt;
ast-grep currently has a more mature and integrated documentation ecosystem, significantly enhanced by its valuable interactive playground. Its YAML and pattern syntax might feel more immediately accessible to some developers due to their more conventional structure. GritQL, while powerful, has a distinct syntax that necessitates dedicated learning. The fragmented documentation experience for Biome's plugin—requiring users to refer to Biome's site for plugin integration and Grit.io for the GritQL language itself—can make the initial learning journey slightly more fragmented and less cohesive.&lt;/p&gt;

&lt;p&gt;The "split documentation" for Biome's GritQL plugin and the absence of a dedicated, integrated playground (requiring users to navigate to Grit.io for general GritQL experimentation) introduce unnecessary friction. Learning a new Domain Specific Language (DSL) like GritQL is already a cognitive hurdle; having to jump between disparate documentation sites and lacking integrated interactive tools exacerbates this challenge. In contrast, ast-grep's unified documentation and interactive playground streamline the entire learning process, making it much more approachable and efficient. This difference directly impacts how quickly a developer can become productive in writing custom rules, suggesting that a cohesive and interactive learning environment is a strong competitive advantage. Biome's current fragmented approach, though understandable for a beta product, poses a higher initial barrier to entry for new users.&lt;/p&gt;

&lt;h3&gt;
  
  
  Editor Support
&lt;/h3&gt;

&lt;p&gt;Seamless integration with Integrated Development Environments (IDEs) and text editors is crucial for developer workflow and productivity.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Biome GritQL Plugin:&lt;/strong&gt;&lt;br&gt;
Biome's existing LSP integrations mean GritQL plugin diagnostics appear directly in editors like VSCode, JetBrains IDEs, and Neovim, just like other lint rules. However, dedicated editor support for &lt;em&gt;authoring&lt;/em&gt; &lt;code&gt;.grit&lt;/code&gt; files is limited, with only a VSCode extension available. Its LSP server currently struggles with wider adoption as other editors don't yet universally recognize the &lt;code&gt;.grit&lt;/code&gt; file type for advanced authoring features.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;ast-grep:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;ast-grep naturally supports a &lt;a href="https://ast-grep.github.io/guide/tools/editors.html" rel="noopener noreferrer"&gt;wider range of editors&lt;/a&gt; for rule authoring because the file format is YAML. Diagnostics and code actions are available in any LSP-compliant editor:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;VSCode:&lt;/strong&gt; An official extension provides a rich Structural Search &amp;amp; Replace UI, diagnostics, Code Actions (quick fixes), and schema validation for &lt;code&gt;rule.yml&lt;/code&gt; files, greatly streamlining rule creation.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Neovim:&lt;/strong&gt; Support exists through &lt;code&gt;nvim-lspconfig&lt;/code&gt; for its LSP server, complemented by specialized plugins like &lt;code&gt;coc-ast-grep&lt;/code&gt;, &lt;code&gt;telescope-sg&lt;/code&gt;, and &lt;code&gt;grug-far.nvim&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;LSP Server:&lt;/strong&gt; Its standalone Language Server Protocol (LSP) server (&lt;code&gt;ast-grep lsp&lt;/code&gt;) ensures seamless integration and broad compatibility for diagnostics and code actions in &lt;em&gt;any&lt;/em&gt; LSP-compliant editor.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Conclusion on Editor Support:&lt;/strong&gt;&lt;br&gt;
ast-grep provides a more mature and comprehensive editor experience, particularly for &lt;em&gt;authoring&lt;/em&gt; custom rules, with its dedicated VSCode UI, schema validation, and broad LSP compatibility. In contrast, Biome's GritQL plugin's rule authoring experience is currently more basic, constrained by limited editor-specific tooling and wider LSP recognition of &lt;code&gt;.grit&lt;/code&gt; files. This makes ast-grep a more productive choice for frequent rule development.&lt;/p&gt;

&lt;h2&gt;
  
  
  Key Features at a Glance
&lt;/h2&gt;

&lt;p&gt;This table provides a concise, side-by-side summary of the most important features and characteristics discussed throughout this comparison. For busy developers, a quick glance at this table allows for rapid assessment of the core differences and an initial evaluation of which tool aligns best with their immediate needs. It serves as a quick reference guide, reinforcing the detailed points made in the preceding sections and making the comparison digestible and actionable.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Aspect&lt;/th&gt;
&lt;th&gt;Biome GritQL Plugin (v2.0 beta)&lt;/th&gt;
&lt;th&gt;ast-grep&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Core Functionality&lt;/td&gt;
&lt;td&gt;Custom diagnostics for Biome linter&lt;/td&gt;
&lt;td&gt;AST-based search, lint, and rewrite&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Syntax Language&lt;/td&gt;
&lt;td&gt;GritQL&lt;/td&gt;
&lt;td&gt;YAML for rules, custom pattern syntax&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Fix/Rewrite Capability&lt;/td&gt;
&lt;td&gt;No (Planned Feature)&lt;/td&gt;
&lt;td&gt;Yes (Built-in fix field in rules)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Performance (General)&lt;/td&gt;
&lt;td&gt;Variable (can be slow if not optimized)&lt;/td&gt;
&lt;td&gt;Generally very high (Rust-based, multi-threading)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Documentation Quality&lt;/td&gt;
&lt;td&gt;Biome docs + GritQL docs (separate)&lt;/td&gt;
&lt;td&gt;Comprehensive, integrated ast-grep docs&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Debugging&lt;/td&gt;
&lt;td&gt;Rudimentary&lt;/td&gt;
&lt;td&gt;Official interactive playground&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Learning Curve&lt;/td&gt;
&lt;td&gt;Moderate to High (GritQL syntax + perf considerations)&lt;/td&gt;
&lt;td&gt;Low to Moderate (YAML + intuitive patterns)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Editor Support&lt;/td&gt;
&lt;td&gt;Diagnostics displayed via Biome's LSP&lt;/td&gt;
&lt;td&gt;Rich VSCode extension, Neovim plugins, general LSP server&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Standalone CLI Availability&lt;/td&gt;
&lt;td&gt;No (part of Biome CLI)&lt;/td&gt;
&lt;td&gt;Yes (&lt;code&gt;sg&lt;/code&gt; command)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  5. Choosing Your Champion: When to Pick Which Tool
&lt;/h2&gt;

&lt;p&gt;The decision between Biome's GritQL plugin and ast-grep is not about one tool being universally "better," but rather about aligning with specific project needs, existing toolchains, and tolerance for beta features. Each tool has distinct strengths that make it more suitable for certain scenarios.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Choose Biome's GritQL Plugin if:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Existing Biome Investment:&lt;/strong&gt; A development team is already heavily invested in the Biome ecosystem and seeks to extend its linting capabilities with custom rules without introducing another standalone tool.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Custom Linting Diagnostics:&lt;/strong&gt; The primary need is to add custom diagnostic rules to Biome's linter specifically for JavaScript/TypeScript or CSS, and immediate requirements for automated fixes are not a top priority.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;GritQL Comfort:&lt;/strong&gt; The developers are comfortable with the GritQL syntax or are willing to learn its distinct approach and its nuances regarding performance optimization.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Acceptance of Beta Status and Future Fixes:&lt;/strong&gt; The team is comfortable with the current beta status of the plugin and its present lack of autofixes, and is actively monitoring for this planned feature to be implemented in the future.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Optimized Performance Alignment:&lt;/strong&gt; The performance characteristics, once rules are carefully optimized, align with the workflow's requirements for linting speed.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Choose ast-grep if:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Immediate Search and Rewrite Capabilities:&lt;/strong&gt; Powerful, performant AST-based search and rewrite capabilities are needed right now, including robust autofixing and complex codemods.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Mature and Stable Tool:&lt;/strong&gt; A mature, stable tool with a rich feature set and strong editor support (including a dedicated VSCode UI for structural search/replace and robust assistance in writing rules) is preferred.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Standalone CLI Tool:&lt;/strong&gt; A standalone CLI tool is needed for scripting, performing one-off refactoring tasks, or integrating into CI pipelines independently of a specific linter.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;YAML Preference:&lt;/strong&gt; Developers prefer YAML for rule configuration and find its pattern syntax more immediately accessible and intuitive.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Complex Codemods and Autofixes:&lt;/strong&gt; The goal is to build complex codemods or enforce coding standards with automated fixes, which is a core strength of ast-grep.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Interactive Playground:&lt;/strong&gt; An interactive playground for developing and testing rules is an important part of the development workflow.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The decision between Biome's GritQL plugin and ast-grep is about aligning with specific project needs, existing toolchains, and tolerance for beta features. Biome's plugin is tightly integrated and serves as an enhancement for existing Biome users, simplifying custom linting within their established ecosystem. Conversely, ast-grep functions as a powerful, versatile standalone solution for broader AST manipulation tasks, including complex refactoring and multi-language support. This distinction means that if a team's primary goal is to extend Biome's linting, the plugin offers convenience. However, if the requirements extend to automated code transformations, polyglot analysis, or flexible CLI integration, ast-grep becomes the more capable and immediate choice. Developers should carefully evaluate their primary use case (e.g., custom linting within an existing Biome setup versus general AST search/rewrite/codemods), their existing development ecosystem, and their comfort level with beta features and dedicated learning curves to make the most informed decision.&lt;/p&gt;

&lt;h2&gt;
  
  
  6. Final Thoughts
&lt;/h2&gt;

&lt;p&gt;Both Biome's GritQL plugin and ast-grep offer powerful AST-based code manipulation capabilities, moving beyond traditional text-based tools for custom standards, refactoring, and quality.&lt;/p&gt;

&lt;p&gt;For immediate, robust AST manipulation with comprehensive fixing, broad language support, and strong editor integration, ast-grep is the clear and versatile choice. Biome's GritQL plugin, though in beta and currently diagnostic-only, is a promising addition for existing Biome users seeking integrated custom linting, with planned autofix features and performance optimizations on the horizon.&lt;/p&gt;

&lt;p&gt;Ultimately, selecting between them depends on specific project needs: ast-grep for immediate, versatile AST control, or Biome's GritQL for extending an existing Biome setup and embracing its evolving ecosystem. The ongoing innovation from both integrated and standalone AST tooling promises an exciting future for code analysis and transformation.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Search Multi-language Documents in ast-grep</title>
      <dc:creator>Herrington Darkholme</dc:creator>
      <pubDate>Wed, 24 Jul 2024 03:27:45 +0000</pubDate>
      <link>https://forem.com/herrington_darkholme/search-multi-language-documents-in-ast-grep-2ajn</link>
      <guid>https://forem.com/herrington_darkholme/search-multi-language-documents-in-ast-grep-2ajn</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/ast-grep/ast-grep" rel="noopener noreferrer"&gt;&lt;strong&gt;ast-grep&lt;/strong&gt;&lt;/a&gt; is a powerful structural code search tool that leverages syntax trees to find patterns in source code. This makes it more accurate and flexible than traditional text-based search tools.&lt;/p&gt;

&lt;p&gt;ast-grep works well searching files of one single language, but it is hard to extract a sub language embedded inside a document.&lt;/p&gt;

&lt;p&gt;However, in modern development, it's common to encounter &lt;strong&gt;multi-language documents&lt;/strong&gt;. These are source files containing code written in multiple different languages. Notable examples include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;HTML files&lt;/strong&gt;: These can contain JavaScript inside &lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt; tags and CSS inside &lt;code&gt;&amp;lt;style&amp;gt;&lt;/code&gt; tags.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;JavaScript files&lt;/strong&gt;: These often contain regular expression, CSS style and query languages like graphql.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ruby files&lt;/strong&gt;: These can contain snippets of code inside heredoc literals, where the heredoc delimiter often indicates the language.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These multi-language documents can be modeled in terms of a parent syntax tree with one or more &lt;em&gt;injected syntax trees&lt;/em&gt; residing &lt;em&gt;inside&lt;/em&gt; certain nodes of the parent tree.&lt;/p&gt;

&lt;p&gt;ast-grep now supports a feature to handle &lt;strong&gt;language injection&lt;/strong&gt;, allowing you to search for code written in one language within documents of another language.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fl818sz5ct0ypv2s16y8b.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fl818sz5ct0ypv2s16y8b.png" alt="ast-grep lang diagram"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This concept and terminology come from &lt;a href="https://tree-sitter.github.io/tree-sitter/syntax-highlighting#language-injection" rel="noopener noreferrer"&gt;tree-sitter's language injection&lt;/a&gt;, which implies you can &lt;em&gt;inject&lt;/em&gt; another language into a language document. (BTW, &lt;a href="https://github.com/nvim-treesitter/nvim-treesitter?tab=readme-ov-file#adding-queries" rel="noopener noreferrer"&gt;neovim&lt;/a&gt; also embraces this terminology.)&lt;/p&gt;

&lt;h2&gt;
  
  
  Example: Search JS/CSS in the CLI
&lt;/h2&gt;

&lt;p&gt;Let's start with a simple example of searching for JavaScript and CSS within HTML files using ast-grep's command-line interface (CLI).&lt;br&gt;
ast-grep has builtin support to search JavaScript and CSS inside HTML files.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Using &lt;code&gt;sg run&lt;/code&gt;&lt;/strong&gt;: find patterns of CSS in an HTML file
&lt;/h3&gt;

&lt;p&gt;Suppose we have an HTML file like below:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;

&lt;span class="nt"&gt;&amp;lt;style&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;h1&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;red&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/style&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;h1&amp;gt;&lt;/span&gt;
  Hello World!
&lt;span class="nt"&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;script&amp;gt;&lt;/span&gt;
  &lt;span class="nf"&gt;alert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;hello world!&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;Running this ast-grep command will extract the matching CSS style code out of the HTML file!&lt;/p&gt;

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

sg run &lt;span class="nt"&gt;-p&lt;/span&gt; &lt;span class="s1"&gt;'color: $COLOR'&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;ast-grep outputs this beautiful CLI report.&lt;/p&gt;

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

./test.html
2│  h1 &lt;span class="o"&gt;{&lt;/span&gt; color: red&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;ast-grep works well even if just providing the pattern without specifying the pattern language!&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Using &lt;code&gt;sg scan&lt;/code&gt;&lt;/strong&gt;: find JavaScript in HTML with rule files
&lt;/h3&gt;

&lt;p&gt;You can also use ast-grep's &lt;a href="https://ast-grep.github.io/guide/rule-config.html" rel="noopener noreferrer"&gt;rule file&lt;/a&gt; to search injected languages.&lt;/p&gt;

&lt;p&gt;For example, we can warn the use of &lt;code&gt;alert&lt;/code&gt; in JavaScript, even if it is inside the HTML file.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;

&lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;no-alert&lt;/span&gt;
&lt;span class="na"&gt;language&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;JavaScript&lt;/span&gt;
&lt;span class="na"&gt;severity&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;warning&lt;/span&gt;
&lt;span class="na"&gt;rule&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;pattern&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;alert($MSG)&lt;/span&gt;
&lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Prefer use appropriate custom UI instead of obtrusive alert call.&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;The rule above will detect usage of &lt;code&gt;alert&lt;/code&gt; in JavaScript. Running the rule via &lt;code&gt;sg scan&lt;/code&gt;.&lt;/p&gt;

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

sg scan &lt;span class="nt"&gt;--rule&lt;/span&gt; no-alert.yml


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

&lt;/div&gt;

&lt;p&gt;The command leverages built-in behaviors in ast-grep to handle language injection seamlessly. It will produce the following warning message for the HTML file above.&lt;/p&gt;

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

warning[no-alert]: Prefer use appropriate custom UI instead of obtrusive alert call.
  ┌─ ./test.html:8:3
  │
8 │   alert&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'hello world!'&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
  │   ^^^^^^^^^^^^^^^^^^^^^


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

&lt;/div&gt;
&lt;h2&gt;
  
  
  How language injections work?
&lt;/h2&gt;

&lt;p&gt;ast-grep employs a multi-step process to handle language injections effectively. Here's a detailed breakdown of the workflow:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;File Discovery&lt;/strong&gt;: The CLI first discovers files on the disk via the venerable &lt;a href="https://crates.io/crates/ignore" rel="noopener noreferrer"&gt;ignore&lt;/a&gt; crate, the same library under &lt;a href="https://github.com/BurntSushi/ripgrep" rel="noopener noreferrer"&gt;ripgrep&lt;/a&gt;'s hood.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Language Inference&lt;/strong&gt;: ast-grep infers the language of each discovered file based on file extensions.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Injection Extraction&lt;/strong&gt;: For documents that contain code written in multiple languages (e.g., HTML with embedded JS), ast-grep extracts the injected language sub-regions. &lt;em&gt;At the moment, ast-grep handles HTML/JS/CSS natively&lt;/em&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Code Matching&lt;/strong&gt;: ast-grep matches the specified patterns or rules against these regions. Pattern code will be interpreted according to the injected language (e.g. JS/CSS), instead of the parent document language (e.g. HTML).&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;
  
  
  Customize Language Injection: styled-components in JavaScript
&lt;/h2&gt;

&lt;p&gt;You can customize language injection via the &lt;code&gt;sgconfig.yml&lt;/code&gt; &lt;a href="https://ast-grep.github.io/reference/sgconfig.html" rel="noopener noreferrer"&gt;configuration file&lt;/a&gt;. This allows you to specify how ast-grep handles multi-language documents based on your specific needs, without modifying ast-grep's built-in behaviors.&lt;/p&gt;

&lt;p&gt;Let's see an example of searching CSS code in JavaScript. &lt;a href="https://styled-components.com/" rel="noopener noreferrer"&gt;styled-components&lt;/a&gt; is a library for styling React applications using &lt;a href="https://bootcamp.uxdesign.cc/css-in-js-libraries-for-styling-react-components-a-comprehensive-comparison-56600605a5a1" rel="noopener noreferrer"&gt;CSS-in-JS&lt;/a&gt;. It allows you to write CSS directly within your JavaScript via &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals" rel="noopener noreferrer"&gt;tagged template literals&lt;/a&gt;, creating styled elements as React components.&lt;/p&gt;

&lt;p&gt;The example will configure ast-grep to detect styled-components' CSS.&lt;/p&gt;
&lt;h3&gt;
  
  
  Injection Configuration
&lt;/h3&gt;

&lt;p&gt;You can add the &lt;code&gt;languageInjections&lt;/code&gt; section in the project configuration file &lt;code&gt;sgconfig.yml&lt;/code&gt;.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;

&lt;span class="na"&gt;languageInjections&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;hostLanguage&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;js&lt;/span&gt;
  &lt;span class="na"&gt;rule&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;pattern&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;styled.$TAG`$CONTENT`&lt;/span&gt;
  &lt;span class="na"&gt;injected&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;css&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;Let's break the configuration down.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;hostLanguage&lt;/code&gt;: Specifies the main language of the document. In this example, it is set to &lt;code&gt;js&lt;/code&gt; (JavaScript).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;rule&lt;/code&gt;: Defines the ast-grep rule to identify the injected language region within the host language.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;- `pattern`: The pattern matches styled components syntax where `styled` is followed by a tag (e.g., `button`, `div`) and a template literal containing CSS.
- the rule should have a meta variable `$CONTENT` to specify the subregion of injected language. In this case, it is the content inside the template string.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;injected&lt;/code&gt;: Specifies the injected language within the identified regions. In this case, it is &lt;code&gt;css&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Example Match
&lt;/h3&gt;

&lt;p&gt;Consider a JSX file using styled components:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;styled&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;styled-components&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Button&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;styled&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;button&lt;/span&gt;&lt;span class="s2"&gt;`
  background: red;
  color: white;
  padding: 10px 20px;
  border-radius: 3px;
`&lt;/span&gt;

&lt;span class="nx"&gt;exporrt&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;App&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Button&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Click&lt;/span&gt; &lt;span class="nx"&gt;Me&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/Button&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;With the above &lt;code&gt;languageInjections&lt;/code&gt; configuration, ast-grep will:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Identify the &lt;code&gt;styled.button&lt;/code&gt; block as a CSS region.&lt;/li&gt;
&lt;li&gt;Extract the CSS code inside the template literal.&lt;/li&gt;
&lt;li&gt;Apply any CSS-specific pattern searches within this extracted region.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;You can search the CSS inside JavaScript in the project configuration folder using this command:&lt;/p&gt;

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

sg &lt;span class="nt"&gt;-p&lt;/span&gt; &lt;span class="s1"&gt;'background: $COLOR'&lt;/span&gt; &lt;span class="nt"&gt;-C&lt;/span&gt; 2


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

&lt;/div&gt;

&lt;p&gt;It will produce the match result:&lt;/p&gt;

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

./styled.js
2│
3│const Button &lt;span class="o"&gt;=&lt;/span&gt; styled.button&lt;span class="sb"&gt;`&lt;/span&gt;
4│  background: red&lt;span class="p"&gt;;&lt;/span&gt;
5│  color: white&lt;span class="p"&gt;;&lt;/span&gt;
6│  padding: 10px 20px&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="sb"&gt;```&lt;/span&gt;

&lt;span class="c"&gt;## Using Custom Language with Injection&lt;/span&gt;

Finally, &lt;span class="nb"&gt;let&lt;/span&gt;&lt;span class="s1"&gt;'s look at an example of searching for GraphQL within JavaScript files.
This demonstrates ast-grep'&lt;/span&gt;s flexibility &lt;span class="k"&gt;in &lt;/span&gt;handling custom language injections.

&lt;span class="c"&gt;### Define graphql custom language in `sgconfig.yml`.&lt;/span&gt;

First, we need to register graphql as a custom language &lt;span class="k"&gt;in &lt;/span&gt;ast-grep. See &lt;span class="o"&gt;[&lt;/span&gt;custom language reference]&lt;span class="o"&gt;(&lt;/span&gt;https://ast-grep.github.io/advanced/custom-language.html&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="k"&gt;for &lt;/span&gt;more details.

&lt;span class="sb"&gt;```&lt;/span&gt;yaml
customLanguages:
  graphql:
    libraryPath: graphql.so &lt;span class="c"&gt;# the graphql tree-sitter parser dynamic library&lt;/span&gt;
    extensions: &lt;span class="o"&gt;[&lt;/span&gt;graphql]   &lt;span class="c"&gt;# graphql file extension&lt;/span&gt;
    expandoChar: &lt;span class="nv"&gt;$ &lt;/span&gt;         &lt;span class="c"&gt;# see reference above for explanation&lt;/span&gt;
&lt;span class="sb"&gt;```&lt;/span&gt;

&lt;span class="c"&gt;### Define graphql injection in `sgconfig.yml`.&lt;/span&gt;

Next, we need to customize what region should be parsed as graphql string &lt;span class="k"&gt;in &lt;/span&gt;JavaScript. This is similar to styled-components example above.

&lt;span class="sb"&gt;```&lt;/span&gt;yaml
languageInjections:
- hostLanguage: js
  rule:
    pattern: graphql&lt;span class="sb"&gt;`&lt;/span&gt;&lt;span class="nv"&gt;$CONTENT&lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt;
  injected: graphql
&lt;span class="sb"&gt;```&lt;/span&gt;

&lt;span class="c"&gt;### Search GraphQL in JavaScript&lt;/span&gt;

Suppose we have this JavaScript file from &lt;span class="o"&gt;[&lt;/span&gt;Relay]&lt;span class="o"&gt;(&lt;/span&gt;https://relay.dev/&lt;span class="o"&gt;)&lt;/span&gt;, a GraphQL client framework.

&lt;span class="sb"&gt;```&lt;/span&gt;js
import React from &lt;span class="s2"&gt;"react"&lt;/span&gt;
import &lt;span class="o"&gt;{&lt;/span&gt; graphql &lt;span class="o"&gt;}&lt;/span&gt; from &lt;span class="s2"&gt;"react-relay"&lt;/span&gt;

const artistsQuery &lt;span class="o"&gt;=&lt;/span&gt; graphql&lt;span class="sb"&gt;`&lt;/span&gt;
  query ArtistQuery&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$artistID&lt;/span&gt;: String!&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    artist&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;id&lt;/span&gt;: &lt;span class="nv"&gt;$artistID&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
      name
      ...ArtistDescription_artist
    &lt;span class="o"&gt;}&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="sb"&gt;`&lt;/span&gt;
&lt;span class="sb"&gt;```&lt;/span&gt;

We can search the GraphQL fragment via this &lt;span class="sb"&gt;`&lt;/span&gt;&lt;span class="nt"&gt;--inline-rules&lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt; scan.

&lt;span class="sb"&gt;```&lt;/span&gt;sh
sg scan &lt;span class="nt"&gt;--inline-rules&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"{id: test, language: graphql, rule: {kind: fragment_spread}}"&lt;/span&gt;
&lt;span class="sb"&gt;```&lt;/span&gt;

Output

&lt;span class="sb"&gt;```&lt;/span&gt;sh
&lt;span class="nb"&gt;help&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;test&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;:
  ┌─ ./relay.js:8:7
  │
8 │       ...ArtistDescription_artist
  │       ^^^^^^^^^^^^^^^^^^^^^^^^^^^
&lt;span class="sb"&gt;```&lt;/span&gt;

&lt;span class="c"&gt;## More Possibility to be Unlocked...&lt;/span&gt;

By following these steps, you can effectively use ast-grep to search and analyze code across multiple languages within the same document, enhancing your ability to manage and understand complex codebases.

This feature extends to various frameworks like &lt;span class="o"&gt;[&lt;/span&gt;Vue]&lt;span class="o"&gt;(&lt;/span&gt;https://vuejs.org/&lt;span class="o"&gt;)&lt;/span&gt; and &lt;span class="o"&gt;[&lt;/span&gt;Svelte]&lt;span class="o"&gt;(&lt;/span&gt;https://svelte.dev/&lt;span class="o"&gt;)&lt;/span&gt;, enables searching &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;SQL &lt;span class="k"&gt;in &lt;/span&gt;React server actions]&lt;span class="o"&gt;(&lt;/span&gt;https://x.com/peer_rich/status/1717609270475194466&lt;span class="o"&gt;)&lt;/span&gt;, and supports new patterns like &lt;span class="o"&gt;[&lt;/span&gt;Vue-Vine]&lt;span class="o"&gt;(&lt;/span&gt;https://x.com/hd_nvim/status/1815300932793663658&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="nb"&gt;.&lt;/span&gt;

Hope you enjoy the feature! Happy ast-grepping!
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>programming</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>ast-grep got 6000 stars!</title>
      <dc:creator>Herrington Darkholme</dc:creator>
      <pubDate>Sun, 19 May 2024 04:16:17 +0000</pubDate>
      <link>https://forem.com/herrington_darkholme/ast-grep-got-6000-stars-3eo2</link>
      <guid>https://forem.com/herrington_darkholme/ast-grep-got-6000-stars-3eo2</guid>
      <description>&lt;p&gt;We are thrilled to announce that &lt;a href="https://ast-grep.github.io/" rel="noopener noreferrer"&gt;ast-grep&lt;/a&gt;, the powerful code search tool, has reached a stellar milestone of 6000 stars on GitHub! This is a testament to the community's trust in our tool and the continuous improvements we've made. Let's dive into the latest features and enhancements that make ast-grep the go-to tool for developers worldwide.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fszm44rnp02gzsmqar7h4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fszm44rnp02gzsmqar7h4.png" alt="ast-grep 6k stars"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Feature Enhancements
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Rewriters Addition&lt;/strong&gt;: We've added support for rewriters &lt;a href="https://github.com/ast-grep/ast-grep/pull/855" rel="noopener noreferrer"&gt;#855&lt;/a&gt;, enabling complex code transformations and refactoring with ease. The new feature unlocks a novel functional programming like code rewrite scheme: &lt;a href="https://ast-grep.github.io/advanced/find-n-patch.html" rel="noopener noreferrer"&gt;find and patch&lt;/a&gt;. Check out our previous &lt;a href="https://dev.to/herrington_darkholme/find-patch-a-novel-functional-programming-like-code-rewrite-scheme-3964"&gt;blog post&lt;/a&gt; for more details.&lt;/li&gt;
&lt;/ul&gt;

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

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Error/Warning Suppression Support&lt;/strong&gt;: The new feature &lt;a href="https://github.com/ast-grep/ast-grep/pull/446" rel="noopener noreferrer"&gt;#446&lt;/a&gt; allows users to suppress specific errors or warnings via the &lt;a href="https://ast-grep.github.io/guide/project/lint-rule.html#suppress-linting-error" rel="noopener noreferrer"&gt;code comment&lt;/a&gt; &lt;code&gt;ast-grep-ignore&lt;/code&gt;. ast-grep also &lt;a href="https://github.com/ast-grep/ast-grep/issues/1019" rel="noopener noreferrer"&gt;respects suppression comments&lt;/a&gt; in Language Server Protocol (LSP), making it easier to manage warnings and errors in your codebase.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Enhanced Rule Constraints&lt;/strong&gt;: The ast-grep rule &lt;code&gt;constraints&lt;/code&gt; previously only accepted &lt;code&gt;pattern&lt;/code&gt;, &lt;code&gt;kind&lt;/code&gt; and &lt;code&gt;regex&lt;/code&gt;.&lt;br&gt;
Now it accepts a full rule &lt;a href="https://github.com/ast-grep/ast-grep/pull/855" rel="noopener noreferrer"&gt;#855&lt;/a&gt;, providing more flexibility than ever before.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  VSCode extension
&lt;/h2&gt;

&lt;p&gt;The &lt;a href="https://marketplace.visualstudio.com/items?itemName=ast-grep.ast-grep-vscode" rel="noopener noreferrer"&gt;ast-grep VSCode extension&lt;/a&gt; is an official &lt;a href="https://ast-grep.github.io/guide/tools/editors.html" rel="noopener noreferrer"&gt;VSCode integration&lt;/a&gt; for this CLI tool. It unleashes the power of structural search and replace (SSR) directly into your editor.&lt;/p&gt;

&lt;h3&gt;
  
  
  Notable Features
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Search&lt;/strong&gt;: Find code patterns with syntax tree.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Replace&lt;/strong&gt;: Refactor code with pattern.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Diagnose&lt;/strong&gt;: Identify issues via ast-grep rule.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/1ZM4RfIvWKc"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  Performance Boost
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Parallel Thread Output Fix&lt;/strong&gt;: A significant fix &lt;a href="https://github.com/ast-grep/ast-grep/commit/be230ca" rel="noopener noreferrer"&gt;#be230ca&lt;/a&gt; ensures parallel thread outputs are now guaranteed, boosting overall performance.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Architectural Evolution
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Tree-Sitter Version Bump&lt;/strong&gt;: We've upgraded to the latest tree-sitter version, enhancing parsing accuracy and speed. In future releases, we plan to leverage tree-sitter's &lt;a href="https://zed.dev/blog/language-extensions-part-1" rel="noopener noreferrer"&gt;new Web Assembly grammar&lt;/a&gt; to support even more languages.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Scan and Diff Merge&lt;/strong&gt;: The &lt;a href="https://github.com/ast-grep/ast-grep/commit/c78299d2902662cd98bda44f3faf3fbc88439078" rel="noopener noreferrer"&gt;refactor&lt;/a&gt; combines &lt;code&gt;CombinedScan::scan&lt;/code&gt; and &lt;code&gt;CombinedScan::diff&lt;/code&gt; for a more streamlined process.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Input Stream Optimization&lt;/strong&gt;: Now, ast-grep avoids unnecessary input stream usage when updating all rules &lt;a href="https://github.com/ast-grep/ast-grep/pull/943" rel="noopener noreferrer"&gt;#943&lt;/a&gt;, making it possible to use &lt;code&gt;sg scan --update-all&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Usability Improvements
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Error Messaging for Rule File Parsing&lt;/strong&gt;: The VSCode extension now provides clearer error messages &lt;a href="https://github.com/ast-grep/ast-grep/pull/968" rel="noopener noreferrer"&gt;#968&lt;/a&gt; when rule file parsing fails, making troubleshooting a breeze.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Better Pattern Parsing&lt;/strong&gt;: Improved expando character replacement &lt;a href="https://github.com/ast-grep/ast-grep/pull/883" rel="noopener noreferrer"&gt;#883&lt;/a&gt; to make pattern .&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;More Permissive Patterns&lt;/strong&gt;: Patterns have become more permissive &lt;a href="https://github.com/ast-grep/ast-grep/pull/1087" rel="noopener noreferrer"&gt;#1087&lt;/a&gt; that allows matching &lt;code&gt;$METAVAR&lt;/code&gt; with different syntax kind.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Enhanced Error Reporting
&lt;/h2&gt;

&lt;p&gt;We've introduced a suite of features to improve error reporting, making it easier to debug and refine your code:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Report undefined meta-variables, errors in fixes, unused rewriters, and undefined utility rules.&lt;/li&gt;
&lt;li&gt;Add field ID errors for relational rules and optimize test updates to avoid erroneous reports.&lt;/li&gt;
&lt;li&gt;Shift from reporting file counts to error counts for a more meaningful insight into code quality.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgyjxysavh7kbxt57309c.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgyjxysavh7kbxt57309c.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Language Support Expansion
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Haskell Support&lt;/strong&gt;: Haskell enthusiasts rejoice! ast-grep now supports Haskell via tree-sitter-haskell &lt;a href="https://github.com/ast-grep/ast-grep/pull/1128" rel="noopener noreferrer"&gt;#1128&lt;/a&gt;, broadening our language coverage.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  NAPI Advancements
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;NAPI Linux x64 musl Support&lt;/strong&gt;: Our latest feat in NAPI &lt;a href="https://github.com/ast-grep/ast-grep/commit/c4d7902" rel="noopener noreferrer"&gt;#c4d7902&lt;/a&gt; adds support for Linux x64 musl, ensuring wider compatibility and performance.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Thanks
&lt;/h2&gt;

&lt;p&gt;As ast-grep continues to grow, we remain committed to providing a tool that not only meets but exceeds the expectations of our diverse user base. &lt;/p&gt;

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

&lt;p&gt;We thank each and every one of you, espeically ast-grep's sponsors, for your support, contributions, and feedback that have shaped ast-grep into what it is today. Here's to many more milestones ahead!&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Migrate to React 19 with ast-grep</title>
      <dc:creator>Herrington Darkholme</dc:creator>
      <pubDate>Mon, 29 Apr 2024 04:00:02 +0000</pubDate>
      <link>https://forem.com/herrington_darkholme/migrate-to-react-19-with-ast-grep-28op</link>
      <guid>https://forem.com/herrington_darkholme/migrate-to-react-19-with-ast-grep-28op</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;The release of React version 19 has been accompanied with a set of new features and enhancements.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftleer15ab4j3tfovyrsv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftleer15ab4j3tfovyrsv.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;However, upgrading to this new version requires certain modifications in the source code. This process can be quite taxing and repetitive, particularly for large codebases.&lt;/p&gt;

&lt;p&gt;This article illustrates the usage of &lt;a href="https://ast-grep.github.io/" rel="noopener noreferrer"&gt;ast-grep&lt;/a&gt;, a tool designed &lt;a href="https://github.com/ast-grep/ast-grep" rel="noopener noreferrer"&gt;to locate and substitute patterns&lt;/a&gt; in your codebase, towards easing your migration to React 19.&lt;/p&gt;

&lt;p&gt;We will focus on three major codemods:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use &lt;code&gt;&amp;lt;Context&amp;gt;&lt;/code&gt; as a provider&lt;/li&gt;
&lt;li&gt;Remove implicit ref callback return&lt;/li&gt;
&lt;li&gt;Use ref as props and remove &lt;code&gt;forwardRef&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Prerequisite: Setting up ast-grep
&lt;/h2&gt;

&lt;p&gt;Initially, you need to set up ast-grep. This can be carried out via npm:&lt;/p&gt;

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

npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-g&lt;/span&gt; @ast-grep/cli


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

&lt;/div&gt;

&lt;p&gt;Once installed, the proper set up of ast-grep can be confirmed by running the command below:&lt;/p&gt;

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

ast-grep &lt;span class="nt"&gt;--version&lt;/span&gt;


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

&lt;/div&gt;
&lt;h2&gt;
  
  
  Use &lt;code&gt;&amp;lt;Context&amp;gt;&lt;/code&gt; as a provider
&lt;/h2&gt;

&lt;p&gt;Let's kick off with the simplest modification: use  as a provider.&lt;/p&gt;

&lt;p&gt;React 19 uses &lt;code&gt;&amp;lt;Context&amp;gt;&lt;/code&gt; as a provider instead of &lt;code&gt;&amp;lt;Context.Provider&amp;gt;&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;&lt;span class="err"&gt;

&lt;/span&gt;&lt;span class="p"&gt;function App() {
&lt;/span&gt;  const [theme, setTheme] = useState('light');
  // ...
  return (
&lt;span class="gd"&gt;-    &amp;lt;UseTheme.Provider value={theme}&amp;gt;
&lt;/span&gt;&lt;span class="gi"&gt;+    &amp;lt;UseTheme value={theme}&amp;gt;
&lt;/span&gt;      &amp;lt;Page /&amp;gt;
&lt;span class="gd"&gt;-    &amp;lt;/UseTheme.Provider&amp;gt;
&lt;/span&gt;&lt;span class="gi"&gt;+    &amp;lt;/UseTheme&amp;gt;
&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;  );
}
&lt;span class="err"&gt;

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

&lt;/div&gt;

&lt;p&gt;With ast-grep, the pattern &lt;code&gt;$CONTEXT.Provider&lt;/code&gt; can be found and replaced with &lt;code&gt;$CONTEXT&lt;/code&gt;.&lt;br&gt;
However, the pattern &lt;code&gt;$CONTEXT.Provider&lt;/code&gt; could appear in multiple locations, requiring us to specifically look for it within a JSX opening and closing element.&lt;/p&gt;

&lt;p&gt;We can utilize the &lt;a href="https://ast-grep.github.io/playground.html" rel="noopener noreferrer"&gt;ast-grep playground&lt;/a&gt; to find the correct names for JSX opening elements and JSX closing elements.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F747vdz2xcyrozsoigflh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F747vdz2xcyrozsoigflh.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Afterwards, using &lt;a href="https://ast-grep.github.io/guide/rule-config/relational-rule.html" rel="noopener noreferrer"&gt;&lt;code&gt;inside&lt;/code&gt;&lt;/a&gt; and &lt;a href="https://ast-grep.github.io/guide/rule-config/composite-rule.html#any" rel="noopener noreferrer"&gt;&lt;code&gt;any&lt;/code&gt;&lt;/a&gt;, we can pinpoint that the pattern should exist within a JSX opening element and a JSX closing element.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;

&lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;use-context-as-provider&lt;/span&gt;
&lt;span class="na"&gt;language&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;javascript&lt;/span&gt;
&lt;span class="na"&gt;rule&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;pattern&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;$CONTEXT.Provider&lt;/span&gt;
  &lt;span class="na"&gt;inside&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;any&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;jsx_opening_element&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;jsx_closing_element&lt;/span&gt;
&lt;span class="na"&gt;fix&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;$CONTEXT&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;&lt;a href="https://ast-grep.github.io/playground.html#eyJtb2RlIjoiQ29uZmlnIiwibGFuZyI6ImphdmFzY3JpcHQiLCJxdWVyeSI6IiIsInJld3JpdGUiOiIkJCRLRUVQIiwiY29uZmlnIjoicnVsZTpcbiAgcGF0dGVybjogJFRIRU1FLlByb3ZpZGVyXG4gIGluc2lkZTpcbiAgICBhbnk6XG4gICAgLSBraW5kOiBqc3hfb3BlbmluZ19lbGVtZW50XG4gICAgLSBraW5kOiBqc3hfY2xvc2luZ19lbGVtZW50XG5maXg6ICRUSEVNRVxuIiwic291cmNlIjoiZnVuY3Rpb24gQXBwKCkge1xuICBjb25zdCBbdGhlbWUsIHNldFRoZW1lXSA9IHVzZVN0YXRlKCdsaWdodCcpO1xuICAvLyAuLi5cbiAgcmV0dXJuIChcbiAgICA8VXNlVGhlbWUuUHJvdmlkZXIgdmFsdWU9e3RoZW1lfT5cbiAgICAgIDxQYWdlIC8+XG4gICAgPC9Vc2VUaGVtZS5Qcm92aWRlcj5cbiAgKTtcbn1cbiJ9" rel="noopener noreferrer"&gt;Example playground link&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F01x0947mqi8pm54q663x.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F01x0947mqi8pm54q663x.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can &lt;a href="https://ast-grep.github.io/reference/cli/scan.html#r-rule-rule-file" rel="noopener noreferrer"&gt;launch the rule from a YAML file&lt;/a&gt; using the command below:&lt;/p&gt;

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

ast-grep scan &lt;span class="nt"&gt;-r&lt;/span&gt; use-context-as-provider.yml


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

&lt;/div&gt;
&lt;h2&gt;
  
  
  Remove implicit-ref-callback-return
&lt;/h2&gt;

&lt;p&gt;Our next example is to remove implicit &lt;code&gt;ref&lt;/code&gt;'s return.&lt;/p&gt;

&lt;p&gt;React 19 now supports returning a cleanup function from ref callbacks.&lt;/p&gt;

&lt;p&gt;Due to the introduction of ref cleanup functions, returning anything else from a ref callback will now be rejected by TypeScript. The fix is usually to stop using implicit returns, for example:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;&lt;span class="err"&gt;

&lt;/span&gt;&lt;span class="gd"&gt;- &amp;lt;div ref={current =&amp;gt; (instance = current)} /&amp;gt;
&lt;/span&gt;&lt;span class="gi"&gt;+ &amp;lt;div ref={current =&amp;gt; {instance = current}} /&amp;gt;
&lt;/span&gt;&lt;span class="err"&gt;

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

&lt;/div&gt;

&lt;p&gt;How can we find this pattern? We should find the pattern &lt;code&gt;&amp;lt;div ref={$A =&amp;gt; $B}/&amp;gt;&lt;/code&gt; where &lt;code&gt;$B&lt;/code&gt; is not a statement block.&lt;/p&gt;

&lt;p&gt;First, ast-grep can use &lt;a href="https://ast-grep.github.io/guide/rule-config/atomic-rule.html#pattern" rel="noopener noreferrer"&gt;pattern object&lt;/a&gt; to find &lt;code&gt;jsx_attribute&lt;/code&gt;, which is the AST kind for the attribute in a JSX element.&lt;/p&gt;

&lt;p&gt;You can use ast-grep's playground to find out the kind name.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fk3ow2qgb9kb0vlrt9lr9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fk3ow2qgb9kb0vlrt9lr9.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Next, we need to find the pattern &lt;code&gt;&amp;lt;div ref={$A =&amp;gt; $B}/&amp;gt;&lt;/code&gt;. The pattern means that we are looking for a JSX element with a &lt;code&gt;ref&lt;/code&gt; attribute that has a callback function.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;

&lt;span class="na"&gt;pattern&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;context&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;lt;div ref={$A =&amp;gt; $B}/&amp;gt;&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;jsx_attribute&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;Finally, we need to check if &lt;code&gt;$B&lt;/code&gt; is not a statement block. We can use the &lt;a href="https://ast-grep.github.io/guide/project/lint-rule.html#constraints" rel="noopener noreferrer"&gt;&lt;code&gt;constraints&lt;/code&gt;&lt;/a&gt; field to specify this condition.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;

&lt;span class="na"&gt;constraints&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;B&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;not&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{&lt;/span&gt;&lt;span class="nv"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;statement_block&lt;/span&gt;&lt;span class="pi"&gt;}&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;Combining all these pieces, we get the following rule:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;

&lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;remove-implicit-ref-callback-return&lt;/span&gt;
&lt;span class="na"&gt;language&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;javascript&lt;/span&gt;
&lt;span class="na"&gt;rule&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;pattern&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;context&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;lt;div ref={$A =&amp;gt; $B}/&amp;gt;&lt;/span&gt;
    &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;jsx_attribute&lt;/span&gt;
&lt;span class="na"&gt;constraints&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;B&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;not&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{&lt;/span&gt;&lt;span class="nv"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;statement_block&lt;/span&gt;&lt;span class="pi"&gt;}&lt;/span&gt;
&lt;span class="na"&gt;fix&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;$A =&amp;gt; {$B}&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Feyexp5tydwohwpsnvq2y.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Feyexp5tydwohwpsnvq2y.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://ast-grep.github.io/playground.html#eyJtb2RlIjoiQ29uZmlnIiwibGFuZyI6ImphdmFzY3JpcHQiLCJxdWVyeSI6IiIsInJld3JpdGUiOiIkJCRLRUVQIiwiY29uZmlnIjoicnVsZTpcbiAgcGF0dGVybjpcbiAgICBjb250ZXh0OiA8ZGl2IHJlZj17JEEgPT4gJEJ9Lz5cbiAgICBzZWxlY3RvcjoganN4X2F0dHJpYnV0ZVxuY29uc3RyYWludHM6XG4gIEI6XG4gICAgbm90OiB7a2luZDogc3RhdGVtZW50X2Jsb2NrfVxuZml4OiAkQSA9PiB7JEJ9Iiwic291cmNlIjoiZnVuY3Rpb24gTXlEaXYoKSB7XG4gIGNvbnN0IHJlZiA9IHVzZVJlZihudWxsKVxuICByZXR1cm4gPGRpdiByZWY9e2N1cnJlbnQgPT4gKHJlZi5jdXJyZW50ID0gY3VycmVudCl9IC8+XG59XG4ifQ==" rel="noopener noreferrer"&gt;Example playground link&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Remove forwardRef
&lt;/h2&gt;

&lt;p&gt;Let's explore our most complex change: Remove forwardRef. In our example, we will only focus on the simplest case where no arrow function nor TypeScript is involved.&lt;/p&gt;

&lt;p&gt;The example code is as follows:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;MyInput&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;forwardRef&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;MyInput&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;ref&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;input&lt;/span&gt; &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;ref&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;ref&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;;&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;Let's first start simple. We can find the pattern &lt;code&gt;forwardRef($FUNC)&lt;/code&gt;.&lt;br&gt;
However, the &lt;code&gt;$FUNC&lt;/code&gt; does not capture the arguments of the function. We need to capture the arguments of the function and rewrite them in the fix.&lt;/p&gt;

&lt;p&gt;This pattern rule captures the function arguments.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;

&lt;span class="na"&gt;rule&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;pattern&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;forwardRef(function $M($PROPS, $REF) { $$$BODY })&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;Next, we need to rewrite the arguments of the function. The easiest way is to rewrite &lt;code&gt;$PROPS&lt;/code&gt; as an object destructuring and to add ref into the object destructuring.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;

&lt;span class="na"&gt;rule&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;pattern&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;forwardRef(function $M($PROPS, $REF) { $$$BODY })&lt;/span&gt;
&lt;span class="na"&gt;fix&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|-&lt;/span&gt;
  &lt;span class="s"&gt;function $M({ref: $REF, ...$PROPS}) {&lt;/span&gt;
    &lt;span class="s"&gt;$$$BODY&lt;/span&gt;
  &lt;span class="s"&gt;}&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;&lt;a href="https://ast-grep.github.io/playground.html#eyJtb2RlIjoiQ29uZmlnIiwibGFuZyI6ImphdmFzY3JpcHQiLCJxdWVyeSI6IiIsInJld3JpdGUiOiIkJCRLRUVQIiwiY29uZmlnIjoicnVsZTpcbiAgcGF0dGVybjogZm9yd2FyZFJlZihmdW5jdGlvbiAkTSgkUFJPUFMsICRSRUYpIHsgJCQkQk9EWSB9KVxuZml4OiB8LVxuICBmdW5jdGlvbiAkTSh7cmVmOiAkUkVGLCAuLi4kUFJPUFN9KSB7XG4gICAgJCQkQk9EWVxuICB9XG4iLCJzb3VyY2UiOiJjb25zdCBNeUlucHV0ID0gZm9yd2FyZFJlZihmdW5jdGlvbiBNeUlucHV0KHByb3BzLCByZWYpIHtcbiAgcmV0dXJuIDxpbnB1dCB7Li4ucHJvcHN9IHJlZj17cmVmfSAvPjtcbn0pO1xuIn0=" rel="noopener noreferrer"&gt;Example playground link&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkqf4ukw9l07riv359mjn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkqf4ukw9l07riv359mjn.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Handle more complex cases
&lt;/h3&gt;

&lt;p&gt;The above rule handles single identifier arguments gracefully. But it does not work for more complex cases like object destructuring, which is popular in React components.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;MyInput&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;forwardRef&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;MyInput&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="nx"&gt;ref&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;input&lt;/span&gt; &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;ref&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;ref&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;;&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;We can use &lt;a href="https://ast-grep.github.io/advanced/find-n-patch.html" rel="noopener noreferrer"&gt;&lt;code&gt;rewriters&lt;/code&gt;&lt;/a&gt; to handle more complex cases. The basic idea is that we can break down the rewriting into two scenarios: object destructuring and identifiers.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;object&lt;/code&gt; rewriter captures the object destructuring pattern and extract the inner content.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;

&lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;object&lt;/span&gt;
&lt;span class="na"&gt;rule&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
&lt;span class="na"&gt;pattern&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;context&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;({ $$$ARGS }) =&amp;gt; {}&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;object_pattern&lt;/span&gt;
&lt;span class="na"&gt;fix&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;$$$ARGS&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;For example, the rewriter above will capture the &lt;code&gt;{value}&lt;/code&gt; inside &lt;code&gt;function MyInput({value}, ref)&lt;/code&gt; and extract &lt;code&gt;value&lt;/code&gt; as &lt;code&gt;$$$ARGS&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;identifier&lt;/code&gt; rewriter captures the identifier pattern and spreads it.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;

&lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;identifier&lt;/span&gt;
&lt;span class="na"&gt;rule&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;pattern&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;$P&lt;/span&gt; &lt;span class="pi"&gt;}&lt;/span&gt;
&lt;span class="na"&gt;fix&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;...$P&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;For example, the rewriter above will capture &lt;code&gt;props&lt;/code&gt; and spread it as &lt;code&gt;...props&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Finally, we can use the &lt;code&gt;rewriters&lt;/code&gt; field to register the two rules above.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;

&lt;span class="na"&gt;rewriters&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;object&lt;/span&gt;
  &lt;span class="na"&gt;rule&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;pattern&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;context&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;({ $$$ARGS }) =&amp;gt; {}&lt;/span&gt;
      &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;object_pattern&lt;/span&gt;
  &lt;span class="na"&gt;fix&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;$$$ARGS&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;identifier&lt;/span&gt;
  &lt;span class="na"&gt;rule&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;pattern&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;$P&lt;/span&gt; &lt;span class="pi"&gt;}&lt;/span&gt;
  &lt;span class="na"&gt;fix&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;...$P&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;And we then can use them in the &lt;code&gt;transform&lt;/code&gt; field to rewrite the arguments and use them in the fix.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;

&lt;span class="na"&gt;transform&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;NEW_ARG&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;rewrite&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;rewriters&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;object&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;identifier&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
      &lt;span class="na"&gt;source&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;$PROPS&lt;/span&gt;
&lt;span class="na"&gt;fix&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|-&lt;/span&gt;
  &lt;span class="s"&gt;function $M({ref: $REF, $NEW_ARG}) {&lt;/span&gt;
    &lt;span class="s"&gt;$$$BODY&lt;/span&gt;
  &lt;span class="s"&gt;}&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;Putting all these together, we get the final rule:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;

&lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;remove-forward-ref&lt;/span&gt;
&lt;span class="na"&gt;language&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;javascript&lt;/span&gt;
&lt;span class="na"&gt;rule&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;pattern&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;forwardRef(function $M($PROPS, $REF) { $$$BODY })&lt;/span&gt;
&lt;span class="na"&gt;rewriters&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;object&lt;/span&gt;
  &lt;span class="na"&gt;rule&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;pattern&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;context&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;({ $$$ARGS }) =&amp;gt; {}&lt;/span&gt;
      &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;object_pattern&lt;/span&gt;
  &lt;span class="na"&gt;fix&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;$$$ARGS&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;identifier&lt;/span&gt;
  &lt;span class="na"&gt;rule&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;pattern&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;$P&lt;/span&gt; &lt;span class="pi"&gt;}&lt;/span&gt;
  &lt;span class="na"&gt;fix&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;...$P&lt;/span&gt;
&lt;span class="na"&gt;transform&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;NEW_ARG&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;rewrite&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;rewriters&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;object&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;identifier&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
      &lt;span class="na"&gt;source&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;$PROPS&lt;/span&gt;
&lt;span class="na"&gt;fix&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|-&lt;/span&gt;
  &lt;span class="s"&gt;function $M({ref: $REF, $NEW_ARG}) {&lt;/span&gt;
    &lt;span class="s"&gt;$$$BODY&lt;/span&gt;
  &lt;span class="s"&gt;}&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;&lt;a href="https://ast-grep.github.io/playground.html#eyJtb2RlIjoiQ29uZmlnIiwibGFuZyI6ImphdmFzY3JpcHQiLCJxdWVyeSI6IiRUSEVNRS5Qcm92aWRlciIsInJld3JpdGUiOiJsb2dnZXIubG9nKCRNQVRDSCkiLCJjb25maWciOiJydWxlOlxuICBwYXR0ZXJuOiBmb3J3YXJkUmVmKGZ1bmN0aW9uICRNKCRQUk9QUywgJFJFRikgeyAkJCRCT0RZIH0pXG5yZXdyaXRlcnM6XG4tIGlkOiBvYmplY3RcbiAgcnVsZTpcbiAgICBwYXR0ZXJuOlxuICAgICAgY29udGV4dDogKHsgJCQkQVJHUyB9KSA9PiB7fVxuICAgICAgc2VsZWN0b3I6IG9iamVjdF9wYXR0ZXJuXG4gIGZpeDogJCQkQVJHU1xuLSBpZDogaWRlbnRpZmllclxuICBydWxlOiB7IHBhdHRlcm46ICRQIH1cbiAgZml4OiAuLi4kUCBcbnRyYW5zZm9ybTpcbiAgTkVXX0FSRzpcbiAgICByZXdyaXRlOlxuICAgICAgcmV3cml0ZXJzOiBbb2JqZWN0LCBpZGVudGlmaWVyXVxuICAgICAgc291cmNlOiAkUFJPUFNcbmZpeDogfC1cbiAgZnVuY3Rpb24gJE0oe3JlZjogJFJFRiwgJE5FV19BUkd9KSB7IFxuICAgICQkJEJPRFlcbiAgfVxuIiwic291cmNlIjoiY29uc3QgTXlJbnB1dCA9IGZvcndhcmRSZWYoZnVuY3Rpb24gTXlJbnB1dChwcm9wcywgcmVmKSB7XG4gIHJldHVybiA8aW5wdXQgey4uLnByb3BzfSByZWY9e3JlZn0gLz47XG59KTtcblxuY29uc3QgTXlJbnB1dCA9IGZvcndhcmRSZWYoZnVuY3Rpb24gTXlJbnB1dCh7dmFsdWV9LCByZWYpIHtcbiAgcmV0dXJuIDxpbnB1dCB2YWx1ZT17dmFsdWV9IHJlZj17cmVmfSAvPjtcbn0pOyJ9" rel="noopener noreferrer"&gt;Example playground link&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3mjkn20qclgl04zuvrpf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3mjkn20qclgl04zuvrpf.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Codemod is a powerful paradigm to automate code changes. In this article, we have shown how to use ast-grep to migrate to React 19.&lt;/p&gt;

&lt;p&gt;We have covered three common changes: use  as a provider, remove implicit-ref-callback-return, and remove forwardRef.&lt;/p&gt;

&lt;p&gt;The examples here are for educational purposes and you are encouraged to use &lt;a href="https://codemod.com/" rel="noopener noreferrer"&gt;codemod.com&lt;/a&gt; to automate these changes in your codebase. codemod.com has curated rules that take care of these changes and more subtle edge cases.&lt;/p&gt;

&lt;p&gt;You can adapt the example and explore ast-grep's power to automate more code changes.&lt;/p&gt;

&lt;p&gt;ast-grep is also available on &lt;a href="https://docs.codemod.com/introduction" rel="noopener noreferrer"&gt;codemod.com&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;Happy coding!&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Explore useEffect Alternatives: Beyond the Well-Trodden Paths</title>
      <dc:creator>Herrington Darkholme</dc:creator>
      <pubDate>Wed, 27 Mar 2024 23:24:50 +0000</pubDate>
      <link>https://forem.com/herrington_darkholme/explore-useeffect-alternatives-beyond-the-well-trodden-paths-ie0</link>
      <guid>https://forem.com/herrington_darkholme/explore-useeffect-alternatives-beyond-the-well-trodden-paths-ie0</guid>
      <description>&lt;p&gt;React hooks have transformed the way we design and structure our React components - they've encouraged more functional and less class-based patterns. The &lt;code&gt;useEffect&lt;/code&gt; hook is one of the most common hooks we use, and for good reason. It allows us to handle side effects - like data fetching, subscriptions, or manual DOM manipulations - in our functional components.&lt;/p&gt;

&lt;p&gt;However, there may be cases where alternatives could suit better. Today, we'll explore both the well-known and lesser-known alternatives to &lt;code&gt;useEffect&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Well-Known Alternatives
&lt;/h3&gt;

&lt;h4&gt;
  
  
  1. Computed State: useMemo
&lt;/h4&gt;

&lt;p&gt;&lt;code&gt;useMemo&lt;/code&gt; is a hook that returns a memorized value. This is typically used to optimize performance in scenarios where a computationally intensive value does not need to be recalculated unless its dependencies change. An instance where &lt;code&gt;useMemo&lt;/code&gt; could be a great alternative is when we have complex computed state.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;computationIntensiveValue&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useMemo&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;performHeavyComputation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  2. Event Handling: useCallback
&lt;/h4&gt;

&lt;p&gt;For event handling scenarios, &lt;code&gt;useCallback&lt;/code&gt; could be a better alternative. It's a hook that returns a memoized version of the callback that only changes if one of the dependencies has changed.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;memoizedCallback&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useCallback&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;eventHandler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  3. State Management: useContext
&lt;/h4&gt;

&lt;p&gt;&lt;code&gt;useContext&lt;/code&gt; allows us to access the value of a context without wrapping a component in a &lt;code&gt;&amp;lt;Context.Consumer&amp;gt;&lt;/code&gt; or using a &lt;code&gt;class&lt;/code&gt; component. It's a perfect choice when it comes to lifting state up.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;contextValue&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useContext&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;MyContext&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  4. Data Fetching: useSWR
&lt;/h4&gt;

&lt;p&gt;For data fetching, &lt;code&gt;useSWR&lt;/code&gt; is a superb choice over &lt;code&gt;useEffect&lt;/code&gt;. &lt;code&gt;useSWR&lt;/code&gt; is a reusable state management tool for data fetching, which includes built-in handling for caching, retries, deduplication, and updates.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useSWR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/api/data&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;fetcher&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Lesser-Known Alternatives
&lt;/h3&gt;

&lt;h4&gt;
  
  
  5. Resetting a component: use new &lt;code&gt;key&lt;/code&gt;
&lt;/h4&gt;

&lt;p&gt;Resetting a component sometimes might be useful to return the component to its initial state. Assigning a new &lt;code&gt;key&lt;/code&gt; prop to a component makes React perceive the latter as a completely new component, thereby remounting it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;MyComponent&lt;/span&gt; &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;uniqueId&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  6. Resetting some state: setState in render
&lt;/h4&gt;

&lt;p&gt;Instead of using &lt;code&gt;useEffect&lt;/code&gt;, setting state directly in the render method is a viable option for some cases. This might seem counter-intuitive, but can be effective when it needs to reset specific state values during rendering.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;needToReset&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;setState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;initialState&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  7. External data source: useSyncExternalStore
&lt;/h4&gt;

&lt;p&gt;The &lt;code&gt;useSyncExternalStore&lt;/code&gt; hook provides a way to read from and subscribe to an external (mutable) source. This can be ideal when dealing with external data sources.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useSyncExternalStore&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;store&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;store&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getState&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;Using &lt;code&gt;useEffect&lt;/code&gt; for everything might seem like a go-to solution, but there's a plethora of hooks and alternatives readily available for particular problems. It's important to understand these to get the best out of React. Use the most suitable tool for your issue and make your React applications shine!&lt;/p&gt;

&lt;p&gt;Remember, the beauty of Hooks lies in the orchestration of simplicity and functionality, making React a more potent and friendly framework. Stay curious, explore more, and keep coding innovative solutions!&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>react</category>
      <category>beginners</category>
      <category>javascript</category>
    </item>
    <item>
      <title>ast-grep VSCode: A Powerful Tool for Structural Search and Replace</title>
      <dc:creator>Herrington Darkholme</dc:creator>
      <pubDate>Sun, 03 Mar 2024 02:10:56 +0000</pubDate>
      <link>https://forem.com/herrington_darkholme/ast-grep-vscode-a-powerful-tool-for-structural-search-and-replace-3g6b</link>
      <guid>https://forem.com/herrington_darkholme/ast-grep-vscode-a-powerful-tool-for-structural-search-and-replace-3g6b</guid>
      <description>&lt;p&gt;Hi, I'm &lt;a href="https://twitter.com/hd_nvim"&gt;Herrington&lt;/a&gt;, the author of &lt;a href="https://ast-grep.github.io/"&gt;ast-grep&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If you've ever searched code with regular expressions, you may have struggled with matching multiple lines, nested structures, or ignoring comments.&lt;/p&gt;

&lt;p&gt;Let me introduce &lt;a href="https://marketplace.visualstudio.com/items?itemName=ast-grep.ast-grep-vscode"&gt;ast-grep VSCode&lt;/a&gt;, a new extension leveraging the power of structural search and replace (SSR) to help you perform more precise and efficient search and replace.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Limitations of Textual Search and Replace
&lt;/h2&gt;

&lt;p&gt;Suppose you want to refactor your JavaScript code to replace the &lt;a href="https://lodash.com/"&gt;lodash&lt;/a&gt; &lt;code&gt;_.filter&lt;/code&gt; function with the native &lt;code&gt;Array.prototype.filter&lt;/code&gt; &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter"&gt;method&lt;/a&gt;. A simple text search and replace might look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Find
_.filter\((\.+), (.+)\)
// Replace
$1.filter($2)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This might work for some cases, but it has several limitations:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It can only match single-line expressions. If your code spans multiple lines, you'll miss some matches or get incorrect replacements.&lt;/li&gt;
&lt;li&gt;It can't handle nested structures like parentheses, brackets, or braces. If your code has complex expressions, you'll get incorrect matches or replacements.&lt;/li&gt;
&lt;li&gt;It can't ignore comments or other irrelevant parts of the code. If your code has comments that contain the search pattern, you'll get unwanted matches or replacements.&lt;/li&gt;
&lt;li&gt;It requires you to use match groups or named capture groups to preserve the arguments of the function. This can be tedious and error-prone, especially with many arguments or nested functions.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Structural Search and Replace Comes to the Rescue
&lt;/h2&gt;

&lt;p&gt;Can we make our search algorithm smarter, understand our code better, and be easier to use? Yes! Structural search and replace (SSR) comes to the rescue!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.jetbrains.com/help/idea/structural-search-and-replace.html"&gt;Structural search and replace&lt;/a&gt; (SSR) is a technique that allows you to find and modify code patterns based on their syntax and semantics, not just their text. Instead of treating code as plain text, SSR treats code as a collection of nodes with types, properties, and relationships.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://ast-grep.github.io/"&gt;ast-grep&lt;/a&gt; is a command-line tool that implements SSR. The query for the lodash example above is quite simple.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Search pattern:&lt;/span&gt;
&lt;span class="nx"&gt;_&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;$ARR&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;$FUNC&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;// Rewrite:&lt;/span&gt;
&lt;span class="nx"&gt;$ARR&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;$FUNC&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The pattern illustrates the basic usage of ast-grep. &lt;code&gt;$ARR&lt;/code&gt; and &lt;code&gt;$FUNC&lt;/code&gt; are &lt;a href="https://ast-grep.github.io/guide/pattern-syntax.html#meta-variable"&gt;meta-variables&lt;/a&gt;. Meta-variables are like the dot &lt;code&gt;.&lt;/code&gt; in regular expressions, except they match AST nodes instead of characters. You can also use captured meta-variables in the rewrite pattern.&lt;/p&gt;

&lt;p&gt;Other than the meta-variables, I hope the pattern and rewrite are self-explanatory.&lt;/p&gt;

&lt;p&gt;This query has several advantages over the text search and replace:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It can match expressions across multiple lines, as long as they are syntactically valid.&lt;/li&gt;
&lt;li&gt;It can handle nested structures like parentheses, brackets, or braces, as they are part of the AST.&lt;/li&gt;
&lt;li&gt;It can ignore comments or other irrelevant parts of the code, as they are not part of the AST.&lt;/li&gt;
&lt;li&gt;It does not require match groups or named capture groups, as the meta-variables are accessed by their names in the search pattern.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Unique Features of ast-grep
&lt;/h3&gt;

&lt;p&gt;ast-grep uses the tree-sitter library, a fast and robust parser for many programming languages. ast-grep allows you to write queries using a simple &lt;a href="https://ast-grep.github.io/guide/pattern-syntax.html#meta-variable"&gt;pattern syntax&lt;/a&gt; that resembles code and apply them to files or directories of code. Some of the unique features of ast-grep are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It supports many languages, including JavaScript, TypeScript, Python, Ruby, Java, C#, Go, Rust, and more. You can also add support for new languages by &lt;a href="https://ast-grep.github.io/advanced/custom-language.html"&gt;registering tree-sitter grammars&lt;/a&gt; in the configuration.&lt;/li&gt;
&lt;li&gt;It is &lt;a href="https://github.com/ast-grep/ast-grep"&gt;written in Rust&lt;/a&gt;, which makes it very fast and memory-efficient. It can process large codebases in a matter of seconds.&lt;/li&gt;
&lt;li&gt;It has a &lt;a href="https://ast-grep.github.io/reference/cli.html"&gt;rich set of options&lt;/a&gt; and flags, such as dry run, interactive mode, color output, and more. You can customize your SSR experience to suit your needs and preferences.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But, ast-grep until now only has a command-line interface. Can we have its power right near our hands instead of switching between terminals and editors?&lt;/p&gt;

&lt;h2&gt;
  
  
  ast-grep VSCode: Bridging the CLI and the Editor
&lt;/h2&gt;

&lt;p&gt;ast-grep VSCode is a new extension that integrates ast-grep with Visual Studio Code, one of the most popular code editors. With ast-grep VSCode, you can use SSR within your editor, without leaving your workflow.&lt;/p&gt;

&lt;h3&gt;
  
  
  Structural Search, Replace, and More
&lt;/h3&gt;

&lt;p&gt;Some features of ast-grep VSCode include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It provides a user interface for writing and executing SSR queries, and you can see the results of your queries in a sidebar, with previews and diffs.&lt;/li&gt;
&lt;li&gt;It also supports linting and code fix. You can set up an ast-grep project and write custom rules tailored to your needs.&lt;/li&gt;
&lt;li&gt;It feels like a native VSCode feature, with seamless integration and consistent design.&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature&lt;/th&gt;
&lt;th&gt;Screenshot&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Search Pattern&lt;/td&gt;
&lt;td&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Fp4fHkpY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://github.com/ast-grep/ast-grep-vscode/blob/main/readme/search-pattern.png%3Fraw%3Dtrue" width="800" height="857"&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Search In Folder&lt;/td&gt;
&lt;td&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--k1hD3cpH--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://github.com/ast-grep/ast-grep-vscode/blob/main/readme/search-in-folder.png%3Fraw%3Dtrue" width="800" height="810"&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Replace Preview&lt;/td&gt;
&lt;td&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--1ifEPj2w--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://github.com/ast-grep/ast-grep-vscode/blob/main/readme/replace.png%3Fraw%3Dtrue" width="800" height="582"&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Commit Replace&lt;/td&gt;
&lt;td&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--WAqtjNQC--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://github.com/ast-grep/ast-grep-vscode/blob/main/readme/commit-replace.png%3Fraw%3Dtrue" width="800" height="413"&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Code Linting&lt;/td&gt;
&lt;td&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--cFU74tL---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://github.com/ast-grep/ast-grep-vscode/blob/main/readme/linter.png%3Fraw%3Dtrue" width="800" height="840"&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Comparing with Other SSR Tools
&lt;/h2&gt;

&lt;p&gt;There are other SSR tools and extensions available. However, I believe ast-grep VSCode is one of the best SSR extensions for VSCode because:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It has good performance, backed by a multi-threaded CLI written in a native language.&lt;/li&gt;
&lt;li&gt;It supports multiple languages, leveraging the tree-sitter grammars widely used and maintained by the community.&lt;/li&gt;
&lt;li&gt;It has a user-friendly and intuitive interface that feels like a VSCode built-in feature. See it in &lt;a href="https://www.youtube.com/watch?v=1ZM4RfIvWKc"&gt;action&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Finally, I want to highlight some React techniques used in ast-grep VSCode that make it fast and responsive:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/ast-grep/ast-grep-vscode/blob/789d27325fb9ce6a0bb969caefdc718942f6d2b3/src/webview/hooks/useSearch.tsx#L150-L159"&gt;&lt;code&gt;useSyncExternalStore&lt;/code&gt;&lt;/a&gt; was used to manage streaming results from ast-grep CLI. This &lt;a href="https://react.dev/reference/react/useSyncExternalStore"&gt;hook&lt;/a&gt; allows components to subscribe to an external mutable source of data and update the rendering accordingly. This way, the extension can show the results as soon as they are available.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/ast-grep/ast-grep-vscode/blob/main/src/webview/SearchSidebar/index.tsx#L13-L16"&gt;&lt;code&gt;useDeferredValue&lt;/code&gt;&lt;/a&gt; deferred rendering the result list. This &lt;a href="https://react.dev/reference/react/useDeferredValue"&gt;hook&lt;/a&gt; can avoid blocking user input and improve the perceived performance of the UI by delaying the update of a derived state until the next concurrent render.&lt;/li&gt;
&lt;li&gt;The extension carefully used plenty of &lt;code&gt;memo&lt;/code&gt; and CSS tricks to reduce the JavaScript workload.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;I hope this article helps you understand the benefits of SSR and the features of ast-grep VSCode. If you are interested in trying it out, you can install it from the &lt;a href="https://marketplace.visualstudio.com/items?itemName=ast-grep.ast-grep-vscode"&gt;VSCode Marketplace&lt;/a&gt;. ast-grep VSCode is still in development and has a lot of room for improvement. I would love to hear your feedback and suggestions, so feel free to open an issue or a pull request on &lt;a href="https://github.com/ast-grep/ast-grep-vscode"&gt;GitHub&lt;/a&gt;. I also want to thank &lt;a href="https://github.com/SoonIter"&gt;SoonIter&lt;/a&gt;, &lt;a href="https://github.com/StevenLove"&gt;Steven Love&lt;/a&gt;, &lt;a href="https://github.com/SigureMo"&gt;Nyakku Shigure&lt;/a&gt;, and &lt;a href="https://github.com/cshuaimin/ssr.nvim"&gt;ssr.nvim&lt;/a&gt; for their contribution and inspiration!&lt;/p&gt;

&lt;p&gt;Happy grepping!&lt;/p&gt;

</description>
      <category>vscode</category>
      <category>extensions</category>
      <category>productivity</category>
      <category>programming</category>
    </item>
    <item>
      <title>Find &amp; Patch: A Novel Functional Programming like Code Rewrite Scheme</title>
      <dc:creator>Herrington Darkholme</dc:creator>
      <pubDate>Thu, 08 Feb 2024 08:29:30 +0000</pubDate>
      <link>https://forem.com/herrington_darkholme/find-patch-a-novel-functional-programming-like-code-rewrite-scheme-3964</link>
      <guid>https://forem.com/herrington_darkholme/find-patch-a-novel-functional-programming-like-code-rewrite-scheme-3964</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Code transformation is a powerful technique that allows you to modify your code programmatically. There are many tools that can help you with code transformation, such as &lt;a href="https://babeljs.io/"&gt;Babel&lt;/a&gt;/&lt;a href="https://github.com/biomejs/biome/discussions/1762"&gt;biome&lt;/a&gt; for JavaScript/TypeScript, &lt;a href="https://libcst.readthedocs.io/en/latest/"&gt;libcst&lt;/a&gt; for Python, or &lt;a href="https://getrector.com/"&gt;Rector&lt;/a&gt; for PHP. Most of these tools use imperative APIs to manipulate the &lt;a href="https://www.wikiwand.com/en/Abstract_syntax_tree"&gt;abstract syntax tree&lt;/a&gt; (AST) of your code.&lt;/p&gt;

&lt;p&gt;In this post, we will introduce a different approach to code transformation called &lt;strong&gt;Find &amp;amp; Patch&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;This scheme lets you rewrite complex code using a fully declarative &lt;a href="https://www.wikiwand.com/en/Domain-specific_language"&gt;Domain-Specific Language&lt;/a&gt; (DSL). While the scheme is powerful, the underlying concept is simple: find certain nodes, rewrite them, and recursively repeat the rewriting.&lt;/p&gt;

&lt;p&gt;The idea of Find &amp;amp; Patch comes from developing &lt;a href="https://ast-grep.github.io/"&gt;ast-grep&lt;/a&gt;, a tool using AST to find and replace code patterns. We realized that this approach can be generalized and extended to support more complex and diverse code transformations!&lt;/p&gt;

&lt;p&gt;At the end of this article, we will compare Find &amp;amp; Patch to functional programming on the tree of syntax nodes. You can apply filter nodes using &lt;code&gt;rule&lt;/code&gt;, map them via &lt;code&gt;transform&lt;/code&gt;, and compose them with &lt;code&gt;rewriters&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;This gives you a lot of flexibility and expressiveness to manipulate your code!&lt;/p&gt;

&lt;h2&gt;
  
  
  What is ast-grep?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/ast-grep/ast-grep"&gt;ast-grep&lt;/a&gt; is a tool to search and rewrite code based on ASTs. It is like &lt;code&gt;grep&lt;/code&gt; for code, but with the power of ASTs.&lt;br&gt;
More concretely, ast-grep can find code patterns using its &lt;a href="https://ast-grep.github.io/guide/rule-config/atomic-rule.html"&gt;rule system&lt;/a&gt;. It can also rewrite the matched code using &lt;a href="https://ast-grep.github.io/guide/pattern-syntax.html#meta-variable"&gt;meta-variables&lt;/a&gt; based on the rule.&lt;/p&gt;

&lt;p&gt;ast-grep's rewriting can be seen as two steps: finding target nodes and patching them with new text.&lt;/p&gt;
&lt;h2&gt;
  
  
  Find and Patch: How ast-grep Rewrites Code
&lt;/h2&gt;

&lt;p&gt;The basic rewriting workflow of ast-grep is like below:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;em&gt;Find&lt;/em&gt;: search the nodes in the AST that match the rewriter rules (hence the name ast-grep).&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;Rewrite&lt;/em&gt;: generate a new string based on the matched meta-variables.&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;Patch&lt;/em&gt;: replace the node text with the generated fix.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Let's see a simple example: replace &lt;code&gt;console.log&lt;/code&gt; with &lt;code&gt;logger.log&lt;/code&gt;. The following rule will do the trick.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;rule&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;pattern&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;console.log($MSG)&lt;/span&gt;
&lt;span class="na"&gt;fix&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;logger.log($MSG)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The rule above is quite straightforward. It matches the &lt;code&gt;console.log&lt;/code&gt; call, using the pattern, and replaces it with the &lt;code&gt;logger.log&lt;/code&gt; call.&lt;br&gt;
The meta-variable &lt;code&gt;$MSG&lt;/code&gt; captures the argument of &lt;code&gt;console.log&lt;/code&gt; and is used in the &lt;code&gt;fix&lt;/code&gt; field.&lt;/p&gt;

&lt;p&gt;ast-grep also has several other fields to fine-tune the process. The core fields in ast-grep's rule map naturally to the idea of &lt;strong&gt;Find &amp;amp; Patch&lt;/strong&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Find&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Find a target node based on the &lt;a href="https://ast-grep.github.io/reference/rule.html"&gt;&lt;code&gt;rule&lt;/code&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Filter the matched nodes based on &lt;a href="https://ast-grep.github.io/reference/yaml.html#constraints"&gt;&lt;code&gt;constraints&lt;/code&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Patch&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Rewrite the matched meta-variable based on &lt;a href="https://ast-grep.github.io/reference/yaml/transformation.html"&gt;&lt;code&gt;transform&lt;/code&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Replace the matched node with &lt;a href="https://ast-grep.github.io/reference/yaml/fix.html"&gt;&lt;code&gt;fix&lt;/code&gt;&lt;/a&gt;, which can use the transformed meta-variables.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Limitation of the Current Workflow
&lt;/h2&gt;

&lt;p&gt;However, this workflow has a limitation: it can only replace one node at a time, which means that we cannot handle complex transformations that involve multiple nodes or lists of nodes.&lt;/p&gt;

&lt;p&gt;For example, suppose we want to rewrite barrel imports to single imports. A &lt;a href="https://adrianfaciu.dev/posts/barrel-files/"&gt;barrel import&lt;/a&gt; is a way to consolidate the exports of multiple modules into a single convenient module that can be imported using a single import statement. For instance:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./barrel&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This imports three modules (&lt;code&gt;a&lt;/code&gt;, &lt;code&gt;b&lt;/code&gt;, and &lt;code&gt;c&lt;/code&gt;) from a single barrel file (&lt;code&gt;barrel.js&lt;/code&gt;) that re-exports them.&lt;/p&gt;

&lt;p&gt;Rewriting this to single imports has &lt;a href="https://vercel.com/blog/how-we-optimized-package-imports-in-next-js"&gt;some&lt;/a&gt; &lt;a href="https://marvinh.dev/blog/speeding-up-javascript-ecosystem-part-7/"&gt;benefits&lt;/a&gt;, such as reducing &lt;a href="https://dev.to/tassiofront/barrel-files-and-why-you-should-stop-using-them-now-bc4"&gt;bundle size&lt;/a&gt; or avoiding &lt;a href="https://flaming.codes/posts/barrel-files-in-javascript/"&gt;conflicting names&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./barrel/a&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./barrel/b&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;c&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./barrel/c&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This imports each module directly from its own file, without going through the barrel file.&lt;/p&gt;

&lt;p&gt;With the simple "Find and Patch" workflow, we cannot achieve this transformation easily. We either have to rewrite the whole import statement or rewrite each identifier one by one. We cannot replace the whole import statement because we cannot process the multiple identifiers, which requires processing a list of nodes at one time.&lt;br&gt;
 Can we rewrite the identifiers one by one? This also fails because we cannot replace the whole import statement, so there will be unwanted import statement text surrounding the identifiers.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// we cannot rewrite the whole import statements&lt;/span&gt;
&lt;span class="c1"&gt;// because we don't know how to rewrite a, b, c as a list&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./barrel&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="c1"&gt;// we cannot rewrite each identifier&lt;/span&gt;
&lt;span class="c1"&gt;// because the replaced text is inside the import statement&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./barrel&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We need a better way to rewrite code that involves multiple nodes or lists of nodes. And here comes &lt;strong&gt;Find &amp;amp; Patch&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Extend the Concept of &lt;code&gt;Find&lt;/code&gt; and &lt;code&gt;Patch&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;Let's reflect: what limits us from rewriting the code above?&lt;/p&gt;

&lt;p&gt;Our old workflow does not allow us to apply a rule to multiple sub-nodes of a node. (This is like not being able to write for loops.)&lt;/p&gt;

&lt;p&gt;Nor does it allow us to generate different text for different sub-nodes in a rule. (This is like not being able to write if/switch statements.)&lt;/p&gt;

&lt;p&gt;I initially thought of adding &lt;a href="https://github.com/ast-grep/ast-grep/issues/723#issuecomment-1890362116"&gt;list comprehension&lt;/a&gt; to transform to overcome these limitations. However, list comprehension will introduce more concepts like loops, filters and probably nested loops. I prefer having &lt;a href="https://www.wikiwand.com/en/Occam%27s_razor"&gt;Occam's razor&lt;/a&gt; to shave off unnecessary constructs.&lt;/p&gt;

&lt;p&gt;Luckily, &lt;a href="https://github.com/emosenkis"&gt;Mosenkis&lt;/a&gt; proposed the &lt;a href="https://github.com/ast-grep/ast-grep/issues/723#issuecomment-1883526774"&gt;refreshing idea&lt;/a&gt; that we can apply sub-rules, called &lt;code&gt;rewriters&lt;/code&gt;, to specific nodes during matching. It can elegantly solve the issue of processing multiple nodes with multiple different rules!&lt;/p&gt;

&lt;p&gt;The idea is simple: we will add three new, but similar, steps in the rewriting step.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;em&gt;Find&lt;/em&gt; a list of different sub-nodes under a meta-variable that match different rewriters.&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;Generate&lt;/em&gt; a different fix for each sub-node based on the matched rewriter sub-rule.&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;Join&lt;/em&gt; the fixes together and store the string in a new metavariable for later use.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The new steps are similar to the existing &lt;strong&gt;"Find and Patch"&lt;/strong&gt; workflow. It is like recursively applying the old workflow to matched nodes!&lt;/p&gt;

&lt;p&gt;We can, taking the previous barrel import as an example, first match the import statement and then apply the rewriter sub-rule to each identifier.&lt;/p&gt;

&lt;h2&gt;
  
  
  Intriguing Example
&lt;/h2&gt;

&lt;p&gt;The idea above is implemented by a new &lt;a href="https://ast-grep.github.io/reference/yaml/rewriter.html"&gt;&lt;code&gt;rewriters&lt;/code&gt;&lt;/a&gt; field and a new &lt;a href="https://ast-grep.github.io/reference/yaml/transformation.html#rewrite"&gt;&lt;code&gt;rewrite&lt;/code&gt;&lt;/a&gt; transformation.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Our first step is to write a rule to capture the import statement.&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;rule&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;pattern&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;import {$$$IDENTS} from './barrel'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will capture the imported identifiers &lt;code&gt;a, b, c&lt;/code&gt; in &lt;code&gt;$$$IDENTS&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Next, we need to transform &lt;code&gt;$$$IDENTS&lt;/code&gt; to individual imports.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The idea is that we can find the identifier nodes in the &lt;code&gt;$$$IDENT&lt;/code&gt; and rewrite them to individual imports.&lt;/p&gt;

&lt;p&gt;To do this, we register a rewriter that acts as a separate rewriter rule for each identifier.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;rewriters&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;rewrite-identifer&lt;/span&gt;
  &lt;span class="na"&gt;rule&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;pattern&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;$IDENT&lt;/span&gt;
    &lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;identifier&lt;/span&gt;
  &lt;span class="na"&gt;fix&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;import $IDENT from './barrel/$IDENT'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;rewrite-identifier&lt;/code&gt; above will:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;First, find each &lt;code&gt;identifier&lt;/code&gt; AST node and capture it as &lt;code&gt;$IDENT&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Rewrite the identifier to a new import statement.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;For example, the rewriter will change identifier &lt;code&gt;a&lt;/code&gt; to  &lt;code&gt;import a from './barrel/a'&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;We can now apply the rewriter to the matched variable &lt;code&gt;$$$IDENTS&lt;/code&gt;.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The counterpart of &lt;code&gt;rewriter&lt;/code&gt; is the &lt;code&gt;rewrite&lt;/code&gt; transformation, which applies the rewriter to a matched variable and generates a new string.&lt;/p&gt;

&lt;p&gt;The yaml fragment below uses &lt;code&gt;rewrite&lt;/code&gt; to find identifiers in &lt;code&gt;$$$IDENTS&lt;/code&gt;, as specified in &lt;code&gt;rewrite-identifier&lt;/code&gt;'s rule,&lt;br&gt;
and rewrites it to single import statement.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;transform&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;IMPORTS&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;rewrite&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;rewriters&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;rewrite-identifer&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
      &lt;span class="na"&gt;source&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;$$$IDENTS&lt;/span&gt;
      &lt;span class="na"&gt;joinBy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note the &lt;code&gt;joinBy&lt;/code&gt; field in the transform section. It specifies how to join the rewritten import statements with a newline character. This means that each identifier will generate a separate import statement, followed by a newline.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Finally, we can use the transformed &lt;code&gt;IMPORTS&lt;/code&gt; in the &lt;code&gt;fix&lt;/code&gt; field to replace the original import statement.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The final rule will be like this. See the &lt;a href="https://ast-grep.github.io/playground.html#eyJtb2RlIjoiQ29uZmlnIiwibGFuZyI6ImphdmFzY3JpcHQiLCJxdWVyeSI6IiIsInJld3JpdGUiOiIiLCJjb25maWciOiJydWxlOlxuICBwYXR0ZXJuOiBpbXBvcnQgeyQkJElERU5UU30gZnJvbSAnLi9iYXJyZWwnXG5yZXdyaXRlcnM6XG4tIGlkOiByZXdyaXRlLWlkZW50aWZlclxuICBydWxlOlxuICAgIHBhdHRlcm46ICRJREVOVFxuICAgIGtpbmQ6IGlkZW50aWZpZXJcbiAgZml4OiBpbXBvcnQgJElERU5UIGZyb20gJy4vYmFycmVsLyRJREVOVCdcbnRyYW5zZm9ybTpcbiAgSU1QT1JUUzpcbiAgICByZXdyaXRlOlxuICAgICAgcmV3cml0ZXJzOiBbcmV3cml0ZS1pZGVudGlmZXJdXG4gICAgICBzb3VyY2U6ICQkJElERU5UU1xuICAgICAgam9pbkJ5OiBcIlxcblwiXG5maXg6ICRJTVBPUlRTIiwic291cmNlIjoiaW1wb3J0IHsgYSwgYiwgYyB9IGZyb20gJy4vYmFycmVsJzsifQ=="&gt;online playground&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;rule&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;pattern&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;import {$$$IDENTS} from './barrel'&lt;/span&gt;
&lt;span class="na"&gt;rewriters&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;rewrite-identifer&lt;/span&gt;
  &lt;span class="na"&gt;rule&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;pattern&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;$IDENT&lt;/span&gt;
    &lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;identifier&lt;/span&gt;
  &lt;span class="na"&gt;fix&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;import $IDENT from './barrel/$IDENT'&lt;/span&gt;
&lt;span class="na"&gt;transform&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;IMPORTS&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;rewrite&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;rewriters&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;rewrite-identifer&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
      &lt;span class="na"&gt;source&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;$$$IDENTS&lt;/span&gt;
      &lt;span class="na"&gt;joinBy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;
&lt;span class="na"&gt;fix&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;$IMPORTS&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Similarity to Functional Programming
&lt;/h2&gt;

&lt;p&gt;Find &amp;amp; Patch is a scheme that allows us to manipulate the syntax tree of the code in a declarative way.&lt;/p&gt;

&lt;p&gt;It reminds me of Rust declarative macro since both Find &amp;amp; Patch and Rust declarative macro can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Match a list of nodes/tokens based on patterns: ast-grep's rule vs. Rust macro pattern matcher.&lt;/li&gt;
&lt;li&gt;Break nodes/tokens into sub parts: ast-grep's metavariable vs. Rust macro variable.&lt;/li&gt;
&lt;li&gt;Recursively use subparts to call other rewrite/macros.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The idea can be further compared to functional programming! We can use different rules to match and transform different sub-nodes of the tree, just like using &lt;a href="https://www.wikiwand.com/en/Pattern_matching"&gt;pattern matching&lt;/a&gt; in functional languages. We can also apply rules to multiple sub-nodes at once, just like using for-comprehension or map/filter/reduce. Moreover, we can break down a large syntax tree into smaller sub-trees by using meta-variables, just like using destructuring or &lt;a href="https://blog.jez.io/intro-elim/"&gt;elimination rules&lt;/a&gt; in functional languages. But all of these can be boiled down to two simple idea: &lt;strong&gt;Finding&lt;/strong&gt; nodes and &lt;strong&gt;Patching&lt;/strong&gt; nodes!&lt;/p&gt;

&lt;p&gt;Find &amp;amp; Patch is a simple and elegant scheme that is tailored for AST manipulation, but it can achieve similar transformations as a general-purpose functional programming language doing rewrites!&lt;/p&gt;

&lt;p&gt;We can think of Find &amp;amp; Patch as a form of "Functional Programming" over the AST! &lt;small&gt;And they both have the same acronym btw.&lt;/small&gt;&lt;/p&gt;




&lt;p&gt;Hope you find this scheme useful and interesting, and I sincerely invite you to try it out with ast-grep. Thank you for reading~&lt;/p&gt;

</description>
      <category>programming</category>
      <category>tooling</category>
      <category>functional</category>
      <category>productivity</category>
    </item>
  </channel>
</rss>
