<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: isaac</title>
    <description>The latest articles on DEV Community by isaac (@gtesei).</description>
    <link>https://dev.to/gtesei</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3930355%2F030fed05-c0c1-433d-bc6c-8ed7743881d4.jpeg</url>
      <title>DEV Community: isaac</title>
      <link>https://dev.to/gtesei</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/gtesei"/>
    <language>en</language>
    <item>
      <title>I Tried to Steal a Watermark Key Without Having It</title>
      <dc:creator>isaac</dc:creator>
      <pubDate>Sat, 15 Aug 2026 10:39:00 +0000</pubDate>
      <link>https://dev.to/gtesei/i-tried-to-steal-a-watermark-key-without-having-it-2pj4</link>
      <guid>https://dev.to/gtesei/i-tried-to-steal-a-watermark-key-without-having-it-2pj4</guid>
      <description>&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
    &lt;div class="c-embed__content"&gt;
        &lt;div class="c-embed__cover"&gt;
          &lt;a href="https://gtesei.github.io/llm-watermark/posts/stealing-a-watermark-key.html" class="c-link align-middle" rel="noopener noreferrer"&gt;
            &lt;img alt="" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgtesei.github.io%2Fllm-watermark%2Fassets%2Fevidence-decay.png" height="429" class="m-0" width="800"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="c-embed__body"&gt;
        &lt;h2 class="fs-xl lh-tight"&gt;
          &lt;a href="https://gtesei.github.io/llm-watermark/posts/stealing-a-watermark-key.html" rel="noopener noreferrer" class="c-link"&gt;
            I Tried to Steal a Watermark Key Without Having It | WMTrace
          &lt;/a&gt;
        &lt;/h2&gt;
          &lt;p class="truncate-at-3"&gt;
            Sixty documents, no key, no model, no detector. One watermark leaked. The second seemed to fight back—until the evidence exposed a false lead.
          &lt;/p&gt;
        &lt;div class="color-secondary fs-s flex items-center"&gt;
          gtesei.github.io
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;


</description>
      <category>ai</category>
      <category>watermark</category>
      <category>cybersecurity</category>
      <category>llm</category>
    </item>
    <item>
      <title>Anthropic is watermarking Claude's output. Here's how text watermarks actually work (with runnable code)</title>
      <dc:creator>isaac</dc:creator>
      <pubDate>Sat, 15 Aug 2026 02:34:52 +0000</pubDate>
      <link>https://dev.to/gtesei/anthropic-is-watermarking-claudes-output-heres-how-text-watermarks-actually-work-with-runnable-218f</link>
      <guid>https://dev.to/gtesei/anthropic-is-watermarking-claudes-output-heres-how-text-watermarks-actually-work-with-runnable-218f</guid>
      <description>&lt;p&gt;Anthropic announced this week that future Claude models will watermark their text output, using a version of Google DeepMind's &lt;strong&gt;SynthID-Text&lt;/strong&gt;. Google already runs it in Gemini at production scale. Which means statistical text watermarks&lt;br&gt;
  just went from research curiosity to something you'll be reading every day — probably without noticing.&lt;/p&gt;

&lt;p&gt;Most people, including most engineers, have never seen how one works. The mechanism is surprisingly simple, and you can hold all of it in your head. Let's build the intuition, then run a real detector.&lt;/p&gt;

&lt;p&gt;## The core trick: a keyed coin flip over the vocabulary&lt;/p&gt;

&lt;p&gt;An LLM produces text by choosing the next token from a probability distribution. At many positions, several tokens are all perfectly fine: &lt;em&gt;team/group&lt;/em&gt;, &lt;em&gt;short/concise&lt;/em&gt;, &lt;em&gt;customer/client&lt;/em&gt;. A watermark hides inside that freedom.&lt;/p&gt;

&lt;p&gt;The classic scheme (Kirchenbauer et al.'s "green list" watermark, the family SynthID-Text belongs to) works like this:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Take a &lt;strong&gt;secret key&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;At each position, hash the key together with the recent context (say, the previous two words). The hash pseudo-randomly marks a fraction γ of the vocabulary as &lt;strong&gt;"green"&lt;/strong&gt; — a different green set at every position.&lt;/li&gt;
&lt;li&gt;When sampling, nudge generation to prefer green tokens &lt;strong&gt;when the choice doesn't matter much&lt;/strong&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;A human writer, or a model without the key, picks green tokens at the base rate γ. The watermarked model picks them far more often. Detection is then just counting:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  z = (X − γN) / sqrt(N·γ·(1−γ))
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;where N is the token count and X the green count. No access to the model needed — only the key.&lt;/p&gt;

&lt;p&gt;## A worked example you can verify&lt;/p&gt;

&lt;p&gt;Here's a toy configuration (from &lt;a href="https://github.com/gtesei/llm-watermark" rel="noopener noreferrer"&gt;WMTrace&lt;/a&gt;, the open-source workbench this post is built on): lowercase word tokens, context = previous two words, γ = 0.25, and a token is green when &lt;code&gt;CRC32(key + "|" +&lt;br&gt;
  context + "|" + token) mod 4 == 0&lt;/code&gt; under the published demo key &lt;code&gt;demo-key-172118&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Original (human-written):&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The project team reviewed the latest safety report during a quiet morning session. Members discussed the updated timeline, examined several open risks, and agreed to publish a concise summary before the next client meeting. …&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Result: 15 green out of 49 tokens. Expected under the null: 12.25. &lt;strong&gt;z = 0.91, p = 0.23.&lt;/strong&gt; Nothing.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Watermarked (same meaning, green-preferring word choices):&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The &lt;strong&gt;initiative&lt;/strong&gt; team &lt;strong&gt;examined&lt;/strong&gt; &lt;strong&gt;the&lt;/strong&gt; &lt;strong&gt;latest&lt;/strong&gt; &lt;strong&gt;safety&lt;/strong&gt; report during &lt;strong&gt;a&lt;/strong&gt; &lt;strong&gt;quiet&lt;/strong&gt; &lt;strong&gt;morning&lt;/strong&gt; meeting. &lt;strong&gt;Participants&lt;/strong&gt; &lt;strong&gt;discussed&lt;/strong&gt; &lt;strong&gt;the&lt;/strong&gt; &lt;strong&gt;current&lt;/strong&gt; timeline, &lt;strong&gt;examined&lt;/strong&gt; multiple &lt;strong&gt;outstanding&lt;/strong&gt; &lt;strong&gt;risks&lt;/strong&gt;, &lt;strong&gt;and&lt;/strong&gt;&lt;br&gt;
  &lt;strong&gt;agreed&lt;/strong&gt; &lt;strong&gt;to&lt;/strong&gt; publish &lt;strong&gt;a&lt;/strong&gt; &lt;strong&gt;concise&lt;/strong&gt; summary before the next &lt;strong&gt;client&lt;/strong&gt; &lt;strong&gt;session&lt;/strong&gt;. …&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Result: 25 green out of 49. &lt;strong&gt;z = 4.21, exact binomial p = 8.0×10⁻⁵.&lt;/strong&gt; The text reads identically to a human — but under the key, it glows.&lt;/p&gt;

&lt;p&gt;Run it yourself in four lines:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;  &lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;wmtrace.core&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;AnalysisContext&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;build&lt;/span&gt;

  &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;build&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;kgw-toy&lt;/span&gt;&lt;span class="sh"&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="nc"&gt;AnalysisContext&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;raw&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;your_text&lt;/span&gt;&lt;span class="p"&gt;)).&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;
  &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;green_tokens&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="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;usable_tokens&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;z =&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;statistic&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;p =&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;p_value&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;## Watch it light up, token by token&lt;/p&gt;

&lt;p&gt;WMTrace ships a small web UI. &lt;code&gt;pip install&lt;/code&gt; from the repo, then:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;  wmtrace serve
  &lt;span class="c"&gt;# open http://127.0.0.1:8177/?demo=1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;code&gt;?demo=1&lt;/code&gt; generates a watermarked sample under the demo key and analyzes it live — every keyed-green token highlighted, exact binomial p-values, and Holm correction across detectors:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fndd73bx182aigyrolw39.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fndd73bx182aigyrolw39.png" alt="WMTrace Analyze tab: per-token green heatmap and calibrated statistics" width="800" height="875"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The Embed tab also does two lower-tech channels that predate LLM watermarks and still show up in the wild:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Zero-width Unicode payloads&lt;/strong&gt; — bits hidden as invisible U+200B/U+200C characters. Fully invisible, trivially destroyed by normalization, and trivially forged.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Lexical codebooks&lt;/strong&gt; — synonym pairs encoding bits (&lt;em&gt;starts/begins&lt;/em&gt; = 0/1).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Both round-trip in the UI, and the Unicode inspector flags them (plus bidi controls and mixed-script confusables — useful far beyond watermarks).&lt;/p&gt;

&lt;p&gt;## What a watermark detector can and cannot tell you&lt;/p&gt;

&lt;p&gt;This is the part most coverage gets wrong, so it's baked into the tool's output format. Every result carries an evidence grade and an explicit scope statement. The rules that matter:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;A negative result does not mean a human wrote it.&lt;/strong&gt; Paraphrasing, translation, short text, or simply a different key all produce negatives.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A positive result means compatibility with a declared scheme + key + configuration.&lt;/strong&gt; Nothing more. Under a published demo key it proves nothing about any provider.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;You cannot detect Claude's or Gemini's production watermark yourself.&lt;/strong&gt; Detection requires the provider's secret key. Any tool claiming otherwise is guessing — WMTrace deliberately has no &lt;code&gt;anthropic&lt;/code&gt; detector and won't until an official
verification API exists.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Unkeyed channels (zero-width, codebooks) are evidence of &lt;em&gt;something&lt;/em&gt;, not of &lt;em&gt;someone&lt;/em&gt;.&lt;/strong&gt; Anyone can insert them, including someone trying to frame a text as AI-written.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That last point generalizes: as watermarks become policy-relevant (schools, courts, hiring), the difference between &lt;em&gt;"this text is compatible with scheme X under key K"&lt;/em&gt; and &lt;em&gt;"an AI wrote this"&lt;/em&gt; stops being pedantry and starts being due&lt;br&gt;
  process.&lt;/p&gt;

&lt;p&gt;## Try it&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/gtesei" rel="noopener noreferrer"&gt;
        gtesei
      &lt;/a&gt; / &lt;a href="https://github.com/gtesei/llm-watermark" rel="noopener noreferrer"&gt;
        llm-watermark
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Forensic detection, benchmarking, and explainable analysis of LLM text watermarks, provenance signals, and hidden-payload channels — with a live web UI
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;🔍 WMTrace&lt;/h1&gt;
&lt;/div&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Forensic detection, benchmarking, and explainable analysis of LLM text watermarks, provenance signals, and hidden-payload channels.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;WMTrace is a scheme-aware forensic workbench, not a monolithic "AI detector". It answers narrow, honest questions — &lt;em&gt;does this text carry calibrated evidence for a declared watermark scheme, key, and configuration?&lt;/em&gt; — and it states, with every result, exactly what that result does &lt;strong&gt;not&lt;/strong&gt; prove.&lt;/p&gt;

&lt;div class="markdown-alert markdown-alert-important"&gt;
&lt;p class="markdown-alert-title"&gt;Important&lt;/p&gt;
&lt;p&gt;A negative watermark result does &lt;strong&gt;not&lt;/strong&gt; mean text was human-written. A recovered payload does &lt;strong&gt;not&lt;/strong&gt; prove who embedded it. No result here supports provider attribution without trusted key provenance.&lt;/p&gt;
&lt;/div&gt;

&lt;div class="highlight highlight-source-shell notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;pip install -e &lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;.[dev]&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt;     &lt;span class="pl-c"&gt;&lt;span class="pl-c"&gt;#&lt;/span&gt; from a clone; Python 3.10+&lt;/span&gt;
wmtrace serve               &lt;span class="pl-c"&gt;&lt;span class="pl-c"&gt;#&lt;/span&gt; polished web UI at http://127.0.0.1:8177&lt;/span&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;&lt;a rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/fe6b08302e1ce06b60fdaf51d713be7093fd13cf34ffa5346a736fe0a90f51ff/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f74657374732d343125323070617373696e672d627269676874677265656e"&gt;&lt;img src="https://camo.githubusercontent.com/fe6b08302e1ce06b60fdaf51d713be7093fd13cf34ffa5346a736fe0a90f51ff/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f74657374732d343125323070617373696e672d627269676874677265656e" alt="Tests"&gt;&lt;/a&gt; &lt;a rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/35b94db23d3ed026343335f74d52ce31e74b77ad7dab4e4b89f49f2026e0937f/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f6c6963656e73652d4170616368652d2d322e302d626c7565"&gt;&lt;img src="https://camo.githubusercontent.com/35b94db23d3ed026343335f74d52ce31e74b77ad7dab4e4b89f49f2026e0937f/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f6c6963656e73652d4170616368652d2d322e302d626c7565" alt="License"&gt;&lt;/a&gt; &lt;a rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/e801a66299d2c15286fe0fee660d9ffa666c1c5576e5e1536acc07b49ce8ac8f/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f707974686f6e2d332e31302532422d626c7565"&gt;&lt;img src="https://camo.githubusercontent.com/e801a66299d2c15286fe0fee660d9ffa666c1c5576e5e1536acc07b49ce8ac8f/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f707974686f6e2d332e31302532422d626c7565" alt="Python"&gt;&lt;/a&gt;&lt;/p&gt;

  
  &lt;img alt="WMTrace web UI — Analyze tab with evidence cards, E0–E5 grade badges, exact statistics, and the per-token green heatmap" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fgtesei%2Fllm-watermark%2FHEAD%2Fdocs%2Fimages%2Fui-analyze-light.png"&gt;

&lt;p&gt;&lt;em&gt;The Analyze tab on a generated watermarked sample: summary pills per detector, calibrated statistics (z = 16.1, Holm-adjusted p = 3.5e-48), and the keyed green-token heatmap. Reproduce it locally with &lt;code&gt;wmtrace serve&lt;/code&gt; → &lt;code&gt;http://127.0.0.1:8177/?demo=1&lt;/code&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Design principles&lt;/h2&gt;
&lt;/div&gt;


&lt;ol&gt;

&lt;li&gt;

&lt;strong&gt;Evidence,&lt;/strong&gt;…&lt;/li&gt;

&lt;/ol&gt;&lt;/div&gt;
&lt;br&gt;
  &lt;/div&gt;
&lt;br&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/gtesei/llm-watermark" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;br&gt;
&lt;/div&gt;
&lt;br&gt;


&lt;p&gt;Pure Python, no ML dependencies, Apache-2.0. The worked example above isn't just prose — it's pinned by golden tests in the repo, so the numbers in this post are executable. The &lt;code&gt;docs/RESEARCH.md&lt;/code&gt; file covers the full scheme taxonomy&lt;br&gt;
  (SynthID's tournament sampling, distortion-free schemes, multi-bit payloads, C2PA provenance) and what each provider has actually deployed, with citations.&lt;/p&gt;

&lt;p&gt;Feedback very welcome — especially from anyone working on watermark robustness, multilingual calibration, or provenance standards.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>python</category>
      <category>machinelearning</category>
      <category>opensource</category>
    </item>
    <item>
      <title>I sketched 29 agentic AI design patterns in a Da Vinci–style notebook (open source)</title>
      <dc:creator>isaac</dc:creator>
      <pubDate>Sun, 31 May 2026 20:56:18 +0000</pubDate>
      <link>https://dev.to/gtesei/i-sketched-29-agentic-ai-design-patterns-in-a-da-vinci-style-notebook-open-source-14o7</link>
      <guid>https://dev.to/gtesei/i-sketched-29-agentic-ai-design-patterns-in-a-da-vinci-style-notebook-open-source-14o7</guid>
      <description>&lt;p&gt;Spent the weekend turning every pattern in my agentic_design_patterns repo into a hand-drawn style diagram, using a sepia/parchment “bozza-scientifica” aesthetic — closer to a Leonardo da Vinci notebook page than a typical slide-style flowchart.&lt;/p&gt;

&lt;p&gt;Repo: &lt;a href="https://github.com/gtesei/agentic_design_patterns" rel="noopener noreferrer"&gt;https://github.com/gtesei/agentic_design_patterns&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Curious to hear feedback. &lt;/p&gt;

</description>
      <category>ai</category>
      <category>opensource</category>
      <category>marmaid</category>
      <category>agents</category>
    </item>
    <item>
      <title>Turning OpenAPI Specs into Runtime LLM Tools in Pi</title>
      <dc:creator>isaac</dc:creator>
      <pubDate>Thu, 14 May 2026 03:12:34 +0000</pubDate>
      <link>https://dev.to/gtesei/turning-openapi-specs-into-runtime-llm-tools-in-pi-6n9</link>
      <guid>https://dev.to/gtesei/turning-openapi-specs-into-runtime-llm-tools-in-pi-6n9</guid>
      <description>&lt;p&gt;I built &lt;a href="https://github.com/gtesei/pi-openapi-tools?utm_source=chatgpt.com" rel="noopener noreferrer"&gt;pi-openapi-tools&lt;/a&gt; — a Pi extension that ingests an OpenAPI/Swagger spec and dynamically registers one callable tool per API operation.&lt;/p&gt;

&lt;p&gt;Instead of hand-writing wrappers for every endpoint, you point Pi at a spec URL and immediately start calling generated tools.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;npm: &lt;a href="https://www.npmjs.com/package/pi-openapi-tools?utm_source=chatgpt.com" rel="noopener noreferrer"&gt;pi-openapi-tools on npm&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Pi package: &lt;a href="https://pi.dev/packages/pi-openapi-tools?utm_source=chatgpt.com" rel="noopener noreferrer"&gt;pi-openapi-tools on Pi&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;GitHub: &lt;a href="https://github.com/gtesei/pi-openapi-tools?utm_source=chatgpt.com" rel="noopener noreferrer"&gt;Repository&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;Why I built this&lt;/p&gt;

&lt;p&gt;Most API-agent integrations still require too much manual glue:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;mapping endpoints to functions&lt;/li&gt;
&lt;li&gt;defining parameter schemas&lt;/li&gt;
&lt;li&gt;maintaining naming consistency&lt;/li&gt;
&lt;li&gt;wiring auth/token handling&lt;/li&gt;
&lt;li&gt;repeating the same setup for every API&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That friction slows experimentation and makes agent tooling brittle.&lt;/p&gt;

&lt;p&gt;I wanted a runtime-first workflow:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;spec → generated tools → live API calls&lt;/strong&gt;&lt;/p&gt;




&lt;p&gt;What the extension does&lt;/p&gt;

&lt;p&gt;Given an OpenAPI or Swagger URL, pi-openapi-tools:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;generates one Pi tool per operation&lt;/li&gt;
&lt;li&gt;supports Swagger 2.0 and OpenAPI 3.x&lt;/li&gt;
&lt;li&gt;builds structured parameter schemas automatically&lt;/li&gt;
&lt;li&gt;resolves request bodies by declared media/content type&lt;/li&gt;
&lt;li&gt;handles path, query, and header parameters&lt;/li&gt;
&lt;li&gt;adds slash commands for managing generated toolsets&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It also includes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;prefix-scoped registrations (&lt;code&gt;/swagger-tools:list-prefixes&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;prefix cleanup (&lt;code&gt;/swagger-tools:remove-prefix&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;tool inspection (&lt;code&gt;/swagger-tools:describe&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;token/auth helpers (&lt;code&gt;/swagger-tools:auth&lt;/code&gt;)&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;60-second quickstart&lt;/p&gt;

&lt;p&gt;Install:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pi &lt;span class="nb"&gt;install &lt;/span&gt;npm:pi-openapi-tools
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Generate tools from Petstore:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/swagger-tools https://petstore.swagger.io/v2/swagger.json --prefix pet
/swagger-tools:list
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You’ll get generated tools like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;pet_getstoreorderbyid&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;pet_postuser&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;etc.&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;Implementation details that mattered&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Prefix-scoped additive registration&lt;br&gt;
Multiple API toolsets can coexist cleanly.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Stable naming + collision-safe dedupe&lt;br&gt;
Generated names are sanitized and safely deduplicated.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;No unregister API in Pi? Stub instead.&lt;br&gt;
Removed tools become non-executable guidance stubs rather than silently disappearing.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Content-type-aware serialization&lt;br&gt;
Request body handling follows declared media types (JSON, multipart, urlencoded, text, etc.).&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;Docs + walkthrough&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Tutorial: &lt;a href="https://github.com/gtesei/pi-openapi-tools/blob/main/docs/swagger-petstore-tutorial.md?utm_source=chatgpt.com" rel="noopener noreferrer"&gt;Petstore walkthrough&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Repo: &lt;a href="https://github.com/gtesei/pi-openapi-tools?utm_source=chatgpt.com" rel="noopener noreferrer"&gt;GitHub repository&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;If you try it on large or messy specs, I’d especially love feedback on:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;naming ergonomics&lt;/li&gt;
&lt;li&gt;auth edge cases&lt;/li&gt;
&lt;li&gt;request body/media handling&lt;/li&gt;
&lt;li&gt;discoverability in very large APIs&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If this is useful, feel free to star the repo and share your API use case.&lt;/p&gt;

</description>
    </item>
  </channel>
</rss>
