<?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: Srinivas Kondepudi</title>
    <description>The latest articles on DEV Community by Srinivas Kondepudi (@sirinivask).</description>
    <link>https://dev.to/sirinivask</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%2F3929806%2F3e582fb0-6ad8-4b28-bd40-b27808c07692.jpg</url>
      <title>DEV Community: Srinivas Kondepudi</title>
      <link>https://dev.to/sirinivask</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/sirinivask"/>
    <language>en</language>
    <item>
      <title>What Evidence Does an AI Agent Actually Need to Leave Behind?</title>
      <dc:creator>Srinivas Kondepudi</dc:creator>
      <pubDate>Wed, 23 Sep 2026 09:28:39 +0000</pubDate>
      <link>https://dev.to/sirinivask/what-evidence-does-an-ai-agent-actually-need-to-leave-behind-2b02</link>
      <guid>https://dev.to/sirinivask/what-evidence-does-an-ai-agent-actually-need-to-leave-behind-2b02</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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fupd2191ms56pg9e75yh1.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%2Fupd2191ms56pg9e75yh1.png" alt="Chron" width="799" height="441"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What Evidence Does an AI Agent Actually Need to Leave Behind?
&lt;/h2&gt;

&lt;p&gt;There is a question that keeps surfacing as AI agents move from answering questions in chat to actually doing things, writing code, modifying configs, calling APIs, deploying services.&lt;/p&gt;

&lt;p&gt;The question is not "how do we stop them from acting?"&lt;/p&gt;

&lt;p&gt;The question is: &lt;strong&gt;what evidence do we need after they act?&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  The Git Commit Problem
&lt;/h2&gt;

&lt;p&gt;The reflex answer is: just look at the diff.&lt;/p&gt;

&lt;p&gt;A Git commit shows you what changed. That used to be enough when a human sat behind every change. The human held the context. You could ask them. The commit message, however brief, was a pointer to a person who understood the decision.&lt;/p&gt;

&lt;p&gt;With an AI agent, the commit is often the &lt;em&gt;only&lt;/em&gt; artifact. And it hides almost everything that mattered:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What did the user actually ask for?&lt;/li&gt;
&lt;li&gt;What did the agent read before deciding what to change?&lt;/li&gt;
&lt;li&gt;Which tools did it call, and in what order?&lt;/li&gt;
&lt;li&gt;Did it touch secrets, authentication tokens, environment variables, or production config along the way?&lt;/li&gt;
&lt;li&gt;Was there a human in the loop, and if so, did they actually review anything, or just click Allow?&lt;/li&gt;
&lt;li&gt;Can someone reconstruct the full sequence six months from now when something breaks in production?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A commit hash answers none of those questions.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why This Is the Practical Governance Problem Right Now
&lt;/h2&gt;

&lt;p&gt;We have spent years building approval workflows for &lt;em&gt;human&lt;/em&gt; code changes. Pull requests, code review, change advisory boards, ticket numbers in commit messages. These processes assume a human author who can be questioned, who made a conscious decision, who can explain their reasoning.&lt;/p&gt;

&lt;p&gt;AI agents break that assumption quietly.&lt;/p&gt;

&lt;p&gt;The agent acts faster than review cycles were designed for. It calls ten tools in thirty seconds. It reads a config file, writes a new one, runs a test, opens a PR, and waits, all before anyone noticed it started. The change looks reasonable. The tests pass. The PR gets merged.&lt;/p&gt;

&lt;p&gt;Three months later, something unexpected happens in production. You need to understand what the agent knew, what it read, what choices it made, and what a human approved.&lt;/p&gt;

&lt;p&gt;If the only record is the commit, you have nothing.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Minimum Viable Evidence Set
&lt;/h2&gt;

&lt;p&gt;I am not arguing for heavyweight approval workflows on every AI action. That path leads to agents being so throttled they are useless.&lt;/p&gt;

&lt;p&gt;But I do think every &lt;em&gt;meaningful&lt;/em&gt; AI action, anything that modifies state outside the agent's own scratchpad, should leave enough evidence to answer questions when it matters.&lt;/p&gt;

&lt;p&gt;Here is what that looks like in practice:&lt;/p&gt;

&lt;h3&gt;
  
  
  1. The original intent
&lt;/h3&gt;

&lt;p&gt;What did the user ask for? Not the agent's interpretation, the actual message. This is the anchor for everything else. If the change cannot be traced back to a human request, that is itself meaningful information.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. The tool call sequence
&lt;/h3&gt;

&lt;p&gt;Which tools did the agent call, in what order, and what did it pass to them? This is the chain of decisions. A file read that preceded a file write tells you the agent saw the old value before replacing it. A secrets lookup before a config change is a different kind of event than a blind write.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. What the agent read
&lt;/h3&gt;

&lt;p&gt;Before an agent modifies something, it usually reads something. That read context is often the difference between "the agent made a reasonable change given what it saw" and "the agent made a change that only makes sense if it misread something."&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Sensitive surface contact
&lt;/h3&gt;

&lt;p&gt;Did the interaction touch authentication, authorization, secrets, infrastructure definitions, or production configuration? These are not just higher-risk changes, they are the category of changes that auditors, security teams, and incident responders will ask about first.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Human approval record
&lt;/h3&gt;

&lt;p&gt;Was a human shown anything before the change happened? Did they click through a permission prompt, review a plan, or simply let the agent run autonomously? The presence or absence of human review is material. So is the &lt;em&gt;kind&lt;/em&gt; of review, "I saw a one-line summary" is different from "I read the full plan and the diff."&lt;/p&gt;

&lt;h3&gt;
  
  
  6. Reconstructability
&lt;/h3&gt;

&lt;p&gt;Can someone who was not in the room replay the sequence? Not re-run the agent, but follow the evidence trail and understand what happened. This is the test. If the answer is no, the evidence is insufficient.&lt;/p&gt;




&lt;h2&gt;
  
  
  Where People Draw the Line
&lt;/h2&gt;

&lt;p&gt;In practice, teams end up in one of a few places:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Git history only.&lt;/strong&gt; Fast, familiar, already required. Works fine when agents are doing what a junior developer would do and the stakes are low. Fails when something goes wrong and you need to explain the decision chain.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Tool-call logs.&lt;/strong&gt; A step up. You know what the agent touched. You do not always know why, or what it read, or what the user originally asked for. Better for incident response than for governance.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Approval records.&lt;/strong&gt; Some teams require a human sign-off checkpoint before the agent can modify certain surfaces — production, secrets, auth config. This is reasonable for high-stakes surfaces. It does not help you reconstruct what happened before the approval, or what the agent read to arrive at its proposal.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Full session traces.&lt;/strong&gt; The full conversation, user messages, tool calls, reads, writes, tool results, stored with tamper-evident hashes. This is the complete evidence set. It is also the most expensive to store and the most sensitive to handle, because it may contain secrets that appeared in tool results.&lt;/p&gt;

&lt;p&gt;The honest answer is that the right level depends on the surface. An agent writing unit tests probably does not need a full session trace. An agent modifying IAM policies probably does.&lt;/p&gt;




&lt;h2&gt;
  
  
  What Chron Is Doing Here
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://www.npmjs.com/package/chron-mcp" rel="noopener noreferrer"&gt;Chron&lt;/a&gt; is an MCP server that creates tamper-evident audit logs of AI sessions — stored locally, on your own machine, in a SQLite database you control.&lt;/p&gt;

&lt;p&gt;Every tool call is logged with a cryptographic hash chain. The user's original message is captured. The sequence is reconstructable. The database does not leave your environment.&lt;/p&gt;

&lt;p&gt;It crossed 9,000 npm downloads this week, which is a signal that the question this article is asking is not just theoretical. People are encountering it in real work and looking for answers.&lt;/p&gt;

&lt;p&gt;Chron's position is deliberately minimal: it records, it does not certify. It does not tell you whether a change was authorized or correct. It gives you the evidence to answer those questions yourself, or to hand to someone else who needs to answer them later.&lt;/p&gt;

&lt;p&gt;That boundary - &lt;strong&gt;recording vs. certifying&lt;/strong&gt; - matters. The tool that captures evidence should not be the same tool that decides what the evidence means. Those are different jobs.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Question Worth Asking Your Team
&lt;/h2&gt;

&lt;p&gt;If an AI agent in your environment made a change right now, something it wrote, deployed, or modified, and three months from now you needed to explain that change to a customer, an auditor, or your own security team, what would you show them?&lt;/p&gt;

&lt;p&gt;If the answer is "the commit," that is worth thinking about.&lt;/p&gt;

&lt;p&gt;Not because commits are bad. Because they were designed for a world where a human sat behind every change, and that world is changing faster than our evidence practices are.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Chron is available as an MCP server: &lt;code&gt;npx chron-mcp&lt;/code&gt;. It works with Claude, Cursor, and any MCP-compatible AI tool. The audit database is yours - local SQLite, no cloud egress.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>aigovernance</category>
      <category>agenticai</category>
      <category>security</category>
      <category>devops</category>
    </item>
    <item>
      <title>The AI Race Has a Missing Question: Can We Explain What Our Agents Already Did?</title>
      <dc:creator>Srinivas Kondepudi</dc:creator>
      <pubDate>Fri, 18 Sep 2026 16:08:34 +0000</pubDate>
      <link>https://dev.to/sirinivask/the-ai-race-has-a-missing-question-can-we-explain-what-our-agents-already-did-4l03</link>
      <guid>https://dev.to/sirinivask/the-ai-race-has-a-missing-question-can-we-explain-what-our-agents-already-did-4l03</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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fjqly1fv0ca4jc4l6mp6m.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%2Fjqly1fv0ca4jc4l6mp6m.png" alt="Chron" width="799" height="441"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The public conversation around advanced AI often collapses into two positions.&lt;/p&gt;

&lt;p&gt;One side says we should slow down.&lt;/p&gt;

&lt;p&gt;The other says progress is inevitable, so we should accelerate and compete.&lt;/p&gt;

&lt;p&gt;Both arguments matter. But teams deploying AI agents today face a more immediate problem:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Can we explain what the agents already did inside our own environments?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;That question is less dramatic than the future of superintelligence. It is also more operationally urgent.&lt;/p&gt;

&lt;p&gt;AI coding assistants and autonomous agents are no longer limited to suggesting text in a chat window. They can inspect repositories, execute commands, call tools, modify files, use credentials, interact with ticketing systems, and reach external services.&lt;/p&gt;

&lt;p&gt;Once that happens, "we have a policy" is no longer enough.&lt;/p&gt;

&lt;p&gt;A team needs to be able to answer basic questions after an incident, review, or audit:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What was the original request?&lt;/li&gt;
&lt;li&gt;Which tools did the agent use?&lt;/li&gt;
&lt;li&gt;What happened between the prompt and the final answer?&lt;/li&gt;
&lt;li&gt;Which files or systems were changed?&lt;/li&gt;
&lt;li&gt;Was a risky action approved?&lt;/li&gt;
&lt;li&gt;Did a person review the result?&lt;/li&gt;
&lt;li&gt;Can someone else reconstruct the sequence later?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The important word is not logging. It is &lt;strong&gt;causality&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;A repository might show that a file changed. A chat transcript might show that someone asked for help. An access log might show that a credential was used.&lt;/p&gt;

&lt;p&gt;But those records often do not explain how the events connect:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Which agent action led to this command, which led to this file write, under which user request, with which approval?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That missing chain is where accountability disappears.&lt;/p&gt;

&lt;h2&gt;
  
  
  This is not an argument for blocking every action
&lt;/h2&gt;

&lt;p&gt;Human checkpoints matter, especially for irreversible or high-impact actions. But prompting a person for approval on every operation creates its own failure mode: approval fatigue.&lt;/p&gt;

&lt;p&gt;Anthropic has written publicly about this tradeoff. Its experience with agent permissions found that people approved the overwhelming majority of prompts, making constant confirmation an unreliable safety mechanism by itself. Their focus is increasingly on technical containment: constraining what an agent can do through boundaries such as sandboxes, virtual machines, and egress controls. Read &lt;a href="https://www.anthropic.com/engineering/how-we-contain-claude" rel="noopener noreferrer"&gt;How we contain Claude across products&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The point is not to eliminate human review.&lt;/p&gt;

&lt;p&gt;It is to reserve it for the moments where it matters, then preserve evidence that the review happened.&lt;/p&gt;

&lt;h2&gt;
  
  
  Governance needs two layers
&lt;/h2&gt;

&lt;p&gt;A useful operating model has two distinct layers.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Preventive controls&lt;/strong&gt; constrain what an agent can do: scoped credentials, network boundaries, sandboxes, policy enforcement, and approval gates.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Detective controls&lt;/strong&gt; preserve what the agent did: requests, tool calls, results, files changed, timestamps, decisions, approvals, and evidence of review.&lt;/p&gt;

&lt;p&gt;One without the other is incomplete.&lt;/p&gt;

&lt;p&gt;Preventive controls can reduce harm, but they cannot explain an action later unless the decision itself is recorded.&lt;/p&gt;

&lt;p&gt;Logs can support an investigation, but they cannot prevent an agent from reaching a system it should never have been allowed to access.&lt;/p&gt;

&lt;p&gt;This is why the conversation should not be "governance versus innovation." Good governance is part of what lets teams adopt useful agents with confidence.&lt;/p&gt;

&lt;p&gt;OpenAI's own discussion of safely operating coding agents describes the same ingredients: technical boundaries, approval decisions, agent-aware telemetry, and the ability to inspect the original request, tool activity, results, and policy decisions when something needs review. Read &lt;a href="https://openai.com/index/running-codex-safely" rel="noopener noreferrer"&gt;Running Codex safely at OpenAI&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Build the evidence trail before you need it
&lt;/h2&gt;

&lt;p&gt;The worst time to ask how an AI agent acted is after something went wrong.&lt;/p&gt;

&lt;p&gt;By then, the prompt may be gone, the context may have been compacted, tool output may have changed, and the person who ran the session may not remember why a decision was made.&lt;/p&gt;

&lt;p&gt;Evidence is cheap to preserve at the moment of action and expensive to reconstruct later.&lt;/p&gt;

&lt;p&gt;That is the problem Chron is built around.&lt;/p&gt;

&lt;p&gt;Chron is a local-first audit trail for AI-assisted work. It records AI sessions and their events, maintains evidence integrity locally, and helps teams find the sessions that warrant review. It does not certify compliance or replace a human auditor. It gives teams a more defensible starting point: a record of what occurred.&lt;/p&gt;

&lt;p&gt;The argument about how quickly AI should progress will continue.&lt;/p&gt;

&lt;p&gt;In the meantime, organizations should make sure that the AI already acting in their codebases and environments is not operating in a black box.&lt;/p&gt;

&lt;p&gt;Because the question after an incident will not be:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Was the model powerful?"&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It will be:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"What did it do?"&lt;/p&gt;
&lt;/blockquote&gt;




&lt;p&gt;Chron has passed 8,852 downloads. It is still early, local-first, and free to try:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-g&lt;/span&gt; chron-mcp
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>ai</category>
      <category>aigovernance</category>
      <category>devsecops</category>
      <category>mcp</category>
    </item>
    <item>
      <title>The AI Race Is a Governance Problem Before It Is a Superintelligence Problem</title>
      <dc:creator>Srinivas Kondepudi</dc:creator>
      <pubDate>Thu, 10 Sep 2026 09:13:56 +0000</pubDate>
      <link>https://dev.to/sirinivask/the-ai-race-is-a-governance-problem-before-it-is-a-superintelligence-problem-2g7i</link>
      <guid>https://dev.to/sirinivask/the-ai-race-is-a-governance-problem-before-it-is-a-superintelligence-problem-2g7i</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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fsmzclm1f0qv2wi90y5bd.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%2Fsmzclm1f0qv2wi90y5bd.png" alt="Chron" width="799" height="418"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The Long-Term Debate Is Already an Operational Problem
&lt;/h2&gt;

&lt;p&gt;This week, a researcher who said he spent three years working at OpenAI and Anthropic resigned publicly and warned that leading labs are moving too quickly toward systems that may become difficult to control.&lt;/p&gt;

&lt;p&gt;His warning is his own assessment, not a prediction anyone can prove today. But it raises a question that engineering teams should not wait to answer:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What evidence do we have of what our AI systems are actually doing?&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  From Answering Questions to Taking Actions
&lt;/h2&gt;

&lt;p&gt;The long-term debate is about increasingly capable and autonomous systems.&lt;/p&gt;

&lt;p&gt;The immediate problem is simpler.&lt;/p&gt;

&lt;p&gt;AI tools already inspect repositories, execute commands, call tools, change files, and influence work in real environments. They are moving from "answering questions" to "taking actions."&lt;/p&gt;

&lt;p&gt;When that happens, a prompt and a final answer are not enough.&lt;/p&gt;

&lt;p&gt;The meaningful security and governance surface is everything in between:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the files an AI inspected&lt;/li&gt;
&lt;li&gt;the tools it invoked&lt;/li&gt;
&lt;li&gt;the commands it ran&lt;/li&gt;
&lt;li&gt;the code it changed&lt;/li&gt;
&lt;li&gt;the secrets it encountered&lt;/li&gt;
&lt;li&gt;the actions a human reviewed or approved&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That is not merely application logging. It is operational evidence.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Gap: There Is No Default Evidence Trail
&lt;/h2&gt;

&lt;p&gt;Most teams have some combination of chat history, source control, CI logs, and cloud audit logs.&lt;/p&gt;

&lt;p&gt;Those are useful, but they are disconnected. They rarely answer one important question cleanly:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;What did this AI-assisted task do, why did it do it, and can another person review the path afterward?&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That gap matters today, even if you have no view on the most extreme forecasts about AI.&lt;/p&gt;

&lt;p&gt;Organizations do not need to wait for hypothetical superintelligence before they make AI actions visible and reviewable.&lt;/p&gt;




&lt;h2&gt;
  
  
  What an Honest Evidence Trail Looks Like
&lt;/h2&gt;

&lt;p&gt;A trustworthy record needs to be explicit about its boundaries.&lt;/p&gt;

&lt;p&gt;If a tool did not observe part of a conversation, it should not recreate it from memory or ask the model to estimate what happened. That would turn self-report into evidence.&lt;/p&gt;

&lt;p&gt;Chron v0.1.56 handles this with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;chron attach codex
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The command begins recording an existing conversation from the current point onward. It marks the session as partial evidence and keeps the boundary visible in verification and coverage reports.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;chron verify &amp;lt;session-id&amp;gt;
chron coverage
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The message is deliberately plain:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Chron began recording after this conversation had already started. Earlier turns are outside the evidence boundary.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That is better than a complete-looking record with a hidden gap.&lt;/p&gt;




&lt;h2&gt;
  
  
  What Chron Is and Is Not
&lt;/h2&gt;

&lt;p&gt;Chron is a local-first audit evidence layer for AI-assisted work. When configured with supported AI tools, it records messages, tool activity, code changes, secret detections, timestamps, and tamper-evident hashes.&lt;/p&gt;

&lt;p&gt;It is &lt;strong&gt;not&lt;/strong&gt; an alignment solution.&lt;/p&gt;

&lt;p&gt;It is &lt;strong&gt;not&lt;/strong&gt; a compliance certification.&lt;/p&gt;

&lt;p&gt;It is &lt;strong&gt;not&lt;/strong&gt; a substitute for human oversight.&lt;/p&gt;

&lt;p&gt;It is one practical control: making AI-assisted actions inspectable after they happen.&lt;/p&gt;




&lt;h2&gt;
  
  
  Accountability Has to Start Somewhere
&lt;/h2&gt;

&lt;p&gt;The AI race may be a global problem. But accountable evidence is something every engineering team can start building now.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-g&lt;/span&gt; chron-mcp@latest
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Chron is local-first and free to try. The public warnings from AI researchers are worth reading alongside the more practical lessons from real evaluation incidents — they are two sides of the same problem.&lt;/p&gt;

&lt;p&gt;As AI gets more capable, "trust us" will not be enough. We need evidence.&lt;/p&gt;

</description>
      <category>aigovernance</category>
      <category>security</category>
      <category>ai</category>
      <category>devops</category>
    </item>
    <item>
      <title>My AI audit tool was merging Claude and Cursor sessions. The bug was one UNIQUE constraint.</title>
      <dc:creator>Srinivas Kondepudi</dc:creator>
      <pubDate>Mon, 07 Sep 2026 18:12:25 +0000</pubDate>
      <link>https://dev.to/sirinivask/my-ai-audit-tool-was-merging-claude-and-cursor-sessions-the-bug-was-one-unique-constraint-5amc</link>
      <guid>https://dev.to/sirinivask/my-ai-audit-tool-was-merging-claude-and-cursor-sessions-the-bug-was-one-unique-constraint-5amc</guid>
      <description>&lt;p&gt;I maintain &lt;a href="https://www.npmjs.com/package/chron-mcp" rel="noopener noreferrer"&gt;Chron&lt;/a&gt;, an MCP server that writes an audit log of AI coding sessions to a local SQLite database. Every message gets a timestamp, and every session records which tool produced it: Claude, Cursor, Codex.&lt;/p&gt;

&lt;p&gt;A while back I opened the history and found Claude messages and Cursor messages interleaved inside a single session. Two different tools, two different terminals, one session record.&lt;/p&gt;

&lt;p&gt;For a tool whose entire job is attribution, that is about as bad as a bug gets.&lt;/p&gt;

&lt;h2&gt;
  
  
  The setup
&lt;/h2&gt;

&lt;p&gt;The sessions table looked like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;sessions&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="n"&gt;id&lt;/span&gt;       &lt;span class="nb"&gt;TEXT&lt;/span&gt; &lt;span class="k"&gt;PRIMARY&lt;/span&gt; &lt;span class="k"&gt;KEY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;title&lt;/span&gt;    &lt;span class="nb"&gt;TEXT&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt; &lt;span class="k"&gt;UNIQUE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;ai_tool&lt;/span&gt;  &lt;span class="nb"&gt;TEXT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;created_at&lt;/span&gt; &lt;span class="nb"&gt;TEXT&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;updated_at&lt;/span&gt; &lt;span class="nb"&gt;TEXT&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When a tool starts work it calls &lt;code&gt;init_session&lt;/code&gt; with a title and its own &lt;code&gt;ai_tool&lt;/code&gt;. If a session with that title already exists, resume it. Otherwise create a new one.&lt;/p&gt;

&lt;p&gt;Both Claude and Cursor generate a short descriptive title from the task. Working in the same repo on the same task, they generate the same title. Something like &lt;code&gt;General assistance session&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;UNIQUE(title)&lt;/code&gt; then guarantees only one row can exist for that title. So the second tool does not get its own session. It resumes the first one. Claude's messages and Cursor's messages land under the same session id, and &lt;code&gt;ai_tool&lt;/code&gt; on that session reports whichever tool happened to start first.&lt;/p&gt;

&lt;p&gt;The constraint was doing exactly what it was written to do. It was just the wrong constraint. A title was never the identity of a session. The pair &lt;code&gt;(title, tool)&lt;/code&gt; was.&lt;/p&gt;

&lt;h2&gt;
  
  
  Fix attempt one, which does not work
&lt;/h2&gt;

&lt;p&gt;The obvious move:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;UNIQUE&lt;/span&gt; &lt;span class="k"&gt;INDEX&lt;/span&gt; &lt;span class="n"&gt;idx_sessions_title_tool&lt;/span&gt; &lt;span class="k"&gt;ON&lt;/span&gt; &lt;span class="n"&gt;sessions&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ai_tool&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is wrong, and it is wrong in a way that survives a casual test.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;ai_tool&lt;/code&gt; is nullable. In SQL, &lt;code&gt;NULL&lt;/code&gt; is never equal to &lt;code&gt;NULL&lt;/code&gt;, and that includes comparisons inside a unique index. The constraint stops constraining the moment the column is NULL:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;title&lt;/span&gt; &lt;span class="nb"&gt;TEXT&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ai_tool&lt;/span&gt; &lt;span class="nb"&gt;TEXT&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;UNIQUE&lt;/span&gt; &lt;span class="k"&gt;INDEX&lt;/span&gt; &lt;span class="n"&gt;ia&lt;/span&gt; &lt;span class="k"&gt;ON&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ai_tool&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;INSERT&lt;/span&gt; &lt;span class="k"&gt;INTO&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="k"&gt;VALUES&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Session'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;INSERT&lt;/span&gt; &lt;span class="k"&gt;INTO&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="k"&gt;VALUES&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Session'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;   &lt;span class="c1"&gt;-- succeeds&lt;/span&gt;

&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="k"&gt;count&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;  &lt;span class="c1"&gt;-- 2&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Two identical rows under a unique index. This is standard SQL behaviour rather than a SQLite quirk, but it is easy to forget the moment you add a nullable column to a composite key.&lt;/p&gt;

&lt;p&gt;It mattered here because Chron has legitimate NULL &lt;code&gt;ai_tool&lt;/code&gt; rows: sessions created through the library API without a tool set.&lt;/p&gt;

&lt;h2&gt;
  
  
  The fix
&lt;/h2&gt;

&lt;p&gt;Index an expression instead of the raw column:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;UNIQUE&lt;/span&gt; &lt;span class="k"&gt;INDEX&lt;/span&gt; &lt;span class="n"&gt;idx_sessions_title_tool&lt;/span&gt;
  &lt;span class="k"&gt;ON&lt;/span&gt; &lt;span class="n"&gt;sessions&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;COALESCE&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ai_tool&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;''&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;NULL collapses to the empty string, which does compare equal to itself:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;title&lt;/span&gt; &lt;span class="nb"&gt;TEXT&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ai_tool&lt;/span&gt; &lt;span class="nb"&gt;TEXT&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;UNIQUE&lt;/span&gt; &lt;span class="k"&gt;INDEX&lt;/span&gt; &lt;span class="n"&gt;ib&lt;/span&gt; &lt;span class="k"&gt;ON&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;COALESCE&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ai_tool&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;''&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

&lt;span class="k"&gt;INSERT&lt;/span&gt; &lt;span class="k"&gt;INTO&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="k"&gt;VALUES&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Session'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;INSERT&lt;/span&gt; &lt;span class="k"&gt;INTO&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="k"&gt;VALUES&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Session'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;      &lt;span class="c1"&gt;-- UNIQUE constraint failed&lt;/span&gt;
&lt;span class="k"&gt;INSERT&lt;/span&gt; &lt;span class="k"&gt;INTO&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="k"&gt;VALUES&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Session'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'claude'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;  &lt;span class="c1"&gt;-- ok&lt;/span&gt;
&lt;span class="k"&gt;INSERT&lt;/span&gt; &lt;span class="k"&gt;INTO&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="k"&gt;VALUES&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Session'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'cursor'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;  &lt;span class="c1"&gt;-- ok&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;One row per tool, duplicates within a tool still rejected. That is the property I actually wanted.&lt;/p&gt;

&lt;p&gt;The lookup code had to match, of course. Resume was searching by title alone, so even with the right constraint it would have kept finding the other tool's row:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// before&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;existing&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;select&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;sessions&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;eq&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;sessions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

&lt;span class="c1"&gt;// after&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;existing&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;select&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;sessions&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;and&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nf"&gt;eq&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;sessions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="nx"&gt;requestedTool&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;
      &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nf"&gt;isNull&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;sessions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ai_tool&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;eq&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;sessions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ai_tool&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;requestedTool&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="p"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A constraint and the query that relies on it are one unit. Changing only one of them just moves the bug.&lt;/p&gt;

&lt;h2&gt;
  
  
  Dropping a constraint in SQLite
&lt;/h2&gt;

&lt;p&gt;SQLite has no &lt;code&gt;ALTER TABLE ... DROP CONSTRAINT&lt;/code&gt;. The inline &lt;code&gt;UNIQUE&lt;/code&gt; on &lt;code&gt;title&lt;/code&gt; is part of the table definition, so removing it means rebuilding the table:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;PRAGMA foreign_keys = OFF&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;BEGIN&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`CREATE TABLE sessions_migration (
    id TEXT PRIMARY KEY,
    title TEXT NOT NULL,     -- no UNIQUE
    ai_tool TEXT,
    ...
  )`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;INSERT INTO sessions_migration SELECT id,title,ai_tool,... FROM sessions&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;DROP TABLE sessions&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ALTER TABLE sessions_migration RENAME TO sessions&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;COMMIT&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ROLLBACK&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="cm"&gt;/* ignore */&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;finally&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;PRAGMA foreign_keys = ON&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Standard shadow-table dance. Nothing surprising.&lt;/p&gt;

&lt;h2&gt;
  
  
  The migration bug that was worse than the original bug
&lt;/h2&gt;

&lt;p&gt;Here is the part worth the post.&lt;/p&gt;

&lt;p&gt;I first wrote the migration guard as: &lt;em&gt;if the composite index does not exist, migrate.&lt;/em&gt; It reads perfectly sensibly, and it fails on exactly the databases that need it.&lt;/p&gt;

&lt;p&gt;The schema bootstrap runs &lt;code&gt;CREATE UNIQUE INDEX IF NOT EXISTS idx_sessions_title_tool ...&lt;/code&gt; &lt;strong&gt;before&lt;/strong&gt; the migration check. On an existing database that still carries the legacy inline &lt;code&gt;UNIQUE(title)&lt;/code&gt;, that statement succeeds. It creates the composite index on the old table. The old constraint is still sitting there, untouched.&lt;/p&gt;

&lt;p&gt;So by the time the migration check runs, the index exists, the guard concludes "already migrated", and it skips. The table keeps &lt;code&gt;UNIQUE(title)&lt;/code&gt; forever.&lt;/p&gt;

&lt;p&gt;Fresh databases were fine, because they were created correctly from the start. The test suite passed, because tests build fresh databases. Every real user upgrading from an older version would have kept the bug.&lt;/p&gt;

&lt;p&gt;The guard has to ask about the constraint, not about a side effect that usually correlates with it. The only way to see the constraint is the stored DDL:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;info&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;SELECT sql FROM sqlite_master WHERE type='table' AND name='sessions'&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;tableSql&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;info&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;rows&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]?.&lt;/span&gt;&lt;span class="nx"&gt;sql&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;hasLegacyTitleUnique&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
  &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="se"&gt;\b&lt;/span&gt;&lt;span class="sr"&gt;title&lt;/span&gt;&lt;span class="se"&gt;\s&lt;/span&gt;&lt;span class="sr"&gt;+TEXT&lt;/span&gt;&lt;span class="se"&gt;\s&lt;/span&gt;&lt;span class="sr"&gt;+NOT&lt;/span&gt;&lt;span class="se"&gt;\s&lt;/span&gt;&lt;span class="sr"&gt;+NULL&lt;/span&gt;&lt;span class="se"&gt;\s&lt;/span&gt;&lt;span class="sr"&gt;+UNIQUE&lt;/span&gt;&lt;span class="se"&gt;\b&lt;/span&gt;&lt;span class="sr"&gt;/i&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;tableSql&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;hasLegacyTitleUnique&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;compositeIdxMissing&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// rebuild&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Regex against DDL is not elegant. It is, however, the thing that is actually true.&lt;/p&gt;

&lt;p&gt;And the test has to start from the old schema, not a fresh one:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// build a legacy database on purpose&lt;/span&gt;
&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`CREATE TABLE sessions (
  id TEXT PRIMARY KEY,
  title TEXT NOT NULL UNIQUE,   -- the old constraint
  ai_tool TEXT, ...
)`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`INSERT INTO sessions VALUES ('old-claude', 'General assistance session', 'claude', ...)`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;initDb&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;dbPath&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;table&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;SELECT sql FROM sqlite_master WHERE type='table' AND name='sessions'&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;table&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;rows&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;sql&lt;/span&gt;&lt;span class="p"&gt;)).&lt;/span&gt;&lt;span class="nx"&gt;not&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toMatch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="se"&gt;\b&lt;/span&gt;&lt;span class="sr"&gt;title&lt;/span&gt;&lt;span class="se"&gt;\s&lt;/span&gt;&lt;span class="sr"&gt;+TEXT&lt;/span&gt;&lt;span class="se"&gt;\s&lt;/span&gt;&lt;span class="sr"&gt;+NOT&lt;/span&gt;&lt;span class="se"&gt;\s&lt;/span&gt;&lt;span class="sr"&gt;+NULL&lt;/span&gt;&lt;span class="se"&gt;\s&lt;/span&gt;&lt;span class="sr"&gt;+UNIQUE&lt;/span&gt;&lt;span class="se"&gt;\b&lt;/span&gt;&lt;span class="sr"&gt;/i&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// cursor can now hold the same title&lt;/span&gt;
&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`INSERT INTO sessions VALUES ('new-cursor', 'General assistance session', 'cursor', ...)`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// but a duplicate within the same tool is still rejected&lt;/span&gt;
&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="s2"&gt;`INSERT INTO sessions VALUES ('dupe-claude', 'General assistance session', 'claude', ...)`&lt;/span&gt;
&lt;span class="p"&gt;)).&lt;/span&gt;&lt;span class="nx"&gt;rejects&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toThrow&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  What I took from this
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;A UNIQUE constraint is an identity claim.&lt;/strong&gt; &lt;code&gt;UNIQUE(title)&lt;/code&gt; asserted "a title identifies a session". That was never true, and the database enforced the false claim faithfully until the day two tools showed up.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Nullable columns in composite unique indexes usually do not do what you want.&lt;/strong&gt; If the column can be NULL, index an expression.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Migration guards should test for the thing you are fixing.&lt;/strong&gt; Not for a marker that normally accompanies it. Ordering inside your own bootstrap can invalidate the marker.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A migration test that starts from a fresh schema tests nothing.&lt;/strong&gt; Construct the old schema, put a row in it, then migrate. This is the one that nearly got me: the fix was correct, the suite was green, and real upgrades would have stayed broken.&lt;/p&gt;

&lt;p&gt;That last point is the general shape of the lesson. Green tests told me the bug was fixed. They were testing a database that never had the bug.&lt;/p&gt;




&lt;p&gt;Chron is on npm as &lt;code&gt;chron-mcp&lt;/code&gt; if you want to look at the code, or run &lt;code&gt;npx chron-mcp&lt;/code&gt; to point it at your own AI sessions.&lt;/p&gt;

</description>
      <category>sqlite</category>
      <category>debugging</category>
      <category>database</category>
      <category>ai</category>
    </item>
    <item>
      <title>npm Trusted Publishing fails with a 404, and the 404 is lying to you</title>
      <dc:creator>Srinivas Kondepudi</dc:creator>
      <pubDate>Sun, 06 Sep 2026 14:43:49 +0000</pubDate>
      <link>https://dev.to/sirinivask/npm-trusted-publishing-fails-with-a-404-and-the-404-is-lying-to-you-3b7i</link>
      <guid>https://dev.to/sirinivask/npm-trusted-publishing-fails-with-a-404-and-the-404-is-lying-to-you-3b7i</guid>
      <description>&lt;p&gt;npm is winding down 2FA-bypass granular access tokens. Since &lt;a href="https://github.blog/changelog/2026-07-31-restricting-npm-bypass-2fa-granular-access-tokens/" rel="noopener noreferrer"&gt;31 July 2026&lt;/a&gt; they can no longer perform account, organisation, or package management operations, which includes editing trusted publishing configuration. In January 2027 they lose direct publish as well, leaving them able to read private packages and stage a publish that a maintainer then approves with 2FA.&lt;/p&gt;

&lt;p&gt;The replacement is OIDC Trusted Publishing, where you register a GitHub repo and workflow on npmjs.com and the workflow authenticates with a short-lived token instead of a stored secret.&lt;/p&gt;

&lt;p&gt;I migrated. The release workflow then failed four times in a row, and the error message pointed nowhere near the actual problem.&lt;/p&gt;

&lt;p&gt;This is the writeup I wanted to find while debugging it.&lt;/p&gt;

&lt;h2&gt;
  
  
  The symptom
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;npm notice publish Signed provenance statement with source and
  build information from GitHub Actions
npm notice publish Provenance statement published to transparency log:
  https://search.sigstore.dev/?logIndex=2685306213
npm error code E404
npm error 404 Not Found - PUT https://registry.npmjs.org/chron-mcp - Not found
npm error 404  'chron-mcp@0.1.55' is not in this registry.
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The package exists. It has published versions. I own it. And the registry says it is not there.&lt;/p&gt;

&lt;p&gt;Two things in that output are actively misleading, and I chased both.&lt;/p&gt;

&lt;h2&gt;
  
  
  Red herring one: the provenance step succeeds
&lt;/h2&gt;

&lt;p&gt;Look at the order. Provenance signing works. It reaches sigstore, signs, and posts to the public transparency log. That requires the GitHub Actions OIDC token, so &lt;code&gt;id-token: write&lt;/code&gt; is clearly working.&lt;/p&gt;

&lt;p&gt;It is very natural to conclude that OIDC is fine and the problem is something else.&lt;/p&gt;

&lt;p&gt;It is not the same feature. Provenance signing uses the OIDC id-token to sign an attestation with sigstore. Trusted Publishing uses the OIDC id-token to exchange for a registry auth token. Different mechanisms, different code paths, introduced in different npm versions. One can work perfectly while the other does not exist.&lt;/p&gt;

&lt;h2&gt;
  
  
  Red herring two: a token that looks leaked
&lt;/h2&gt;

&lt;p&gt;The step environment shows this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;NPM_CONFIG_USERCONFIG&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/home/runner/work/_temp/.npmrc&lt;/span&gt;
  &lt;span class="na"&gt;NODE_AUTH_TOKEN&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;XXXXX-XXXXX-XXXXX-XXXXX&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That looks like a masked secret. My first theory was that a stale &lt;code&gt;NPM_TOKEN&lt;/code&gt; was being injected and overriding OIDC, so I removed it from the workflow and added &lt;code&gt;unset NODE_AUTH_TOKEN&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;It made no difference, because that value is not a secret at all. GitHub is not masking anything. Those are real X characters.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;actions/setup-node@v4&lt;/code&gt; writes an &lt;code&gt;.npmrc&lt;/code&gt; containing &lt;code&gt;//registry.npmjs.org/:_authToken=${NODE_AUTH_TOKEN}&lt;/code&gt;, and then exports a dummy value when you have not supplied one, so that npm does not warn about a missing variable. From &lt;code&gt;src/authutil.ts&lt;/code&gt; on the &lt;code&gt;v4&lt;/code&gt; tag:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Export empty node_auth_token if didn't exist so npm doesn't complain&lt;/span&gt;
&lt;span class="c1"&gt;// about not being able to find it&lt;/span&gt;
&lt;span class="nx"&gt;core&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;exportVariable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;NODE_AUTH_TOKEN&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;NODE_AUTH_TOKEN&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;XXXXX-XXXXX-XXXXX-XXXXX&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Worth knowing that this is version-specific. On &lt;code&gt;main&lt;/code&gt; the action has changed to only export the variable when the user actually provided one, so if you are on a newer major you may not see this at all. If you are pinned to &lt;code&gt;v4&lt;/code&gt;, you will, and it looks exactly like a leaked credential.&lt;/p&gt;

&lt;p&gt;For completeness, a pre-set token would not block OIDC anyway. In &lt;code&gt;lib/commands/publish.js&lt;/code&gt;, &lt;code&gt;oidc()&lt;/code&gt; is called before credentials are read, and it overwrites the auth token directly:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;oidc&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;packageName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;manifest&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;registry&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;opts&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;config&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;npm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;config&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;creds&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;npm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getCredentialsByURI&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;registry&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The actual cause
&lt;/h2&gt;

&lt;p&gt;The workflow pinned Node 20:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/setup-node@v4&lt;/span&gt;
  &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;node-version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;20&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Node 20 bundles npm 10.8.2. npm documents the requirement as &lt;strong&gt;npm CLI 11.5.1 or later, and Node 22.14.0 or higher&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;npm 10 does not have a partial or broken implementation. It has none at all. You can verify this without reading a changelog:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="k"&gt;for &lt;/span&gt;v &lt;span class="k"&gt;in &lt;/span&gt;10.8.2 11.5.0 11.5.1 11.19.0&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;do
  &lt;/span&gt;npm pack npm@&lt;span class="nv"&gt;$v&lt;/span&gt; &lt;span class="nt"&gt;--silent&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt;/dev/null
  &lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; ex-&lt;span class="nv"&gt;$v&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;tar &lt;/span&gt;xzf npm-&lt;span class="nv"&gt;$v&lt;/span&gt;.tgz &lt;span class="nt"&gt;-C&lt;/span&gt; ex-&lt;span class="nv"&gt;$v&lt;/span&gt;
  &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"npm &lt;/span&gt;&lt;span class="nv"&gt;$v&lt;/span&gt;&lt;span class="s2"&gt; -&amp;gt; &lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;ls &lt;/span&gt;ex-&lt;span class="nv"&gt;$v&lt;/span&gt;/package/lib/utils/oidc.js 2&amp;gt;/dev/null &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s1"&gt;'NO OIDC'&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="k"&gt;done&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm 10.8.2  -&amp;gt; NO OIDC
npm 11.5.0  -&amp;gt; ex-11.5.0/package/lib/utils/oidc.js
npm 11.5.1  -&amp;gt; ex-11.5.1/package/lib/utils/oidc.js
npm 11.19.0 -&amp;gt; ex-11.19.0/package/lib/utils/oidc.js
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So npm 10 never attempts the token exchange. It falls back to the &lt;code&gt;_authToken&lt;/code&gt; in the generated &lt;code&gt;.npmrc&lt;/code&gt;, which resolves to nothing useful, and publishes unauthenticated.&lt;/p&gt;

&lt;p&gt;You will notice 11.5.0 has the file too, which is worth explaining rather than glossing over. The OIDC code first shipped in 11.5.0, and the only difference in 11.5.1 is a scoping fix in the same file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;&lt;span class="gd"&gt;-      let enableProvenance = false     // declared inside the inner block
&lt;/span&gt;&lt;span class="gi"&gt;+    let enableProvenance = false       // hoisted out
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In 11.5.0 the provenance-enabling branch sat inside an inner block, so it could not fire correctly. The token exchange itself is byte-identical between the two. That is why npm's documented floor is 11.5.1 rather than 11.5.0, and it is the version to pin. The distinction does not matter for the 404 in this post, because Node 20 gives you npm 10, which has nothing at all.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why an unauthenticated publish returns 404
&lt;/h2&gt;

&lt;p&gt;This is the part that wasted the most time.&lt;/p&gt;

&lt;p&gt;The publish went out with no usable credential at all, and the registry answered &lt;strong&gt;404&lt;/strong&gt; rather than 401 or 403. The explanation usually given is that answering 403 would confirm a package exists, letting anyone enumerate private package names by guessing, so the registry collapses "does not exist" and "you may not see this" into one response. I have not found npm stating that intent in those words, so take the reasoning as the community explanation and the behaviour as the observed fact.&lt;/p&gt;

&lt;p&gt;The distinction that actually helps you debug is this one:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;403&lt;/strong&gt; usually means your credential arrived and the identity behind it is not allowed to publish this package. The familiar form is &lt;code&gt;You do not have permission to publish "x". Are you logged in as the correct user?&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;404&lt;/strong&gt; on a package you own usually means the registry never established who you are at all. The credential is missing, empty, or never sent.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So read &lt;code&gt;'chron-mcp@0.1.55' is not in this registry&lt;/code&gt; as a statement about &lt;strong&gt;your identity&lt;/strong&gt;, not about your package name. That is the most useful reframing in this post. I spent a long time re-checking the package name, the scope, and the registry URL, when the message was really telling me the request was anonymous.&lt;/p&gt;

&lt;h2&gt;
  
  
  The fix, part one
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/setup-node@v4&lt;/span&gt;
  &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;node-version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;24&lt;/span&gt;
    &lt;span class="na"&gt;registry-url&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;https://registry.npmjs.org&lt;/span&gt;

&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Ensure npm supports OIDC trusted publishing&lt;/span&gt;
  &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
    &lt;span class="s"&gt;npm install -g npm@^11.5.1&lt;/span&gt;
    &lt;span class="s"&gt;npm --version&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Node 24 bundles npm 11.19.0, which is already sufficient. The explicit global install is a guard: Node 24.0.0 shipped npm 11.3.0, which is below the threshold, so pinning the major alone is not a guarantee. Printing &lt;code&gt;npm --version&lt;/code&gt; into the log means the next person to debug this can rule it out in one glance.&lt;/p&gt;

&lt;h2&gt;
  
  
  The fix, part two, which the first fix revealed
&lt;/h2&gt;

&lt;p&gt;With authentication working, the error changed. That is progress, even when it is still red:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;npm error code E422
npm error 422 Unprocessable Entity - PUT https://registry.npmjs.org/chron-mcp -
  Error verifying sigstore provenance bundle: Unsupported GitHub Actions source
  repository visibility: "private". Only public source repositories are
  supported when publishing with provenance.
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Provenance requires a &lt;strong&gt;public&lt;/strong&gt; source repository. The repo publishing this package is private, so provenance was never achievable, and &lt;code&gt;--provenance&lt;/code&gt; had been wrong from the first commit. It stayed invisible because the auth failure happened first.&lt;/p&gt;

&lt;p&gt;The fix is to drop the flag rather than to add &lt;code&gt;--no-provenance&lt;/code&gt;. From &lt;code&gt;lib/utils/oidc.js&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;isDefaultProvenance&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;isDefault&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;provenance&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;isDefaultProvenance&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;ciInfo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;CIRCLE&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;payload&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="cm"&gt;/* decoded id-token */&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ciInfo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;GITHUB_ACTIONS&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;repository_visibility&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;public&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;visibility&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;libaccess&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getVisibility&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;packageName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;opts&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;visibility&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="kr"&gt;public&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;opts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;provenance&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;npm auto-enables provenance only when the flag was left at its default &lt;strong&gt;and&lt;/strong&gt; &lt;code&gt;repository_visibility&lt;/code&gt; is &lt;code&gt;"public"&lt;/code&gt;. Passing &lt;code&gt;--provenance&lt;/code&gt; explicitly sets &lt;code&gt;isDefault&lt;/code&gt; to false and forces it on regardless. Omitting it lets npm make the correct decision on its own.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;&lt;span class="gd"&gt;-  npm publish --access public --provenance --ignore-scripts
&lt;/span&gt;&lt;span class="gi"&gt;+  npm publish --access public --ignore-scripts
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Green on the next run.&lt;/p&gt;

&lt;h2&gt;
  
  
  The working workflow
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;permissions&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;contents&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;read&lt;/span&gt;
  &lt;span class="na"&gt;id-token&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;write&lt;/span&gt;     &lt;span class="c1"&gt;# required for OIDC&lt;/span&gt;

&lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v4&lt;/span&gt;

  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/setup-node@v4&lt;/span&gt;
    &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;node-version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;24&lt;/span&gt;
      &lt;span class="na"&gt;registry-url&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;https://registry.npmjs.org&lt;/span&gt;

  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Ensure npm supports OIDC trusted publishing&lt;/span&gt;
    &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
      &lt;span class="s"&gt;npm install -g npm@^11.5.1&lt;/span&gt;
      &lt;span class="s"&gt;npm --version&lt;/span&gt;

  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npm ci&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npm test&lt;/span&gt;

  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Publish&lt;/span&gt;
    &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npm publish --access public --ignore-scripts&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No &lt;code&gt;NODE_AUTH_TOKEN&lt;/code&gt;. No &lt;code&gt;NPM_TOKEN&lt;/code&gt; secret. The Trusted Publisher is configured on npmjs.com under the package's Settings, pointing at the repo and the workflow filename, and both have to match exactly.&lt;/p&gt;

&lt;h2&gt;
  
  
  Checklist if you hit this
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Print &lt;code&gt;npm --version&lt;/code&gt; in the job.&lt;/strong&gt; npm 10 and below will not attempt OIDC at all, and 11.5.1 is npm's documented floor. This is the single highest-value check and it takes one line.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Read a 404 on a package you own as an identity problem, not a naming one.&lt;/strong&gt; A 403 usually means your credential arrived and was rejected; a 404 usually means it was never established.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Do not treat a successful provenance step as proof that auth works.&lt;/strong&gt; They are separate features.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;NODE_AUTH_TOKEN: XXXXX-XXXXX-XXXXX-XXXXX&lt;/code&gt; is a literal placeholder,&lt;/strong&gt; not a masked secret.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Only use &lt;code&gt;--provenance&lt;/code&gt; if the source repo is public.&lt;/strong&gt; Otherwise omit it and let npm decide.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Check the Trusted Publisher's workflow filename&lt;/strong&gt; matches the workflow that actually runs the publish.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The general lesson is about error messages that withhold information. The 404 was not a bug. It was the registry saying it did not know who I was, in the least specific way available to it, and I read it literally for far longer than I should have.&lt;/p&gt;

</description>
      <category>npm</category>
      <category>githubactions</category>
      <category>cicd</category>
      <category>devops</category>
    </item>
    <item>
      <title>From Audit Log to AI Governance Platform. How Chron Is Closing the Gap</title>
      <dc:creator>Srinivas Kondepudi</dc:creator>
      <pubDate>Wed, 26 Aug 2026 07:54:48 +0000</pubDate>
      <link>https://dev.to/sirinivask/from-audit-log-to-ai-governance-platform-how-chron-is-closing-the-gap-16m4</link>
      <guid>https://dev.to/sirinivask/from-audit-log-to-ai-governance-platform-how-chron-is-closing-the-gap-16m4</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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fz1332c1lvv6fma41xh1c.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%2Fz1332c1lvv6fma41xh1c.png" alt="Chron" width="800" height="440"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The Problem Nobody Talked About
&lt;/h2&gt;

&lt;p&gt;When teams started adopting AI coding tools — Claude, Cursor, Codex, GitHub Copilot, they got productivity. What they didn't get was visibility.&lt;/p&gt;

&lt;p&gt;No one could answer: &lt;em&gt;What did the AI actually do? What prompts were sent? What code was changed? Were any secrets exposed?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;For developers, this didn't matter much. For a CISO or a compliance officer trying to prepare a SOC 2 audit or respond to an incident? It was a blindspot the size of a barn door.&lt;/p&gt;

&lt;p&gt;That's the gap Chron was built to close.&lt;/p&gt;




&lt;h2&gt;
  
  
  What Chron Does
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://www.npmjs.com/package/chron-mcp" rel="noopener noreferrer"&gt;Chron&lt;/a&gt; is an MCP server that sits alongside your AI tool and creates a &lt;strong&gt;tamper-evident, locally-stored audit trail&lt;/strong&gt; of every session.&lt;/p&gt;

&lt;p&gt;Every message, every tool call, every code change — logged to a SQLite database on your machine. No cloud. No vendor. Your data stays with you.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-g&lt;/span&gt; chron-mcp
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once installed, it plugs into Claude, Cursor, Windsurf, Codex, or any MCP-compatible tool and starts recording immediately.&lt;/p&gt;




&lt;h2&gt;
  
  
  Maturing Into AI Actions Recording
&lt;/h2&gt;

&lt;p&gt;Chron started as a session logger. It's now becoming something more: a full &lt;strong&gt;AI actions recorder&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;What that means in practice:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Message logging&lt;/strong&gt; — every user prompt and AI response, timestamped and hashed&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tool call recording&lt;/strong&gt; — when the AI reads a file, runs a command, or calls an API, it's logged&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Code change tracking&lt;/strong&gt; — diffs of what was written or modified&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Secret detection (DLP)&lt;/strong&gt; — Luhn, IBAN, API keys, email, phone, internal IPs detected in real time before they leave your terminal&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ed25519 signing&lt;/strong&gt; — each session gets a cryptographic keypair; the log is tamper-evident by construction&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;NTP clock attestation&lt;/strong&gt; — timestamps are anchored to a real time source, not the local clock alone&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The result: a chain of custody for every AI interaction in your organisation.&lt;/p&gt;




&lt;h2&gt;
  
  
  Making CISOs and Teams Aware
&lt;/h2&gt;

&lt;p&gt;The honest reality is: most developers don't think about audit trails. They shouldn't have to.&lt;/p&gt;

&lt;p&gt;But when something goes wrong — a leaked credential, an unexpected code change, a compliance question from a regulator — the CISO needs answers fast.&lt;/p&gt;

&lt;p&gt;Chron's &lt;code&gt;report&lt;/code&gt; command generates evidence packages mapped to frameworks:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# SOC 2 evidence package&lt;/span&gt;
chron report &lt;span class="nt"&gt;--format&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;soc2

&lt;span class="c"&gt;# Activity summary&lt;/span&gt;
chron report &lt;span class="nt"&gt;--since&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;30d
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The SOC 2 report maps Chron's controls to CC6, CC7, and CC8 — the access, change management, and risk mitigation criteria auditors look for. ISO 27001, ISO 42001, EU AI Act, and NIST AI RMF mappings are also included.&lt;/p&gt;

&lt;p&gt;SIEM integrations mean the logs can flow to Splunk, CrowdStrike LogScale, or Azure Sentinel, so the security team sees AI activity alongside everything else.&lt;/p&gt;




&lt;h2&gt;
  
  
  What's Still on the Roadmap
&lt;/h2&gt;

&lt;p&gt;We're not done. The direction is clear: move from individual developer tool to &lt;strong&gt;organisational AI auditor platform&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;What's coming:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Centralised org dashboard&lt;/strong&gt; — a CIO/CISO-facing view across all team members' AI activity&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Centralised database mode&lt;/strong&gt; — teams push audit logs to a shared store, not just local SQLite&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Policy enforcement integration&lt;/strong&gt; — tie into CLAIIM, our companion governance layer, for approval tokens and human-in-the-loop gates&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Anomaly alerting&lt;/strong&gt; — flag unusual patterns: after-hours sessions, mass file reads, credential-adjacent prompts&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Audit report scheduler&lt;/strong&gt; — automated weekly/monthly evidence packages for compliance teams&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The goal: the moment a regulator or external auditor asks "show me what your AI tools did last quarter," you hit one command and hand them a signed, timestamped, tamper-evident package.&lt;/p&gt;




&lt;h2&gt;
  
  
  Where We Are
&lt;/h2&gt;

&lt;p&gt;Chron has crossed &lt;strong&gt;8,000 downloads&lt;/strong&gt; — organic, without a launch campaign. The teams installing it are doing so because they recognise the gap.&lt;/p&gt;

&lt;p&gt;Big compliance platforms are now moving in the same direction. We shipped months ahead of them. And the local-first, data-sovereignty-first architecture is something a SaaS compliance cloud simply can't match for regulated industries.&lt;/p&gt;

&lt;p&gt;If you're running AI tools in your organisation and don't yet have an audit trail — Chron is the fastest way to get one.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-g&lt;/span&gt; chron-mcp
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Try it. If it helps you — or if something's missing for your workflow — &lt;a href="https://github.com/nivaya/chron-mcp" rel="noopener noreferrer"&gt;let us know&lt;/a&gt;. Real feedback gets rewarded.&lt;/p&gt;

</description>
      <category>security</category>
      <category>ai</category>
      <category>devops</category>
      <category>aigovernance</category>
    </item>
    <item>
      <title>The compliance frameworks were written before AI coding tools existed</title>
      <dc:creator>Srinivas Kondepudi</dc:creator>
      <pubDate>Wed, 19 Aug 2026 20:58:05 +0000</pubDate>
      <link>https://dev.to/sirinivask/the-compliance-frameworks-were-written-before-ai-coding-tools-existed-2pja</link>
      <guid>https://dev.to/sirinivask/the-compliance-frameworks-were-written-before-ai-coding-tools-existed-2pja</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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fqvt2f005wukcbfvmtep2.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%2Fqvt2f005wukcbfvmtep2.png" alt="Audit needs AI adoption" width="800" height="1252"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;ISO 27001, SOC 2, and NIST assume humans made decisions and left a paper trail. That assumption is breaking.&lt;/p&gt;




&lt;p&gt;Imagine an auditor sitting across from your engineering team. They're working through your change management controls. They want to know: who approved this code change? What was the review process? Is there evidence that a qualified person made a deliberate decision?&lt;/p&gt;

&lt;p&gt;Six months ago, the answer was straightforward: here's the pull request, here's the review, here are the approvals.&lt;/p&gt;

&lt;p&gt;Today, the honest answer for many teams is: "We described the problem to Claude, it suggested this implementation, we thought it looked right, and we merged it."&lt;/p&gt;

&lt;p&gt;That answer is not covered anywhere in ISO 27001. It barely appears in SOC 2. NIST is only now beginning to grapple with it. And the gap between those frameworks and how engineering teams actually work in 2026 is widening every week.&lt;/p&gt;




&lt;h2&gt;
  
  
  What compliance frameworks actually assume
&lt;/h2&gt;

&lt;p&gt;ISO 27001, SOC 2 Type II, and NIST SP 800-53 were designed with a set of assumptions that seemed self-evident at the time:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;A human made a decision.&lt;/li&gt;
&lt;li&gt;That human was authenticated and authorized to make it.&lt;/li&gt;
&lt;li&gt;The decision was documented — a ticket, a comment, a change record, a signature.&lt;/li&gt;
&lt;li&gt;If something went wrong, you could trace back to who decided what.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;These frameworks are not wrong. They describe exactly the kind of accountability that responsible engineering requires. The problem is not the principles — it's that they were operationalized around human workflows. Every control, every audit procedure, every evidence request assumes the actor was a person who left a recognizable trail.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;AI coding tools are not authenticated. They don't sign commits. They don't have a name in your issue tracker. The conversation that produced a significant architectural decision might exist for exactly as long as the browser tab stays open.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;When an organization gets ISO 27001 certified or completes a SOC 2 Type II audit, the auditors are certifying a snapshot: as of this date, these controls were in place. What they are increasingly unable to assess is whether those controls account for the AI sessions happening every day in the engineering org.&lt;/p&gt;




&lt;h2&gt;
  
  
  Three gaps that are already present
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Change management evidence
&lt;/h3&gt;

&lt;p&gt;SOC 2 CC6.6 requires that changes to infrastructure and software are authorized, tested, and documented before deployment. Most interpretations of this control assume a human reviewer in the loop who exercised judgment.&lt;/p&gt;

&lt;p&gt;When an AI tool suggests and partially writes a change, the question becomes: what is the evidence of review? "A developer approved the PR" is technically true. But if that review consisted of reading an AI-generated summary of the AI's own change, is that the control your auditor is certifying? What judgment was actually exercised, and by whom?&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;The auditor question you'll face:&lt;/strong&gt; "Can you walk me through how this change was reviewed before it was approved?" — and the honest answer involves an AI session that no longer exists.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  2. Audit trails and session records
&lt;/h3&gt;

&lt;p&gt;NIST SP 800-53 AU-2 through AU-12 cover audit and accountability: what events are logged, how records are retained, and how they can be reconstructed for investigation.&lt;/p&gt;

&lt;p&gt;By default, none of your AI coding sessions are covered by any of this. The conversation where you asked your AI assistant to redesign the authentication flow, the session where you refactored database access patterns, the task that generated your API client library — these produced real changes to production systems, and they leave no audit record whatsoever.&lt;/p&gt;

&lt;p&gt;Your git commits are logged. Your database queries are traced. Your API calls are metered. Your CI/CD pipeline has more observability than the AI sessions that increasingly drive what goes through it.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Data handling and third-party disclosure
&lt;/h3&gt;

&lt;p&gt;GDPR Article 30 requires records of processing activities. ISO 27001 Annex A.15 covers supplier relationships and information security in them.&lt;/p&gt;

&lt;p&gt;In practice, developers regularly paste production schemas, error logs with user context, and system architecture details into AI prompts to get better answers. Some organizations have explicit policies against this. Most do not. Even where policies exist, enforcement is near-zero because there is no log of what was shared and when.&lt;/p&gt;

&lt;p&gt;If your organization is SOC 2 certified, your auditors have reviewed your data handling controls. The question is whether those controls — as written and as assessed — account for what your engineers are pasting into their AI sessions every day.&lt;/p&gt;




&lt;h2&gt;
  
  
  What organizations are doing — and what's missing
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Prohibition.&lt;/strong&gt; Some organizations have banned AI coding tools entirely, citing compliance risk. This is understandable and also losing ground. The productivity differential is real, and enforcement on personal devices is functionally impossible.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Policy without enforcement.&lt;/strong&gt; More common: "Don't paste customer data into AI tools" lives in the acceptable use policy. There is no technical control, no session record, no way to verify. The policy exists; the assurance does not.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Output review.&lt;/strong&gt; Some teams have added AI-specific code review steps. This is better than nothing. It partially addresses change management but doesn't touch data handling or audit trail requirements.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;What's mostly absent: any systematic approach to capturing what AI tools did, what context they received, and what decisions they influenced. The record of AI involvement in engineering work is today almost entirely missing from compliance evidence packages.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  What needs to change — at two speeds
&lt;/h2&gt;

&lt;h3&gt;
  
  
  The slow track: framework updates
&lt;/h3&gt;

&lt;p&gt;ISO and NIST revision cycles are measured in years. The NIST AI Risk Management Framework is a meaningful step, but it is not yet integrated into how SP 800-53 controls are assessed in standard audits. Building your compliance strategy around waiting for it is not a viable approach.&lt;/p&gt;

&lt;h3&gt;
  
  
  The fast track: interim controls
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Treat AI sessions as auditable activity.&lt;/strong&gt; Decide — explicitly — whether AI coding sessions are in scope for your audit and accountability controls. If they are, log them. If they are not, document why not and what compensating controls exist.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Define AI involvement in your change management policy.&lt;/strong&gt; What does adequate review of an AI-generated change look like? Does it differ from review of human-written code? Every team operating under SOC 2 or ISO 27001 needs a written answer before their next audit.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Update your data classification policy to cover AI context.&lt;/strong&gt; Which data classifications may be used as prompt context? This belongs alongside your existing data handling controls — and should be technically enforced where possible.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Include AI providers in your vendor and subprocessor inventory.&lt;/strong&gt; If your team uses an AI provider's API, that provider is a data processor under GDPR and potentially a subservice organization under SOC 2. Most compliance programs have not updated their vendor inventories to reflect this reality.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  The question coming for every engineering org
&lt;/h2&gt;

&lt;p&gt;Compliance frameworks will update. They always do, eventually. The organizations that will be best positioned are the ones that start treating AI tool usage as an auditable activity now, before they are formally required to.&lt;/p&gt;

&lt;p&gt;The question an auditor will eventually ask is not complicated: &lt;em&gt;"Show me what your AI tools did, what they had access to, and how you controlled it."&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Most engineering teams cannot answer that today. Building the answer is not a compliance checkbox exercise — it is engineering discipline catching up to how the work actually happens.&lt;/p&gt;

&lt;p&gt;The frameworks weren't wrong. They just couldn't see this coming. Neither could most of us.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;If you found this useful, I'd be curious what your team's approach has been — especially if you've been through a SOC 2 or ISO audit recently. The practical experience is ahead of where the guidance is.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>compliance</category>
      <category>security</category>
      <category>ai</category>
      <category>devtools</category>
    </item>
    <item>
      <title>What did your AI actually do last week? Nobody knows.</title>
      <dc:creator>Srinivas Kondepudi</dc:creator>
      <pubDate>Fri, 14 Aug 2026 21:41:41 +0000</pubDate>
      <link>https://dev.to/sirinivask/what-did-your-ai-actually-do-last-week-nobody-knows-4i6f</link>
      <guid>https://dev.to/sirinivask/what-did-your-ai-actually-do-last-week-nobody-knows-4i6f</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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fbg20mbgdeq368jegzs2g.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%2Fbg20mbgdeq368jegzs2g.png" alt="Chron" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Think back to the last AI-assisted coding session you had. You asked Claude or Codex or Cursor to help with something. It worked. You shipped it.&lt;/p&gt;

&lt;p&gt;Now answer this: what exactly did it say? What did you ask, what did it propose, what did you approve? Can you reconstruct the reasoning chain, or is it gone the moment you close the tab?&lt;/p&gt;

&lt;p&gt;Every other tool in your stack has an audit trail. Your git commits are logged. Your deploys are timestamped. Your database queries are traced. Your API calls are observable.&lt;/p&gt;

&lt;p&gt;Your AI coding sessions, where increasingly consequential decisions are made, produce no persistent record whatsoever.&lt;/p&gt;

&lt;p&gt;That's the gap Chron was built to close. And based on what's happened in the past few months, a lot of developers had the same feeling.&lt;/p&gt;

&lt;p&gt;~7,500 downloads&lt;br&gt;
v0.1.52 current version&lt;br&gt;
5 AI clients supported&lt;/p&gt;

&lt;p&gt;What Chron actually is&lt;br&gt;
Chron is an MCP server that sits between you and your AI tools and logs every exchange, timestamped, cryptographically signed, stored in a local SQLite database that lives on your machine. No cloud. No subscription. No data leaving your environment.&lt;/p&gt;

&lt;p&gt;One install. Then every Claude Code session, every Cursor agent run, every Codex task, every Gemini CLI interaction is captured automatically. You don't change how you work.&lt;/p&gt;

&lt;p&gt;$ npm install -g chron-mcp&lt;br&gt;
then restart your AI client&lt;br&gt;
That's it. From that point, chron history shows you everything:&lt;/p&gt;

&lt;p&gt;chron history&lt;br&gt;
$ chron history&lt;br&gt;
2026-08-14 09:12 claude 14 msgs · 8min Refactor auth middleware&lt;br&gt;
2026-08-13 22:47 codex 22 msgs · 31min Review vendor onboarding policy&lt;br&gt;
2026-08-13 18:03 cursor 9 msgs · 12min Add rate limiting to API routes&lt;br&gt;
2026-08-12 14:55 claude 41 msgs · 1h4m Chron release gate — v0.1.50&lt;br&gt;
4 sessions · 127 messages · 2.1h tracked&lt;/p&gt;

&lt;p&gt;What changed between 0 and ~7,500 installs&lt;br&gt;
The early versions were minimal: log the session, store the messages, expose a CLI. The core thesis was right, but the friction was real, developers had to manually configure each AI client and write instruction files by hand.&lt;/p&gt;

&lt;p&gt;The last three months were about eliminating that friction entirely. Here's what shipped:&lt;/p&gt;

&lt;p&gt;// Zero-friction install&lt;br&gt;
npm install -g chron-mcp now configures everything, MCP server entries for every AI client you have installed, global instruction files (~/CLAUDE.md, ~/.cursor/rules/chron.mdc, ~/AGENTS.md), and permission fixes. The only required manual step is restarting your AI client, so it picks up the new MCP server.&lt;/p&gt;

&lt;p&gt;// Session boundary integrity&lt;br&gt;
The most important fix wasn't a feature, it was correctness. Early versions had a bug where resume latest would attach new, unrelated work to an old session from hours ago, polluting the audit trail. The fix introduced a three-guard system: a 30-minute time window, title pattern matching for compaction recovery, and same-tool scoping. Your sessions are now distinct records, not one long accumulation.&lt;/p&gt;

&lt;p&gt;// Doctor, self-diagnosing setup&lt;br&gt;
chron doctor now catches real-world problems that were previously invisible. The most important: when you have Chron configured in both user scope (npx -y chron-mcp) and local scope (a dev path), Claude picks the local one, it fails, and sessions silently don't log. Doctor now parses ~/.claude.json directly, detects the conflict, and prints the exact fix:&lt;/p&gt;

&lt;p&gt;chron doctor&lt;br&gt;
$ chron doctor&lt;br&gt;
! Claude Code chron configured in conflicting scopes&lt;br&gt;
user scope: npx -y chron-mcp&lt;br&gt;
local scope: node /Users/you/chron/dist/index.js ← remove this&lt;br&gt;
Fix: claude mcp remove chron -s local&lt;/p&gt;

&lt;p&gt;// Multi-client project bootstrap&lt;br&gt;
When Chron's MCP server starts inside a real project directory, it now automatically writes AGENTS.md and .cursor/rules/chron.mdc into that project. Codex and Cursor pick these up on the next session start. No manual chron connect needed per project.&lt;/p&gt;

&lt;p&gt;// STORAGE&lt;br&gt;
Local SQLite&lt;br&gt;
All data stays on your machine. No accounts, no cloud sync, no telemetry.&lt;/p&gt;

&lt;p&gt;// INTEGRITY&lt;br&gt;
Ed25519 signatures&lt;br&gt;
Sessions are cryptographically signed. Tamper-evident by default.&lt;/p&gt;

&lt;p&gt;// PATTERNS&lt;br&gt;
Behavioral detection&lt;br&gt;
SIEM-compatible patterns flag prompt injection, credential exposure, scope creep.&lt;/p&gt;

&lt;p&gt;// RISK&lt;br&gt;
Attention scoring&lt;br&gt;
Sessions get a deterministic risk score based on content, tool calls, and patterns.&lt;/p&gt;

&lt;p&gt;// EXPORT&lt;br&gt;
SIEM integration&lt;br&gt;
Forward events to Splunk, Microsoft Sentinel, or CrowdStrike LogScale.&lt;/p&gt;

&lt;p&gt;// CLIENTS&lt;br&gt;
All major AI tools&lt;br&gt;
Claude Code, Cursor, Codex, Gemini CLI, Claude Desktop — one install covers all.&lt;/p&gt;

&lt;p&gt;The thing about ~7,500 downloads&lt;br&gt;
I expected the early adopters to be security-conscious teams or compliance-driven orgs. They're not, or at least, that's not the majority. The bulk of installs are individual developers who want to know what their AI tools did.&lt;/p&gt;

&lt;p&gt;The instinct driving it isn't compliance. It's the same instinct that makes you run git log before a release or check your query logs when something's slow. You want to know. The AI is making real changes to real code, and the conversation that produced those changes is currently ephemeral.&lt;/p&gt;

&lt;p&gt;Chron makes it permanent. Not for auditors, for you.&lt;/p&gt;

&lt;p&gt;Chron records. It does not certify. The record is yours, and it stays on your machine.&lt;/p&gt;

&lt;p&gt;What's next&lt;br&gt;
The logging layer is stable. The next layer is enforcement, runtime ALLOW/DENY gates that sit on top of the Chron proof and let teams define what AI tools are and aren't allowed to do. That's being built as CLAIIM, a companion project. Chron is the "what happened" record; CLAIIM is "was it authorized."&lt;/p&gt;

&lt;p&gt;For now: if you're using any AI coding tool and you don't have a session log, you're flying blind. The install takes 30 seconds.&lt;/p&gt;

&lt;p&gt;$ npm install -g chron-mcp&lt;br&gt;
v0.1.52 · Node 18+&lt;br&gt;
Start logging your AI sessions&lt;br&gt;
Local-first · No accounts · Works with Claude, Cursor, Codex, Gemini&lt;/p&gt;

&lt;p&gt;GitHub: &lt;a href="https://github.com/nivaya/chron" rel="noopener noreferrer"&gt;https://github.com/nivaya/chron&lt;/a&gt;&lt;br&gt;
npm: chron-mcp&lt;/p&gt;

</description>
      <category>ai</category>
      <category>devtools</category>
      <category>productivity</category>
      <category>security</category>
    </item>
    <item>
      <title>If Chron helped your team, we want to hear from you with a reward in return</title>
      <dc:creator>Srinivas Kondepudi</dc:creator>
      <pubDate>Sun, 09 Aug 2026 19:15:24 +0000</pubDate>
      <link>https://dev.to/sirinivask/if-chron-helped-your-team-we-want-to-hear-from-you-with-a-reward-in-return-1i4e</link>
      <guid>https://dev.to/sirinivask/if-chron-helped-your-team-we-want-to-hear-from-you-with-a-reward-in-return-1i4e</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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Flppem5cdhptwi513oz3t.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%2Flppem5cdhptwi513oz3t.png" alt="Chron" width="800" height="443"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;We want to hear how Chron is working in your workflow — and we'll thank you properly for sharing.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;No form. No survey. Just a real answer to one question:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;What does Chron catch that you would have otherwise missed?&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That's it. One sentence or five paragraphs — whatever you have.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why we're asking
&lt;/h2&gt;

&lt;p&gt;Chron just crossed 6,000 downloads. We know it's running in real teams, on real codebases, in real compliance workflows. But download numbers don't tell us what actually matters to people using it.&lt;/p&gt;

&lt;p&gt;We're building the next layer — evidence connectors, board-ready intelligence reports, a live UI — and the most useful thing you can give us right now is a real story. Not a feature request. A story.&lt;/p&gt;




&lt;h2&gt;
  
  
  What you get for sharing
&lt;/h2&gt;

&lt;p&gt;We don't think "thank you for your feedback" is enough. So here's what we're offering:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. We feature you.&lt;/strong&gt;&lt;br&gt;
If you share a case study (your org, your workflow, what Chron surfaced), we'll feature it in our next article — with full credit to you and your team. Public signal for your work.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. We gift you a coffee.&lt;/strong&gt;&lt;br&gt;
For any substantive feedback — one paragraph minimum — we'll send you a Buy Me a Coffee gift directly. Small, but real.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Early access to NitivAI.&lt;/strong&gt;&lt;br&gt;
If you're dealing with compliance at scale — SOC 2, ISO 27001, EU AI Act — and want early access to the commercial governance layer we're building on top of Chron, tell us. We'll move you to the front of the list.&lt;/p&gt;

&lt;p&gt;You can get one, two, or all three. Your call.&lt;/p&gt;




&lt;h2&gt;
  
  
  Two ways to share
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Public:&lt;/strong&gt; Open a thread in &lt;a href="https://github.com/nivaya/chron/discussions" rel="noopener noreferrer"&gt;GitHub Discussions&lt;/a&gt; — your story becomes part of the community record and helps the next person deciding whether Chron is worth trying.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Private:&lt;/strong&gt; DM &lt;a href="https://dev.to/sirinivask"&gt;@sirinivask&lt;/a&gt; here on dev.to, or reach out directly if you'd prefer the conversation stays internal. Enterprise workflows often can't go public — that's fine.&lt;/p&gt;




&lt;p&gt;Chron is local-first. Your audit trail lives on your machine. No cloud, no vendor lock-in. If that's been useful to you, we'd love to know how.&lt;/p&gt;

&lt;p&gt;→ &lt;a href="https://github.com/sirinivask/chron" rel="noopener noreferrer"&gt;github.com/sirinivask/chron&lt;/a&gt;&lt;/p&gt;

</description>
      <category>devops</category>
      <category>security</category>
      <category>ai</category>
      <category>webdev</category>
    </item>
    <item>
      <title>We crossed 6,000 downloads. Here's what we shipped to get there.</title>
      <dc:creator>Srinivas Kondepudi</dc:creator>
      <pubDate>Mon, 03 Aug 2026 09:39:55 +0000</pubDate>
      <link>https://dev.to/sirinivask/we-crossed-6000-downloads-heres-what-we-shipped-to-get-there-3a1j</link>
      <guid>https://dev.to/sirinivask/we-crossed-6000-downloads-heres-what-we-shipped-to-get-there-3a1j</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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fap2blzp2unap9fz5gmd9.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%2Fap2blzp2unap9fz5gmd9.png" alt="Chron" width="800" height="448"&gt;&lt;/a&gt;Tuesday morning. Your SOC 2 auditor emails you.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Can you provide evidence of human review for all AI-assisted code changes in the last 90 days — which files were modified, what prompts were used, and whether any credentials were visible in context?"&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;You open your IDE. Git log? Commits are there. PR history? Reviews too. But the AI session itself — the conversation, the code it proposed, whether it saw your &lt;code&gt;.env&lt;/code&gt; file, which compliance controls it touched — gone.&lt;/p&gt;

&lt;p&gt;That gap is why I built Chron.&lt;/p&gt;




&lt;h2&gt;
  
  
  What Chron is
&lt;/h2&gt;

&lt;p&gt;Chron is an MCP server that runs alongside your AI coding tool. Every message, every code change, every detected secret — locally timestamped, hash-chained, and stored in a SQLite database you own. No cloud. No data sharing. Works offline.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Install once&lt;/span&gt;
npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-g&lt;/span&gt; chron-mcp

&lt;span class="c"&gt;# Check setup&lt;/span&gt;
chron doctor
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Works with Claude Code, Cursor, Windsurf, Continue.dev — any MCP-compatible tool.&lt;/p&gt;




&lt;h2&gt;
  
  
  The last four releases: answers to questions auditors actually ask
&lt;/h2&gt;

&lt;h3&gt;
  
  
  v0.1.39 — "Which sessions are worth reviewing first?"
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;chron risk &lt;span class="nt"&gt;--since&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;30d

SESSION           SCORE  BAND      SIGNALS
a1b2c3d4          87     critical  secrets·auth·infra
e5f6g7h8          52     high      auth·findings&lt;span class="o"&gt;(&lt;/span&gt;2&lt;span class="o"&gt;)&lt;/span&gt;
i9j0k1l2          28     review    code_changes
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The attention score: deterministic 0–100 per session. No ML, no API calls. Pure signal from what actually happened: secrets detected (+25), auth code changed (+15), infra modified (+12), open compliance findings (+8 each). A security lead can triage 90 days of AI sessions in under a minute.&lt;/p&gt;




&lt;h3&gt;
  
  
  v0.1.40 — "Can I get a one-pager for this audit?"
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;chron dashboard &lt;span class="nt"&gt;--since&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;30d &lt;span class="nt"&gt;--output&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;q3-audit.html

✓ Written: q3-audit.html
  8 sessions · 4 open findings · 1 critical · 2 high
  Coverage: 6 controls covered · 3 needs evidence
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Five sections in a single static HTML file — no server, no login, no port: executive summary, sessions ranked by risk score, findings grouped by framework (SOC 2 / ISO 27001 / EU AI Act / NIST AI RMF), a control coverage map, and contextual next actions. Open in a browser. Print to PDF. Attach to the audit package.&lt;/p&gt;




&lt;h3&gt;
  
  
  v0.1.41 — "Walk me through this specific session."
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;chron dashboard &lt;span class="nt"&gt;--session&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;a1b2c3d4

✓ Written: chron-session-a1b2c3d.html
  Score: 87/100 &lt;span class="o"&gt;(&lt;/span&gt;critical&lt;span class="o"&gt;)&lt;/span&gt; · 3 findings · tamper: ✓ ok
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The session detail report: attention score breakdown, full timeline with code diffs, secrets with masked values, compliance finding cards with pre-built accept/dismiss CLI commands, which controls the session touches, and a tamper evidence bar (hash chain + NTP clock + Ed25519 signature).&lt;/p&gt;

&lt;p&gt;An auditor can open one file and understand what happened, why it matters, which policies it touched, and what action remains — without accessing any internal system.&lt;/p&gt;




&lt;h3&gt;
  
  
  v0.1.42 — "Is this a one-off, or a pattern?"
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;chron patterns &lt;span class="nt"&gt;--since&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;30d
&lt;span class="go"&gt;
Chron Patterns  last 30d · 8 sessions

●●●● HIGH    Repeated auth/access-control code modified
             4 sessions touched these paths
             · auth, login, rbac, permission…
             Sessions: a1b2c3d4  e5f6g7h8  +2 more

●●●○ MEDIUM  Recurring SOC 2 finding unresolved
             soc2.cc6_1.ai_access_control_change in 2 sessions

●●●○ MEDIUM  Findings unresolved for 28+ days
             3 open findings across 2 sessions

4 patterns detected  2 high  2 medium
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Six pattern types: repeated secret exposure, repeated code-signal category changes (auth, infra, AI governance, monitoring), recurring unresolved findings, high-attention recurring sessions, stale findings (configurable: &lt;code&gt;--stale=21&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;&lt;code&gt;--json&lt;/code&gt; outputs &lt;code&gt;{ patterns, session_count }&lt;/code&gt; — already shaped for SIEM ingestion in the next release. Pattern IDs are stable keys (&lt;code&gt;repeated_auth_access_control_code_modified&lt;/code&gt;, &lt;code&gt;recurring_finding:soc2.cc6_1.*&lt;/code&gt;) so SIEM rules can match without parsing titles.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;One-off findings are noise. Patterns are risk.&lt;/strong&gt; This command tells you which is which.&lt;/p&gt;




&lt;h2&gt;
  
  
  The number
&lt;/h2&gt;

&lt;p&gt;We crossed &lt;strong&gt;6,000 downloads&lt;/strong&gt; this week. As of publishing: &lt;strong&gt;6,139&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;No fundraise. No acquisition. No VC backing. Just a CLI that answers a question nobody had an answer for, installed by 6,000+ developers who needed an audit trail for their AI coding sessions.&lt;/p&gt;




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

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;v0.1.43 — SIEM Risk Events:&lt;/strong&gt; emit &lt;code&gt;pattern_detected&lt;/code&gt;, &lt;code&gt;high_attention_session&lt;/code&gt;, &lt;code&gt;attention_score_computed&lt;/code&gt; events into your pipeline&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;v0.1.44 — Evidence Connectors:&lt;/strong&gt; &lt;code&gt;chron evidence import&lt;/code&gt; to link policy documents to coverage gaps&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Phase 3.5 — Policy Evidence Registry:&lt;/strong&gt; map your policies to the controls Chron already tracks&lt;/li&gt;
&lt;/ul&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;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-g&lt;/span&gt; chron-mcp
chron doctor

&lt;span class="c"&gt;# After a few AI sessions:&lt;/span&gt;
chron risk
chron patterns &lt;span class="nt"&gt;--since&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;30d
chron dashboard &lt;span class="nt"&gt;--output&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;report.html
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;GitHub: &lt;a href="https://github.com/sirinivask/chron" rel="noopener noreferrer"&gt;https://github.com/sirinivask/chron&lt;/a&gt;&lt;/p&gt;

</description>
      <category>devops</category>
      <category>security</category>
      <category>typescript</category>
      <category>webdev</category>
    </item>
    <item>
      <title>From AI logger to AI governance layer, what 5,600 downloads taught us about Chron</title>
      <dc:creator>Srinivas Kondepudi</dc:creator>
      <pubDate>Mon, 27 Jul 2026 18:06:28 +0000</pubDate>
      <link>https://dev.to/sirinivask/from-ai-logger-to-ai-governance-layer-what-5600-downloads-taught-us-about-chron-1iek</link>
      <guid>https://dev.to/sirinivask/from-ai-logger-to-ai-governance-layer-what-5600-downloads-taught-us-about-chron-1iek</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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fkoealdbv4xzrx50ejkgp.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%2Fkoealdbv4xzrx50ejkgp.png" alt="Chron" width="800" height="336"&gt;&lt;/a&gt;When we shipped Chron six months ago, the pitch was simple: &lt;em&gt;every AI conversation should leave a timestamped, tamper-evident record.&lt;/em&gt; Developers installing AI coding tools had no answer to the question "what did the AI actually do?" Chron was that answer.&lt;/p&gt;

&lt;p&gt;5,600 installs later, the question has changed.&lt;/p&gt;

&lt;p&gt;It's no longer "did we log it?" — most teams using Chron have solved that. The new question is: &lt;strong&gt;which sessions should I look at first?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;That question is harder, and it's where Chron is heading next.&lt;/p&gt;




&lt;h2&gt;
  
  
  What Chron does today
&lt;/h2&gt;

&lt;p&gt;Chron is an MCP server that runs locally alongside Claude Code, Cursor, Windsurf, and Codex. Every message, every file change, every tool call gets logged to a local SQLite database with a precise timestamp and a tamper-evident hash chain.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;chron &lt;span class="nb"&gt;history&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;8f3a7c9e  claude-code  API refactor         2026-07-19  14 events
b91c2a11  cursor        Contract review       2026-07-18  8 events
3d0a5f22  claude-code  Auth middleware fix   2026-07-17  31 events
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;chron verify 8f3a
&lt;span class="c"&gt;# ✓ hash chain intact — 14 events, no tampering detected&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;On top of that, &lt;code&gt;chron review&lt;/code&gt; runs a deterministic compliance analysis across four frameworks:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;SOC 2&lt;/strong&gt; — access control changes, secret exposure, infrastructure modifications&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;ISO 27001&lt;/strong&gt; — cryptography changes, access management, incident handling&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;EU AI Act&lt;/strong&gt; — risk management, data governance, human oversight&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;NIST AI RMF&lt;/strong&gt; — AI policy changes, model evaluation, incident response
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;chron review &lt;span class="nt"&gt;--framework&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;soc2 &lt;span class="nt"&gt;--output&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;evidence.html
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The output is a printable HTML evidence package — not a compliance opinion, but session evidence a control owner can actually use.&lt;/p&gt;




&lt;h2&gt;
  
  
  The coverage map: honest about what Chron sees
&lt;/h2&gt;

&lt;p&gt;One of the things we deliberately got right: Chron doesn't claim to "cover" a framework. It covers specific controls that are observable from AI session activity. Everything else — policy documentation, physical access, contractual obligations — requires evidence from other sources.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;chron review &lt;span class="nt"&gt;--framework&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;nist-ai-rmf &lt;span class="nt"&gt;--full-map&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;NIST AI RMF — Full Control Coverage Map

  Covered by session evidence (12)
  ────────────────────────────────
  GOVERN 1.1   AI policy and governance changes    rule: nist-ai-rmf.govern.ai_policy_change
  MAP 3.5      Sensitive data in AI sessions       rule: nist-ai-rmf.map.sensitive_data_in_session
  MEASURE 2.7  AI monitoring modifications         rule: nist-ai-rmf.measure.ai_monitoring_change
  ...

  Needs additional evidence (28)
  ────────────────────────────────
  GOVERN 2.1   Organizational roles defined        source: policy_docs
  MAP 2.2      Scientific findings documented      source: policy_docs
  ...

  Manual review required (18)
  ────────────────────────────────
  GOVERN 3.1   Feedback mechanisms in place        human judgement required
  ...

  Out of scope (8)
  ────────────────────────────────
  GOVERN 5.2   Organizational policies current     not observable from session logs
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;66 NIST AI RMF subcategories. 12 covered by Chron session evidence. 54 classified honestly. The disclaimer at the top of every report: &lt;strong&gt;"Covered does not mean compliant."&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  What's coming next: Attention Score
&lt;/h2&gt;

&lt;p&gt;At 5,600 installs, the missing piece is triage.&lt;/p&gt;

&lt;p&gt;When you have 200 sessions logged, you don't need a list — you need a signal. Which of these sessions involved something worth a second look?&lt;/p&gt;

&lt;p&gt;The next release adds an &lt;strong&gt;Attention Score&lt;/strong&gt; to every session: a deterministic 0–100 score computed from three signal categories.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Secret exposure&lt;/strong&gt; — was a credential, API key, or token detected in the session? (+30)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Sensitive code changes&lt;/strong&gt; — did the AI modify auth, production config, infrastructure, or AI oversight code? (up to +30, based on path patterns)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Open compliance findings&lt;/strong&gt; — does this session have unresolved findings from &lt;code&gt;chron review&lt;/code&gt;? Severity-weighted, capped at +30.&lt;/p&gt;

&lt;p&gt;The result is visible everywhere you already look:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;chron &lt;span class="nb"&gt;history&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;8f3a7c9e  claude-code  API refactor         [ATTENTION: 86]  ●●●●
3d0a5f22  claude-code  Auth middleware fix  [ATTENTION: 72]  ●●●○
b91c2a11  cursor        Contract review       [ATTENTION: 12]  ●○○○
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;chron risk &lt;span class="nt"&gt;--since&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;30d
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Sessions requiring attention  (last 30 days)

  1.  8f3a7c9e  claude-code  API refactor         Score: 86
      ↳ secret detected in session
      ↳ auth code modified (3 files)
      ↳ 2 unresolved SOC 2 findings (1 critical)

  2.  3d0a5f22  claude-code  Auth middleware fix  Score: 72
      ↳ access control code modified
      ↳ production config changed
      ↳ 1 unresolved ISO 27001 finding
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No AI in the scoring path. Pure path matching + database queries. Same session, same score, every time.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why this matters now
&lt;/h2&gt;

&lt;p&gt;The compliance question used to be "do we have logs?" Most teams can answer that today.&lt;/p&gt;

&lt;p&gt;The question in 2026 is "did the AI touch anything that warrants a review?" That's a triage problem, not a logging problem. Attention Score is the answer.&lt;/p&gt;

&lt;p&gt;After that: a static local dashboard — &lt;code&gt;chron dashboard&lt;/code&gt; — that generates an HTML snapshot with session list, scores, top reasons, open findings, and framework coverage. No server, no cloud account, no new dependencies. Same personality as the rest of Chron.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Chron is available on npm:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-g&lt;/span&gt; chron-mcp
chron-mcp   &lt;span class="c"&gt;# auto-configures Claude Code, Cursor, Windsurf&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Source and docs: &lt;a href="https://github.com/SirinivasK/chron" rel="noopener noreferrer"&gt;github.com/SirinivasK/chron&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Chron logs every AI conversation to a local SQLite database you own. Nothing leaves your machine.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>security</category>
      <category>devtools</category>
      <category>audit</category>
    </item>
    <item>
      <title>CLAIIM: Governing AI Agents Before They Act</title>
      <dc:creator>Srinivas Kondepudi</dc:creator>
      <pubDate>Mon, 20 Jul 2026 08:34:38 +0000</pubDate>
      <link>https://dev.to/sirinivask/claiim-governing-ai-agents-before-they-act-32b7</link>
      <guid>https://dev.to/sirinivask/claiim-governing-ai-agents-before-they-act-32b7</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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F4uq3tjindsvyjwtomlot.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%2F4uq3tjindsvyjwtomlot.png" alt="Claiim" width="800" height="420"&gt;&lt;/a&gt;Building AI agents is becoming easier.&lt;/p&gt;

&lt;p&gt;Running them safely once they can take real action is the harder problem.&lt;/p&gt;

&lt;p&gt;The moment an agent can deploy, approve, investigate, escalate, refund, send, export, or trigger a workflow, the question changes from:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Can the agent complete the task?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;to:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Should this agent be allowed to take this action, under whose accountability, and what proof will exist afterward?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That is the problem we are building CLAIIM around.&lt;/p&gt;

&lt;p&gt;CLAIIM is a self-hosted governance and accountability layer for AI agents. It is designed for teams that want AI agents to operate inside real organizational boundaries, not just inside a prompt or a notebook.&lt;/p&gt;

&lt;p&gt;The core idea is simple:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Give every agent a governed identity.&lt;/li&gt;
&lt;li&gt;Bind that agent to a named human accountability anchor.&lt;/li&gt;
&lt;li&gt;Check actions against policy before they run.&lt;/li&gt;
&lt;li&gt;Record every ALLOW and DENY decision in Chron.&lt;/li&gt;
&lt;li&gt;Keep the data in the customer's environment.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is not about adding another dashboard after the agent acts. It is about putting a control point before execution.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why this matters now
&lt;/h2&gt;

&lt;p&gt;Most organizations already know how to govern humans.&lt;/p&gt;

&lt;p&gt;They have identity providers, access reviews, privileged access workflows, audit logs, separation of duties, and change approval processes.&lt;/p&gt;

&lt;p&gt;But AI agents often enter the organization through a different path:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;a shared API key&lt;/li&gt;
&lt;li&gt;a service account&lt;/li&gt;
&lt;li&gt;a workflow token&lt;/li&gt;
&lt;li&gt;a CI/CD secret&lt;/li&gt;
&lt;li&gt;a browser session&lt;/li&gt;
&lt;li&gt;a tool wrapper&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That is enough to make something work. It is not enough to prove that it was governed.&lt;/p&gt;

&lt;p&gt;When an AI agent takes an action, a security or compliance team will eventually ask:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Which agent was it?&lt;/li&gt;
&lt;li&gt;Who owned that agent?&lt;/li&gt;
&lt;li&gt;What was it allowed to do?&lt;/li&gt;
&lt;li&gt;Which policy applied?&lt;/li&gt;
&lt;li&gt;Was the decision made before execution?&lt;/li&gt;
&lt;li&gt;Was the action allowed, denied, or approved by a human?&lt;/li&gt;
&lt;li&gt;Can we prove that later?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If the answer is buried in logs written by the agent itself, the organization has a weak chain of custody.&lt;/p&gt;

&lt;p&gt;CLAIIM is our attempt to make that chain explicit.&lt;/p&gt;

&lt;h2&gt;
  
  
  What we have added recently
&lt;/h2&gt;

&lt;p&gt;Over the last few weeks, CLAIIM moved from a working governance prototype toward a more serious public-preview product.&lt;/p&gt;

&lt;h3&gt;
  
  
  Evaluation and offline licensing
&lt;/h3&gt;

&lt;p&gt;CLAIIM now has an evaluation mode with clear limits.&lt;/p&gt;

&lt;p&gt;No license file means the system runs as an evaluation instance. The UI shows the evaluation state, the remaining evaluation window, and the active limits.&lt;/p&gt;

&lt;p&gt;For design partners and paid deployments, CLAIIM supports offline license files. The license is verified locally. There is no phone-home requirement in the runtime.&lt;/p&gt;

&lt;p&gt;That matters for the kind of organizations we are building for. If the product claim is "your environment, your database," licensing should not quietly become a cloud dependency.&lt;/p&gt;

&lt;h3&gt;
  
  
  Guided rehearsals
&lt;/h3&gt;

&lt;p&gt;One problem with governance products is that they can sound abstract until someone sees the loop.&lt;/p&gt;

&lt;p&gt;So we added guided rehearsals in the product UI.&lt;/p&gt;

&lt;p&gt;The current rehearsal templates cover:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;DevOps agent: staging deploy allowed, production deploy blocked&lt;/li&gt;
&lt;li&gt;Support agent: escalation allowed, sensitive data access blocked&lt;/li&gt;
&lt;li&gt;Finance agent: report access allowed, payment initiation blocked&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Each rehearsal provisions real CLAIIM entities:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;organization boundary&lt;/li&gt;
&lt;li&gt;accountability anchor&lt;/li&gt;
&lt;li&gt;skill&lt;/li&gt;
&lt;li&gt;policy&lt;/li&gt;
&lt;li&gt;agent identity&lt;/li&gt;
&lt;li&gt;ALLOW gate call&lt;/li&gt;
&lt;li&gt;DENY gate call&lt;/li&gt;
&lt;li&gt;Chron proof&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These are not fake frontend animations. They run through the real backend APIs and real policy gate.&lt;/p&gt;

&lt;h3&gt;
  
  
  Chron proof export
&lt;/h3&gt;

&lt;p&gt;After a rehearsal or real gate decision, CLAIIM can produce a proof report from Chron.&lt;/p&gt;

&lt;p&gt;The important part of the report is plain English:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;This report shows that before this agent took any action, it was required to identify itself, name a human accountable for its behavior, and pass a policy check. The allowed action proceeded. The denied action was blocked before any system was touched. Every decision is timestamped and cannot be altered.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That paragraph is the product.&lt;/p&gt;

&lt;p&gt;The UUIDs, policy IDs, timestamps, and hashes matter. But the buyer needs to understand the governance outcome first.&lt;/p&gt;

&lt;h3&gt;
  
  
  Production readiness work
&lt;/h3&gt;

&lt;p&gt;We have also been hardening the platform for enterprise-style evaluation:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;rate limiting on sensitive API paths&lt;/li&gt;
&lt;li&gt;security headers&lt;/li&gt;
&lt;li&gt;clearer RBAC roles&lt;/li&gt;
&lt;li&gt;SSO first-login least privilege&lt;/li&gt;
&lt;li&gt;persistent SAML service-provider keys&lt;/li&gt;
&lt;li&gt;Kubernetes/Helm deployment chart&lt;/li&gt;
&lt;li&gt;production Kubernetes runbook&lt;/li&gt;
&lt;li&gt;external PostgreSQL deployment path&lt;/li&gt;
&lt;li&gt;license secret mounting in Kubernetes&lt;/li&gt;
&lt;li&gt;health probes and resource defaults&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is not glamorous work, but it matters.&lt;/p&gt;

&lt;p&gt;If a large enterprise asks whether CLAIIM can be deployed safely in their environment, the answer cannot be "run this demo script and trust us."&lt;/p&gt;

&lt;h2&gt;
  
  
  The product direction: Agent Chain of Custody
&lt;/h2&gt;

&lt;p&gt;The more we test CLAIIM, the more one phrase keeps standing out:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Agent Chain of Custody&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Single-agent governance is only the first step.&lt;/p&gt;

&lt;p&gt;Real AI work is becoming delegated:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Human objective
  -&amp;gt; main agent
    -&amp;gt; research agent
    -&amp;gt; coding agent
    -&amp;gt; test agent
    -&amp;gt; review agent
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Without a governance layer, that delegation becomes invisible.&lt;/p&gt;

&lt;p&gt;With CLAIIM, we want the chain to be visible:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Human -&amp;gt; Main Agent -&amp;gt; Subagent -&amp;gt; Scoped Action -&amp;gt; Policy Decision -&amp;gt; Chron Proof
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That means tracking:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;who delegated the task&lt;/li&gt;
&lt;li&gt;which subagent received it&lt;/li&gt;
&lt;li&gt;what scope it was given&lt;/li&gt;
&lt;li&gt;what risk level applied&lt;/li&gt;
&lt;li&gt;what policy decided&lt;/li&gt;
&lt;li&gt;whether a human checkpoint was required&lt;/li&gt;
&lt;li&gt;what evidence was produced&lt;/li&gt;
&lt;li&gt;what proof exists afterward&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is where we think the category is going.&lt;/p&gt;

&lt;p&gt;AI agents will not stay as single isolated scripts. They will become multi-agent workflows. The governance model has to follow that shape.&lt;/p&gt;

&lt;h2&gt;
  
  
  What we are building next
&lt;/h2&gt;

&lt;p&gt;The next pieces are focused on making CLAIIM more useful for serious evaluations.&lt;/p&gt;

&lt;h3&gt;
  
  
  SIEM export
&lt;/h3&gt;

&lt;p&gt;Chron remains the source of truth, but security teams need events in their existing SOC pipeline.&lt;/p&gt;

&lt;p&gt;SIEM export is now available. It is a signed webhook export for Chron decisions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;ALLOW&lt;/li&gt;
&lt;li&gt;DENY&lt;/li&gt;
&lt;li&gt;agent identity&lt;/li&gt;
&lt;li&gt;action type&lt;/li&gt;
&lt;li&gt;accountability anchor&lt;/li&gt;
&lt;li&gt;policy version&lt;/li&gt;
&lt;li&gt;skill version&lt;/li&gt;
&lt;li&gt;deny reason&lt;/li&gt;
&lt;li&gt;Chron hash metadata where available&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It is disabled by default. No outbound traffic occurs unless the customer explicitly enables it.&lt;/p&gt;

&lt;h3&gt;
  
  
  Chain of Custody MVP
&lt;/h3&gt;

&lt;p&gt;The first Chain of Custody version will be deliberately small:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;parent agent&lt;/li&gt;
&lt;li&gt;subagent&lt;/li&gt;
&lt;li&gt;delegated task ID&lt;/li&gt;
&lt;li&gt;risk level&lt;/li&gt;
&lt;li&gt;scope&lt;/li&gt;
&lt;li&gt;allowed scoped action&lt;/li&gt;
&lt;li&gt;denied out-of-scope action&lt;/li&gt;
&lt;li&gt;Chron proof report showing the chain&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The goal is not to build a full agent orchestration engine.&lt;/p&gt;

&lt;p&gt;The goal is to prove governed delegation.&lt;/p&gt;

&lt;h3&gt;
  
  
  Runtime credential governance
&lt;/h3&gt;

&lt;p&gt;Eventually, an approved action should not just pass policy. It should also receive only the credentials needed for that approved action.&lt;/p&gt;

&lt;p&gt;That points toward:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;scoped credential grants&lt;/li&gt;
&lt;li&gt;credential injection after policy ALLOW&lt;/li&gt;
&lt;li&gt;revocation without breaking unrelated agents&lt;/li&gt;
&lt;li&gt;tool-level enforcement&lt;/li&gt;
&lt;li&gt;secrets kept out of agent context&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This belongs in CLAIIM, but it should support the governance story rather than replace it.&lt;/p&gt;

&lt;h3&gt;
  
  
  Workflow lifecycle control
&lt;/h3&gt;

&lt;p&gt;Long-running agents also need operational state:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;active&lt;/li&gt;
&lt;li&gt;paused&lt;/li&gt;
&lt;li&gt;approval required&lt;/li&gt;
&lt;li&gt;cooldown&lt;/li&gt;
&lt;li&gt;disabled&lt;/li&gt;
&lt;li&gt;rollback requested&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We see this as a future layer around governed execution. CLAIIM should know not only whether an action is allowed, but whether the workflow itself is in a state where action is permitted.&lt;/p&gt;

&lt;h2&gt;
  
  
  What CLAIIM is not trying to be
&lt;/h2&gt;

&lt;p&gt;CLAIIM is not trying to replace agent frameworks.&lt;/p&gt;

&lt;p&gt;Use LangGraph, CrewAI, custom Python, internal orchestration, MCP servers, browser agents, or whatever runtime fits your team.&lt;/p&gt;

&lt;p&gt;The governance question sits around those systems:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Before this agent acts, does the organization know who it is, what it can do, who is accountable, and what proof will exist?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That is the layer CLAIIM is focused on.&lt;/p&gt;

&lt;h2&gt;
  
  
  A simple mental model
&lt;/h2&gt;

&lt;p&gt;If you are evaluating production AI agents, think of the stack like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Agent runtime: how the agent reasons and executes
Workflow layer: how long-running work is coordinated
Credential layer: what secrets and tools the agent can access
Governance layer: whether the action is allowed before execution
Proof layer: what evidence exists afterward
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;CLAIIM is focused on the governance and proof layers first, with runtime security and workflow control coming in as the product matures.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why public preview matters
&lt;/h2&gt;

&lt;p&gt;This space is still early.&lt;/p&gt;

&lt;p&gt;The vocabulary is forming in public. People are talking about agent identity, delegated authority, approval gates, credential isolation, workflow lifecycle, audit receipts, and chain of custody because the same pressure is appearing in different organizations.&lt;/p&gt;

&lt;p&gt;That is a good sign.&lt;/p&gt;

&lt;p&gt;It means the problem is real.&lt;/p&gt;

&lt;p&gt;Our job with CLAIIM is to turn that problem into a product that security, platform, compliance, and business teams can actually use.&lt;/p&gt;

&lt;p&gt;Not just another agent demo.&lt;/p&gt;

&lt;p&gt;A governed execution layer.&lt;/p&gt;

&lt;p&gt;Identity before action.&lt;/p&gt;

&lt;p&gt;Policy before execution.&lt;/p&gt;

&lt;p&gt;Proof after every decision.&lt;/p&gt;

&lt;p&gt;If you are working on production AI agents and want to compare notes, I would be happy to talk.&lt;/p&gt;

&lt;p&gt;Public preview: &lt;a href="https://claiim.io" rel="noopener noreferrer"&gt;https://claiim.io&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Contact: &lt;a href="mailto:support@claiim.io"&gt;support@claiim.io&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>security</category>
      <category>governance</category>
      <category>devops</category>
    </item>
  </channel>
</rss>
