<?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: Iwasoft</title>
    <description>The latest articles on DEV Community by Iwasoft (@kissoid).</description>
    <link>https://dev.to/kissoid</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%2F4097027%2F4ccb2a25-f038-4f6e-adff-85a202ce0e75.png</url>
      <title>DEV Community: Iwasoft</title>
      <link>https://dev.to/kissoid</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/kissoid"/>
    <language>en</language>
    <item>
      <title>We started writing docs for AI agents, not humans — and made it an open standard</title>
      <dc:creator>Iwasoft</dc:creator>
      <pubDate>Sun, 30 Aug 2026 07:50:56 +0000</pubDate>
      <link>https://dev.to/kissoid/we-started-writing-docs-for-ai-agents-not-humans-and-made-it-an-open-standard-3ija</link>
      <guid>https://dev.to/kissoid/we-started-writing-docs-for-ai-agents-not-humans-and-made-it-an-open-standard-3ija</guid>
      <description>&lt;h2&gt;
  
  
  Most people install our tools through an agent now
&lt;/h2&gt;

&lt;p&gt;We build a few developer products — an event-ledger database, an S3-compatible&lt;br&gt;
object store, and others. Over the last few months we noticed a shift: most&lt;br&gt;
people who try them don't start in a browser. They tell a coding agent “add this&lt;br&gt;
to my project,” and the agent does the install and the wiring.&lt;/p&gt;

&lt;p&gt;So we started watching agents work against our documentation.&lt;/p&gt;

&lt;h2&gt;
  
  
  Watching an agent guess
&lt;/h2&gt;

&lt;p&gt;Most of the time it went fine. But every so often the agent would invent a&lt;br&gt;
config flag that didn't exist, or reach for the wrong port, or call an endpoint&lt;br&gt;
that was &lt;em&gt;almost&lt;/em&gt; right. It wasn't the model being dumb — our docs were written&lt;br&gt;
to persuade and onboard a &lt;strong&gt;human&lt;/strong&gt;, and the agent was reconstructing facts from&lt;br&gt;
prose three paragraphs apart. A fact an agent has to infer is a fact you failed&lt;br&gt;
to state.&lt;/p&gt;

&lt;h2&gt;
  
  
  A second document, for a different reader
&lt;/h2&gt;

&lt;p&gt;So per release we started shipping a second file: &lt;code&gt;documentation.ai.md&lt;/code&gt;. Not a&lt;br&gt;
terser translation of the human docs — a different document, for a different&lt;br&gt;
reader, held to a stricter standard of precision.&lt;/p&gt;

&lt;p&gt;It's English, dense, and self-sufficient: an agent that has read &lt;em&gt;only&lt;/em&gt; that file&lt;br&gt;
can install, configure and call the product. Fixed sections, in order:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;One-line identity&lt;/li&gt;
&lt;li&gt;Install / run — exact commands, exact image names and ports&lt;/li&gt;
&lt;li&gt;Configuration — every env var / key, with its default&lt;/li&gt;
&lt;li&gt;API quickstart — a real request/response, not pseudocode&lt;/li&gt;
&lt;li&gt;Admin surface — how the first credential is obtained, the common operations&lt;/li&gt;
&lt;li&gt;Architecture facts that affect integration&lt;/li&gt;
&lt;li&gt;Links&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;No marketing language. Absolute honesty about status — if something is early or&lt;br&gt;
unaudited, the file says so, because an agent that recommends an unstable feature&lt;br&gt;
to a user because the doc oversold it is a real failure.&lt;/p&gt;

&lt;h2&gt;
  
  
  “Why not just llms.txt?”
&lt;/h2&gt;

&lt;p&gt;Fair question, and we get it a lot. We're not trying to replace&lt;br&gt;
&lt;a href="https://llmstxt.org" rel="noopener noreferrer"&gt;llms.txt&lt;/a&gt;. It's a great &lt;em&gt;site-level index&lt;/em&gt; of your content.&lt;br&gt;
&lt;code&gt;documentation.ai.md&lt;/code&gt; is a &lt;em&gt;per-product, per-release operational doc&lt;/em&gt; — closer in&lt;br&gt;
spirit to &lt;code&gt;llms-full.txt&lt;/code&gt;: complete, not an index. They compose cleanly.&lt;/p&gt;

&lt;h2&gt;
  
  
  We made it a standard
&lt;/h2&gt;

&lt;p&gt;It worked well enough across our products that we wrote it up as an open standard&lt;br&gt;
(CC BY 4.0), so anyone can adopt it:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;GitHub: &lt;a href="https://github.com/iwasoftcom/ai-docs-standard" rel="noopener noreferrer"&gt;https://github.com/iwasoftcom/ai-docs-standard&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Write-up: &lt;a href="https://iwasoft.com/blog/ai-docs-standard" rel="noopener noreferrer"&gt;https://iwasoft.com/blog/ai-docs-standard&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you build developer tools, your users' agents are already reading your docs.&lt;br&gt;
This is just writing the version they actually need.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>llm</category>
      <category>devtools</category>
      <category>opensource</category>
    </item>
    <item>
      <title>We didn't build a code-review agent. Here's why.</title>
      <dc:creator>Iwasoft</dc:creator>
      <pubDate>Thu, 27 Aug 2026 09:13:35 +0000</pubDate>
      <link>https://dev.to/kissoid/we-didnt-build-a-code-review-agent-heres-why-4mn0</link>
      <guid>https://dev.to/kissoid/we-didnt-build-a-code-review-agent-heres-why-4mn0</guid>
      <description>&lt;h1&gt;
  
  
  We didn't build a code-review agent. Here's why.
&lt;/h1&gt;

&lt;p&gt;We just shipped a Code Review API for &lt;a href="https://consensusroom.com" rel="noopener noreferrer"&gt;Consensus Room&lt;/a&gt;, and the most interesting part of building it wasn't the AI — it was deciding what &lt;em&gt;not&lt;/em&gt; to build.&lt;/p&gt;

&lt;h2&gt;
  
  
  The tempting wrong answer
&lt;/h2&gt;

&lt;p&gt;The obvious pitch is: "point our agent at your repo, it reviews everything, done." That's what a lot of AI code review tools do. We almost built it too.&lt;/p&gt;

&lt;p&gt;Then we looked at what it would actually require:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Tool-calling/function-calling wired up per LLM provider (we had zero of this — our stack is pure text completion via Claude, GPT, Gemini, and a dozen OpenRouter models)&lt;/li&gt;
&lt;li&gt;A sandboxed execution environment to let models poke around an arbitrary user-submitted repo — a real security surface on a multi-tenant SaaS&lt;/li&gt;
&lt;li&gt;Open-ended cost. If an agent decides how many files to read and how many tool calls to make, you can't tell a user "this will cost $0.03" before you start. Our whole product's trust model is a pre-flight cost estimate before anything runs.&lt;/li&gt;
&lt;li&gt;Much higher latency — a multi-step tool loop per review vs. a couple of LLM calls.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;None of that is impossible. It's just a different, much bigger project than "let multiple models review this code and merge their findings."&lt;/p&gt;

&lt;h2&gt;
  
  
  What we built instead
&lt;/h2&gt;

&lt;p&gt;A single, boring, fast endpoint: &lt;code&gt;POST /api/v1/code-review&lt;/code&gt;. You send one code unit — a file, a function, a diff — and get back a structured report from multiple models plus a merged verdict. That's it. No repo access, no tool calls, no crawling.&lt;/p&gt;

&lt;p&gt;The trick is who calls it. If &lt;em&gt;your own&lt;/em&gt; coding agent (Claude Code, Cursor, a CI script, whatever) already knows how to walk a repo and decide what's worth reviewing, it can just call our endpoint once per file as part of its own loop. We don't need to reinvent repo traversal — every coding agent already does that. We just need to be a really good "get a second, third, and fourth opinion on this specific piece of code" primitive that's cheap and fast to call repeatedly.&lt;/p&gt;

&lt;p&gt;This reframing cut the actual engineering scope by an order of magnitude, and it's honestly a better fit for how people already work with coding agents.&lt;/p&gt;

&lt;h2&gt;
  
  
  The part that was still a real problem: structured output across providers
&lt;/h2&gt;

&lt;p&gt;We wanted findings back as structured data — severity, category, line number — not just a paragraph of prose. Obvious answer: JSON mode.&lt;/p&gt;

&lt;p&gt;Except we support Claude, GPT, Gemini (via an OpenAI-compatible endpoint), and whatever OpenRouter has that week. Checking the actual Spring AI option classes: &lt;code&gt;OpenAiChatOptions&lt;/code&gt; has a &lt;code&gt;responseFormat&lt;/code&gt; field. &lt;code&gt;AnthropicChatOptions&lt;/code&gt; does not. There's no single JSON-mode contract that works uniformly across all of them.&lt;/p&gt;

&lt;p&gt;So we didn't fight it. Each reviewer is instructed to emit one strict line format instead:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;- [SEVERITY:HIGH] [CATEGORY:security] [LINE:42] SQL injection — user input is concatenated directly into the query.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The server regex-parses that into structured JSON for the API response. If a model ever drifts from the format, the raw text is still returned in full alongside the (possibly incomplete) parsed findings — a parsing miss never silently drops information, it just means one field is less structured than usual.&lt;/p&gt;

&lt;p&gt;The moderator step takes every reviewer's raw findings, deduplicates the ones multiple models independently flagged (&lt;code&gt;[CONFIRMED BY:2/3]&lt;/code&gt;), and closes with a single &lt;code&gt;VERDICT: APPROVE|COMMENT|REQUEST_CHANGES&lt;/code&gt; line.&lt;/p&gt;

&lt;h2&gt;
  
  
  Making it resumable, because money is involved
&lt;/h2&gt;

&lt;p&gt;Every LLM call costs real money the moment it completes, and it's charged immediately — not batched at the end. That means a review that fails halfway through (a provider hiccup, balance running out mid-flight) must not throw away work you already paid for.&lt;/p&gt;

&lt;p&gt;So the run loop is checkpointed: every reviewer's finding is persisted the instant it comes back. If a review fails or pauses, calling it again reloads what's already stored and only retries what's missing — nothing gets recharged, nothing gets lost. This wasn't a nice-to-have we added later; it came directly from asking "what happens when this fails halfway, with a customer's money on the line."&lt;/p&gt;

&lt;h2&gt;
  
  
  Trying it
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-s&lt;/span&gt; &lt;span class="s2"&gt;"https://consensusroom.com/api/v1/code-review?wait=90"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Authorization: Bearer cr_live_..."&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Content-Type: application/json"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{
    "code": "def get_user(username):\n    query = \"SELECT * FROM users WHERE username = \" + username\n    return db.execute(query)",
    "filename": "users.py",
    "panelists": [
      {"key": "claude", "model": "claude-haiku-4-5", "role": "security"},
      {"key": "gpt",    "model": "gpt-4o-mini",       "role": "bugs"}
    ]
  }'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Full reference (fields, limits, error codes, the exact parsing regex) is in &lt;a href="https://consensusroom.com/documentation.ai.md" rel="noopener noreferrer"&gt;documentation.ai.md&lt;/a&gt; — written to be pasted straight into an agent's context.&lt;/p&gt;

&lt;p&gt;Would genuinely like feedback from anyone who's solved the "structured output across heterogeneous LLM providers" problem differently — curious if there's a cleaner approach we're missing.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>api</category>
      <category>webdev</category>
      <category>showdev</category>
    </item>
  </channel>
</rss>
