<?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: wd400</title>
    <description>The latest articles on DEV Community by wd400 (@wd400).</description>
    <link>https://dev.to/wd400</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%2F1355918%2F247930ae-4e07-4667-a5c3-c261e6e08a4d.jpeg</url>
      <title>DEV Community: wd400</title>
      <link>https://dev.to/wd400</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/wd400"/>
    <language>en</language>
    <item>
      <title>I code-reviewed 3 "vibe-coded" PRs last week. Every one had hardcoded API keys. So I built a grader.</title>
      <dc:creator>wd400</dc:creator>
      <pubDate>Sat, 11 Apr 2026 03:19:17 +0000</pubDate>
      <link>https://dev.to/wd400/i-code-reviewed-3-vibe-coded-prs-last-week-every-one-had-hardcoded-api-keys-so-i-built-a-grader-21ii</link>
      <guid>https://dev.to/wd400/i-code-reviewed-3-vibe-coded-prs-last-week-every-one-had-hardcoded-api-keys-so-i-built-a-grader-21ii</guid>
      <description>&lt;p&gt;"Vibe coding" is everywhere. You prompt an AI, it writes your whole project, you ship it.&lt;/p&gt;

&lt;p&gt;Last week I reviewed 3 PRs from vibe-coded projects. All three had hardcoded API keys in the source. Two had no tests. One had a raw &lt;code&gt;eval()&lt;/code&gt; on user input.&lt;/p&gt;

&lt;p&gt;So I built &lt;a href="https://github.com/stef41/vibescore" rel="noopener noreferrer"&gt;vibescore&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  What it does
&lt;/h2&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;vibescore
vibescore &lt;span class="nb"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;One command. Letter grade from A+ to F. Four dimensions:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Category&lt;/th&gt;
&lt;th&gt;What it checks&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Security&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Hardcoded secrets, SQL injection, eval/exec, insecure defaults&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Code Quality&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Function length, complexity, nesting depth, type hint coverage&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Dependencies&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Pinning, lock files, deprecated packages, known CVEs&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Testing&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Test count vs LOC ratio, coverage setup, CI configuration&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Example output
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;vibescore v0.4.0 — Project Report
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
  Security     B+  (no hardcoded secrets, 2 eval() calls found)
  Code Quality C   (4 functions &amp;gt;50 lines, low type hint coverage)
  Dependencies A-  (all pinned, lock file present)
  Testing      D   (3 tests for 2,400 LOC)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
  OVERALL      C+
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Supported languages
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Python&lt;/strong&gt; (AST-based analysis)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;JavaScript/TypeScript&lt;/strong&gt; (regex-based)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Rust&lt;/strong&gt; (VC221-VC227: unwrap density, unsafe blocks, doc comments, clone detection)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Go&lt;/strong&gt; (VC231-VC237: unchecked errors, goroutine leaks, naked returns, panic in library code)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Extra features
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;vibescore --init-ci&lt;/code&gt; — generates a GitHub Actions workflow&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;vibescore --watch&lt;/code&gt; — re-scans on file changes in real-time&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;vibescore --dashboard&lt;/code&gt; — historical grade tracking (Streamlit web UI)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;vibescore --save-history&lt;/code&gt; — save scan results for trend analysis&lt;/li&gt;
&lt;li&gt;Zero dependencies. 201 tests.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Comparison
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;SonarQube&lt;/strong&gt;: requires a Java server, complex setup, enterprise pricing&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Codacy/CodeClimate&lt;/strong&gt;: SaaS, requires account, sends code to servers&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;pylint/ruff&lt;/strong&gt;: lint rules only, no security/testing/dependency analysis, no single grade&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;vibescore&lt;/strong&gt;: one pip install, one command, local-only, zero deps, covers 4 dimensions with a letter grade&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;strong&gt;GitHub&lt;/strong&gt;: &lt;a href="https://github.com/stef41/vibescore" rel="noopener noreferrer"&gt;github.com/stef41/vibescore&lt;/a&gt;&lt;br&gt;
&lt;strong&gt;PyPI&lt;/strong&gt;: &lt;a href="https://pypi.org/project/vibescore/" rel="noopener noreferrer"&gt;pypi.org/project/vibescore&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Feedback welcome — especially ideas for new check categories or language support.&lt;/p&gt;

</description>
      <category>python</category>
      <category>javascript</category>
      <category>opensource</category>
      <category>showdev</category>
    </item>
    <item>
      <title>I got mass-flagged by GPTZero for my own writing. So I built an open-source alternative in pure Python.</title>
      <dc:creator>wd400</dc:creator>
      <pubDate>Sat, 11 Apr 2026 03:18:51 +0000</pubDate>
      <link>https://dev.to/wd400/i-got-mass-flagged-by-gptzero-for-my-own-writing-so-i-built-an-open-source-alternative-in-pure-5aj2</link>
      <guid>https://dev.to/wd400/i-got-mass-flagged-by-gptzero-for-my-own-writing-so-i-built-an-open-source-alternative-in-pure-5aj2</guid>
      <description>&lt;p&gt;Every AI text detector is either paid or closed-source.&lt;/p&gt;

&lt;p&gt;GPTZero charges $15/month. Originality.ai charges per scan. Turnitin locks you into institutional contracts. And all of them are black boxes — when they flag your text as AI-generated, you have no idea &lt;em&gt;why&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;I got tired of this. Especially after GPTZero flagged my own human-written paragraphs as "98% AI."&lt;/p&gt;

&lt;p&gt;So I built &lt;a href="https://github.com/stef41/lmscan" rel="noopener noreferrer"&gt;lmscan&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  What it does
&lt;/h2&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;lmscan
lmscan &lt;span class="s2"&gt;"paste any text here"&lt;/span&gt;
→ 82% AI probability, likely GPT-4
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It analyzes &lt;strong&gt;12 statistical features&lt;/strong&gt; — burstiness, entropy, Zipf deviation, vocabulary richness, slop-word density — and &lt;strong&gt;fingerprints 9 LLM families&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;No neural network. No API key. No internet. Runs in &amp;lt;50ms.&lt;/p&gt;

&lt;h2&gt;
  
  
  The detection approach
&lt;/h2&gt;

&lt;p&gt;AI text is &lt;strong&gt;unnaturally smooth&lt;/strong&gt;. Humans write in bursts — short punchy sentences followed by long rambling ones. LLMs produce eerily consistent sentence lengths.&lt;/p&gt;

&lt;p&gt;LLMs also have vocabulary tells:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;GPT-4&lt;/strong&gt; loves "delve" and "tapestry"&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Claude&lt;/strong&gt; says "I think it's worth noting"&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Llama&lt;/strong&gt; overuses "comprehensive" and "crucial"&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;lmscan scores text against each family's marker set to fingerprint the source.&lt;/p&gt;

&lt;h2&gt;
  
  
  Python API
&lt;/h2&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;lmscan&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;scan&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;scan&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;your text&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;print&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="si"&gt;{&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;ai_probability&lt;/span&gt;&lt;span class="si"&gt;:&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; AI, likely &lt;/span&gt;&lt;span class="si"&gt;{&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;fingerprint&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;model&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Features
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;12 statistical features (burstiness, entropy, Zipf deviation, hapax legomena, vocabulary richness, slop-word density, and more)&lt;/li&gt;
&lt;li&gt;9 LLM fingerprints (GPT-4, Claude, Gemini, Llama, Mistral, Qwen, DeepSeek, Cohere, Phi)&lt;/li&gt;
&lt;li&gt;Multilingual support (English, French, Spanish, German, Portuguese + CJK auto-detection)&lt;/li&gt;
&lt;li&gt;Batch directory scanning with &lt;code&gt;--dir&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Mixed-content paragraph analysis with &lt;code&gt;--mixed&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;HTML reports with &lt;code&gt;--format html&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Streamlit web UI with &lt;code&gt;pip install lmscan[web]&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Pre-commit hook integration&lt;/li&gt;
&lt;li&gt;Calibration API for tuning thresholds on your own data&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Honest limitations
&lt;/h2&gt;

&lt;p&gt;This is statistical analysis, not a transformer classifier. It won't catch heavily paraphrased AI text. But:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You can see exactly which features triggered&lt;/li&gt;
&lt;li&gt;No black-box false positives&lt;/li&gt;
&lt;li&gt;Calibration API lets you tune for your domain&lt;/li&gt;
&lt;li&gt;193 tests, Apache-2.0&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;strong&gt;GitHub&lt;/strong&gt;: &lt;a href="https://github.com/stef41/lmscan" rel="noopener noreferrer"&gt;github.com/stef41/lmscan&lt;/a&gt;&lt;br&gt;
&lt;strong&gt;PyPI&lt;/strong&gt;: &lt;a href="https://pypi.org/project/lmscan/" rel="noopener noreferrer"&gt;pypi.org/project/lmscan&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Feedback welcome — especially on which types of text it struggles with. That helps calibrate the feature weights.&lt;/p&gt;

</description>
      <category>python</category>
      <category>ai</category>
      <category>opensource</category>
      <category>showdev</category>
    </item>
  </channel>
</rss>
