<?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: Dhrubojyoti Gangopadhyay</title>
    <description>The latest articles on DEV Community by Dhrubojyoti Gangopadhyay (@dhrubojyoti).</description>
    <link>https://dev.to/dhrubojyoti</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%2F4210575%2F8fc91994-1e1e-4509-bbbb-57f1dd7b775b.jpg</url>
      <title>DEV Community: Dhrubojyoti Gangopadhyay</title>
      <link>https://dev.to/dhrubojyoti</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/dhrubojyoti"/>
    <language>en</language>
    <item>
      <title>Hybrid retrieval with reciprocal rank fusion: notes from a RAG prototype</title>
      <dc:creator>Dhrubojyoti Gangopadhyay</dc:creator>
      <pubDate>Mon, 02 Nov 2026 17:18:01 +0000</pubDate>
      <link>https://dev.to/dhrubojyoti/hybrid-retrieval-with-reciprocal-rank-fusion-notes-from-a-rag-prototype-1d93</link>
      <guid>https://dev.to/dhrubojyoti/hybrid-retrieval-with-reciprocal-rank-fusion-notes-from-a-rag-prototype-1d93</guid>
      <description>&lt;p&gt;&lt;em&gt;Why dense and sparse retrieval disagree, why fusing ranks beats blending scores, and what a 20-question evaluation set revealed about a B2B sales-intelligence prototype.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;This is a set of notes from a retrieval prototype, the &lt;a href="https://www.dhrubo.shop/projects/b2b-sales-intelligence-rag" rel="noopener noreferrer"&gt;B2B Sales Intelligence RAG&lt;/a&gt; repository. It is a prototype: it has fifty unit tests, a twenty-question evaluation set and no deployment. The notes are about the retrieval design, which is the part I would reuse.&lt;/p&gt;

&lt;h2&gt;
  
  
  The problem with one retriever
&lt;/h2&gt;

&lt;p&gt;A sales team asks questions like "which accounts in the North East mentioned a budget freeze on a call in the last quarter?" The useful evidence lives in CRM notes, call transcripts and account plans. Two retrieval families fail in opposite ways on this:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Dense retrieval&lt;/strong&gt; (embeddings) understands "budget freeze" and "spending pause" are the same thing. It is poor at exact tokens: account codes, product SKUs, a person's surname, a region string.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Sparse retrieval&lt;/strong&gt; (BM25) nails exact tokens and dates and is blind to paraphrase.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Sales questions always contain both kinds of signal. So the retriever uses both and then has to combine them.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why fuse ranks instead of scores
&lt;/h2&gt;

&lt;p&gt;The tempting approach is &lt;code&gt;final = a * dense_score + b * bm25_score&lt;/code&gt;. It does not work in practice because the two scores live on different scales and distributions, and the right &lt;code&gt;a&lt;/code&gt; and &lt;code&gt;b&lt;/code&gt; change with the corpus. You end up tuning a magic number per customer.&lt;/p&gt;

&lt;p&gt;Reciprocal rank fusion (RRF) avoids the scales entirely. Each retriever returns a ranked list; a document's fused score is the sum over retrievers of &lt;code&gt;1 / (k + rank)&lt;/code&gt;, with &lt;code&gt;k&lt;/code&gt; typically 60. A document ranked first by both retrievers wins; a document ranked first by one and absent from the other still surfaces. The prototype applies a weight per retriever on top of that, which is the only knob, and in the evaluation it barely needed moving.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;rrf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ranked_lists&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;60&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;weights&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;scores&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;defaultdict&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;float&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;docs&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;enumerate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ranked_lists&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;w&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;weights&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mf"&gt;1.0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ranked_lists&lt;/span&gt;&lt;span class="p"&gt;))[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;rank&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;doc_id&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;enumerate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;docs&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="n"&gt;scores&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;doc_id&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;w&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;rank&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;sorted&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;scores&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;scores&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;reverse&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Re-ranking the fused list
&lt;/h2&gt;

&lt;p&gt;RRF gives a good top fifty, not a good top five. A cross-encoder re-ranker reads the query and each candidate together and scores relevance directly. It is too slow to run over the whole corpus and exactly fast enough to run over fifty candidates. The prototype uses a small open cross-encoder; the quality jump from fused top-k to re-ranked top-k was the single largest improvement in the evaluation.&lt;/p&gt;

&lt;h2&gt;
  
  
  The evaluation set
&lt;/h2&gt;

&lt;p&gt;Twenty questions is small, and it was still the most useful artefact in the project. Each question has an expected set of source documents and a reference answer. An LLM judge scores the generated answer for faithfulness to the retrieved context and for coverage of the reference. Retrieval is scored separately with recall at k, which is the number that actually told me whether a change helped.&lt;/p&gt;

&lt;p&gt;Three things the set revealed:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Chunk size mattered more than the embedding model. Transcripts needed smaller chunks with overlap; account plans needed whole sections.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;BM25 alone beat dense alone on this corpus, because sales questions are full of proper nouns. Fusion beat both.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The judge was lenient on answers that hedged. Faithfulness scoring needs a strict rubric or it rewards vagueness.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  What is honest to say about this prototype
&lt;/h2&gt;

&lt;p&gt;The dependency pins did not resolve in CI, so the tests have never run in a pipeline, only locally. There is no deployment and no production traffic. I include it here because the retrieval and evaluation design is sound and reusable, and because the &lt;a href="https://www.dhrubo.shop/projects" rel="noopener noreferrer"&gt;projects page&lt;/a&gt; exists to show status honestly rather than to impress.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I would do in production
&lt;/h2&gt;

&lt;p&gt;Trace every query with the retrieved IDs and scores so failures can be replayed. Grow the evaluation set from real questions, not invented ones. Add a freshness feature, because sales context goes stale in weeks. And keep RRF; in a year of reading about retrieval I have not found a simpler combiner that works as reliably.&lt;/p&gt;

&lt;p&gt;Originally published at &lt;a href="https://www.dhrubo.shop/writing/hybrid-retrieval-reciprocal-rank-fusion" rel="noopener noreferrer"&gt;https://www.dhrubo.shop/writing/hybrid-retrieval-reciprocal-rank-fusion&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>machinelearning</category>
      <category>python</category>
      <category>llm</category>
    </item>
    <item>
      <title>What a forward deployed AI engineer actually does</title>
      <dc:creator>Dhrubojyoti Gangopadhyay</dc:creator>
      <pubDate>Mon, 02 Nov 2026 17:17:12 +0000</pubDate>
      <link>https://dev.to/dhrubojyoti/what-a-forward-deployed-ai-engineer-actually-does-4ioe</link>
      <guid>https://dev.to/dhrubojyoti/what-a-forward-deployed-ai-engineer-actually-does-4ioe</guid>
      <description>&lt;p&gt;&lt;em&gt;Not a solutions engineer, not a researcher. A working definition of the forward deployed AI engineer role, drawn from doing it inside a company and from reading a hundred job descriptions.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The title "forward deployed engineer" was popularised by Palantir and is now on job boards from Databricks to Sarvam. The AI version of the role is defined inconsistently. Having read about a hundred postings while preparing a job search, and having done the work inside a company since mid-2026, this is my working definition.&lt;/p&gt;

&lt;h2&gt;
  
  
  The one-sentence version
&lt;/h2&gt;

&lt;p&gt;A forward deployed AI engineer sits with the people who have the problem, scopes a workflow a language model can improve, builds it, deploys it into the tools those people already use, and stays until the numbers move.&lt;/p&gt;

&lt;p&gt;Each clause rules something out. "Sits with the people" rules out building from a ticket. "Scopes a workflow" rules out building a chatbot and hoping. "Builds it" rules out pure solutions engineering. "Deploys into existing tools" rules out a demo on a laptop. "Stays until the numbers move" rules out handing over a repo and leaving.&lt;/p&gt;

&lt;h2&gt;
  
  
  What the week looks like
&lt;/h2&gt;

&lt;p&gt;In my current role at 1XL I own AI adoption across HR, sales, marketing, operations, support, finance and technology. A typical week includes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Discovery.&lt;/strong&gt; Sitting with a department head and watching the work. Most "we need AI" requests turn out to be a data-entry problem, an approval-chain problem or a reporting problem. The model is sometimes the smallest part.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Scoping.&lt;/strong&gt; Writing one page: the input, the output, who approves, what happens when the model is wrong, and the metric. If I cannot write the failure paragraph, the project is not ready.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Building.&lt;/strong&gt; Usually a small service: a document goes in, structured data comes out, a human reviews, a system of record is updated. Python or TypeScript, a hosted model behind an adapter, a queue if volume needs it.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Teaching.&lt;/strong&gt; Role-specific curricula and field manuals, because a tool nobody can operate is not deployed. The induction programme for new joiners in the India and UAE offices is part of this.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Infrastructure advice.&lt;/strong&gt; Which messaging platform, which workflow engine, where the data may live. For us that has meant WhatsApp infrastructure, n8n and agentic-workflow tooling.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What it is not
&lt;/h2&gt;

&lt;p&gt;It is not research. I do not train models and I do not claim to. It is not pure solutions engineering either; a solutions engineer demonstrates the product, a forward deployed engineer changes the customer's process and ships code into it. It is not an internal tools team: the measure of success is a departmental metric, not a shipped feature.&lt;/p&gt;

&lt;h2&gt;
  
  
  The skills that matter, in order
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Scoping judgement.&lt;/strong&gt; Knowing which 20 percent of a process is worth automating and which 80 percent should be left to a human with a better form.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Integration plumbing.&lt;/strong&gt; Auth, webhooks, idempotency, retries, logging. Most of the code in a forward deployed project is not AI.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Evaluation.&lt;/strong&gt; A fixed test set, a judge, and a number that moves. Without it every demo is a success and every deployment is a surprise.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Guardrails.&lt;/strong&gt; Approval steps before consequential actions. I wrote about how &lt;a href="https://www.dhrubo.shop/projects/sahkarmi" rel="noopener noreferrer"&gt;Sahkarmi&lt;/a&gt; does this in &lt;a href="https://www.dhrubo.shop/writing/approval-gates-for-ai-agents" rel="noopener noreferrer"&gt;Approval gates for AI agents&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Explaining.&lt;/strong&gt; To a finance head who will never read the code, in their vocabulary.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Model knowledge is on the list, but it is fifth or sixth. Providers change monthly; scoping judgement does not.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why a revenue-operations background helps
&lt;/h2&gt;

&lt;p&gt;I spent sixteen years in enterprise revenue operations before writing software full time. That turns out to be the right preparation for the first two skills on the list. I have been the person whose approval chain was bypassed by a clever spreadsheet, and the person who had to reconcile what the system said against what the dealer received. Operations people can tell when an engineer has never been on the receiving end of their own automation.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to evaluate a candidate for this role
&lt;/h2&gt;

&lt;p&gt;If you are hiring, look for three artefacts. A deployed system with an approval or review step in it, not a demo. An evaluation set with a number attached. And a document written for a non-technical owner that explains what the system will not do. Résumés list frameworks; these three show judgement.&lt;/p&gt;

&lt;p&gt;If you want to see mine, the &lt;a href="https://www.dhrubo.shop/projects" rel="noopener noreferrer"&gt;projects page&lt;/a&gt; lists every public system with an honest status, and the &lt;a href="https://www.dhrubo.shop/resume" rel="noopener noreferrer"&gt;résumé&lt;/a&gt; is one page.&lt;/p&gt;

&lt;p&gt;Originally published at &lt;a href="https://www.dhrubo.shop/writing/what-a-forward-deployed-ai-engineer-does" rel="noopener noreferrer"&gt;https://www.dhrubo.shop/writing/what-a-forward-deployed-ai-engineer-does&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>career</category>
      <category>productivity</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Approval gates for AI agents: how Sahkarmi decides what a coworker may do</title>
      <dc:creator>Dhrubojyoti Gangopadhyay</dc:creator>
      <pubDate>Mon, 02 Nov 2026 17:15:01 +0000</pubDate>
      <link>https://dev.to/dhrubojyoti/approval-gates-for-ai-agents-how-sahkarmi-decides-what-a-coworker-may-do-c7k</link>
      <guid>https://dev.to/dhrubojyoti/approval-gates-for-ai-agents-how-sahkarmi-decides-what-a-coworker-may-do-c7k</guid>
      <description>&lt;p&gt;&lt;em&gt;The permission model behind Sahkarmi: sixteen action categories, six that can never be auto-approved, time-boxed delegated authority, and a browser take-over flow that keeps passwords away from the model.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Most agent demos answer one question well: &lt;em&gt;what did the model say?&lt;/em&gt; Operations work asks a harder one: &lt;em&gt;what did the system actually do, and who allowed it?&lt;/em&gt; Sahkarmi is a desktop platform where AI coworkers browse, file, draft and report on a user's own Windows machine. This article is about the part of it I spent the most design time on, which is the part that stops the agent.&lt;/p&gt;

&lt;h2&gt;
  
  
  The failure we are designing against
&lt;/h2&gt;

&lt;p&gt;An agent with a browser and a shell can pay an invoice, message a customer, submit a government form, publish a page or delete a folder. Each of those is a one-way door. A chat assistant that hallucinates wastes a minute; an agent that hallucinates a bank transfer costs real money and trust. So the first design rule in Sahkarmi is blunt:&lt;/p&gt;

&lt;p&gt;The model proposes. A human approves. The decision is recorded.&lt;/p&gt;

&lt;p&gt;Everything below is machinery to make that rule cheap enough that people keep it switched on.&lt;/p&gt;

&lt;h2&gt;
  
  
  Sixteen categories, six hard gates
&lt;/h2&gt;

&lt;p&gt;Every tool call an agent can make is classified into one of sixteen permission categories in &lt;code&gt;permission-policy.ts&lt;/code&gt;: reading files, writing files, browsing, form filling, payments, external messages, publication, shell access, deletions, official forms, and so on. Each category has a default decision: allow, ask, or deny.&lt;/p&gt;

&lt;p&gt;Six categories are special. Payments, messages to customers or third parties, publication, shell commands, destructive file operations and official or government forms are hard-coded to &lt;strong&gt;ask&lt;/strong&gt;. The model cannot auto-approve them. The settings UI cannot switch them to allow. A coworker template cannot override them. The reasoning is simple: a policy an agent can talk its way around is not a policy, and a setting a tired user can flip at midnight is not a safeguard.&lt;/p&gt;

&lt;h2&gt;
  
  
  Delegated authority with an expiry
&lt;/h2&gt;

&lt;p&gt;Asking on every action makes an agent useless for repetitive work, so Sahkarmi has an approval store with two kinds of memory. A specific approval ("yes, send this message") is single-use. A delegated approval ("you may send order confirmations to existing customers for the next thirty days") is scoped to a category and a pattern and carries a hard expiry. Nothing is remembered forever; the store evicts delegated authority at thirty days and plain approvals at seven. Expiry is not a UX nicety. It forces the user to re-read what they have delegated.&lt;/p&gt;

&lt;h2&gt;
  
  
  The browser take-over flow
&lt;/h2&gt;

&lt;p&gt;The most common place an agent meets a secret is a login page. The naive design is to give the agent the password. Sahkarmi refuses. When a coworker reaches a login or a one-time code, it requests secure input. The sandboxed browser is handed to the human, who signs in with their own hands; the coworker then takes the session back. The model never sees the password or the OTP, which means it can never log them, leak them into a transcript or be tricked into typing them somewhere else.&lt;/p&gt;

&lt;p&gt;Each coworker gets its own browser profile, so a coworker that handles supplier portals never shares cookies with the one that drafts marketing posts.&lt;/p&gt;

&lt;h2&gt;
  
  
  Approvals from your phone
&lt;/h2&gt;

&lt;p&gt;Operations do not wait for someone to be at a desk. The Telegram bridge forwards approval requests to an allow-listed chat and accepts a decision back. The bridge is deliberately narrow: it can approve, reject and report status, and nothing else. A compromised phone can let a pending action through; it cannot start new work.&lt;/p&gt;

&lt;h2&gt;
  
  
  What this looks like in code
&lt;/h2&gt;

&lt;p&gt;The agent runtime is the Claude Agent SDK, and the hook is &lt;code&gt;canUseTool&lt;/code&gt;. Every tool call is routed through the permission policy before execution; the policy returns allow, deny or a pending-approval token. The same policy guards the Codex app-server path and the Agent Client Protocol bridge to OpenCode and Gemini runtimes, so switching models does not change what the system is allowed to do. Tools arrive over the Model Context Protocol, including user-configured MCP servers, which means third-party tools inherit the same gates as built-in ones.&lt;/p&gt;

&lt;p&gt;A short honesty note: the gates are enforced in the Sahkarmi host, not in the model. For non-Claude runtimes that call tools through their own loop, the policy is applied at the tool boundary the bridge controls. If a runtime had a side channel the bridge does not mediate, the policy would not see it. That is why the Electron shell is hardened separately: context isolation, sandbox, a strict CSP, Electron fuses and sender-validated IPC on all 209 channels.&lt;/p&gt;

&lt;h2&gt;
  
  
  Costs
&lt;/h2&gt;

&lt;p&gt;This design has prices. Approval fatigue is real; the fix is good defaults in the 175 coworker templates, so the ask prompts are rare and specific. Delegation expiry annoys power users. The take-over flow adds a minute to any task that needs a login. I think every one of these is worth paying, because the alternative is an agent whose worst day is unbounded.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I would do next
&lt;/h2&gt;

&lt;p&gt;Three things are missing. Approval requests should show a diff of the effect, not a description of the intent. Delegations should be exportable so an owner can audit what their staff have granted. And the policy needs a formal test suite that proves no path from any runtime can reach a gated category without a token. The test files exist for the policy itself; the end-to-end proof across runtimes does not yet.&lt;/p&gt;

&lt;p&gt;Sahkarmi's source, releases and permission policy are public on &lt;a href="https://github.com/ganguydhrubo/sahakarmi" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;. The project page on this site lists what is verified and what is not: &lt;a href="https://www.dhrubo.shop/projects/sahkarmi" rel="noopener noreferrer"&gt;Sahkarmi&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Originally published at &lt;a href="https://www.dhrubo.shop/writing/approval-gates-for-ai-agents" rel="noopener noreferrer"&gt;https://www.dhrubo.shop/writing/approval-gates-for-ai-agents&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>opensource</category>
      <category>typescript</category>
      <category>security</category>
    </item>
    <item>
      <title>Why We Built Sahkarmi: The Open-Source AI Coworker That Never Acts Without Your Approval</title>
      <dc:creator>Dhrubojyoti Gangopadhyay</dc:creator>
      <pubDate>Tue, 27 Oct 2026 10:33:13 +0000</pubDate>
      <link>https://dev.to/dhrubojyoti/why-we-built-sahkarmi-the-open-source-ai-coworker-that-never-acts-without-your-approval-51mo</link>
      <guid>https://dev.to/dhrubojyoti/why-we-built-sahkarmi-the-open-source-ai-coworker-that-never-acts-without-your-approval-51mo</guid>
      <description>&lt;p&gt;&lt;strong&gt;By Dhrubojyoti Gangopadhyay (Founder, Sahkarmi)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Website: &lt;a href="https://sahkarmi.site" rel="noopener noreferrer"&gt;sahkarmi.site&lt;/a&gt; | GitHub: &lt;a href="https://github.com/ganguydhrubo/sahakarmi" rel="noopener noreferrer"&gt;github.com/ganguydhrubo/sahakarmi&lt;/a&gt; | License: Apache-2.0&lt;/em&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  The AI Agent Dilemma: Autonomy vs. Control
&lt;/h2&gt;

&lt;p&gt;Over the past two years, the promise of autonomous AI agents has captured the imagination of every software engineer and startup founder. We were told agents would write our code, debug production incidents, handle customer support, and deploy our cloud infrastructure while we sleep.&lt;/p&gt;

&lt;p&gt;Yet in practice, most developers still hesitate to hand full control over to autonomous scripts. Why?&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Unpredictable Destructive Actions&lt;/strong&gt;: An autonomous script with bash access can easily run &lt;code&gt;rm -rf&lt;/code&gt;, drop a database table during a migration attempt, or overwrite critical configuration files.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cloud Lock-in &amp;amp; Privacy Leaks&lt;/strong&gt;: Sending proprietary codebases, database schemas, and private API tokens to third-party hosted agent clouds poses major enterprise security and data privacy risks.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The Black Box Problem&lt;/strong&gt;: When an agent works in the background without real-time observability, catching mistakes requires tedious forensic post-mortems after damage is already done.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;We asked ourselves: &lt;strong&gt;What if autonomous AI agents didn't replace human judgement, but instead operated like trusted colleagues with built-in human verification gates?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;That is why we built &lt;strong&gt;Sahkarmi (सहकर्मी)&lt;/strong&gt; — the Hindi word for &lt;em&gt;coworker&lt;/em&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  What is Sahkarmi?
&lt;/h2&gt;

&lt;p&gt;Sahkarmi is an &lt;strong&gt;open-source desktop team workspace&lt;/strong&gt; where autonomous AI coworkers run locally on your own machine.&lt;/p&gt;

&lt;p&gt;Unlike traditional scripts or chat windows, Sahkarmi's agents are equipped with specialized tools — a sandboxed local terminal, filesystem access, an embedded Chromium browser, and persistent long-term memory — while strictly obeying a single foundational principle:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Zero Unapproved Impact&lt;/strong&gt;: An agent can plan, inspect files, draft code, and browse documentation autonomously; but the moment it attempts a sensitive action — such as executing a shell command, writing a file, submitting a web form, or executing a transaction — it pauses and presents a clear, interactive &lt;strong&gt;Human-in-the-Loop Approval Card&lt;/strong&gt;.&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[ Sahkarmi Human Verification Card ]
--------------------------------------------------
Task: Deploy backend schema migration
Agent: Dev_Backend_Coworker
Proposed Command: python manage.py migrate --database=prod
Working Dir: /home/user/project

[ APPROVE ]     [ REJECT ]     [ REVISE ]
--------------------------------------------------
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You maintain complete oversight. You can approve with a single keystroke, reject with corrective feedback, or take over directly.&lt;/p&gt;




&lt;h2&gt;
  
  
  Under the Hood: The 3-Tier Architecture
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. The Supervised Desktop Interface (Electron + React)
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Multi-Agent Tabs&lt;/strong&gt;: Collaborate simultaneously with specialized coworkers (Code Reviewer, Growth Engineer, System Admin).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Embedded Chromium Engine&lt;/strong&gt;: Watch your AI coworker navigate websites, test web applications, and take snapshots beside your conversation thread.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Code Diff &amp;amp; Terminal Stream&lt;/strong&gt;: Real-time syntax-highlighted diffs and streaming terminal stdout/stderr.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  2. Local Memory &amp;amp; Routine Engine
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Persistent Knowledge Graph&lt;/strong&gt;: Coworkers remember your project architecture, tech stack preferences, and past decisions across sessions.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Background Scheduled Routines&lt;/strong&gt;: Define cron-like recurring jobs (check PR reviews every 3 hours, monitor error logs, reconcile ledgers) that trigger autonomously.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  3. Sandboxed Tool Execution (Model Context Protocol / MCP)
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Local Shell &amp;amp; File Operations&lt;/strong&gt;: Run builds, tests, git commits, and linters directly on your machine.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Strict Security Boundaries&lt;/strong&gt;: Passwords, OTPs, and card details are NEVER typed by the agent. If an authentication challenge arises, the agent hands over the browser or requests secure input from you.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Provider Agnostic: Bring Your Own Models
&lt;/h2&gt;

&lt;p&gt;Sahkarmi never locks you into a proprietary LLM API. You can switch models per task:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Local Privacy&lt;/strong&gt;: Connect to &lt;strong&gt;Ollama&lt;/strong&gt; or &lt;strong&gt;vLLM&lt;/strong&gt; to run Llama, DeepSeek, or Qwen fully offline, with zero cloud data transmission.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;High-Reasoning Cloud&lt;/strong&gt;: Plug in your own API keys for Google Gemini, Anthropic Claude, or OpenAI models.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Getting Started
&lt;/h2&gt;

&lt;p&gt;Sahkarmi is free and open-source under the &lt;strong&gt;Apache-2.0&lt;/strong&gt; license.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Platform support, honestly stated:&lt;/strong&gt; Sahkarmi ships a &lt;strong&gt;Windows 10/11 (x64)&lt;/strong&gt; desktop build today. macOS and Linux are planned but are &lt;em&gt;not&lt;/em&gt; released yet — installer scripts exist in the repository but are not used for releases.&lt;/p&gt;

&lt;h3&gt;
  
  
  Download the Windows installer
&lt;/h3&gt;

&lt;p&gt;Grab the latest signed release directly:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://sahkarmi.site" rel="noopener noreferrer"&gt;sahkarmi.site&lt;/a&gt; — download button always points at the current release&lt;/li&gt;
&lt;li&gt;Or from &lt;a href="https://github.com/ganguydhrubo/sahakarmi/releases/latest" rel="noopener noreferrer"&gt;GitHub Releases&lt;/a&gt;, with a published &lt;code&gt;SHA256SUMS-windows.txt&lt;/code&gt; so you can verify the download before running it.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Build from source
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/ganguydhrubo/sahakarmi.git
&lt;span class="nb"&gt;cd &lt;/span&gt;sahakarmi
bun &lt;span class="nb"&gt;install
&lt;/span&gt;bun run dev
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Package managers
&lt;/h3&gt;

&lt;p&gt;WinGet and Scoop manifests are submitted and currently awaiting review by their respective communities. Once those land, installation will also be a one-liner. Until then, please use the direct download above.&lt;/p&gt;




&lt;h2&gt;
  
  
  Join the Community
&lt;/h2&gt;

&lt;p&gt;We believe the future of software development belongs to collaborative human-AI teams, where humans provide intent and strategic oversight while autonomous coworkers handle the execution grind.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Star the repo&lt;/strong&gt;: &lt;a href="https://github.com/ganguydhrubo/sahakarmi" rel="noopener noreferrer"&gt;github.com/ganguydhrubo/sahakarmi&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Contribute&lt;/strong&gt;: pull requests welcome for new coworker personas, MCP tool integrations, and UI improvements.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you try it, I would genuinely like to hear where the approvals model gets in your way — that feedback is what shapes the roadmap.&lt;/p&gt;

</description>
      <category>opensource</category>
      <category>ai</category>
      <category>agents</category>
      <category>showdev</category>
    </item>
  </channel>
</rss>
