<?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: Rohith Matam</title>
    <description>The latest articles on DEV Community by Rohith Matam (@rohith_matam_be6aea5caf13).</description>
    <link>https://dev.to/rohith_matam_be6aea5caf13</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%2F4010141%2F8149fa5c-b027-4ecf-a100-5b1432dc0aa1.png</url>
      <title>DEV Community: Rohith Matam</title>
      <link>https://dev.to/rohith_matam_be6aea5caf13</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/rohith_matam_be6aea5caf13"/>
    <language>en</language>
    <item>
      <title>The Redis URL That Leaked Its Own Password Into AI Agent Context</title>
      <dc:creator>Rohith Matam</dc:creator>
      <pubDate>Thu, 16 Jul 2026 16:50:56 +0000</pubDate>
      <link>https://dev.to/rohith_matam_be6aea5caf13/the-redis-url-that-leaked-its-own-password-into-ai-agent-context-5c6n</link>
      <guid>https://dev.to/rohith_matam_be6aea5caf13/the-redis-url-that-leaked-its-own-password-into-ai-agent-context-5c6n</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for &lt;a href="https://dev.to/bugsmash"&gt;DEV's Summer Bug Smash: Clear the Lineup&lt;/a&gt; powered by &lt;a href="https://sentry.io/" rel="noopener noreferrer"&gt;Sentry&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Project Overview
&lt;/h2&gt;

&lt;p&gt;ContextOS is a context operating system for AI coding agents: it scans a repo, ranks the relevant files, and builds a context pack under a token budget for the agent to work from. Before anything goes into that pack, a secret detector redacts API keys, tokens, and credentials so agents never see live secrets, published on PyPI with 980+ automated tests and an 80% coverage gate.&lt;/p&gt;

&lt;h2&gt;
  
  
  Bug Fix or Performance Improvement
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;database_url&lt;/code&gt; secret-detection pattern was supposed to catch connection strings like &lt;code&gt;postgres://user:password@host&lt;/code&gt; and redact the password. It required at least one character for the username segment before it would match. That's fine for Postgres and MySQL, which always have a username. It's not fine for Redis, where the standard URI convention is &lt;code&gt;redis://:password@host&lt;/code&gt;, no username at all, just a password. That empty-username shape silently failed the pattern's &lt;code&gt;[^:@/\s]+&lt;/code&gt; requirement, so detection was skipped entirely. The password sailed straight into the context pack, unredacted, ready to be handed to an LLM agent.&lt;/p&gt;

&lt;p&gt;I found it while auditing detection coverage against real-world connection string formats rather than just the formats already covered by existing tests. The exact format Redis's own documentation recommends when only a password is configured didn't get caught.&lt;/p&gt;

&lt;h2&gt;
  
  
  Code
&lt;/h2&gt;

&lt;p&gt;PR: Rohithmatham12/ContextOS#1&lt;/p&gt;

&lt;p&gt;Before (username segment requires 1+ chars):&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="sa"&gt;r&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;(?i)(?P&amp;lt;key&amp;gt;(?:postgres(?:ql)?|mysql|mongodb(?:\+srv)?|redis)&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="sa"&gt;r&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;://[^:@/\s]+:)&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="sa"&gt;r&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;(?P&amp;lt;value&amp;gt;[^@\s]{4,})&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="sa"&gt;r&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After (username segment allows 0+ chars):&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="sa"&gt;r&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;(?i)(?P&amp;lt;key&amp;gt;(?:postgres(?:ql)?|mysql|mongodb(?:\+srv)?|redis)&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="sa"&gt;r&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;://[^:@/\s]*:)&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="sa"&gt;r&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;(?P&amp;lt;value&amp;gt;[^@\s]{4,})&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="sa"&gt;r&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Before, this stayed exactly as-is, verbatim, in the context pack handed to the agent:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight conf"&gt;&lt;code&gt;&lt;span class="n"&gt;REDIS_URL&lt;/span&gt;=&lt;span class="n"&gt;redis&lt;/span&gt;://:&lt;span class="n"&gt;supersecretpass123&lt;/span&gt;@&lt;span class="n"&gt;cache&lt;/span&gt;.&lt;span class="n"&gt;internal&lt;/span&gt;:&lt;span class="m"&gt;6379&lt;/span&gt;/&lt;span class="m"&gt;0&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight conf"&gt;&lt;code&gt;&lt;span class="n"&gt;REDIS_URL&lt;/span&gt;=&lt;span class="n"&gt;redis&lt;/span&gt;://:[&lt;span class="n"&gt;REDACTED_DB_PASSWORD&lt;/span&gt;]@&lt;span class="n"&gt;cache&lt;/span&gt;.&lt;span class="n"&gt;internal&lt;/span&gt;:&lt;span class="m"&gt;6379&lt;/span&gt;/&lt;span class="m"&gt;0&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  My Improvements
&lt;/h2&gt;

&lt;p&gt;One character, &lt;code&gt;+&lt;/code&gt; to &lt;code&gt;*&lt;/code&gt;. That's the entire regex fix, but the real work was proving it was safe: I added two regression tests covering both detection and redaction for the empty-username case, then ran the full suite: 952 passed, 2 skipped, no regressions.&lt;/p&gt;

&lt;p&gt;This isn't a cosmetic bug. ContextOS exists specifically to hand code to AI agents safely. A credential-detection gap in that exact pipeline defeats the entire point of the tool for any project using Redis, which is most projects doing caching or session storage. The fix closes the gap for every future scan, not just the one string I tested.&lt;/p&gt;

&lt;p&gt;The bigger lesson: test coverage that only exercises the formats you thought to write tests for will always look complete. It wasn't a logic bug so much as a coverage gap disguised as a passing test suite. The fix that matters isn't just the regex change, it's making the URL-shape assumption ("usernames are always present") explicit in a code comment so the next person doesn't reintroduce it.&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>bugsmash</category>
    </item>
    <item>
      <title>Preserving Resource Attributes During Span Flattening: A Trace Data Collision Story</title>
      <dc:creator>Rohith Matam</dc:creator>
      <pubDate>Thu, 16 Jul 2026 15:53:26 +0000</pubDate>
      <link>https://dev.to/rohith_matam_be6aea5caf13/preserving-resource-attributes-during-span-flattening-a-trace-data-collision-story-odf</link>
      <guid>https://dev.to/rohith_matam_be6aea5caf13/preserving-resource-attributes-during-span-flattening-a-trace-data-collision-story-odf</guid>
      <description>&lt;p&gt;Tracing pipelines flatten nested OpenTelemetry data (resource attributes + span attributes) into a single flat record before storage. Simple in theory. In OpenObserve, it was quietly losing data.&lt;/p&gt;

&lt;p&gt;The bug: When a span's attributes and its resource's attributes shared the same key, for example service_name appearing in both places, the flattening step let the span-level value silently overwrite the resource-level one. Resource attributes are supposed to be the authoritative source (they describe the entity emitting the trace); span attributes are per-operation and shouldn't be able to clobber them. But the flattening code had no collision handling at all: last write wins, whoever happened to serialize second.&lt;/p&gt;

&lt;p&gt;That's a correctness bug that's invisible until it isn't. Your dashboards keep working. Your queries keep returning results. They're just returning the wrong service_name for a subset of spans, and nothing errors to tell you.&lt;/p&gt;

&lt;p&gt;Root cause: No collision-avoidance strategy existed between BLOCK_FIELDS and RESERVED_SPAN_FIELDS. Two separate reserved-field lists, no coordination between them, and no prefixing scheme to keep colliding keys distinguishable during flattening.&lt;/p&gt;

&lt;p&gt;The fix:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Resource's canonical service.name stays authoritative as service_name, full stop.&lt;/li&gt;
&lt;li&gt;Any other resource attribute that collides gets a service_attr_ prefix instead of silently competing.&lt;/li&gt;
&lt;li&gt;Colliding span attributes get an attr_ prefix before flattening, so they land next to the resource value instead of over it.&lt;/li&gt;
&lt;li&gt;Merged the two separate reserved-field lists into one unified list, closing the gap that let the collision happen in the first place.&lt;/li&gt;
&lt;li&gt;Added regression tests specifically covering the three-way collision: resource service.name, resource name, and span service_name all present at once.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Impact: Trace data integrity restored for any pipeline where span and resource attributes overlap, which in practice is common (service metadata gets attached at both levels by different instrumentation layers). The unified reserved-field list also closes the door on the same class of bug reappearing with a different field name.&lt;/p&gt;

&lt;p&gt;Lesson: Attribute collisions are a "works on the happy path" bug class. Nothing throws, nothing fails a test that only checks the non-colliding case. The fix wasn't just patching the one field, it was building a naming convention (canonical vs. prefixed) that makes the next collision safe by construction instead of requiring another one-off fix.&lt;/p&gt;

&lt;p&gt;PR: openobserve/openobserve#12456 (merged)&lt;/p&gt;

&lt;p&gt;&lt;em&gt;This is a submission for &lt;a href="https://dev.to/bugsmash"&gt;DEV's Summer Bug Smash: Smash Stories&lt;/a&gt; powered by &lt;a href="https://sentry.io/" rel="noopener noreferrer"&gt;Sentry&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>bugsmash</category>
    </item>
    <item>
      <title>I built a "context OS" that stops AI agents from drowning in your codebase</title>
      <dc:creator>Rohith Matam</dc:creator>
      <pubDate>Wed, 01 Jul 2026 03:44:37 +0000</pubDate>
      <link>https://dev.to/rohith_matam_be6aea5caf13/i-built-a-context-os-that-stops-ai-agents-from-drowning-in-your-codebase-636</link>
      <guid>https://dev.to/rohith_matam_be6aea5caf13/i-built-a-context-os-that-stops-ai-agents-from-drowning-in-your-codebase-636</guid>
      <description>&lt;h2&gt;
  
  
  The problem every AI coding session hits
&lt;/h2&gt;

&lt;p&gt;You open Claude or Copilot, paste in your task, and immediately hit the wall: the codebase is too big. You either:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Dump everything and burn 80% of your context window on irrelevant files&lt;/li&gt;
&lt;li&gt;Hand-pick files and miss the one import that breaks everything&lt;/li&gt;
&lt;li&gt;Pay for a bigger context window and repeat the problem at scale&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I got tired of this and built &lt;strong&gt;ContextOS&lt;/strong&gt; — a local CLI that acts as an intelligent context layer between your repo and your AI agent.&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;rm-contextos
&lt;span class="nb"&gt;cd &lt;/span&gt;your-project
contextos scan
contextos pack &lt;span class="nt"&gt;--task&lt;/span&gt; &lt;span class="s2"&gt;"add rate limiting to the auth endpoint"&lt;/span&gt; &lt;span class="nt"&gt;--budget&lt;/span&gt; 8000
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Output: a Markdown (or JSON) context pack with only the files that matter for that task — ranked by keyword match, import graph centrality, AST symbol overlap, and git churn. Secrets redacted automatically.&lt;/p&gt;

&lt;p&gt;Token savings report on every pack:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Packed 12 files · ~6,840 tokens · saved ~47,200 tokens (87%) vs full repo
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  How ranking works
&lt;/h2&gt;

&lt;p&gt;Five signals combine into a score per file:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Signal&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;Keyword match&lt;/td&gt;
&lt;td&gt;Files whose content/name overlap with your task&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Import graph centrality&lt;/td&gt;
&lt;td&gt;Files that everything else imports (critical shared modules)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;AST symbol overlap&lt;/td&gt;
&lt;td&gt;Function/class names, not just grep strings&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Git churn score&lt;/td&gt;
&lt;td&gt;Recently modified files are probably active code&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Secret penalty&lt;/td&gt;
&lt;td&gt;Credential files silently excluded&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;No LLM calls. No cloud. Fully offline.&lt;/p&gt;




&lt;h2&gt;
  
  
  MCP server (for Claude Desktop / Claude Code)
&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; &lt;span class="s2"&gt;"rm-contextos[mcp]"&lt;/span&gt;
contextos serve &lt;span class="nt"&gt;--stdio&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Register in &lt;code&gt;claude_desktop_config.json&lt;/code&gt; and your AI agent can call &lt;code&gt;pack_context&lt;/code&gt;, &lt;code&gt;scan_repo&lt;/code&gt;, &lt;code&gt;list_files&lt;/code&gt;, &lt;code&gt;get_file&lt;/code&gt;, &lt;code&gt;churn_report&lt;/code&gt; directly as tools — no CLI needed.&lt;/p&gt;




&lt;h2&gt;
  
  
  What's shipped
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;980 tests, 96% coverage&lt;/li&gt;
&lt;li&gt;Apache-2.0, no telemetry, no accounts&lt;/li&gt;
&lt;li&gt;Python 3.11–3.13, Linux + macOS&lt;/li&gt;
&lt;li&gt;Export formats: Claude, Codex, Cursor, Aider, JSON&lt;/li&gt;
&lt;li&gt;Incremental scan cache — re-scans only changed files
&lt;/li&gt;
&lt;/ul&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;rm-contextos
pip &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="s2"&gt;"rm-contextos[mcp]"&lt;/span&gt;   &lt;span class="c"&gt;# + MCP server&lt;/span&gt;
pip &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="s2"&gt;"rm-contextos[all]"&lt;/span&gt;   &lt;span class="c"&gt;# everything&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;GitHub: &lt;a href="https://github.com/Rohithmatham12/ContextOS" rel="noopener noreferrer"&gt;https://github.com/Rohithmatham12/ContextOS&lt;/a&gt;&lt;br&gt;
Docs: &lt;a href="https://Rohithmatham12.github.io/ContextOS/" rel="noopener noreferrer"&gt;https://Rohithmatham12.github.io/ContextOS/&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Would love feedback&lt;/strong&gt; — especially on the ranking signals and MCP integration. What signals are you missing?&lt;/p&gt;

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