<?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: vamshidhar reddy</title>
    <description>The latest articles on DEV Community by vamshidhar reddy (@vamshidhar_reddy_392c2302).</description>
    <link>https://dev.to/vamshidhar_reddy_392c2302</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%2F3864360%2Ffc51ae1e-f901-4a80-86e8-9919d2babd09.jpg</url>
      <title>DEV Community: vamshidhar reddy</title>
      <link>https://dev.to/vamshidhar_reddy_392c2302</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/vamshidhar_reddy_392c2302"/>
    <language>en</language>
    <item>
      <title>I built a linter that proves 74% of your AGENTS.md is wasting your AI agent's time</title>
      <dc:creator>vamshidhar reddy</dc:creator>
      <pubDate>Mon, 06 Apr 2026 18:11:34 +0000</pubDate>
      <link>https://dev.to/vamshidhar_reddy_392c2302/i-built-a-linter-that-proves-74-of-your-agentsmd-is-wasting-your-ai-agents-time-46an</link>
      <guid>https://dev.to/vamshidhar_reddy_392c2302/i-built-a-linter-that-proves-74-of-your-agentsmd-is-wasting-your-ai-agents-time-46an</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyiucp8upbl60djy2zhyt.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyiucp8upbl60djy2zhyt.png" alt="Ctxlint command line"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you use Claude Code, Cursor, Codex, or Gemini CLI, you probably have an AGENTS.md or CLAUDE.md sitting in your project root.&lt;/p&gt;

&lt;p&gt;It gets loaded into every single session. Every token in it competes for attention with your actual task.&lt;/p&gt;

&lt;p&gt;And most of them are full of junk.&lt;/p&gt;

&lt;h2&gt;
  
  
  The problem I kept seeing
&lt;/h2&gt;

&lt;p&gt;I was reviewing context files across open-source repos and noticed the same patterns everywhere:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Directory trees that agents discover with &lt;code&gt;ls&lt;/code&gt; in 200ms&lt;/li&gt;
&lt;li&gt;"Built with React 18, TypeScript, and Tailwind CSS" — readable from &lt;code&gt;package.json&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;References to &lt;code&gt;src/middleware/auth.ts&lt;/code&gt; that was renamed to &lt;code&gt;src/auth/middleware.ts&lt;/code&gt; three months ago&lt;/li&gt;
&lt;li&gt;"Use 2-space indentation" when &lt;code&gt;.prettierrc&lt;/code&gt; already enforces it&lt;/li&gt;
&lt;li&gt;Entire sections copy-pasted from the README&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;None of this helps the agent. All of it costs tokens on every session.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I built
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/vamshidhar199/Ctxlint" rel="noopener noreferrer"&gt;ctxlint&lt;/a&gt; — a CLI linter for AI agent context files.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx @ctxlint/ctxlint check
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;8 deterministic rules. Zero LLM dependency. Pure filesystem analysis. Runs in milliseconds.&lt;/p&gt;

&lt;p&gt;It supports AGENTS.md, CLAUDE.md, GEMINI.md, &lt;code&gt;.cursorrules&lt;/code&gt;, and &lt;code&gt;copilot-instructions.md&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  The 8 rules
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Rule&lt;/th&gt;
&lt;th&gt;Severity&lt;/th&gt;
&lt;th&gt;What it catches&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;stale-file-ref&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;error&lt;/td&gt;
&lt;td&gt;References to files or directories that no longer exist&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;stale-command&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;error&lt;/td&gt;
&lt;td&gt;Build/test scripts that don't match your actual &lt;code&gt;package.json&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;no-directory-tree&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;error&lt;/td&gt;
&lt;td&gt;Embedded directory structures agents discover on their own&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;no-inferable-stack&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;warn&lt;/td&gt;
&lt;td&gt;Tech stack descriptions already in your config files&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;redundant-readme&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;warn&lt;/td&gt;
&lt;td&gt;Sections that duplicate your README.md&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;no-style-guide&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;info&lt;/td&gt;
&lt;td&gt;Coding style rules that belong in eslint/prettier/ruff&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;max-lines&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;warn&lt;/td&gt;
&lt;td&gt;Files over 200 lines (production teams keep theirs under 60)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;token-budget&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;warn&lt;/td&gt;
&lt;td&gt;Token cost estimate with signal-to-noise breakdown&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Every rule runs against your actual codebase — it checks whether referenced files exist, whether npm scripts are real, whether your linter config already covers a style rule.&lt;/p&gt;

&lt;h2&gt;
  
  
  What it looks like
&lt;/h2&gt;

&lt;p&gt;Running &lt;code&gt;ctxlint check&lt;/code&gt; on a typical bloated context file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;AGENTS.md

  ✗ no-directory-tree  Lines 4-7 contain a directory tree (~14 tokens)
     Agents discover file structure via ls/find — this just adds noise.

  ✗ stale-command  `npm run test:e2e` — script does not exist
     Available: dev, build, test, lint, typecheck

  ✗ stale-file-ref  `src/config/auth.ts` does not exist
     Stale refs mislead agents into searching for ghost files.

  ⚠ token-budget  24 lines, ~104 tokens
     Signal: 40 tokens (38%) ✓  Noise: 64 tokens (62%) ✗
     Ratio: 0.38 (poor)  Monthly: $0.09 → $0.03 (67% saved)

  Summary: 3 errors, 1 warning, 0 info
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  I tested it on real repos
&lt;/h2&gt;

&lt;p&gt;I didn't just test against toy fixtures. I cloned 8 popular open-source repos that have real context files maintained by their teams, and ran ctxlint against each one.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Repo&lt;/th&gt;
&lt;th&gt;Context file&lt;/th&gt;
&lt;th&gt;Key findings&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;next.js&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;AGENTS.md&lt;/td&gt;
&lt;td&gt;Directory tree present. Multiple stale file refs — paths are relative to &lt;code&gt;packages/next/&lt;/code&gt; but written as root-relative&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;langchain&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;CLAUDE.md&lt;/td&gt;
&lt;td&gt;Directory tree. Stale monorepo paths. Parent-relative refs (&lt;code&gt;../&lt;/code&gt;) that don't resolve from root&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;codex&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;AGENTS.md&lt;/td&gt;
&lt;td&gt;5 stale file refs — files live under &lt;code&gt;codex-rs/&lt;/code&gt; subdirectory but refs assume root&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;ruff&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;CLAUDE.md&lt;/td&gt;
&lt;td&gt;Borderline redundant-readme overlap. Architectural naming convention flagged (false positive — we fixed it)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;anthropic-cookbook&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;CLAUDE.md&lt;/td&gt;
&lt;td&gt;Directory tree flagged correctly&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Overall precision: 91%.&lt;/strong&gt; Zero crashes across all repos.&lt;/p&gt;

&lt;p&gt;The most common issue by far: &lt;strong&gt;stale file references in monorepos&lt;/strong&gt;. People write paths assuming root, but the files actually live two directories deep in a workspace package.&lt;/p&gt;

&lt;h2&gt;
  
  
  What surprised me
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Directory trees are universal and universally useless.&lt;/strong&gt; Almost every auto-generated context file has one. Agents don't use them — they run &lt;code&gt;ls&lt;/code&gt; and &lt;code&gt;find&lt;/code&gt; themselves. It's the single biggest source of token waste.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Stale commands are dangerous, not just wasteful.&lt;/strong&gt; When your context file says &lt;code&gt;npm run test:e2e&lt;/code&gt; but that script was renamed to &lt;code&gt;test:integration&lt;/code&gt; last month, the agent runs the stale command, gets an error, spends tokens debugging a non-existent script, and then discovers the right one on its own. You paid triple.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The hardest rule to get right was &lt;code&gt;redundant-readme&lt;/code&gt;.&lt;/strong&gt; I use trigram overlap to detect similarity between context file sections and README sections. At 40% threshold, it catches real duplication but occasionally flags sections that share vocabulary without actually saying the same thing. Still tuning this one.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Style guide rules are always inferable.&lt;/strong&gt; If you have &lt;code&gt;.prettierrc&lt;/code&gt; or &lt;code&gt;.eslintrc&lt;/code&gt; in your repo, every style rule in your context file is redundant. The agent reads the formatter output, not your prose.&lt;/p&gt;

&lt;h2&gt;
  
  
  The technical decisions
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Why rule-based instead of LLM-powered?&lt;/strong&gt; Because the problem is deterministic. Checking if &lt;code&gt;src/auth.ts&lt;/code&gt; exists is &lt;code&gt;fs.existsSync()&lt;/code&gt;. Checking if &lt;code&gt;npm run test:e2e&lt;/code&gt; is a real script is JSON parsing. Using an LLM to do filesystem checks would be slower, more expensive, and less reliable.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why zero dependencies beyond &lt;code&gt;commander&lt;/code&gt;?&lt;/strong&gt; Keeps the install fast, the attack surface small, and &lt;code&gt;npx @ctxlint/ctxlint check&lt;/code&gt; works without polluting &lt;code&gt;node_modules&lt;/code&gt;. No chalk (ANSI codes directly), no glob (recursive readdir), no YAML parser (regex for key fields in &lt;code&gt;pyproject.toml&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why synchronous I/O?&lt;/strong&gt; A linter runs once and exits. &lt;code&gt;fs.readFileSync&lt;/code&gt; is simpler than async/await chains and fast enough — the entire analysis takes under 100ms on repos with 10,000+ files.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try it
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Check your context file&lt;/span&gt;
npx @ctxlint/ctxlint check

&lt;span class="c"&gt;# Generate a minimal one from scratch&lt;/span&gt;
npx @ctxlint/ctxlint init &lt;span class="nt"&gt;--dry-run&lt;/span&gt;

&lt;span class="c"&gt;# Strip the bloat from an existing file&lt;/span&gt;
npx @ctxlint/ctxlint slim &lt;span class="nt"&gt;--dry-run&lt;/span&gt; AGENTS.md

&lt;span class="c"&gt;# Check for drift since last update&lt;/span&gt;
npx @ctxlint/ctxlint diff
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  What's next — and where I need help
&lt;/h2&gt;

&lt;p&gt;This is early stage. 116 npm downloads on day 1 tells me the problem is real, but the tool needs work:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Monorepo awareness&lt;/strong&gt; — the biggest source of false positives. Paths in context files often assume a workspace root, not the repo root&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Python/Rust/Go ecosystems&lt;/strong&gt; — currently strongest on Node.js projects. Need &lt;code&gt;pyproject.toml&lt;/code&gt;, &lt;code&gt;Cargo.toml&lt;/code&gt;, and &lt;code&gt;go.mod&lt;/code&gt; command extraction&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;VS Code extension&lt;/strong&gt; — inline diagnostics instead of CLI output&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;GitHub Action&lt;/strong&gt; — run ctxlint in CI and fail on stale refs&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Good first issues are tagged in the repo. Whether it's a one-line regex fix or a full new rule, contributions are welcome.&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.amazonaws.com%2Fuploads%2Farticles%2Fpc57mryq400gh137ogx7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpc57mryq400gh137ogx7.png" alt="ctxlint npm package"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;GitHub&lt;/strong&gt;: &lt;a href="https://github.com/vamshidhar199/Ctxlint" rel="noopener noreferrer"&gt;github.com/vamshidhar199/Ctxlint&lt;/a&gt;&lt;br&gt;
&lt;strong&gt;npm&lt;/strong&gt;: &lt;a href="https://www.npmjs.com/package/@ctxlint/ctxlint" rel="noopener noreferrer"&gt;npmjs.com/package/@ctxlint/ctxlint&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;What's in your context file that you're not sure belongs there? Run &lt;code&gt;npx @ctxlint/ctxlint check&lt;/code&gt; and share what it finds — I'm curious how it performs on projects I haven't tested yet.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>opensource</category>
      <category>productivity</category>
      <category>discuss</category>
    </item>
  </channel>
</rss>
