<?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: Kaushikreddy Lingi</title>
    <description>The latest articles on DEV Community by Kaushikreddy Lingi (@lingikaushikreddy).</description>
    <link>https://dev.to/lingikaushikreddy</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%2F4155517%2F874f87e3-84a9-47b2-8e19-67bd9ea7100f.jpg</url>
      <title>DEV Community: Kaushikreddy Lingi</title>
      <link>https://dev.to/lingikaushikreddy</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/lingikaushikreddy"/>
    <language>en</language>
    <item>
      <title>A Hindi sentence costs 4.4x the tokens of English. Malayalam costs 7.3x.</title>
      <dc:creator>Kaushikreddy Lingi</dc:creator>
      <pubDate>Mon, 19 Oct 2026 05:11:20 +0000</pubDate>
      <link>https://dev.to/lingikaushikreddy/a-hindi-sentence-costs-44x-the-tokens-of-english-malayalam-costs-73x-o1</link>
      <guid>https://dev.to/lingikaushikreddy/a-hindi-sentence-costs-44x-the-tokens-of-english-malayalam-costs-73x-o1</guid>
      <description>&lt;p&gt;If you serve an LLM to Indian-language users, your GPU bill has a hidden multiplier. I measured it instead of quoting it.&lt;/p&gt;

&lt;h2&gt;
  
  
  The measurement
&lt;/h2&gt;

&lt;p&gt;I took the 1,012 FLORES devtest sentences, tokenized each language and its English counterpart with the Qwen3 tokenizer, and compared the median per-sentence token count:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Language&lt;/th&gt;
&lt;th&gt;Tokens vs the same English sentence&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Hindi&lt;/td&gt;
&lt;td&gt;4.44x&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Malayalam&lt;/td&gt;
&lt;td&gt;7.27x&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Per word it is starker: Malayalam averages 13.47 tokens per word against 1.27 for English.&lt;/p&gt;

&lt;p&gt;More tokens means a bigger KV-cache per user, which means fewer users per GPU. Same model, same hardware, a fraction of the concurrency, for a user who typed one sentence.&lt;/p&gt;

&lt;h2&gt;
  
  
  It depends heavily on the tokenizer
&lt;/h2&gt;

&lt;p&gt;Same Hindi sentence, different tokenizers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Qwen3 / Qwen2.5: 4.44x&lt;/li&gt;
&lt;li&gt;Sarvam-M: 1.79x&lt;/li&gt;
&lt;li&gt;Gemma-3: 1.31x&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So "Indic text is expensive" is only half true. Which model you pick can matter more than any serving trick.&lt;/p&gt;

&lt;h2&gt;
  
  
  Romanizing is not a free fix
&lt;/h2&gt;

&lt;p&gt;The obvious workaround is to write Hindi in Latin script. On Qwen3 that does help: 2.06x against 4.44x. On Gemma-3 it makes things worse: 1.85x against 1.31x. My transliteration scheme (ITRANS) keeps schwas and spells loanwords phonetically, so it is not natural Hinglish. I flag that in the ledger and treat this as a limit, not a result about real chat text.&lt;/p&gt;

&lt;h2&gt;
  
  
  Checking myself first
&lt;/h2&gt;

&lt;p&gt;Before trusting my own numbers I reproduced the published table from "The Tokenizer Tax" (arXiv 2607.24276): 66 of 66 cells within 0.5%. Mean tax under cl100k_base comes out at 8.03x against the paper's 8.0x, and under o200k_base at 2.14x against 2.1x. I also checked token counts against a second independent implementation of each tokenizer: 44 of 44 model-by-language rows with zero mismatches.&lt;/p&gt;

&lt;p&gt;I also found that many FLORES sentences are not Unicode NFC-normalized (609 of 1,012 in Bengali, 573 in Punjabi, 93 in Hindi), which changes token counts if you do not normalize first.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I have not measured yet
&lt;/h2&gt;

&lt;p&gt;The GPU half: how much FP8 KV-cache wins back on AMD MI300X. That run is pending, so there are no GPU numbers here. The repo keeps a claims ledger in which every number points to a result file and a commit, and a number with no row does not get published.&lt;/p&gt;

&lt;p&gt;Repo: &lt;a href="https://github.com/Lingikaushikreddy/indic-kv-tax" rel="noopener noreferrer"&gt;https://github.com/Lingikaushikreddy/indic-kv-tax&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Which Indian-language workload are you serving, and which tokenizer are you paying for?&lt;/p&gt;

</description>
      <category>llm</category>
      <category>ai</category>
      <category>python</category>
      <category>india</category>
    </item>
    <item>
      <title>Two sessions sent the same request id. My MCP server swapped their results.</title>
      <dc:creator>Kaushikreddy Lingi</dc:creator>
      <pubDate>Mon, 19 Oct 2026 05:10:40 +0000</pubDate>
      <link>https://dev.to/lingikaushikreddy/two-sessions-sent-the-same-request-id-my-mcp-server-swapped-their-results-471h</link>
      <guid>https://dev.to/lingikaushikreddy/two-sessions-sent-the-same-request-id-my-mcp-server-swapped-their-results-471h</guid>
      <description>&lt;p&gt;I audited my own Rust MCP server against the spec, line by line. One row of the audit was a bug I would not have guessed: two clients that happened to use the same JSON-RPC request id received each other's results.&lt;/p&gt;

&lt;p&gt;That is not a protocol nitpick. It is the server answering session A with session B's data.&lt;/p&gt;

&lt;h2&gt;
  
  
  How I found it
&lt;/h2&gt;

&lt;p&gt;I did not trust my own README. I pinned the MCP 2025-11-25 spec at one commit, turned every MUST and SHOULD into a row, and gave each row a verdict backed by one of four kinds of evidence: a test in the repo, a scenario from the official conformance suite, a black-box probe, or a replay of a real session from MCP Inspector or Claude Code.&lt;/p&gt;

&lt;p&gt;Result, from the official suite's 2025-11-25 requirements:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;Before&lt;/th&gt;
&lt;th&gt;After&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Checks&lt;/td&gt;
&lt;td&gt;48 passed, 13 failed&lt;/td&gt;
&lt;td&gt;62 passed, 10 failed&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Failures that were spec violations&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Non-conformant rows in my matrix&lt;/td&gt;
&lt;td&gt;20&lt;/td&gt;
&lt;td&gt;1 (deliberate)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The 10 checks that still fail are features the SDK does not implement (completion, subscriptions, audio content, sampling, elicitation). I list them as "not implemented", not as defects.&lt;/p&gt;

&lt;h2&gt;
  
  
  The ones that surprised me
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Same id, two sessions, swapped results.&lt;/strong&gt; Over HTTP, responses were routed by request id alone. Fixed by scoping routing to the session; there is a regression test for it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ping waited for a running tool call.&lt;/strong&gt; The spec says ping must be answered promptly. In my probe it took 1.5 seconds because it queued behind a slow tool. After the fix it answers immediately.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cancellation did nothing until it was too late.&lt;/strong&gt; The cancel notification was read only after the request finished, so the request ran to completion and was answered anyway.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A panicking tool was answered with &lt;code&gt;id: 0&lt;/code&gt;.&lt;/strong&gt; The client could not match the error to its request.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tool failures were protocol errors.&lt;/strong&gt; A tool that failed returned JSON-RPC -32603 instead of a result with &lt;code&gt;isError: true&lt;/code&gt;, so a model never got to see and recover from the error.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The server bound to &lt;code&gt;0.0.0.0&lt;/code&gt; by default and ignored &lt;code&gt;Origin&lt;/code&gt;.&lt;/strong&gt; Now it binds to localhost and checks Host and Origin, which closes the DNS-rebinding hole.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  One thing I deliberately left "wrong"
&lt;/h2&gt;

&lt;p&gt;The spec says a missing resource SHOULD return -32002. I left my -32602. The next revision standardizes on -32602 and the official suite already checks for it, so "fixing" it would only get reverted. The matrix says so in the row instead of hiding it.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I will not claim
&lt;/h2&gt;

&lt;p&gt;An earlier README said "high-performance" and implied completeness. I removed both, because I had no benchmark behind the first and the matrix disproves the second. The audit document is more useful to a reader than the adjectives were.&lt;/p&gt;

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

&lt;p&gt;The full matrix, with a &lt;code&gt;file:line&lt;/code&gt; citation for every requirement, is in &lt;code&gt;docs/CONFORMANCE.md&lt;/code&gt;: &lt;a href="https://github.com/Lingikaushikreddy/mcp-rust-sdk" rel="noopener noreferrer"&gt;https://github.com/Lingikaushikreddy/mcp-rust-sdk&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The fixes are in an open draft PR on the repo, so check the branch rather than assuming they are on &lt;code&gt;main&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;If you maintain an MCP server in any language, how many of these would your server fail? I would like to know which ones are most common.&lt;/p&gt;

</description>
      <category>rust</category>
      <category>mcp</category>
      <category>ai</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Deleting a user's data from backups: crypto-shredding with one key per person</title>
      <dc:creator>Kaushikreddy Lingi</dc:creator>
      <pubDate>Thu, 15 Oct 2026 00:19:27 +0000</pubDate>
      <link>https://dev.to/lingikaushikreddy/deleting-a-users-data-from-backups-crypto-shredding-with-one-key-per-person-36e9</link>
      <guid>https://dev.to/lingikaushikreddy/deleting-a-users-data-from-backups-crypto-shredding-with-one-key-per-person-36e9</guid>
      <description>&lt;p&gt;A user asks you to delete their data. You delete the row. Then you remember the replica, last month's backup, the S3 export someone made for analytics, and the log line with their email in it. You can't edit most of those.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Crypto-shredding&lt;/strong&gt; is the standard way out: encrypt each person's data under their own key, keep the keys in one small keystore, and "delete" a person by destroying their key. The ciphertext can stay wherever it is. Without the key it's noise.&lt;/p&gt;

&lt;p&gt;I built a small library for this called &lt;strong&gt;aegis-shred&lt;/strong&gt;: a Rust core, a Python package and a CLI.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;aegis_shred&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;MasterKey&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Vault&lt;/span&gt;

&lt;span class="n"&gt;vault&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Vault&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;keys.db&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;MasterKey&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;from_env&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;AEGIS_MASTER_KEY&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;create&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;blob&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;vault&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;seal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;user-42&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sa"&gt;b&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;alice@example.com&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sa"&gt;b&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;users.email&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;# store anywhere
&lt;/span&gt;&lt;span class="n"&gt;vault&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;unseal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;blob&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sa"&gt;b&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;users.email&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;   &lt;span class="c1"&gt;# b'alice@example.com'
&lt;/span&gt;&lt;span class="n"&gt;vault&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;shred&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;user-42&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;                       &lt;span class="c1"&gt;# erase user-42, everywhere, at once
&lt;/span&gt;&lt;span class="n"&gt;vault&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;unseal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;blob&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sa"&gt;b&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;users.email&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;   &lt;span class="c1"&gt;# raises aegis_shred.Shredded
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;master key (from your secret manager)
  └─ wraps one data key per subject ───── keystore (SQLite file)
        └─ HKDF → one key per sealed object
              └─ AES-256-GCM, chunked (STREAM)
                    └─ sealed blob/file ── your database, S3, backups, …
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;seal&lt;/code&gt; creates the subject's key on first use and returns a self-describing blob. The blob names a random key id, never the user.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;unseal&lt;/code&gt; checks every chunk. A modified byte, a reordered or missing chunk, truncation, or a different &lt;code&gt;context&lt;/code&gt; all fail.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;shred&lt;/code&gt; deletes the wrapped key in one transaction, writes a tombstone and a hash-chained audit entry, and returns a receipt. From then on, in every process, that user's blobs raise &lt;code&gt;Shredded&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;The keystore stores subjects only as &lt;code&gt;HMAC(index_key, subject_id)&lt;/code&gt;, so the keystore and audit log don't list your users either.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The &lt;code&gt;context&lt;/code&gt; argument binds a blob to where it lives, so a ciphertext copied from one column into another won't decrypt.&lt;/p&gt;

&lt;p&gt;Large files are streamed in 64 KiB chunks with constant memory, and the output file only appears if every chunk verifies.&lt;/p&gt;

&lt;h2&gt;
  
  
  Install
&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;aegis-shred          &lt;span class="c"&gt;# prebuilt wheels for Linux, macOS, Windows&lt;/span&gt;
cargo add aegis-shred            &lt;span class="c"&gt;# Rust library&lt;/span&gt;
cargo &lt;span class="nb"&gt;install &lt;/span&gt;aegis-shred-cli    &lt;span class="c"&gt;# the aegis command&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Honest limits
&lt;/h2&gt;

&lt;p&gt;This is &lt;strong&gt;v0.1, alpha&lt;/strong&gt;. The byte format is specified and versioned, every guarantee has a test, and a second independent implementation in Python runs in CI. But there has been &lt;strong&gt;no independent security audit&lt;/strong&gt;. Read the threat model in the repo before relying on it.&lt;/p&gt;

&lt;p&gt;Whether crypto-shredding satisfies GDPR Art. 17, CCPA or India's DPDP Act for your situation is a question for your lawyers. The library gives you the mechanism and an audit trail, not legal cover.&lt;/p&gt;

&lt;p&gt;Repo (MIT OR Apache-2.0): &lt;a href="https://github.com/Lingikaushikreddy/Aegis" rel="noopener noreferrer"&gt;https://github.com/Lingikaushikreddy/Aegis&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Feedback on the threat model and the file format is the most useful thing you could send me.&lt;/p&gt;

</description>
      <category>security</category>
      <category>privacy</category>
      <category>rust</category>
      <category>python</category>
    </item>
    <item>
      <title>Settlement: a village strategy game where you can see why every agent did what it did</title>
      <dc:creator>Kaushikreddy Lingi</dc:creator>
      <pubDate>Thu, 15 Oct 2026 00:18:59 +0000</pubDate>
      <link>https://dev.to/lingikaushikreddy/settlement-a-village-strategy-game-where-you-can-see-why-every-agent-did-what-it-did-dg6</link>
      <guid>https://dev.to/lingikaushikreddy/settlement-a-village-strategy-game-where-you-can-see-why-every-agent-did-what-it-did-dg6</guid>
      <description>&lt;p&gt;Most multi-agent demos show you what the agents did. I wanted to see &lt;strong&gt;why&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Settlement&lt;/strong&gt; is a village strategy game and a small AI simulation lab. You give six residents a shared objective (grow the village, prepare for a raid, restock supplies) and watch them claim jobs, gather, build and upgrade. Then you click any resident and read their decision, their route and their memories.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Play it in the browser, no signup, no API key:&lt;/strong&gt; &lt;a href="https://settlement-village.vercel.app" rel="noopener noreferrer"&gt;https://settlement-village.vercel.app&lt;/a&gt;&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%2Fsc1lue5tvkzct3t07nz2.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%2Fsc1lue5tvkzct3t07nz2.gif" alt="Settlement in 15 seconds: give the village an objective, watch residents claim jobs and gather, then read the log of why each resident took its job" width="560" height="315"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;A real recording of the live site: one click on Grow the village, then the decision log.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  How the agents cooperate
&lt;/h2&gt;

&lt;p&gt;The six residents bid for exclusive jobs using role suitability, distance and bounded experience. When a workplace or resource changes, they replan. Campaign residents use deterministic game AI, so there are no model calls and nothing to pay for.&lt;/p&gt;

&lt;p&gt;Try this: choose &lt;strong&gt;Village orders → Grow the village&lt;/strong&gt;, start it, then open &lt;strong&gt;View plan&lt;/strong&gt; to see the dependencies, the waiting reasons and the actual spending. Give a working resident a 20-tick rest and watch another one take over the job.&lt;/p&gt;

&lt;p&gt;The growth plan has a spending ceiling and protected reserves. In a fresh village it authorizes at most 1,560 gold and 1,240 timber and keeps 250 gold, 200 timber and 150 food back.&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%2F3xpbq374emi6gwiy4tsm.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%2F3xpbq374emi6gwiy4tsm.png" alt="Village development plan showing construction dependencies, spending ceiling and protected reserves" width="800" height="500"&gt;&lt;/a&gt;&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%2Fhhafeoclksyqqu2f0jot.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%2Fhhafeoclksyqqu2f0jot.png" alt="The agent inspector: a resident's current job, route and memories" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Test your own agent
&lt;/h2&gt;

&lt;p&gt;The part I care about most: it's also a testbed for external agents.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx settlement-testbed &lt;span class="nt"&gt;--agent&lt;/span&gt; http://127.0.0.1:8765/decide &lt;span class="nt"&gt;--name&lt;/span&gt; my-agent
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Point it at an HTTP endpoint, and it evaluates your agent, compares it with built-in policies, and records the answers so anyone can verify, replay or share the results. There are twelve scenarios, attacks and honest controls, based on manipulation tactics from published agent-safety studies, each citing its sources.&lt;/p&gt;

&lt;p&gt;Optional Claude decisions exist for explicit steps in local-worker research experiments. They're off unless you configure them.&lt;/p&gt;

&lt;h2&gt;
  
  
  Run it locally
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/Lingikaushikreddy/Settlement-Village.git
&lt;span class="nb"&gt;cd &lt;/span&gt;Settlement-Village
npm ci
npm run dev
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Needs Node 24+. TypeScript, MIT licensed, CI on every push.&lt;/p&gt;

&lt;p&gt;Repo: &lt;a href="https://github.com/Lingikaushikreddy/Settlement-Village" rel="noopener noreferrer"&gt;https://github.com/Lingikaushikreddy/Settlement-Village&lt;/a&gt;&lt;br&gt;
npm: &lt;a href="https://www.npmjs.com/package/settlement-testbed" rel="noopener noreferrer"&gt;https://www.npmjs.com/package/settlement-testbed&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you like games where agent decisions are visible, a star helps me find out whether anyone else does.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>typescript</category>
      <category>gamedev</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Your voice agent sounds right. Did it place the right order?</title>
      <dc:creator>Kaushikreddy Lingi</dc:creator>
      <pubDate>Thu, 15 Oct 2026 00:18:28 +0000</pubDate>
      <link>https://dev.to/lingikaushikreddy/your-voice-agent-sounds-right-did-it-place-the-right-order-55i8</link>
      <guid>https://dev.to/lingikaushikreddy/your-voice-agent-sounds-right-did-it-place-the-right-order-55i8</guid>
      <description>&lt;p&gt;Here is a Hinglish call to a restaurant voice agent:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="err"&gt;caller:&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="err"&gt;Do&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;paneer&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;wrap...&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;actually&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;ek&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;hi&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;karo.&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Bina&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;pyaaz.&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Aur&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;ek&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;mango&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;lassi.&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="err"&gt;agent:&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Paneer&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Wrap&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;add&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;kar&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;diya.&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Paneer&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Wrap&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;kar&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;diya.&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Paneer&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Wrap&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;No&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;onion&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;kar&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;diya.&lt;/span&gt;&lt;span class="w"&gt;
         &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Mango&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Lassi&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;add&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;kar&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;diya.&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Aur&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;kuch?&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="err"&gt;caller:&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="err"&gt;Bas&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;itna&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;hi,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;thanks.&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="err"&gt;agent:&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="err"&gt;Aapka&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;order:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Paneer&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Wrap,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;No&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;onion;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Mango&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Lassi.&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Order&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;place&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;ho&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;gaya,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;shukriya!&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The agent &lt;em&gt;read back&lt;/em&gt; one wrap without onion. This is what it &lt;em&gt;committed&lt;/em&gt;:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Field&lt;/th&gt;
&lt;th&gt;Expected&lt;/th&gt;
&lt;th&gt;Actual&lt;/th&gt;
&lt;th&gt;Result&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Submitted orders&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;Pass&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Paneer Wrap quantity&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;Fail&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Paneer Wrap · Onion&lt;/td&gt;
&lt;td&gt;No onion&lt;/td&gt;
&lt;td&gt;With onion&lt;/td&gt;
&lt;td&gt;Fail&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Mango Lassi quantity&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;Pass&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;A transcript-based test, or an LLM judge reading the conversation, passes this call. The customer gets two wraps with onion.&lt;/p&gt;

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

&lt;p&gt;&lt;strong&gt;IndicOrderBench&lt;/strong&gt; is an open-source benchmark and CI gate for voice ordering agents. It compares the &lt;strong&gt;committed backend state&lt;/strong&gt; against each scenario's acceptable end states, in English and Hinglish, instead of grading the words the agent said.&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%2Fm9gqndr8tj2c8yhzu9oe.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%2Fm9gqndr8tj2c8yhzu9oe.png" alt="IndicOrderBench HTML report for a passing run: order check, conversation and tool-call trace" width="800" height="938"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;The single-file HTML report from the fixed reference agent. The failing run of the same scenario is the one that catches the wrong order.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The hard failures it targets aren't accent or latency. They're mid-sentence corrections ("two... actually one"), modifiers ("no onion"), cancellations and duplicate submissions, especially in code-mixed speech where number words and negations don't look like English.&lt;br&gt;
&lt;/p&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;indicorderbench

iob demo &lt;span class="nt"&gt;--out&lt;/span&gt; demo-out     &lt;span class="c"&gt;# buggy vs fixed reference agent, no network, no keys&lt;/span&gt;
iob run starter &lt;span class="nt"&gt;--agent&lt;/span&gt; &lt;span class="nb"&gt;builtin&lt;/span&gt;:correct &lt;span class="nt"&gt;--tag&lt;/span&gt; smoke &lt;span class="nt"&gt;--trials&lt;/span&gt; 3
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A run writes &lt;code&gt;results.json&lt;/code&gt; (every transcript, tool call and backend snapshot), &lt;code&gt;junit.xml&lt;/code&gt; for any CI system, and a single-file &lt;code&gt;report.html&lt;/code&gt; that opens from &lt;code&gt;file://&lt;/code&gt;. The exit code is non-zero when an agent change starts placing wrong orders, so the build fails before a customer sees it.&lt;/p&gt;

&lt;p&gt;You can connect your agent in-process from Python, or over an HTTP adapter. The sandbox backend hands you JSON-schema tool definitions to give your LLM.&lt;/p&gt;

&lt;h2&gt;
  
  
  Scope
&lt;/h2&gt;

&lt;p&gt;It's small and deterministic on purpose: reproducible runs, no API keys for the demo. It's an early benchmark, not a leaderboard of production systems.&lt;/p&gt;

&lt;p&gt;Repo (Apache-2.0): &lt;a href="https://github.com/Lingikaushikreddy/indicorderbench" rel="noopener noreferrer"&gt;https://github.com/Lingikaushikreddy/indicorderbench&lt;/a&gt;&lt;br&gt;
PyPI: &lt;a href="https://pypi.org/project/indicorderbench/" rel="noopener noreferrer"&gt;https://pypi.org/project/indicorderbench/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you've seen a voice agent fail in a way this doesn't cover, open an issue with the transcript. Scenarios are easy to add.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>python</category>
      <category>testing</category>
      <category>opensource</category>
    </item>
    <item>
      <title>An Analytics Agent's Permissions Should Survive a Bad Prompt</title>
      <dc:creator>Kaushikreddy Lingi</dc:creator>
      <pubDate>Thu, 01 Oct 2026 17:53:57 +0000</pubDate>
      <link>https://dev.to/lingikaushikreddy/an-analytics-agents-permissions-should-survive-a-bad-prompt-4gb</link>
      <guid>https://dev.to/lingikaushikreddy/an-analytics-agents-permissions-should-survive-a-bad-prompt-4gb</guid>
      <description>&lt;p&gt;An analytics agent receives a hostile instruction: return every customer's unmasked payment identifier.&lt;/p&gt;

&lt;p&gt;The key question is what the system permits that agent to read—even if the model decides to follow the instruction.&lt;/p&gt;

&lt;p&gt;That is the boundary I am exploring in &lt;a href="https://github.com/Lingikaushikreddy/MerchantLens" rel="noopener noreferrer"&gt;MerchantLens&lt;/a&gt;, a merchant analytics lakehouse built with Databricks, Delta tables and Unity Catalog.&lt;/p&gt;

&lt;p&gt;The demo uses synthetic payments data. There is no real cardholder data in the project.&lt;/p&gt;

&lt;h2&gt;
  
  
  Put the caller's identity in the query path
&lt;/h2&gt;

&lt;p&gt;MerchantLens moves data through Bronze, Silver and Gold layers. An agent searches live catalog metadata and uses tools to query metrics or SQL.&lt;/p&gt;

&lt;p&gt;The agent executes under its own service principal. Unity Catalog applies column masks and row filters for that principal before returning query results.&lt;/p&gt;

&lt;p&gt;The README includes a comparison using the same SQL under two principals: the analyst sees a broader dataset, while the agent sees a restricted region and masked identifiers. The entitlement decision belongs to the query engine.&lt;/p&gt;

&lt;h2&gt;
  
  
  Separate reliability controls from authorization
&lt;/h2&gt;

&lt;p&gt;The project has several layers:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Layer&lt;/th&gt;
&lt;th&gt;Purpose&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Certified metrics&lt;/td&gt;
&lt;td&gt;Keep definitions and grain consistent&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Application checks&lt;/td&gt;
&lt;td&gt;Constrain SQL, schemas, rows and tool steps&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Unity Catalog policies&lt;/td&gt;
&lt;td&gt;Enforce identity-based row and column access&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Audit records&lt;/td&gt;
&lt;td&gt;Record tool activity independently of the answer&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The first two help keep the agent's behavior controlled. The catalog policies enforce data access.&lt;/p&gt;

&lt;p&gt;This does not make the entire application immune to attack. Its protection depends on correctly configured identities, grants, masks and filters, and on every query using the intended principal.&lt;/p&gt;

&lt;h2&gt;
  
  
  Test the protected table
&lt;/h2&gt;

&lt;p&gt;One practical lesson documented in the repository: checking a membership expression alone can give a misleading picture of what a mask does.&lt;/p&gt;

&lt;p&gt;A better proof exercises the protected table under the actual identity. Ask what rows and values come back, then compare those results with the intended entitlement.&lt;/p&gt;

&lt;p&gt;The repository also documents ambient grants on new service principals. Creating a new identity is not automatically a deny-by-default setup.&lt;/p&gt;

&lt;h2&gt;
  
  
  Metric definitions need boundaries too
&lt;/h2&gt;

&lt;p&gt;MerchantLens attributes chargebacks to the month of the originating transaction. Using the date a chargeback was opened can shift the apparent incident across months because disputes arrive later.&lt;/p&gt;

&lt;p&gt;That definition belongs in the semantic layer so a dashboard and an agent can use the same metric. Correct permissions do not compensate for an inconsistent denominator or time definition.&lt;/p&gt;

&lt;h2&gt;
  
  
  A review checklist
&lt;/h2&gt;

&lt;p&gt;Before giving an agent a warehouse tool, I would ask:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Which principal executes its queries?&lt;/li&gt;
&lt;li&gt;Can it retrieve restricted columns through another table or grant?&lt;/li&gt;
&lt;li&gt;Are protected-table results tested under that principal?&lt;/li&gt;
&lt;li&gt;Are tool calls logged somewhere the agent cannot modify?&lt;/li&gt;
&lt;li&gt;Are metric definitions explicit and shared?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Where does your analytics agent's access control execute: in the prompt, the application, or the database?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/Lingikaushikreddy/MerchantLens" rel="noopener noreferrer"&gt;Read the architecture and platform findings&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Drafted with AI from the public project documentation. Demo observations are repository-reported, not a new verification run.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>security</category>
      <category>database</category>
      <category>dataengineering</category>
    </item>
    <item>
      <title>A RAG Agent Can Refuse Every Attack and Still Fail Its Users</title>
      <dc:creator>Kaushikreddy Lingi</dc:creator>
      <pubDate>Thu, 01 Oct 2026 17:53:49 +0000</pubDate>
      <link>https://dev.to/lingikaushikreddy/a-rag-agent-can-refuse-every-attack-and-still-fail-its-users-3fe0</link>
      <guid>https://dev.to/lingikaushikreddy/a-rag-agent-can-refuse-every-attack-and-still-fail-its-users-3fe0</guid>
      <description>&lt;p&gt;Suppose an agent refuses every request. Its attack success rate might look excellent. Its usefulness would be terrible.&lt;/p&gt;

&lt;p&gt;That tradeoff is a central design concern in &lt;a href="https://github.com/Lingikaushikreddy/aegiseval" rel="noopener noreferrer"&gt;AegisEval&lt;/a&gt;, my adversarial evaluation project for a tool-using customer-support RAG agent.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Status first:&lt;/strong&gt; the evaluation machinery is implemented, but no evaluation run has been recorded yet. This post describes the design, not measured safety improvements.&lt;/p&gt;

&lt;h2&gt;
  
  
  Evaluate actions, not just answers
&lt;/h2&gt;

&lt;p&gt;The fictional retailer's chatbot retrieves help-centre content and has tools for refunds, cancellations and shipping-address changes.&lt;/p&gt;

&lt;p&gt;That creates questions a text-only test misses. Did the agent act on the correct order? Did it follow the applicable policy? Did it obtain confirmation? Did a malicious instruction in retrieved content influence a tool call?&lt;/p&gt;

&lt;p&gt;Ownership checks and the refund ceiling are enforced in the tools. Other business rules intentionally live in the target's prompt, so the evaluation can probe failures at that boundary.&lt;/p&gt;

&lt;p&gt;This is a test target, not a recommendation to leave production authorization to a prompt.&lt;/p&gt;

&lt;h2&gt;
  
  
  Include customers who should succeed
&lt;/h2&gt;

&lt;p&gt;The golden set contains 260 cases. Of those, 68 are legitimate customer requests, including 12 hard negatives that resemble attacks.&lt;/p&gt;

&lt;p&gt;For example, an angry customer may be entitled to a large refund. Someone saying “ignore my last message” may simply be correcting a request.&lt;/p&gt;

&lt;p&gt;If a mitigation blocks those users, the report needs to show that cost alongside attack outcomes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Tool output can carry hostile text
&lt;/h2&gt;

&lt;p&gt;AegisEval covers four injection surfaces:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Direct user input&lt;/li&gt;
&lt;li&gt;Retrieved documents&lt;/li&gt;
&lt;li&gt;Web results&lt;/li&gt;
&lt;li&gt;Free-text fields inside order records&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That fourth surface is easy to overlook. Gift messages and delivery notes can contain customer-controlled text even when they arrive through a tool the agent called itself. Retrieval sanitization alone does not cover that path.&lt;/p&gt;

&lt;p&gt;Matched payloads across indirect surfaces help separate differences in the boundary from differences in attack wording.&lt;/p&gt;

&lt;h2&gt;
  
  
  Treat the judge as another component to evaluate
&lt;/h2&gt;

&lt;p&gt;The judge uses a different model and vendor from the target. It does not see the case author's expected behavior. Human labeling is blind to the judge's verdict.&lt;/p&gt;

&lt;p&gt;The pipeline is designed to report agreement by harm category with confidence intervals. Those validation numbers still require recorded runs and human labels.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I would want in a useful report
&lt;/h2&gt;

&lt;p&gt;I would look for attack outcomes, legitimate-task outcomes, raw counts, category breakdowns and the configuration tested. I would also want the limitations visible: this project is English-only, uses one target configuration and has a modest dataset.&lt;/p&gt;

&lt;p&gt;A passing result for that setup would be evidence about that setup. It would not establish that the underlying model is universally safe.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How do you measure whether an agent's safety controls are also blocking legitimate work?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/Lingikaushikreddy/aegiseval" rel="noopener noreferrer"&gt;Explore the threat model, taxonomy and pipeline&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Drafted with AI from the repository documentation. No evaluation results are claimed.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>security</category>
      <category>python</category>
      <category>discuss</category>
    </item>
    <item>
      <title>I Built a Village of Six Agents You Can Actually Inspect</title>
      <dc:creator>Kaushikreddy Lingi</dc:creator>
      <pubDate>Thu, 01 Oct 2026 17:53:40 +0000</pubDate>
      <link>https://dev.to/lingikaushikreddy/i-built-a-village-of-six-agents-you-can-actually-inspect-1ci5</link>
      <guid>https://dev.to/lingikaushikreddy/i-built-a-village-of-six-agents-you-can-actually-inspect-1ci5</guid>
      <description>&lt;p&gt;An agent claims a task. Another agent needs the same resources. A third is resting. Who gets the job, and can you explain the decision afterward?&lt;/p&gt;

&lt;p&gt;That is the kind of question I am exploring with &lt;a href="https://github.com/Lingikaushikreddy/Settlement-Village" rel="noopener noreferrer"&gt;Settlement&lt;/a&gt;, a village strategy game and an inspectable simulation lab.&lt;/p&gt;

&lt;p&gt;With &lt;a href="https://dev.to/t/hacktoberfest"&gt;Hacktoberfest focusing on open-source AI this October&lt;/a&gt;, it feels like a useful time to share a project where the behavior is visible and the default setup needs no model API key.&lt;/p&gt;

&lt;h2&gt;
  
  
  One objective, six residents
&lt;/h2&gt;

&lt;p&gt;Choose an objective such as preparing for a raid or restocking supplies. The planner splits it into jobs. Six residents bid using role suitability, distance and bounded experience. Each job has one owner.&lt;/p&gt;

&lt;p&gt;Residents walk to workplaces, gather resources and coordinate recruitment. If a resident rests, its work can be released for another resident to take over. When resources or workplaces change, agents reconsider their tasks.&lt;/p&gt;

&lt;p&gt;The interesting part is the inspector: current jobs, blocked work, spending limits and recent memories are available to read alongside the action log.&lt;/p&gt;

&lt;h2&gt;
  
  
  The boundary matters
&lt;/h2&gt;

&lt;p&gt;The default campaign uses deterministic game AI. It does not understand arbitrary natural-language goals, train a neural network or call a model behind the scenes.&lt;/p&gt;

&lt;p&gt;Optional Claude proposals belong to explicitly configured local-worker research experiments. Keeping those paths separate makes it clearer what a result actually measures.&lt;/p&gt;

&lt;p&gt;The world also enforces constraints. Actions validate funds, capacity and the objective's spending allowance. A decision needs to become a valid action before it changes the treasury or army.&lt;/p&gt;

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

&lt;p&gt;Use Node.js 24+:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/Lingikaushikreddy/Settlement-Village.git
&lt;span class="nb"&gt;cd &lt;/span&gt;Settlement-Village
npm ci
npm run dev
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Open &lt;a href="http://localhost:5173" rel="noopener noreferrer"&gt;http://localhost:5173&lt;/a&gt;. Choose &lt;strong&gt;Village orders → Prepare for a raid&lt;/strong&gt;, then &lt;strong&gt;View plan → Shared jobs&lt;/strong&gt;. Inspect one resident before and after giving it a rest.&lt;/p&gt;

&lt;h2&gt;
  
  
  A small experiment to try
&lt;/h2&gt;

&lt;p&gt;Ask three questions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Did the job change owners when the resident rested?&lt;/li&gt;
&lt;li&gt;Can I identify why the replacement took it?&lt;/li&gt;
&lt;li&gt;Did the action respect the objective's budget?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The research view adds matched seeds, JSON/CSV exports and replay verification. Its authored scenarios are a bounded testbed; results there should not be treated as a general AI safety benchmark.&lt;/p&gt;

&lt;p&gt;Contributions could explore richer objectives, recovery behavior or more adversarial and honest-control scenarios. The &lt;a href="https://github.com/Lingikaushikreddy/Settlement-Village/blob/main/CONTRIBUTING.md" rel="noopener noreferrer"&gt;contribution guide&lt;/a&gt; is the starting point.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What would you want to inspect first in a multi-agent system: task ownership, memory, or spending?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Drafted with AI from the public project README; project behavior and limitations are linked above.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>opensource</category>
      <category>typescript</category>
      <category>hacktoberfest</category>
    </item>
  </channel>
</rss>
