<?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: Ofekv</title>
    <description>The latest articles on DEV Community by Ofekv (@grloper).</description>
    <link>https://dev.to/grloper</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%2F3562478%2Faf654072-81a0-4f60-94aa-90da4693723c.png</url>
      <title>DEV Community: Ofekv</title>
      <link>https://dev.to/grloper</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/grloper"/>
    <language>en</language>
    <item>
      <title>Your AI agent says "done". Here is what I check before I believe it</title>
      <dc:creator>Ofekv</dc:creator>
      <pubDate>Wed, 04 Nov 2026 08:13:48 +0000</pubDate>
      <link>https://dev.to/grloper/your-ai-agent-says-done-here-is-what-i-check-before-i-believe-it-48gi</link>
      <guid>https://dev.to/grloper/your-ai-agent-says-done-here-is-what-i-check-before-i-believe-it-48gi</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;⭐ &lt;strong&gt;GitHub: &lt;a href="https://github.com/grloper/plumbgraph" rel="noopener noreferrer"&gt;github.com/grloper/plumbgraph&lt;/a&gt;&lt;/strong&gt; · open source (Apache-2.0) · by &lt;a href="https://github.com/grloper" rel="noopener noreferrer"&gt;@grloper&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&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/grloper" rel="noopener noreferrer"&gt;
        grloper
      &lt;/a&gt; / &lt;a href="https://github.com/grloper/plumbgraph" rel="noopener noreferrer"&gt;
        plumbgraph
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Local code intelligence and a pre-submit verification gate for AI coding agents: dead code, hallucinated dependencies, weakened tests. CLI + MCP.
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;&lt;p&gt;&lt;a rel="noopener noreferrer" href="https://github.com/grloper/plumbgraph/assets/logo.svg"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fgrloper%2Fplumbgraph%2FHEAD%2Fassets%2Flogo.svg" width="112" alt="Plumbgraph logo: a plumb line through a small code graph"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;Plumbgraph&lt;/h1&gt;
&lt;/div&gt;
&lt;p&gt;&lt;b&gt;Know your code. Verify the change.&lt;/b&gt;&lt;br&gt;
Local code intelligence and a pre-submit gate for AI coding agents, over CLI and MCP.&lt;/p&gt;
&lt;p&gt;
&lt;a href="https://github.com/grloper/plumbgraph/actions/workflows/ci.yml" rel="noopener noreferrer"&gt;&lt;img src="https://github.com/grloper/plumbgraph/actions/workflows/ci.yml/badge.svg?branch=main" alt="CI"&gt;&lt;/a&gt;
&lt;a href="https://github.com/grloper/plumbgraph/LICENSE" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/35b94db23d3ed026343335f74d52ce31e74b77ad7dab4e4b89f49f2026e0937f/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f6c6963656e73652d4170616368652d2d322e302d626c7565" alt="License: Apache-2.0"&gt;&lt;/a&gt;
&lt;a href="https://github.com/grloper/plumbgraph/releases/latest" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/f9a404da901e826bba04232f6382bcc5b159a0efa8044e0254f290356d377fd0/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f762f72656c656173652f67726c6f7065722f706c756d6267726170683f6c6162656c3d72656c65617365" alt="Latest release"&gt;&lt;/a&gt;
&lt;a rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/84323ffd21f08ec9ece6d602feb6716e5b2f2930fe17d1101a5237b8b030cda2/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f727573742d312e38352532422d6f72616e67653f6c6f676f3d72757374"&gt;&lt;img src="https://camo.githubusercontent.com/84323ffd21f08ec9ece6d602feb6716e5b2f2930fe17d1101a5237b8b030cda2/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f727573742d312e38352532422d6f72616e67653f6c6f676f3d72757374" alt="Rust 1.85+"&gt;&lt;/a&gt;
&lt;a rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/b32512d234bad0b4be24ad72932a3f5f02d40600867b6bf2abd2026f2acf3533/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f4d43502d737464696f2d354235424436"&gt;&lt;img src="https://camo.githubusercontent.com/b32512d234bad0b4be24ad72932a3f5f02d40600867b6bf2abd2026f2acf3533/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f4d43502d737464696f2d354235424436" alt="MCP over stdio"&gt;&lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;&lt;a rel="noopener noreferrer" href="https://github.com/grloper/plumbgraph/docs/demo/verify.svg"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fgrloper%2Fplumbgraph%2FHEAD%2Fdocs%2Fdemo%2Fverify.svg" alt="Terminal recording of `plumb verify --run --online` on the demo app: a hallucinated import, an unused function, an eval() and a print() are reported; verdict FAIL" width="860"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Real output of &lt;code&gt;plumb verify&lt;/code&gt; on &lt;a href="https://github.com/grloper/plumbgraph/examples/demo-app" rel="noopener noreferrer"&gt;examples/demo-app&lt;/a&gt; (captured by &lt;code&gt;scripts/render-demo.py&lt;/code&gt;; raw text in &lt;a href="https://github.com/grloper/plumbgraph/docs/demo/verify.txt" rel="noopener noreferrer"&gt;docs/demo/verify.txt&lt;/a&gt;).&lt;/p&gt;

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

&lt;p&gt;AI agents write code fast and check it badly. Plumbgraph answers the questions an agent should ask &lt;strong&gt;before&lt;/strong&gt; it says "done", and says how sure it is:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Is this code used?&lt;/strong&gt; &lt;code&gt;dead-code&lt;/code&gt;, with reachability evidence and false-positive risks.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Is this dependency real?&lt;/strong&gt; &lt;code&gt;check-deps&lt;/code&gt; compares imports with your manifests and, optionally, PyPI / npm / crates.io, so a hallucinated package is caught.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Did the tests get weaker?&lt;/strong&gt; &lt;code&gt;weakening&lt;/code&gt; reads &lt;code&gt;git diff&lt;/code&gt; for deleted tests, new skips and loosened assertions.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;What breaks if I change this?&lt;/strong&gt; &lt;code&gt;impact&lt;/code&gt; lists transitive callers and the tests to run; &lt;code&gt;map&lt;/code&gt; gives a token-budgeted overview.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;One verdict.&lt;/strong&gt; &lt;code&gt;verify&lt;/code&gt; merges all of that with diagnostics, semgrep and ast-grep…&lt;/li&gt;
&lt;/ul&gt;&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/grloper/plumbgraph" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&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%2Flme8ccnublwg3yk9dhs9.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%2Flme8ccnublwg3yk9dhs9.png" alt="Plumbgraph: Know your code. Verify the change. CLI + MCP server, fails closed, runs no code by default, Apache-2.0" width="800" height="250"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;AI coding agents write code quickly and verify it badly. After a few months of watching them work on my own projects, the same three failures kept turning up, and none of them are caught by "the tests pass". So I built a small open-source tool, Plumbgraph, that checks them on the diff before the agent is allowed to say it is done.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fbx5qp7jbo8j6ie6pbe37.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fbx5qp7jbo8j6ie6pbe37.gif" alt="Animated terminal: plumb map, plumb impact, then plumb verify passing on a clean copy and failing after a simulated agent edit" width="800" height="847"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Real output of &lt;code&gt;plumb 1.1.0&lt;/code&gt; (built from the v1.1.0 tag) on a throwaway copy of the Python CLI of my other project, PlayGoblin: 35 Python files. The clean copy passes. Then I made an edit by hand that imitates an agent (a fake import, an unused helper, a skip marker, a deleted assertion) and &lt;code&gt;plumb verify&lt;/code&gt; fails. The edit is simulated by me; the output is not. The GIF is a replay of captured text, and long lines are cut in the picture; the verbatim output is in &lt;a href="https://github.com/grloper/plumbgraph/blob/main/docs/media/demo-output.txt" rel="noopener noreferrer"&gt;&lt;code&gt;docs/media/demo-output.txt&lt;/code&gt;&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  The three failures
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Packages that do not exist.&lt;/strong&gt; The agent imports something plausible and the install fails, or worse, someone registers the name later. A USENIX Security 2025 study cited in the repo's &lt;code&gt;docs/STRATEGY.md&lt;/code&gt; reported that 19.7% of package recommendations from 16 models were hallucinated; I have not reproduced that number, I just find it reason enough to check.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Tests that got weaker.&lt;/strong&gt; Deleted tests, new skips, loosened assertions. The suite is green because the suite shrank. A diff-level check catches this subset of test tampering (not every kind, for example special-casing inputs).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Code nothing calls.&lt;/strong&gt; Agents add helpers and forget them.&lt;/p&gt;
&lt;h3&gt;
  
  
  What Plumbgraph does
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;plumb&lt;/code&gt; indexes your repo with tree-sitter into a local SQLite file (Python, JS/TS, Rust, Go, Java, C#). It executes none of your code by default. Every result carries a &lt;code&gt;source&lt;/code&gt; and a &lt;code&gt;confidence&lt;/code&gt;, so an agent (or you) can tell a guess from compiler-grade evidence.&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%2F854ci01i6ktl53c7wh43.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%2F854ci01i6ktl53c7wh43.png" alt="Architecture: source files and an optional SCIP index feed a SQLite graph; manifests, git diff and opt-in tools feed the other checks; verify diffs against a baseline and returns pass, fail or incomplete" width="800" height="390"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;check-deps&lt;/code&gt;: imports vs your manifests, and with &lt;code&gt;--online&lt;/code&gt;, against PyPI, npm and crates.io. Registry errors are never reported as "does not exist".&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;weakening&lt;/code&gt;: reads &lt;code&gt;git diff&lt;/code&gt; for deleted tests, new skips and loosened assertions. On seeded commits it flagged 12/12 on Python, JS, Rust, Go and C# with 0 of 3 benign changes flagged per repo. I seeded those myself, so read that as a regression check, not a benchmark.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;dead-code&lt;/code&gt;: reachability from entry points and tests, with evidence and false-positive risks per finding.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;map&lt;/code&gt; and &lt;code&gt;impact&lt;/code&gt;: a PageRank-ranked overview under a hard token budget, and transitive callers plus the tests to run.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;verify&lt;/code&gt;: merges all of it (plus diagnostics, semgrep and ast-grep with &lt;code&gt;--run&lt;/code&gt;), diffs against a baseline so only new findings count, and returns one verdict.&lt;/li&gt;
&lt;/ul&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%2Fsa2ahww6udoexcd4uod2.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%2Fsa2ahww6udoexcd4uod2.png" alt="plumb verify failing after the simulated agent edit: unused function, skip marker, a package that returns 404 on PyPI, one fewer assertion; verdict FAIL" width="800" height="706"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The four findings above are what the tool printed for my simulated edit, each with a &lt;code&gt;why:&lt;/code&gt; and a &lt;code&gt;risk:&lt;/code&gt; line. The &lt;code&gt;risk:&lt;/code&gt; lines matter: the skip marker could be a legitimate platform skip, and a Python import name can differ from its package name. The tool says so instead of pretending to be sure.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;map&lt;/code&gt; and &lt;code&gt;impact&lt;/code&gt; are the other half, the part an agent uses before it edits. On the same copy, &lt;code&gt;plumb impact load_run&lt;/code&gt; lists 68 affected symbols across 11 files and the six test files to run, each edge with a confidence that drops with distance:&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%2F0ba4duuh933o59wmdu62.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%2F0ba4duuh933o59wmdu62.png" alt="plumb map under a 300 token budget, then plumb impact load_run showing callers and tests to run" width="800" height="857"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  A gate that fails closed
&lt;/h3&gt;

&lt;p&gt;The verdict is the part I spent the most time on. &lt;code&gt;pass&lt;/code&gt; means the selected checks completed and nothing new met its threshold. &lt;code&gt;fail&lt;/code&gt; means new enforcing findings. &lt;code&gt;incomplete&lt;/code&gt; means a required check failed, timed out or could not run, or the Git base is missing; it never passes. Dead code is advisory by default because an index cannot prove an external caller, reflection or safe deletion. It is a gate over the checks you selected, not proof the change is correct. In the clean run of the demo, two optional checks were skipped, and the output says so rather than counting them as passed.&lt;/p&gt;

&lt;p&gt;For MCP, an &lt;code&gt;isError: false&lt;/code&gt; response is not a pass: you must check &lt;code&gt;data.verdict == "pass"&lt;/code&gt;. And the agent cannot grant itself powers: running external tools needs &lt;code&gt;--allow-exec&lt;/code&gt; and writing baselines needs &lt;code&gt;--allow-baseline-update&lt;/code&gt;, both set by the operator when the server starts. Results are marked &lt;code&gt;untrusted: true&lt;/code&gt;, because text from repository files is data, never instructions.&lt;/p&gt;

&lt;h3&gt;
  
  
  Quickstart
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/grloper/plumbgraph &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;cd &lt;/span&gt;plumbgraph
git checkout v1.1.0
cargo &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--path&lt;/span&gt; crates/cli &lt;span class="nt"&gt;--locked&lt;/span&gt;      &lt;span class="c"&gt;# Rust 1.85+; installs `plumb`&lt;/span&gt;

plumb map &lt;span class="nb"&gt;.&lt;/span&gt; &lt;span class="nt"&gt;--tokens&lt;/span&gt; 1500
plumb check-deps &lt;span class="nb"&gt;.&lt;/span&gt; &lt;span class="nt"&gt;--online&lt;/span&gt;                   &lt;span class="c"&gt;# sends package names only&lt;/span&gt;
plumb verify &lt;span class="nb"&gt;.&lt;/span&gt;                                &lt;span class="c"&gt;# needs a Git base&lt;/span&gt;
claude mcp add plumbgraph &lt;span class="nt"&gt;--&lt;/span&gt; plumb mcp &lt;span class="nt"&gt;--root&lt;/span&gt; /path/to/project
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;plumb init --dry-run&lt;/code&gt; previews the AGENTS.md block and MCP config it would write. The AGENTS.md block is deliberately minimal: a study cited in the docs found verbose context files can reduce agent success and raise cost.&lt;/p&gt;

&lt;p&gt;For this article I built it again on a Windows machine with the GNU toolchain. It needed a MinGW &lt;code&gt;gcc&lt;/code&gt; on &lt;code&gt;PATH&lt;/code&gt; (the &lt;code&gt;ring&lt;/code&gt; crate failed to compile without it), and it then built in about a minute.&lt;/p&gt;

&lt;h3&gt;
  
  
  What real repos taught me
&lt;/h3&gt;

&lt;p&gt;I ran it on requests, express, ripgrep, cobra, gson, Newtonsoft.Json, kubernetes and VS Code. The first version took 640 s to index kubernetes and ran out of memory on later commands; after fixes (PR #14: edge dedup, an ambiguity cap, a resolver fix), the index takes 41 s and commands finish in 6-13 s on a 16 GB Linux box. Running it on one of my own Unity projects exposed false positives (Unity message methods on partial classes), which are fixed in v1.0.3. Using v1.0.0 on Windows showed that every provider was reported missing because lookup ignored &lt;code&gt;.exe&lt;/code&gt; and &lt;code&gt;.cmd&lt;/code&gt;. None of that shows up on toy fixtures.&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%2Flyh1mt8vf1cbtl07gas9.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%2Flyh1mt8vf1cbtl07gas9.png" alt="Left: cold index time on five small repos, 0.11 s to 0.55 s. Right: kubernetes index time 640 s before the fix and 41 s after" width="800" height="360"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Left: &lt;code&gt;docs/bench/results-2026-10-10.json&lt;/code&gt;, measured by &lt;code&gt;scripts/bench.py&lt;/code&gt; with an older build (plumb 0.2.0) on an 8-CPU Linux machine, one run per repo. Right: &lt;code&gt;docs/VALIDATION.md&lt;/code&gt;. These are not comparisons with other tools, and I have not measured any other tool.&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Honest limits
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Without a SCIP index the analysis is name-based: no types, and common names give lower-confidence edges.&lt;/li&gt;
&lt;li&gt;Dead-code precision on libraries in the default app mode is low (use &lt;code&gt;--lib&lt;/code&gt;). A hand review of 76 findings on chi and gson found 1 real unused function. Recall is unmeasured on real code.&lt;/li&gt;
&lt;li&gt;Reflection, &lt;code&gt;eval&lt;/code&gt;, DI containers and macros are invisible.&lt;/li&gt;
&lt;li&gt;MCP: stdio only. I tested with the official TypeScript SDK, the inspector CLI and one agent host on Windows. I have not tested Claude Code, Cursor or Codex end to end.&lt;/li&gt;
&lt;li&gt;Windows was exercised by hand on one machine and CI is Linux only. There are no prebuilt binaries and no crates.io package.&lt;/li&gt;
&lt;li&gt;I have not run an experiment showing that the tool improves agent outcomes on real tasks. I make no claim about that.&lt;/li&gt;
&lt;li&gt;The demo edit above is a hand-made imitation of an agent, on a small repo. It shows what the checks print, not how often real agents make these mistakes.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Try it, and help
&lt;/h3&gt;

&lt;p&gt;Run &lt;code&gt;plumb verify .&lt;/code&gt; on a branch an agent wrote and tell me what it got wrong: false positives, false negatives, and anything that breaks in Claude Code, Cursor or Codex. Issue templates for bugs and false positives are in the repo: &lt;a href="https://github.com/grloper/plumbgraph" rel="noopener noreferrer"&gt;github.com/grloper/plumbgraph&lt;/a&gt;. Packaging (prebuilt binaries, crates.io) and more SCIP indexers are the obvious contributions.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>opensource</category>
      <category>rust</category>
      <category>mcp</category>
    </item>
    <item>
      <title>I built a bot that plays my Unreal game and files the bugs</title>
      <dc:creator>Ofekv</dc:creator>
      <pubDate>Wed, 04 Nov 2026 06:50:42 +0000</pubDate>
      <link>https://dev.to/grloper/i-built-a-bot-that-plays-my-unreal-game-and-files-the-bugs-45he</link>
      <guid>https://dev.to/grloper/i-built-a-bot-that-plays-my-unreal-game-and-files-the-bugs-45he</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;⭐ &lt;strong&gt;GitHub: &lt;a href="https://github.com/grloper/playgoblin" rel="noopener noreferrer"&gt;github.com/grloper/playgoblin&lt;/a&gt;&lt;/strong&gt; · open source (Apache-2.0) · by &lt;a href="https://github.com/grloper" rel="noopener noreferrer"&gt;@grloper&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&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/grloper" rel="noopener noreferrer"&gt;
        grloper
      &lt;/a&gt; / &lt;a href="https://github.com/grloper/playgoblin" rel="noopener noreferrer"&gt;
        playgoblin
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      A goblin plays your game overnight and files the bugs it breaks. Open-source QA bot for Unity, Unreal and any engine, with an MCP server for AI agents.
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;&lt;p&gt;&lt;a rel="noopener noreferrer" href="https://github.com/grloper/playgoblin/docs/media/logo.png"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fgrloper%2Fplaygoblin%2FHEAD%2Fdocs%2Fmedia%2Flogo.png" alt="PlayGoblin logo" width="120"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;PlayGoblin&lt;/h1&gt;
&lt;/div&gt;
&lt;p&gt;&lt;b&gt;An open-source QA bot that plays your game like a person and files the bugs with evidence.&lt;/b&gt;&lt;br&gt;
Unity, Unreal, or any engine that can write a log file. Deterministic checks, no LLM in the loop, no account.&lt;/p&gt;
&lt;p&gt;&lt;a rel="noopener noreferrer" href="https://github.com/grloper/playgoblin/docs/media/demo.gif"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fgrloper%2Fplaygoblin%2FHEAD%2Fdocs%2Fmedia%2Fdemo.gif" alt="A real PlayGoblin run on an Unreal Engine 5.8 game, with a status overlay of time, waypoints, coverage and stuck events" width="720"&gt;&lt;/a&gt;&lt;br&gt;A real 150 s run on a UE 5.8 game (3x time-lapse of seconds 19-52, overlay added). Full run: 251 m walked, 19 waypoints, 12.0% coverage, 1 confirmed and 12 unconfirmed stuck spots.&lt;/p&gt;
&lt;p&gt;
&lt;a href="https://github.com/grloper/playgoblin/actions/workflows/ci.yml" rel="noopener noreferrer"&gt;&lt;img alt="CI" src="https://github.com/grloper/playgoblin/actions/workflows/ci.yml/badge.svg"&gt;&lt;/a&gt;
&lt;a href="https://github.com/grloper/playgoblin/LICENSE" rel="noopener noreferrer"&gt;&lt;img alt="License: Apache-2.0" src="https://camo.githubusercontent.com/35b94db23d3ed026343335f74d52ce31e74b77ad7dab4e4b89f49f2026e0937f/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f6c6963656e73652d4170616368652d2d322e302d626c7565"&gt;&lt;/a&gt;
&lt;a rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/96abf9b704f80578ea56dd10cab0d911c56d46dbec347f431ece9cf60ac175ad/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f707974686f6e2d332e31312532422d626c7565"&gt;&lt;img alt="Python 3.11+" src="https://camo.githubusercontent.com/96abf9b704f80578ea56dd10cab0d911c56d46dbec347f431ece9cf60ac175ad/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f707974686f6e2d332e31312532422d626c7565"&gt;&lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;
&lt;a rel="noopener noreferrer" href="https://github.com/grloper/playgoblin/docs/media/uyf-run-frame.jpg"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fgrloper%2Fplaygoblin%2FHEAD%2Fdocs%2Fmedia%2Fuyf-run-frame.jpg" alt="A frame captured by PlayGoblin while walking the town level of an Unreal Engine 5.8 game" width="720"&gt;&lt;/a&gt;&lt;br&gt;
A frame PlayGoblin captured while walking the town level of a real Unreal Engine 5.8 game (Use Your Friends). Frames and clips like this are attached to findings.
&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Status: pre-release (0.1.0-dev).&lt;/strong&gt; Works on Unity 6000.4, and on Unreal 5.8.3 (Win64) with a sample project and one real game
Expect rough edges. See &lt;a href="https://github.com/grloper/playgoblin#status" rel="noopener noreferrer"&gt;Status&lt;/a&gt; for exactly what has and has not been verified.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;What it catches&lt;/h2&gt;
&lt;/div&gt;

&lt;p&gt;These come from real runs, not mock-ups. Most were found by running on a…&lt;/p&gt;&lt;/div&gt;


&lt;/div&gt;
&lt;br&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/grloper/playgoblin" 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;&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%2Fxoo3y3i3cvxeyox23sz1.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%2Fxoo3y3i3cvxeyox23sz1.png" alt="PlayGoblin" width="800" height="250"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I'm making an indie game in Unreal Engine 5.8, and like most solo developers I have a testing problem: nobody walks the whole game after every change. I do it for ten minutes, see nothing wrong, and ship the build. So I wrote a bot to do the boring part, and I'm releasing it as open source. It is called PlayGoblin, and it is pre-release (0.1.0-dev), so please read the limits section before you get excited.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fgkpy1l9sytf6zpmdn2f8.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fgkpy1l9sytf6zpmdn2f8.gif" alt="A real 150 s PlayGoblin run on the town level of Use Your Friends, shown as a time-lapse with a status overlay of time, waypoints, coverage and stuck events" width="560" height="315"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;A real 150 s run on my game, shown as a 3x time-lapse of seconds 19 to 52 (overlay added by me). The full run walked 251 m and reached 19 waypoints, but covered only 12.0% of the 1137 walkable cells; it logged 1 confirmed and 12 unconfirmed stuck spots. Coverage in the overlay is derived from sampled positions. The goblin is not a speedrunner yet.&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  The problem
&lt;/h3&gt;

&lt;p&gt;Unit tests check what you thought to assert. Recorded input replays only cover the path you recorded and break when the level changes. Manual QA is great, but it does not run at 3 a.m. after every commit. The gap I care about is "nobody walked there": a stuck spot behind a prop, a fall through a missing collision, a menu button wired to nothing, a TODO that made it into a title screen.&lt;/p&gt;

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

&lt;p&gt;An engine-side component walks the game and writes a plain run folder: &lt;code&gt;events.jsonl&lt;/code&gt; plus a summary. A Python CLI reads that folder and produces findings, an HTML report, and optionally GitHub issues. Each finding has evidence, meaning an event, a frame, or a log line. If the bot cannot show it, it does not report it.&lt;/p&gt;

&lt;p&gt;There are engine sides for Unity (6000.4 tested) and Unreal (5.8.3 Win64 tested). Any other engine that can write the run-folder format (documented in &lt;code&gt;docs/PROTOCOL.md&lt;/code&gt;) gets the same checks and reports. I tested that with a fake Godot-style run, not a real Godot game.&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%2F30v7oaqp0p8nd85h0d4y.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%2F30v7oaqp0p8nd85h0d4y.png" alt="PlayGoblin pipeline: game writes a run folder, deterministic checks produce report.html, findings.json and GitHub issues; optional MCP server and Claude Code skill for agents" width="800" height="380"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  The bugs it found on my game
&lt;/h3&gt;

&lt;p&gt;I ran it on my Unreal game this week. Three results are worth telling honestly.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The player could not move.&lt;/strong&gt; The game had no input bound to move the pawn. The bot, which reads the game's own key and axis bindings and presses the keys that should move the player, never left the spawn point and reported "The player never moved" as critical.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A bug in the bot, found by the game.&lt;/strong&gt; My game has a level-sized invisible blocking volume. It hid the ground from every floor probe, so the bot saw nothing walkable. That was a bug in PlayGoblin, not in the game, and the fix is that the bot now skips actors it starts inside and logs them. Real games are weirder than sample projects, and this is why I am asking for run folders from yours.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Grey-box look.&lt;/strong&gt; It lists visible actors still using &lt;code&gt;/Engine/BasicShapes&lt;/code&gt; meshes or the engine grid material and reports each as "Prototype look". It is a cheap way to see how much of a level is still placeholder art.&lt;/p&gt;

&lt;p&gt;On the Unreal sample project, which has bugs I planted, it also finds a UMG "Options" button that does nothing and menu text reading "TODO: title". Another false positive taught me something: it flagged a pastel-pink game as missing-material pink. Now only pure magenta counts.&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%2Feuu5chnwqwv93xw13jv4.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%2Feuu5chnwqwv93xw13jv4.png" alt="Findings PlayGoblin caught on a real Unreal Engine 5.8 game and a sample project, with severity and source chips" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

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

&lt;p&gt;&lt;strong&gt;It plays through real input.&lt;/strong&gt; In key mode (&lt;code&gt;-PlayGoblinKeys&lt;/code&gt;) it presses the game's bound keys, turns with simulated mouse movement rather than setting the camera, taps action keys at irregular intervals, and tries a jump when stuck. If nothing moves the player, or the mouse does nothing after repeated probes, that is itself a finding (&lt;code&gt;dead_input&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;It crawls UMG menus.&lt;/strong&gt; About every two seconds it finds visible widgets, reports placeholder text, and clicks each enabled button once. A button is dead if nothing observable changed within a second.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;It explores on purpose.&lt;/strong&gt; Instead of random destinations it heads for the nearest unvisited ground next to what it has already seen. On the sample project, same seed and 150 seconds, coverage went from 34% to 73% on one level and from 48% to 93% on the other. Every report prints coverage.&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%2Fu80aso8ceiitj3oix4yg.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%2Fu80aso8ceiitj3oix4yg.png" alt="Bar chart: coverage on the broken level 33.8% to 72.5%, on the clean level 47.5% to 92.8%, same seed, 150 s, sample project" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The checks have no LLM in them.&lt;/strong&gt; Each check is a pure function: run folder in, findings out. The same events give the same findings every time, and there are 62 Python tests. A stuck spot only counts as confirmed once it repeats, so one unlucky run does not file a fake bug. An LLM can optionally write a summary paragraph, labelled as such.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Agents can drive it.&lt;/strong&gt; There is an MCP server (&lt;code&gt;playgoblin mcp&lt;/code&gt;) with five tools: status, run, report, findings and file_issues. The repo is also a Claude Code plugin with a skill that teaches an agent when to run it and how to read confidence. Filing GitHub issues is a dry run unless you explicitly confirm.&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%2Fv8e5f7iv2buyne6l92pt.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%2Fv8e5f7iv2buyne6l92pt.png" alt="A real PlayGoblin HTML report" width="800" height="978"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;The HTML report: each finding links to its evidence.&lt;/em&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Quickstart
&lt;/h3&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; &lt;span class="s2"&gt;"git+https://github.com/grloper/playgoblin#subdirectory=cli"&lt;/span&gt;   &lt;span class="c"&gt;# Python 3.11+&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Unreal: copy &lt;code&gt;unreal/PlayGoblin&lt;/code&gt; into your project's &lt;code&gt;Plugins/&lt;/code&gt; and launch the game with the flag:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;UnrealEditor-Cmd.exe MyGame.uproject &lt;span class="nt"&gt;-game&lt;/span&gt; &lt;span class="nt"&gt;-playgoblin&lt;/span&gt; &lt;span class="nt"&gt;-PlayGoblinSeconds&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;300 &lt;span class="nt"&gt;-PlayGoblinSeed&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;1 &lt;span class="nt"&gt;-PlayGoblinOut&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;D:/runs &lt;span class="nt"&gt;-PlayGoblinExit&lt;/span&gt;
playgoblin report D:/runs/&amp;lt;run &lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;     &lt;span class="c"&gt;# report.html, report.md, findings.json&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Unity: add the package from &lt;code&gt;https://github.com/grloper/playgoblin.git?path=/unity&lt;/code&gt;, put the PlayGoblin Player component on your player, press Play, then &lt;code&gt;playgoblin run --minutes 10 --runs 3&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The plugin does nothing unless &lt;code&gt;-playgoblin&lt;/code&gt; is on the command line, so shipping with it enabled is harmless.&lt;/p&gt;

&lt;h3&gt;
  
  
  Honest limits
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;It is pre-release. Unity 6000.4 and Unreal 5.8.3 on Win64 are the only tested combinations.&lt;/li&gt;
&lt;li&gt;Accuracy on real games is not measured. My samples were written by the people who wrote the checks, so treat them as regression tests. The Unreal plugin passed its sample (all 5 planted bugs, nothing on the clean twin) on one seed and one machine.&lt;/li&gt;
&lt;li&gt;UMG buttons are clicked by broadcasting &lt;code&gt;OnClicked&lt;/code&gt;, so Slate hit testing is not exercised; Enhanced-Input-driven and CommonUI-only menus are not covered.&lt;/li&gt;
&lt;li&gt;It walks and clicks. It does not judge fun, balance, visuals or audio, and "no findings" never means bug free.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Try it, and help
&lt;/h3&gt;

&lt;p&gt;The most useful contribution right now is running it on a game and telling me what it missed or got wrong, with the run folder attached. Open an issue at &lt;a href="https://github.com/grloper/playgoblin" rel="noopener noreferrer"&gt;https://github.com/grloper/playgoblin&lt;/a&gt;. Roadmap items: more real-game runs with published precision numbers, other Unreal versions and Enhanced Input, Unity UI Toolkit and player builds, and a GitHub Action. If you build for another engine, the run-folder format is short; a writer for it is a good first contribution.&lt;/p&gt;

</description>
      <category>gamedev</category>
      <category>opensource</category>
      <category>unrealengine</category>
      <category>testing</category>
    </item>
    <item>
      <title>Supercharging DeepSeek Harness: Bringing Claude Pro/Max with One-Click Google/Gmail OAuth Login and Real-Time Quota Tracking</title>
      <dc:creator>Ofekv</dc:creator>
      <pubDate>Sun, 06 Sep 2026 11:01:15 +0000</pubDate>
      <link>https://dev.to/grloper/supercharging-deepseek-harness-bringing-claude-promax-with-one-click-googlegmail-oauth-login-and-253d</link>
      <guid>https://dev.to/grloper/supercharging-deepseek-harness-bringing-claude-promax-with-one-click-googlegmail-oauth-login-and-253d</guid>
      <description>&lt;p&gt;&lt;em&gt;By **grloper&lt;/em&gt;* (&lt;a href="https://github.com/grloper" rel="noopener noreferrer"&gt;GitHub @grloper&lt;/a&gt;)*&lt;/p&gt;




&lt;h2&gt;
  
  
  1. Introduction: The Subscription Dilemma in Modern Agent Frameworks
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/deepseek-ai/deepseek-harness" rel="noopener noreferrer"&gt;DeepSeek Harness (DSH)&lt;/a&gt; has quickly established itself as one of the most capable, modular agent orchestration environments. Built on an extensible Cordis architecture where every feature â€” from persistence and sandboxing to tools and UI components â€” is a hot-pluggable plugin, DSH allows developers to assemble tailored autonomous coding environments.&lt;/p&gt;

&lt;p&gt;However, many AI developers face a common friction point: &lt;strong&gt;how do you use your existing Claude subscription in DSH?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Millions of developers subscribe to &lt;strong&gt;Claude Pro&lt;/strong&gt; or &lt;strong&gt;Claude Max&lt;/strong&gt; directly through &lt;code&gt;claude.ai&lt;/code&gt;. These subscriptions include substantial usage allowances, but they authenticate via browser OAuth rather than raw developer console API keys. Previously, attempting to use Claude in DSH meant:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Being forced to open a terminal, run &lt;code&gt;claude login&lt;/code&gt;, and hope local files were parsed correctly.&lt;/li&gt;
&lt;li&gt;Manually dumping tokens and editing YAML configuration files.&lt;/li&gt;
&lt;li&gt;Dealing with silent token expiry without any visual feedback.&lt;/li&gt;
&lt;li&gt;If you originally signed up with &lt;strong&gt;"Continue with Google" (Gmail)&lt;/strong&gt;, there was no native UI in DSH Settings to authenticate.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;To eliminate this friction once and for all, I built and open-sourced &lt;strong&gt;&lt;a href="https://github.com/grloper/dsh-claude-oauth" rel="noopener noreferrer"&gt;&lt;code&gt;dsh-claude-oauth&lt;/code&gt;&lt;/a&gt;&lt;/strong&gt; â€” a complete, production-grade DSH plugin that provides a native &lt;strong&gt;Claude Settings section&lt;/strong&gt; with &lt;strong&gt;one-click Google / Gmail sign-in&lt;/strong&gt;, auto-refreshing tokens, live model discovery, and real-time subscription quota tracking.&lt;/p&gt;




&lt;h2&gt;
  
  
  2. Visual Walkthrough: How It Looks in DSH
&lt;/h2&gt;

&lt;p&gt;Here is the native Settings interface that &lt;code&gt;dsh-claude-oauth&lt;/code&gt; contributes to DeepSeek Harness:&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%2Fvfnqu111x5elncdfnv7s.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%2Fvfnqu111x5elncdfnv7s.png" alt="DSH Claude Settings UI" width="800" height="512"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  What You See in Settings
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Dedicated Navigation Entry&lt;/strong&gt;: Positioned at order &lt;code&gt;13&lt;/code&gt; in the Settings sidebar, sitting cleanly alongside Antigravity (Google Gemini) and OpenAI Codex.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Account Status Card&lt;/strong&gt;: When authenticated, displays your linked Google/Gmail address, subscription tier pill (&lt;code&gt;CLAUDE MAX&lt;/code&gt; or &lt;code&gt;CLAUDE PRO&lt;/code&gt;), and active connection status.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Live Subscription Quota Bars&lt;/strong&gt;: Shows real-time utilization for both the &lt;strong&gt;5-Hour&lt;/strong&gt; and &lt;strong&gt;7-Day&lt;/strong&gt; subscription windows with live countdown timers until reset.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Active Model Catalog&lt;/strong&gt;: Displays available models (&lt;code&gt;Claude Sonnet 4.5&lt;/code&gt;, &lt;code&gt;Claude Opus 4.5&lt;/code&gt;, &lt;code&gt;Claude Haiku 4.5&lt;/code&gt;, and &lt;code&gt;Claude 3.7 Sonnet&lt;/code&gt;) verified live from Anthropic's API.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  3. Architecture Deep-Dive: How It Works
&lt;/h2&gt;

&lt;p&gt;Under the hood, &lt;code&gt;dsh-claude-oauth&lt;/code&gt; is divided into two cooperative halves: a &lt;strong&gt;Host plugin&lt;/strong&gt; running in Node.js and a &lt;strong&gt;Web Client plugin&lt;/strong&gt; running in the browser.&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%2Fl2z2lssezh0ixtlbh2io.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%2Fl2z2lssezh0ixtlbh2io.png" alt="OAuth Architecture Flow" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  3.1 The PKCE Loopback Flow &amp;amp; The Windows IPv6 Pitfall
&lt;/h3&gt;

&lt;p&gt;When you click &lt;strong&gt;"Sign in with Google / Gmail"&lt;/strong&gt;:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The client opens a tab pointing to &lt;code&gt;/api/anthropic-oauth/login&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;The host generates a cryptographically random 32-byte PKCE code verifier and computes its SHA-256 code challenge (&lt;code&gt;S256&lt;/code&gt;), along with a random CSRF state token.&lt;/li&gt;
&lt;li&gt;The host binds an ephemeral HTTP callback listener on &lt;code&gt;localhost:0&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Here is a critical engineering detail: &lt;strong&gt;Windows localhost resolution&lt;/strong&gt;.&lt;br&gt;
On modern Windows systems, &lt;code&gt;localhost&lt;/code&gt; often resolves to IPv6 &lt;code&gt;::1&lt;/code&gt; before IPv4 &lt;code&gt;127.0.0.1&lt;/code&gt;. A server that only binds to &lt;code&gt;127.0.0.1&lt;/code&gt; will result in &lt;code&gt;ECONNREFUSED&lt;/code&gt; when the browser redirects back to &lt;code&gt;http://localhost:&amp;lt;port&amp;gt;/callback&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;dsh-claude-oauth&lt;/code&gt; implements a dual-stack listener that binds both IPv4 and IPv6 on the identical ephemeral port:&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;server4&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;http&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createServer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;handler&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;await&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;res&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;server4&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;listen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;127.0.0.1&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="nx"&gt;resolvedPort&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;server4&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;address&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;port&lt;/span&gt;

&lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;server6&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;http&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createServer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;handler&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;await&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;res&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;server6&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;listen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;resolvedPort&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;::1&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;The user is redirected to &lt;code&gt;https://claude.ai/oauth/authorize&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;On the Claude sign-in screen, the user chooses &lt;strong&gt;"Continue with Google"&lt;/strong&gt; and selects their Gmail account.&lt;/li&gt;
&lt;li&gt;Once authorized, Anthropic redirects back to &lt;code&gt;http://localhost:&amp;lt;port&amp;gt;/callback?code=...&amp;amp;state=...&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;The loopback server verifies the state, exchanges the authorization code for tokens via &lt;code&gt;https://claude.ai/v1/oauth/token&lt;/code&gt;, and queries &lt;code&gt;https://api.anthropic.com/api/oauth/profile&lt;/code&gt; to retrieve the user's Gmail address and subscription tier.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  3.2 Multi-Store Credential Synchronization
&lt;/h3&gt;

&lt;p&gt;To prevent isolated silos, &lt;code&gt;dsh-claude-oauth&lt;/code&gt; synchronizes credentials across all relevant stores upon authentication:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;~/.claude/.credentials.json&lt;/code&gt;&lt;/strong&gt;: Writes the &lt;code&gt;claudeAiOauth&lt;/code&gt; session (access token, refresh token, expiry, scopes, email). This ensures the official Claude Code CLI also recognizes the login!&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;~/.dsh/.credentials.yaml&lt;/code&gt;&lt;/strong&gt;: Mounts &lt;code&gt;ANTHROPIC_OAUTH_TOKEN&lt;/code&gt; and &lt;code&gt;CLAUDE_CODE_OAUTH_TOKEN&lt;/code&gt; into the native DSH credential resolution seam.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;~/.dsh/settings.yaml&lt;/code&gt;&lt;/strong&gt;: Automatically declares &lt;code&gt;llm-pi-ai.providers.anthropic&lt;/code&gt; with the live discovered model list.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;~/.dsh/plugins/subscriptions/auth.json&lt;/code&gt;&lt;/strong&gt;: Syncs with the multi-provider subscriptions store so other plugins stay updated.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  3.3 Real-Time Unified Rate Limit Probing
&lt;/h3&gt;

&lt;p&gt;Anthropic attaches its unified subscription rate-limit headers only to inference responses (&lt;code&gt;POST /v1/messages&lt;/code&gt;), &lt;strong&gt;never&lt;/strong&gt; to catalog endpoints (&lt;code&gt;/v1/models&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;To provide live 5-hour and 7-day usage readouts without burning quota, &lt;code&gt;dsh-claude-oauth&lt;/code&gt; executes an ultra-cheap &lt;code&gt;max_tokens: 1&lt;/code&gt; probe using Claude 3.5 Haiku:&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;res&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://api.anthropic.com/v1/messages&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="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;POST&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;claudeCodeHeaders&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;accessToken&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;OAUTH_DISCOVERY_BETAS&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;model&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;claude-haiku-4-5-20251001&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;max_tokens&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="na"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt; &lt;span class="na"&gt;role&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;user&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;hi&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;From this single-token response, it extracts:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;anthropic-ratelimit-unified-5h-utilization&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;anthropic-ratelimit-unified-5h-reset&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;anthropic-ratelimit-unified-7d-utilization&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;anthropic-ratelimit-unified-7d-reset&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These values are cached with a 60-second TTL and rendered into smooth, color-coded progress bars (green below 70%, amber 70â€“89%, red 90%+).&lt;/p&gt;




&lt;h2&gt;
  
  
  4. How to Install and Use
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Step 1: Install the Plugin
&lt;/h3&gt;

&lt;p&gt;Run this command from your terminal:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;dsh plugin &lt;span class="nt"&gt;--profile&lt;/span&gt; web add github:grloper/dsh-claude-oauth
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 2: Open Settings &amp;amp; Sign In
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Start DSH Web: &lt;code&gt;dsh web&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Click the gear icon in the lower-left corner to open &lt;strong&gt;Settings&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Click on &lt;strong&gt;Claude (Anthropic)&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;"Sign in with Google / Gmail"&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Select your Google/Gmail account and click &lt;strong&gt;Authorize&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;The browser confirms success; return to DSH and see your account and quota live!&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Step 3: Start Coding with Claude
&lt;/h3&gt;

&lt;p&gt;Open any session and select &lt;strong&gt;Claude Sonnet 4.5&lt;/strong&gt; or &lt;strong&gt;Claude 3.7 Sonnet&lt;/strong&gt; from the composer model picker.&lt;/p&gt;

&lt;p&gt;To make Claude your default agent model across all sessions, set it in &lt;code&gt;~/.dsh/settings.yaml&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="na"&gt;agent-default-model&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;provider&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;anthropic&lt;/span&gt;
  &lt;span class="na"&gt;model&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;claude-sonnet-4-5&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  5. Conclusion &amp;amp; Open Source Repository
&lt;/h2&gt;

&lt;p&gt;DeepSeek Harness provides an outstanding foundation for autonomous AI coding. With &lt;code&gt;dsh-claude-oauth&lt;/code&gt;, utilizing your existing Claude Pro or Max subscription with Google/Gmail login is now as frictionless as a single click.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;GitHub Repository&lt;/strong&gt;: &lt;a href="https://github.com/grloper/dsh-claude-oauth" rel="noopener noreferrer"&gt;https://github.com/grloper/dsh-claude-oauth&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;License&lt;/strong&gt;: MIT&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Contributions&lt;/strong&gt;: Pull requests, feature suggestions, and bug reports are warmly welcomed!&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>opensource</category>
      <category>claude</category>
      <category>ai</category>
      <category>oauth</category>
    </item>
  </channel>
</rss>
