<?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: Stephanie Dover</title>
    <description>The latest articles on DEV Community by Stephanie Dover (@stephanie_dover_b49c2e8d1).</description>
    <link>https://dev.to/stephanie_dover_b49c2e8d1</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%2F3973257%2Fc8e1d96f-a1aa-41c7-b0bd-88095d5b29b7.jpg</url>
      <title>DEV Community: Stephanie Dover</title>
      <link>https://dev.to/stephanie_dover_b49c2e8d1</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/stephanie_dover_b49c2e8d1"/>
    <language>en</language>
    <item>
      <title>Decoupling a High-Throughput Engagement Service from a Monetization System</title>
      <dc:creator>Stephanie Dover</dc:creator>
      <pubDate>Tue, 23 Jun 2026 17:17:14 +0000</pubDate>
      <link>https://dev.to/stephanie_dover_b49c2e8d1/decoupling-a-high-throughput-engagement-service-from-a-monetization-system-45hd</link>
      <guid>https://dev.to/stephanie_dover_b49c2e8d1/decoupling-a-high-throughput-engagement-service-from-a-monetization-system-45hd</guid>
      <description>&lt;p&gt;At large-scale consumer platforms, product reuse can quietly turn into technical debt.&lt;/p&gt;

&lt;p&gt;In this case, a non-monetized &lt;em&gt;engagement points&lt;/em&gt; feature shared a backend with a wallet-based &lt;em&gt;monetization&lt;/em&gt; service.&lt;/p&gt;

&lt;p&gt;The engagement system handled &lt;strong&gt;over a million transactions per second&lt;/strong&gt;, far beyond what the transactional payments backend was built for.&lt;/p&gt;

&lt;p&gt;What began as a pragmatic shortcut led to rising latency, ballooning storage costs, and operational strain on a system optimized for financial correctness rather than lightweight interactivity.&lt;/p&gt;

&lt;p&gt;The only sustainable fix was to &lt;strong&gt;decouple them completely&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Problem Context
&lt;/h2&gt;

&lt;p&gt;The &lt;strong&gt;monetization system&lt;/strong&gt; prioritized:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Durable writes&lt;/li&gt;
&lt;li&gt;Idempotency&lt;/li&gt;
&lt;li&gt;Strong transactional guarantees&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The &lt;strong&gt;engagement system&lt;/strong&gt; prioritized:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Speed&lt;/li&gt;
&lt;li&gt;Throughput&lt;/li&gt;
&lt;li&gt;Low operational cost&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;By sharing a backend, the engagement workload forced the payments infrastructure to scale inefficiently adding expensive transactional overhead to a system that didn’t need it.&lt;/p&gt;

&lt;p&gt;Scaling further wasn’t the answer. Isolation was.&lt;/p&gt;

&lt;h2&gt;
  
  
  Designing the New Backend
&lt;/h2&gt;

&lt;p&gt;The decoupling required two major components:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;A &lt;strong&gt;dedicated API and data model&lt;/strong&gt; built for high-TPS, low-latency operations.&lt;/li&gt;
&lt;li&gt;A &lt;strong&gt;live migration pipeline&lt;/strong&gt; capable of achieving full data parity with zero downtime.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Infrastructure Overview
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Component&lt;/th&gt;
&lt;th&gt;Purpose&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Go microservice&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Core logic and API layer&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Protobuf + gRPC&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Internal RPC communication&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;AWS DynamoDB&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Primary datastore: high throughput, flexible schema&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;AWS Kinesis Streams&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Real-time change-data capture&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;AWS Lambda functions&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Stream processors handling event ordering and writes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Redis cache&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Idempotency layer to prevent duplicate writes during dual-write and stream replay&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Terraform&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Infrastructure-as-code provisioning&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;CloudWatch metrics&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Observability for throughput, lag, and latency&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Feature flag service&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Safe rollout and traffic control&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The new backend used a lightweight schema aligned to engagement interactions, simpler, cheaper, and better suited for massive write volume.&lt;/p&gt;

&lt;h2&gt;
  
  
  Architecture Diagrams
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Diagram 1: System Overview&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;flowchart TD
    A[Engagement API] --&amp;gt; B[Old DynamoDB Table]
    B --&amp;gt; C[AWS Kinesis Stream]
    C --&amp;gt; D[AWS Lambda Functions]
    D --&amp;gt; E[New DynamoDB Table]
    D --&amp;gt; F[Redis Cache&amp;lt;br/&amp;gt;(idempotency)]
    F --&amp;gt; E
    E --&amp;gt; G[Feature-flag Dual-Write]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Diagram 2: Migration Lifecycle&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;flowchart TD
    A[1. Export snapshot → S3 → Import new table] --&amp;gt; B[2. Sync updates via Kinesis + Lambda]
    B --&amp;gt; C[3. Redis ensures idempotency&amp;lt;br/&amp;gt;for dual-writes &amp;amp; replayed events]
    C --&amp;gt; D[4. Feature flag directs dual-writes]
    D --&amp;gt; E[5. Cutover &amp;amp; validation]

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

&lt;/div&gt;



&lt;h2&gt;
  
  
  Migration Strategy
&lt;/h2&gt;

&lt;p&gt;Building the API was straightforward.&lt;/p&gt;

&lt;p&gt;Migrating live data at 1M+ TPS without downtime was the challenge.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Snapshot Bootstrap
&lt;/h3&gt;

&lt;p&gt;AWS provides a built-in mechanism to export a DynamoDB table snapshot to S3, which can then be imported into a new table.&lt;/p&gt;

&lt;p&gt;This seeded the new database with a point-in-time baseline, no long-running scans or Glue jobs required.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Real-Time Sync via Kinesis + Lambda
&lt;/h3&gt;

&lt;p&gt;Once the snapshot was imported, &lt;strong&gt;Kinesis Streams&lt;/strong&gt; captured every subsequent change (insert, update, delete) from the source table.&lt;/p&gt;

&lt;p&gt;Each event was processed by an &lt;strong&gt;AWS Lambda&lt;/strong&gt; consumer that replayed the change into the new DynamoDB table.&lt;/p&gt;

&lt;p&gt;Maintaining &lt;strong&gt;transaction order&lt;/strong&gt; was critical, out-of-sequence events could cause corruption or lost updates.&lt;/p&gt;

&lt;p&gt;To handle retries and potential duplicate delivery, I introduced a &lt;strong&gt;Redis-based idempotency layer&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Each event carried a unique transaction ID. Before processing, Lambda performed a fast Redis lookup to check whether that ID had already been written.&lt;/p&gt;

&lt;p&gt;If found, the event was skipped, eliminating double writes both from Kinesis replays and from the feature-flagged dual-write traffic hitting the same endpoint.&lt;/p&gt;

&lt;p&gt;This lightweight Redis layer made the migration &lt;em&gt;safe&lt;/em&gt;, ensuring exactly-once behavior without compromising throughput.&lt;/p&gt;

&lt;p&gt;Monitoring &lt;strong&gt;IteratorAge&lt;/strong&gt; and &lt;strong&gt;Duration&lt;/strong&gt; metrics in CloudWatch remained critical.&lt;/p&gt;

&lt;p&gt;If IteratorAge rose, the stream was falling behind, meaning either smaller batches or more concurrency were needed.&lt;/p&gt;

&lt;p&gt;With tuning and caching in place, the pipeline kept pace with over a million updates per second.&lt;/p&gt;

&lt;p&gt;The full migration completed within hours, not days.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cutover with Feature Flags
&lt;/h2&gt;

&lt;p&gt;After the real-time sync stabilized, I rolled out the new backend via a &lt;strong&gt;feature-flagged dual-write&lt;/strong&gt;:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Dual-write requests to both APIs.&lt;/li&gt;
&lt;li&gt;Use Redis for idempotency checks to prevent duplicate writes.&lt;/li&gt;
&lt;li&gt;Validate data parity.&lt;/li&gt;
&lt;li&gt;Monitor Kinesis lag until zero.&lt;/li&gt;
&lt;li&gt;Cut traffic to the old API.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Once validation passed, the engagement service ran entirely on its new infrastructure.&lt;/p&gt;

&lt;p&gt;The monetization system was finally free of the extra load, and both systems could scale independently.&lt;/p&gt;

&lt;h2&gt;
  
  
  Safety and Verification
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Extended Kinesis retention to &lt;strong&gt;24+ hours&lt;/strong&gt; during migration.&lt;/li&gt;
&lt;li&gt;Kept the source table intact until post-cutover validation completed.&lt;/li&gt;
&lt;li&gt;Used Redis TTLs to automatically expire processed transaction keys, keeping cache cost minimal.&lt;/li&gt;
&lt;li&gt;Continuously compared record counts and hash digests between tables during dual-write.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These guardrails ensured recovery options, consistency, and full traceability throughout the migration.&lt;/p&gt;

&lt;h2&gt;
  
  
  Results and Takeaways
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Kinesis Streams + Lambda&lt;/strong&gt; enable live, high-TPS migrations when tuned for throughput and ordering.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Redis caching&lt;/strong&gt; ensures idempotency and prevents double writes under dual-write conditions.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Feature-flag rollouts&lt;/strong&gt; provide control and observability for safe cutovers.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Decoupling mismatched systems&lt;/strong&gt; is often cheaper and safer than scaling them together.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;“Scaling isn’t always about adding resources, sometimes it’s about removing coupling.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;After the final cutover, metrics flatlined exactly where they should, and I finally took that long-delayed vacation.&lt;/p&gt;




&lt;h2&gt;
  
  
  Technologies Referenced
&lt;/h2&gt;

&lt;p&gt;AWS Lambda — Serverless compute service for running backend logic without managing servers.&lt;/p&gt;

&lt;p&gt;Amazon DynamoDB — Fully managed NoSQL database optimized for high-throughput workloads.&lt;/p&gt;

&lt;p&gt;Amazon Kinesis Data Streams — Real-time event streaming service used for data replication and ingestion.&lt;/p&gt;

&lt;p&gt;AWS CloudWatch — Metrics and observability platform for monitoring throughput, latency, and iterator age.&lt;/p&gt;

&lt;p&gt;Amazon S3 — Object storage service used for snapshot exports and imports.&lt;/p&gt;

&lt;p&gt;Redis — In-memory cache used here for idempotency checks during dual-writes and stream replay.&lt;/p&gt;

&lt;p&gt;Terraform — Infrastructure-as-code tool for provisioning and managing AWS resources.&lt;/p&gt;

&lt;p&gt;gRPC — High-performance RPC framework for service-to-service communication.&lt;/p&gt;

&lt;p&gt;Protocol Buffers (Protobuf) — Serialization format used with gRPC to define and enforce API contracts.&lt;/p&gt;

&lt;p&gt;Feature Toggles / Flags — Technique for gradual rollouts and safe cutovers.&lt;/p&gt;

&lt;p&gt;Go Concurrency: Goroutines — Lightweight thread mechanism for concurrent workloads.&lt;/p&gt;

&lt;p&gt;Go Channels — Synchronization and communication primitive used for concurrent fan-out/fan-in patterns.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Written by Stephanie Dover, Software Engineer 10+ YOE, ex GitHub, Twitch, Microsoft. Creator of Klaussy.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.linkedin.com/in/stephaniedover/" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt; · &lt;a href="https://github.com/steph-dove" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt; · &lt;a href="https://www.klaussy.com/" rel="noopener noreferrer"&gt;Klaussy Desktop&lt;/a&gt; · &lt;a href="https://github.com/steph-dove/klaussy-agents" rel="noopener noreferrer"&gt;Klaussy Agents&lt;/a&gt;&lt;/p&gt;

</description>
      <category>systemdesign</category>
      <category>distributedsystems</category>
      <category>architecture</category>
      <category>database</category>
    </item>
    <item>
      <title>Why I scrub AI prose with regex, not a second LLM</title>
      <dc:creator>Stephanie Dover</dc:creator>
      <pubDate>Sat, 20 Jun 2026 00:11:10 +0000</pubDate>
      <link>https://dev.to/stephanie_dover_b49c2e8d1/why-i-scrub-ai-prose-with-regex-not-a-second-llm-5gnb</link>
      <guid>https://dev.to/stephanie_dover_b49c2e8d1/why-i-scrub-ai-prose-with-regex-not-a-second-llm-5gnb</guid>
      <description>&lt;p&gt;&lt;em&gt;Written by Stephanie Dover, Software Engineer 10+ YOE, ex GitHub, Twitch, Microsoft. Creator of Klaussy.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.linkedin.com/in/stephaniedover/" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt; · &lt;a href="https://github.com/steph-dove" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt; · &lt;a href="https://www.klaussy.com/" rel="noopener noreferrer"&gt;Klaussy Desktop&lt;/a&gt; · &lt;a href="https://github.com/steph-dove/klaussy-agents" rel="noopener noreferrer"&gt;Klaussy Agents&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  TL;DR
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;klaussy-agents&lt;/strong&gt; is a free, MIT-licensed CLI (&lt;code&gt;pip install klaussy-agents&lt;/code&gt;) that makes the prose an AI coding agent writes, PR comments, review notes, commit messages, read like a person wrote them. It works in two layers: a humanization spec baked into the agent's skills so it writes clean prose up front, and a deterministic &lt;code&gt;klaussy humanize&lt;/code&gt; pass that scrubs the output afterward. The scrubber is rule-based regex, not an LLM, and it never touches code. There's also a part I didn't expect going in: once the AI tells are gone, what's left can read curt and run long, so the spec also handles tone (don't be rude) and length (one sentence for a reply, one to five for a review comment). Repo: github.com/steph-dove/klaussy-agents.&lt;/p&gt;

&lt;h2&gt;
  
  
  The problem
&lt;/h2&gt;

&lt;p&gt;You can spot AI-written text now. Everyone can. And the place it grates most is a code review comment or a commit message, where the prose sits next to your name in a thread your teammates read.&lt;/p&gt;

&lt;p&gt;The tells are consistent. The em-dash is the biggest one. Right behind it: filler openers like "It's worth noting that…" and "I wanted to point out that…", chatbot scaffolding like "Hope this helps!" and "Let me know if you have questions!", and stacked hedges like &lt;code&gt;could potentially&lt;/code&gt;. An agent that leaves those in your PR reads like a bot, and people notice.&lt;/p&gt;

&lt;p&gt;The obvious fix is to tell the model not to do it. Add "don't sound like AI" to the prompt and move on. That helps, inconsistently, and it regresses silently the moment you change the model or the prompt drifts. Editing every comment by hand works too, but hand-editing every comment defeats the point of having an agent write them. I wanted something I could trust without rereading.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why "just tell the model" wasn't enough
&lt;/h2&gt;

&lt;p&gt;The honest answer to "why not just prompt for it" is: a prompt asks, it doesn't enforce. The model tries to comply. Sometimes it complies fully, sometimes it slips an em-dash back in on a longer comment, and you don't find out until the tell is already in the thread. Prompt compliance is soft by nature: you can make it better, never guaranteed.&lt;/p&gt;

&lt;p&gt;So I stopped treating the prompt as the whole answer and treated it as the first of two layers.&lt;/p&gt;

&lt;p&gt;The first layer is prompt-side. There's a single shared humanization block, internally &lt;code&gt;HUMANIZE_BLOCK&lt;/code&gt;, that gets substituted into every prose-output skill: review, pr, commit, explain, across all five of the agents klaussy-agents ships. The rules in it are plain: no em or en dashes, no filler openers, no chatbot scaffolding, tighten hedges, no emoji, no "Certainly", vary sentence shape, and never reword code. One spec, applied everywhere, so the agent isn't given conflicting instructions in different places.&lt;/p&gt;

&lt;p&gt;The second layer is the part that actually enforces. After the agent writes, the text goes through &lt;code&gt;klaussy humanize&lt;/code&gt;, a deterministic pass that makes the high-confidence edits regardless of how well the model followed instructions. The prompt asks; the scrubber enforces. Neither layer alone is enough, which is the whole reason there are two.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why deterministic, and not a second model
&lt;/h2&gt;

&lt;p&gt;The tempting design is to run the agent's prose through another LLM with a "rewrite this to sound human" instruction. That's how most "AI humanizer" tools on the market work. I deliberately didn't.&lt;/p&gt;

&lt;p&gt;A rewrite model can fix awkward phrasing a regex never will. But it can also paraphrase something into being subtly wrong, and over technical prose that's a real risk: it can rewrite an identifier, mangle a command, or "improve" an example until it no longer runs. For text that ends up in a PR comment a teammate will act on, I didn't want a process that could introduce a new mistake while removing an em-dash.&lt;/p&gt;

&lt;p&gt;So the scrubber is rule-based regex. The consequences of that choice are all upsides for this job: it's fast, it's free, it runs offline with no network call, and because it only ever does a fixed set of high-confidence substitutions, it can't introduce a new error. It will not restructure a sentence or paraphrase a paragraph. It does a small, reliable set of edits and stops.&lt;/p&gt;

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

&lt;h3&gt;
  
  
  The edits it makes
&lt;/h3&gt;

&lt;p&gt;The scrubber does a short list of conservative transforms. Each one is a tell with a known, safe fix:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Dashes.&lt;/strong&gt; Em-dashes (&lt;code&gt;—&lt;/code&gt;) and en-dashes (&lt;code&gt;–&lt;/code&gt;) in prose become commas or hyphens.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Filler openers.&lt;/strong&gt; Sentence-initial filler ("It's worth noting that", "I noticed that", "Please note that", and similar) is stripped, and the next word is re-capitalized so the sentence still reads correctly.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Chatbot scaffolding.&lt;/strong&gt; Trailing lines like "Let me know if…", "Hope this helps", "Feel free to…" are dropped.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Verbose phrasings.&lt;/strong&gt; A few get tightened: &lt;code&gt;in order to&lt;/code&gt; becomes &lt;code&gt;to&lt;/code&gt;, &lt;code&gt;could potentially&lt;/code&gt; becomes &lt;code&gt;could&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here's the before and after on the exact cases the test suite covers:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Input&lt;/th&gt;
&lt;th&gt;Output&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Leaks a connection — wrap it.&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Leaks a connection, wrap it.&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;range 1–5 here&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;range 1 - 5 here&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;It's worth noting that the handler swallows the error.&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;The handler swallows the error.&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;This races on startup.&lt;/code&gt;&lt;br&gt;&lt;code&gt;Let me know if you have questions!&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;&lt;code&gt;This races on startup.&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Refactor in order to avoid the N+1.&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Refactor to avoid the N+1.&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;This could potentially deadlock.&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;This could deadlock.&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Every one of those is a rule a human editor would apply without thinking. None of them changes what the comment means. That's the bar for inclusion: if an edit could change meaning, it doesn't make the list.&lt;/p&gt;

&lt;h3&gt;
  
  
  Never touching code
&lt;/h3&gt;

&lt;p&gt;The single biggest risk in running any text transform over developer prose is that it reaches into a code example and breaks it. A "humanizer" that turns a dash inside a shell command into a comma has made your example wrong.&lt;/p&gt;

&lt;p&gt;The scrubber avoids this structurally. It splits the input on fenced &lt;code&gt;blocks and on&lt;/code&gt; &lt;code&gt;inline code&lt;/code&gt;, scrubs only the prose segments, and leaves every code segment byte-for-byte untouched. The dashes in a command stay dashes. The identifiers stay identifiers.&lt;/p&gt;

&lt;p&gt;Concretely, given a string that mixes prose and code like &lt;code&gt;Use `a — b` then:&lt;/code&gt;, followed by a fenced block containing &lt;code&gt;x — y&lt;/code&gt;, the dashes inside the inline span and inside the fence are kept exactly as written. Only a dash out in the prose would be normalized. Code in, code out, unchanged.&lt;/p&gt;

&lt;h3&gt;
  
  
  The interface
&lt;/h3&gt;

&lt;p&gt;There are two ways to use it. As a library:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;klaussy.humanize&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;humanize&lt;/span&gt;

&lt;span class="n"&gt;clean&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;humanize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;It&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;s worth noting that this races, fix it.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;# -&amp;gt; "This races, fix it."
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;code&gt;humanize(text: str) -&amp;gt; str&lt;/code&gt;. Non-string input passes through unchanged.&lt;/p&gt;

&lt;p&gt;As a CLI, it's built to drop into a pipe or a CI gate:&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;# stdin to stdout&lt;/span&gt;
&lt;span class="nb"&gt;printf&lt;/span&gt; &lt;span class="s1"&gt;'%s'&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$comment&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; | klaussy humanize

&lt;span class="c"&gt;# rewrite a file in place&lt;/span&gt;
klaussy humanize NOTES.md &lt;span class="nt"&gt;--write&lt;/span&gt;

&lt;span class="c"&gt;# CI gate: exit 1 if the file would change&lt;/span&gt;
klaussy humanize NOTES.md &lt;span class="nt"&gt;--check&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The &lt;code&gt;--check&lt;/code&gt; mode is the one I lean on most. It turns "did an AI tell slip into this doc" into a check that fails a pull request instead of a thing someone has to catch by eye.&lt;/p&gt;
&lt;h3&gt;
  
  
  One spec, shared across products
&lt;/h3&gt;

&lt;p&gt;The rules in both layers, the prompt-side block and the CLI, are a faithful port of one source: &lt;code&gt;humanize-comment.js&lt;/code&gt; from the klaussy desktop codebase. (That desktop app is a separate product; this is the open-source &lt;code&gt;klaussy-agents&lt;/code&gt; package. That's the only time I'll mention it.) Porting from one canonical implementation means the prompt rules and the scrubber rules don't drift apart over time, and any pipeline, CI, the desktop app, or your own scripts, can pipe through the same behavior.&lt;/p&gt;
&lt;h3&gt;
  
  
  Comment hygiene, not just prose
&lt;/h3&gt;

&lt;p&gt;The same instinct shows up one layer down, in code review. Beyond the prose tells, the generated &lt;code&gt;review&lt;/code&gt; skill flags excessive or narrating comments in code, the kind that restate what the line does or read like a changelog, and the commit guard blocks committed commented-out code via &lt;code&gt;ruff --select ERA&lt;/code&gt;. The judgment-heavy part lives in the skill where a model can weigh context; the deterministic part lives in the hook. Same division of labor as the two prose layers: ask where you need judgment, enforce where you can be certain.&lt;/p&gt;
&lt;h2&gt;
  
  
  Clean isn't the same as kind, or short
&lt;/h2&gt;

&lt;p&gt;Removing the tells exposed a second problem I didn't plan for: stripping the filler also strips the softening. Scrub "It's worth noting that this could potentially swallow the error, you may want to wrap it" down to its substance and you get "This swallows the error. Wrap it." That's clean, and on a PR thread it's also a little cold, and cold reads as curt. Review comments are the worst case, because they land on a person's work. A real one, lightly defanged: "Personally I don't find these unit tests useful, because you are mocking everything." The tells aren't the problem there; the framing is.&lt;/p&gt;

&lt;p&gt;So humanizing can't be purely subtractive. After removing what makes prose sound like a machine, the spec adds back what makes it sound like a considerate human, split the same two ways as everything else.&lt;/p&gt;

&lt;p&gt;Prompt-side, a civility floor: critique the work, never the person; prefer a question over a flat verdict; keep it a light touch, not filler praise. It's a floor, not forced warmth, so a review you asked to be blunt stays blunt, it just can't tip into insulting. A second rule covers replies: read the comment you're answering for substance but not temperature, and neutralize its rudeness before drafting, so a hostile thread doesn't prime a hostile reply. And a brevity rule with actual numbers instead of "be concise": a thread reply aims for one sentence, a single review comment for one to five, anything longer gets cut, not summarized.&lt;/p&gt;

&lt;p&gt;Deterministic-side, the scrubber's opener list grew to catch the editorializing lead-ins that prime a dismissive read, "Personally," "Honestly," "Frankly," "IMO," "In my opinion," "If you ask me," so &lt;code&gt;Personally I don't find these useful.&lt;/code&gt; becomes &lt;code&gt;I don't find these useful.&lt;/code&gt; with the same guarantee as the rest, and still never inside code.&lt;/p&gt;

&lt;p&gt;The honest caveat: tone and brevity are mostly judgment, so most of it lives in the soft prompt layer, only the openers are guaranteed.&lt;/p&gt;
&lt;h2&gt;
  
  
  A quick demo
&lt;/h2&gt;

&lt;p&gt;The clearest way to see it is to pipe a comment that has several tells stacked up:&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="nb"&gt;printf&lt;/span&gt; &lt;span class="s1"&gt;'%s'&lt;/span&gt; &lt;span class="s2"&gt;"It's worth noting that this handler swallows the error, wrap it. Hope this helps!"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
 | klaussy humanize
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The opener gets stripped, the next word re-capitalized, the em-dash becomes a comma, and the trailing scaffolding line is dropped. What comes out reads like a note an engineer left, because the things that made it read like a bot are gone and nothing else was touched.&lt;/p&gt;

&lt;p&gt;The whole pass is pure standard library, no network, no model. The test suite covers every transform above plus the code-preservation cases, ported from the desktop test suite; 137 tests pass overall.&lt;/p&gt;
&lt;h2&gt;
  
  
  What's next, and where the line is
&lt;/h2&gt;

&lt;p&gt;The deliberate limit is the headline tradeoff: deterministic means limited. A regex scrubber catches the reliable tells, but it will not rewrite genuinely awkward phrasing the way an LLM could. That's the trade I chose on purpose, the same property that makes it safe, fast, and incapable of introducing an error is the property that keeps it from doing deeper rewrites. If you want paraphrasing, this isn't that tool, and it's not trying to be.&lt;/p&gt;

&lt;p&gt;A couple of other honest limits:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;The prompt layer is soft.&lt;/strong&gt; The &lt;code&gt;{{HUMANIZE}}&lt;/code&gt; block depends on the model following instructions. Two layers because neither alone is enough.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;It's opinionated.&lt;/strong&gt; Some people like em-dashes. The scrubber normalizes them, and that's a stance. It's also open code, so if you disagree, the rules are right there to edit.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Scope is prose, not code.&lt;/strong&gt; By design it won't touch anything inside a code block. The flip side is that it won't fix a tell living inside a code comment unless you wire it to do so.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;None of these are things I'm hiding. They're the consequences of picking "safe and predictable" over "clever and risky" for text that goes in front of your team.&lt;/p&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;pip &lt;span class="nb"&gt;install &lt;/span&gt;klaussy-agents
&lt;span class="nb"&gt;printf&lt;/span&gt; &lt;span class="s1"&gt;'%s'&lt;/span&gt; &lt;span class="s2"&gt;"It's worth noting that this races, fix it. Hope this helps!"&lt;/span&gt; | klaussy humanize
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Repo and docs: &lt;a href="https://github.com/steph-dove/klaussy-agents" rel="noopener noreferrer"&gt;github.com/steph-dove/klaussy-agents&lt;/a&gt;&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/steph-dove" rel="noopener noreferrer"&gt;
        steph-dove
      &lt;/a&gt; / &lt;a href="https://github.com/steph-dove/klaussy-agents" rel="noopener noreferrer"&gt;
        klaussy-agents
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Claude Code boilerplate generator. One command to make any repo Claude Code-ready.
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;klaussy&lt;/h1&gt;
&lt;/div&gt;

&lt;p&gt;Multi-agent repo boilerplate generator. One command to make any repo ready for
&lt;strong&gt;Claude Code, Gemini CLI, Cursor, Codex, and GitHub Copilot&lt;/strong&gt; — each gets the
same conventions and the same workflow skills in its own native format.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Install&lt;/h2&gt;
&lt;/div&gt;
&lt;div class="highlight highlight-source-shell notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;pip install klaussy-agents&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;Requires &lt;a href="https://pypi.org/project/klaussy-repo-conventions/" rel="nofollow noopener noreferrer"&gt;klaussy-repo-conventions&lt;/a&gt; (installed automatically).&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Quick Start&lt;/h2&gt;
&lt;/div&gt;
&lt;div class="highlight highlight-source-shell notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;&lt;span class="pl-c1"&gt;cd&lt;/span&gt; your-repo
klaussy init&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;That's it. You'll be prompted for your base branch (auto-detects &lt;code&gt;dev&lt;/code&gt;, &lt;code&gt;main&lt;/code&gt;, etc.), then klaussy generates everything.&lt;/p&gt;
&lt;p&gt;By default klaussy bootstraps &lt;strong&gt;all&lt;/strong&gt; supported agents from the same conventions. To narrow to a subset, pass &lt;code&gt;--agents&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight highlight-source-shell notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;klaussy init                                   &lt;span class="pl-c"&gt;&lt;span class="pl-c"&gt;#&lt;/span&gt; all agents (default)&lt;/span&gt;
klaussy init --agents claude                   &lt;span class="pl-c"&gt;&lt;span class="pl-c"&gt;#&lt;/span&gt; Claude Code only&lt;/span&gt;
klaussy init --agents claude,gemini,cursor     &lt;span class="pl-c"&gt;&lt;span class="pl-c"&gt;#&lt;/span&gt; a subset&lt;/span&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;See &lt;a href="https://github.com/steph-dove/klaussy-agents#multi-agent-targets" rel="noopener noreferrer"&gt;Multi-agent targets&lt;/a&gt; for what each agent gets.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;What Gets Generated&lt;/h2&gt;

&lt;/div&gt;
&lt;p&gt;klaussy discovers your repo's conventions once, then writes — &lt;strong&gt;for every selected agent (all five by default)&lt;/strong&gt; — that agent's native conventions file, the workflow skills, stack-appropriate permissions…&lt;/p&gt;&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/steph-dove/klaussy-agents" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;If you've got an AI tell that drives you up the wall and the scrubber doesn't catch it yet, open an issue with the before/after, that's exactly the kind of case I want to see.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>opensource</category>
      <category>python</category>
      <category>showdev</category>
    </item>
    <item>
      <title>Building repo conventions aware coding agents</title>
      <dc:creator>Stephanie Dover</dc:creator>
      <pubDate>Thu, 18 Jun 2026 01:51:18 +0000</pubDate>
      <link>https://dev.to/stephanie_dover_b49c2e8d1/building-repo-conventions-aware-coding-agents-1ep8</link>
      <guid>https://dev.to/stephanie_dover_b49c2e8d1/building-repo-conventions-aware-coding-agents-1ep8</guid>
      <description>&lt;p&gt;&lt;em&gt;Written by Stephanie Dover, Software Engineer 10+ YOE, ex GitHub, Twitch, Microsoft. Creator of Klaussy.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.linkedin.com/in/stephaniedover/" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt; · &lt;a href="https://github.com/steph-dove" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt; · &lt;a href="https://www.klaussy.com/" rel="noopener noreferrer"&gt;Klaussy Desktop&lt;/a&gt; · &lt;a href="https://github.com/steph-dove/klaussy-agents" rel="noopener noreferrer"&gt;Klaussy Agents&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  TL;DR
&lt;/h2&gt;

&lt;p&gt;I built &lt;strong&gt;klaussy-agents&lt;/strong&gt;, an open-source CLI (&lt;code&gt;pip install klaussy-agents&lt;/code&gt;) that reads your repo's conventions once and scaffolds repo-aware skills for five coding agents: Claude Code, Gemini CLI, Cursor, Codex, and GitHub Copilot. The interesting part is the adaptation layer: one Claude-authored &lt;code&gt;SKILL.md&lt;/code&gt; gets rewritten into each agent's native form, including how sub-agent and plan-mode wording maps to each agent's own primitive. It's a scaffolder, not a runtime, it's at v0.3.2, and the per-agent translation has real seams. Repo: github.com/steph-dove/klaussy-agents.&lt;/p&gt;

&lt;h2&gt;
  
  
  The problem
&lt;/h2&gt;

&lt;p&gt;Each AI coding agent carries repo context its own way. Claude Code reads &lt;code&gt;CLAUDE.md&lt;/code&gt;, Gemini CLI reads &lt;code&gt;GEMINI.md&lt;/code&gt;, Codex reads &lt;code&gt;AGENTS.md&lt;/code&gt;, Cursor reads &lt;code&gt;.cursor/rules&lt;/code&gt;, and Copilot reads &lt;code&gt;.github/copilot-instructions.md&lt;/code&gt;. On top of that, each one has its own folder of reusable "skills" or "commands." So the conventions you write for one agent, and any review or plan workflow you tune in it, don't transfer to the others. Point a second agent at the same repo and it starts from zero, because it's reading a file the first agent never wrote.&lt;/p&gt;

&lt;p&gt;You can keep all five context files and skill folders in sync by hand, but that's busywork that rots the first time one gets edited and the rest don't. The practical outcome is that whichever agent you open is the one that knows the least about your repo, unless you've redone the setup five times.&lt;/p&gt;

&lt;p&gt;What makes a real fix possible is that all five agents now read the same open &lt;a href="https://agentskills.io/specification" rel="noopener noreferrer"&gt;Agent Skills&lt;/a&gt; &lt;code&gt;SKILL.md&lt;/code&gt; format. One folder format, genuinely portable. So a tool can discover the repo's conventions once and emit skills, adapted, into every agent's native layout. This post is about the adaptation step, because that's where it stops being a clean copy-paste.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why hand-rolling five configs didn't scale for me
&lt;/h2&gt;

&lt;p&gt;To be clear about what the alternatives actually are: hand-maintaining per-agent config works fine when you use one agent. A &lt;code&gt;CLAUDE.md&lt;/code&gt; plus a couple of &lt;code&gt;.claude/skills/&lt;/code&gt; is a perfectly good setup, and if your whole team is on one tool, you don't need any of this.&lt;/p&gt;

&lt;p&gt;Generic scaffolders (cookiecutter and friends) are great for stamping out project structure, but they don't know what a sub-agent is or how Cursor scopes a rule versus how Copilot does. The gap is specifically the multi-agent one: the same review workflow, expressed five different ways, kept in sync forever. This is a translation problem, not a templating problem. The &lt;code&gt;SKILL.md&lt;/code&gt; spec provides a shared source format; the work klaussy does is the discovery, the per-agent adaptation, and the native wiring so I'm not hand-maintaining five copies of the same skill.&lt;/p&gt;

&lt;p&gt;The honest framing is: the spec made portability possible. klaussy does the boring, error-prone part on top of it.&lt;/p&gt;

&lt;h2&gt;
  
  
  The approach
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;klaussy init&lt;/code&gt; does the whole thing in one pass and defaults to all five agents. Under the hood it runs a repo-conventions discovery step once, produces a project-wide &lt;code&gt;CLAUDE.md&lt;/code&gt; plus path-scoped &lt;code&gt;.claude/rules/*.md&lt;/code&gt;, then translates that into each agent's native form. Path-scoped rules map onto each agent's own scoping mechanism: Copilot's &lt;code&gt;.github/instructions/*.instructions.md&lt;/code&gt; with &lt;code&gt;applyTo:&lt;/code&gt; frontmatter, Cursor's &lt;code&gt;.cursor/rules/*.mdc&lt;/code&gt; with &lt;code&gt;globs:&lt;/code&gt; frontmatter, and so on.&lt;/p&gt;

&lt;p&gt;The same one-discovery-then-translate shape applies to skills. klaussy ships 11 namespaced workflow skills, written once in Claude Code's syntax, and writes them into each agent's dedicated skills directory. The skills are namespaced &lt;code&gt;&amp;lt;repo&amp;gt;-&amp;lt;skill&amp;gt;&lt;/code&gt; so they don't collide across repos when an agent has several checked out.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pip &lt;span class="nb"&gt;install &lt;/span&gt;klaussy-agents
klaussy init                     &lt;span class="c"&gt;# prompts for base branch, scaffolds all five agents&lt;/span&gt;
klaussy init &lt;span class="nt"&gt;--agents&lt;/span&gt; claude,cursor   &lt;span class="c"&gt;# narrow to a subset&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can also run individual steps (&lt;code&gt;klaussy skills&lt;/code&gt;, &lt;code&gt;settings&lt;/code&gt;, &lt;code&gt;hooks&lt;/code&gt;, &lt;code&gt;github&lt;/code&gt;, and so on) if you only want part of it. The rest of this post zooms in on the skills step, because the adaptation it does is the part I'd actually want to read about.&lt;/p&gt;

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

&lt;h3&gt;
  
  
  One authored skill, five target dialects
&lt;/h3&gt;

&lt;p&gt;The skills are authored in Claude Code's syntax. That means they lean on a few Claude-specific constructs: &lt;code&gt;&lt;/code&gt;`&lt;code&gt;!&lt;/code&gt; dynamic-shell blocks that run a command and inline its output, parallel sub-agents invoked through the &lt;code&gt;Agent&lt;/code&gt; tool with a &lt;code&gt;subagent_type&lt;/code&gt;, and &lt;code&gt;ExitPlanMode&lt;/code&gt; for plan mode. None of those tokens mean anything to Gemini or Codex verbatim.&lt;/p&gt;

&lt;p&gt;So klaussy doesn't copy the body across. It rewrites each body to capture the same intent in the target agent's terms. Three concrete rewrites happen:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Dynamic shell blocks become explicit instructions.&lt;/strong&gt; A &lt;code&gt;&lt;/code&gt;&lt;code&gt;&lt;/code&gt;! &lt;code&gt; block that silently runs &lt;/code&gt;git diff` and inlines the result is rewritten into a plain "run this command and use its output" instruction the other agent will actually follow.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Path references get retargeted.&lt;/strong&gt; A skill that points at &lt;code&gt;.claude/skills/...&lt;/code&gt; is rewritten to the target agent's own skills directory, so cross-skill references don't dangle.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Sub-agent and plan-mode orchestration gets an adaptation note.&lt;/strong&gt; This is the subtle one, and it's the next section.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These directories are the targets, exactly:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.claude/skills/     # Claude Code
.gemini/skills/     # Gemini CLI
.cursor/skills/     # Cursor
.agents/skills/     # Codex (neutral .agents/ path)
.github/skills/     # GitHub Copilot
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Sub-agents and plan mode
&lt;/h3&gt;

&lt;p&gt;Several of the skills orchestrate parallel sub-agents. The review skill, for instance, fans out separate lenses (correctness, architecture, security, scope) and runs them concurrently. In Claude Code that's the &lt;code&gt;Agent&lt;/code&gt; tool with a &lt;code&gt;subagent_type&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Different agents handle parallel sub-agents differently. Most have their own model-invocable parallel sub-agent tool, and they name it differently; a given agent or setup might not expose one:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Claude Code: &lt;code&gt;Agent&lt;/code&gt; / &lt;code&gt;subagent_type&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Cursor: &lt;code&gt;Task&lt;/code&gt; (GA)&lt;/li&gt;
&lt;li&gt;Codex: &lt;code&gt;spawn_agent&lt;/code&gt; (GA)&lt;/li&gt;
&lt;li&gt;Gemini CLI: subagents (default-on, toggled under &lt;code&gt;experimental&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;GitHub Copilot: &lt;code&gt;task&lt;/code&gt; / &lt;code&gt;read_agent&lt;/code&gt; (plus an experimental &lt;code&gt;context: fork&lt;/code&gt;)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So instead of hardcoding sequential, the adaptation note tells the target agent to map Claude's sub-agent wording onto its own equivalent primitive, and to fall back to sequential execution only if it genuinely has none. The note carries intent ("these lenses are independent, run them in parallel"), not Claude-specific tool names. The same goes for &lt;code&gt;ExitPlanMode&lt;/code&gt;: the note describes the plan-then-confirm intent rather than naming a tool that only Claude has.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Illustrative — exact wording is generated per skill, confirm in the emitted SKILL.md
# Adaptation note (appended when a skill orchestrates sub-agents):
# This skill runs independent lenses in parallel. Use your own
# parallel sub-agent tool (e.g. Task / spawn_agent / subagents / task).
# Only run them sequentially if you have no sub-agent tool.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is the part I find genuinely teachable: portability across agents isn't "find and replace the tool name." It's separating intent from primitive, then letting each agent rebind the intent to whatever primitive it owns. The &lt;code&gt;SKILL.md&lt;/code&gt; spec gives you a shared container; it doesn't give you shared tools, so the body has to be written to degrade gracefully.&lt;/p&gt;

&lt;h3&gt;
  
  
  A real skill, so this isn't abstract
&lt;/h3&gt;

&lt;p&gt;To make "what a generated skill actually does" concrete: the review skill triages by diff size, then runs parallel lenses. Beyond the four standard lenses it adds an Agentic/Evals lens when the change touches AI code, and an Architecture-Decision/Design-Doc lens when the PR contains an ADR, RFC, or design doc. It's precision-biased: an empty review (nothing worth flagging) is a valid outcome. Every finding has to name a concrete trigger, and a final validation phase self-refutes false positives before anything is reported.&lt;/p&gt;

&lt;p&gt;That whole workflow is authored once and adapted into all five agents' skills folders. The lens fan-out is exactly the piece that needs the sub-agent translation above; the precision-bias and validation phases are plain prose and carry across unchanged.&lt;/p&gt;

&lt;h3&gt;
  
  
  Permissions and hooks ride along
&lt;/h3&gt;

&lt;p&gt;The skills step is the headline, but &lt;code&gt;klaussy init&lt;/code&gt; also writes native permission allow-lists per agent (Claude &lt;code&gt;settings.json&lt;/code&gt; allow/deny, Gemini &lt;code&gt;settings.json&lt;/code&gt; &lt;code&gt;tools.allowed&lt;/code&gt;, Cursor &lt;code&gt;permissions.json&lt;/code&gt; &lt;code&gt;terminalAllowlist&lt;/code&gt;, Codex &lt;code&gt;config.toml&lt;/code&gt; approval/sandbox) and tries to keep secrets like &lt;code&gt;.env&lt;/code&gt;, &lt;code&gt;*.pem&lt;/code&gt;, and &lt;code&gt;credentials*&lt;/code&gt; out of each agent's reach using that agent's own mechanism.&lt;/p&gt;

&lt;p&gt;It also wires two cross-agent hooks: a git-commit guard that runs your detected format and lint before a commit, and a read-injection guard that scans file and fetch content for prompt-injection markers. The guard scripts pull the command or path out of whatever agent's hook payload they're handed and block with &lt;code&gt;exit 2&lt;/code&gt; plus stderr, which every supported agent honors. They're pure-stdlib and hardened so any parse error falls back to allow rather than crashing. The current suite is 130 tests passing, ruff clean.&lt;/p&gt;

&lt;h2&gt;
  
  
  A quick demo
&lt;/h2&gt;

&lt;p&gt;Point it at a repo and run it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pip &lt;span class="nb"&gt;install &lt;/span&gt;klaussy-agents
klaussy init
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It prompts for the base branch, then scaffolds conventions files, skills, permissions, and hooks for all five agents. If you only want a subset, name them:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;klaussy init &lt;span class="nt"&gt;--agents&lt;/span&gt; claude,cursor
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After that, opening any of the configured agents in the repo means it already has the conventions file it looks for and the namespaced skills in its own directory. You're still installing and running the agents yourself; klaussy generates the files they read.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's next, and where the seams are
&lt;/h2&gt;

&lt;p&gt;A deep-dive owes you the honest version, so here's what doesn't fully reach:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;The skills are Claude-authored then adapted, not hand-tuned per agent.&lt;/strong&gt; The adaptation captures intent, and the sub-agent note tells each agent to use its own primitive, but it's a translation, not five bespoke skill sets written from scratch for each agent's quirks. If you want a skill perfectly idiomatic to Codex, you may still tweak it by hand.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Hook coverage is uneven, by design.&lt;/strong&gt; The read-injection guard is wired for Claude, Gemini, and Cursor only. Codex exposes no pre-file-read hook event, and Copilot's &lt;code&gt;preToolUse&lt;/code&gt; is fail-closed with unconfirmed read-tool args, so those two get the commit guard only. klaussy logs that rather than pretending the guard is everywhere.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Secret exclusion isn't universally possible.&lt;/strong&gt; Codex's sandbox governs writes and network, not reads, so there's no read-exclusion there; Copilot content-exclusion is a GitHub setting, not a committed file. klaussy says so instead of faking a &lt;code&gt;.ignore&lt;/code&gt; that wouldn't do anything.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;It leans on the SKILL.md spec being honored.&lt;/strong&gt; Portability is real today, but the spec and the agents are young. If an agent changes how it reads skills, klaussy has to track it.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;None of those are agents being "equal." They're not. The whole point of the adaptation layer is that the agents differ and the skill set has to bend to each one. klaussy is a scaffolder: it generates files the agents read, it does not run the agents or change their model quality.&lt;/p&gt;

&lt;p&gt;(One disambiguation: there's a separate, paid klaussy desktop app. Different product, same developer. This post is only about the open-source &lt;code&gt;klaussy-agents&lt;/code&gt; CLI.)&lt;/p&gt;

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

&lt;p&gt;Repo: &lt;a href="https://github.com/steph-dove/klaussy-agents" rel="noopener noreferrer"&gt;github.com/steph-dove/klaussy-agents&lt;/a&gt;&lt;br&gt;
Install: &lt;code&gt;pip install klaussy-agents&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{% github steph-dove/klaussy-agents %}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you run more than one coding agent in the same repo, I'd like to know which skill survived the translation cleanly and which one came out awkward in your agent of choice. Open an issue or drop a comment with what broke.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>opensource</category>
      <category>showdev</category>
      <category>agentskills</category>
    </item>
    <item>
      <title>How I made one desktop app drive four AI coding agent CLIs</title>
      <dc:creator>Stephanie Dover</dc:creator>
      <pubDate>Mon, 08 Jun 2026 02:45:26 +0000</pubDate>
      <link>https://dev.to/stephanie_dover_b49c2e8d1/how-i-made-one-desktop-app-drive-four-ai-coding-agent-clis-2gi</link>
      <guid>https://dev.to/stephanie_dover_b49c2e8d1/how-i-made-one-desktop-app-drive-four-ai-coding-agent-clis-2gi</guid>
      <description>&lt;h2&gt;
  
  
  TL;DR
&lt;/h2&gt;

&lt;p&gt;I built &lt;strong&gt;Klaussy&lt;/strong&gt;, a desktop app that runs AI coding-agent CLIs in parallel across git worktrees and pairs them with a GitHub PR review surface. The v0.3.0 release (out June 5) replaced its hard dependency on Claude Code with a provider registry, so it now drives &lt;strong&gt;Claude Code, OpenAI Codex, Google Gemini, or GitHub Copilot&lt;/strong&gt; — your pick per task. This post covers how the registry works, the side-by-side terminal model, and where the deeper AI features are still uneven across agents. It's closed-source and in beta. Site: &lt;a href="https://www.klaussy.com/" rel="noopener noreferrer"&gt;klaussy.com&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  The problem
&lt;/h2&gt;

&lt;p&gt;Until a few weeks ago, Klaussy had one ugly constraint baked into its core: it only worked if you used Claude Code. The early-access docs said it outright — if you didn't run Claude Code, there was nothing in the app for you.&lt;/p&gt;

&lt;p&gt;That was fine for the first users, who mostly did run Claude Code. But it ruled out a large chunk of the people the app is actually for: engineers who already use &lt;em&gt;an&lt;/em&gt; agent CLI daily, have two or three tasks in flight at once, and want a structured way to run them without juggling branches in a single clone. A lot of those people had standardized on Codex, or Gemini, or Copilot — often for cost, procurement, or data-handling reasons that had nothing to do with the tool's quality. For them, Klaussy was "the Claude thing," and that was the end of the conversation.&lt;/p&gt;

&lt;p&gt;The pain Klaussy targets isn't agent-specific. It's the workflow around the agent: starting task B while the agent grinds on task A, hopping between the terminal (where the agent lives) and the browser (where PR review lives), and triaging a CI failure across GitHub, the terminal, and the editor. None of that cares which agent you run. So hard-wiring one agent into the foundation was a self-inflicted limit. v0.3.0 is the release that removed it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why a single-agent design was the wrong foundation
&lt;/h2&gt;

&lt;p&gt;The original architecture made the easy assumption: there's one agent CLI, so call it directly. Spawn &lt;code&gt;claude&lt;/code&gt;, parse its output, wire its session resume into the terminal manager. Every AI surface in the app — the interactive terminal, the PR-review actions, the CI-failure debugger — reached for Claude by name.&lt;/p&gt;

&lt;p&gt;That works right up until you want a second agent. Then every one of those call sites is a place that knows too much. The four agent CLIs differ in obvious ways (&lt;code&gt;@anthropic-ai/claude-code&lt;/code&gt; vs &lt;code&gt;@openai/codex&lt;/code&gt; vs &lt;code&gt;@google/gemini-cli&lt;/code&gt; vs &lt;code&gt;@github/copilot&lt;/code&gt;) and in annoying ones: different model-selection flags, different session-resume mechanics, different output streams to parse, different auth quirks. You can't paper over that with a single &lt;code&gt;if agent == "codex"&lt;/code&gt; branch sprinkled everywhere — you end up with the same conditional copied across a dozen files, and adding a fifth agent later means finding all of them again.&lt;/p&gt;

&lt;p&gt;The terminal multiplexers people would otherwise reach for (tmux, zellij) don't help here either. They'll give you N shells in one window, but they don't know what a git worktree is, what an agent session is, or what state a PR review is in. Klaussy ties each terminal to a specific agent instance, a branch, and a worktree — so the abstraction it needed was a clean seam between "which agent" and "what we're asking the agent to do."&lt;/p&gt;

&lt;h2&gt;
  
  
  The approach
&lt;/h2&gt;

&lt;p&gt;The fix was a provider registry: one module that owns everything agent-specific, and a rule that nothing outside it hard-codes an agent. Each provider declares its npm package, how to launch it, which models it exposes, and how its output should be parsed. The rest of the app asks the registry for "the current agent" and works against that interface.&lt;/p&gt;

&lt;p&gt;On top of the registry sits a small amount of UI: a global default agent you set once, plus a per-action picker so you can override it for a single task. Set Gemini as your default and every agent action follows it, persisting across restarts; reach for Codex on one specific worktree without changing the global setting. The orchestration layer above — parallel worktrees, one task per terminal, the PR review surface — didn't change. It just stopped caring which agent was underneath.&lt;/p&gt;

&lt;p&gt;The honest version of this story is that the registry isn't uniformly deep yet. Phase 1 nailed the parts every agent shares — launching, switching, resuming, running two side by side. The parts that require parsing each agent's particular output stream are mature on Claude and still being verified on the other three. More on that below, because it's the most important caveat in the release.&lt;/p&gt;

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

&lt;h3&gt;
  
  
  The provider registry
&lt;/h3&gt;

&lt;p&gt;Every AI surface in the app now routes through the registry instead of calling an agent by name. A provider entry knows its npm package, its launch command, and its model list. Adding agent number five means adding one entry, not editing a dozen call sites.&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="c1"&gt;// Illustrative — confirm exact API in docs.&lt;/span&gt;
&lt;span class="c1"&gt;// Conceptual shape of the provider registry (main/state/ai-providers.js).&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;PROVIDERS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;claude&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;pkg&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@anthropic-ai/claude-code&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;models&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;opus&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;sonnet&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;haiku&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="na"&gt;codex&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;   &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;pkg&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@openai/codex&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;             &lt;span class="na"&gt;models&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;gpt-5.5&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;gpt-5.4-mini&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="na"&gt;gemini&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;pkg&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@google/gemini-cli&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;        &lt;span class="na"&gt;models&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;2.5-flash&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;3-pro&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="na"&gt;copilot&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;pkg&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@github/copilot&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;           &lt;span class="na"&gt;models&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;default&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="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Model selection is verified for three of the four. Claude takes &lt;code&gt;--model&lt;/code&gt; aliases (opus/sonnet/haiku), Codex exposes gpt-5.5 and gpt-5.4-mini, and Gemini offers its 2.5/3 flash and pro tiers. Copilot is Default-model-only in v0.3.0 — its model slugs aren't verified yet, so the picker doesn't pretend to offer a choice it can't honor. That's a deliberate "show what's real" call rather than a missing feature dressed up as one.&lt;/p&gt;

&lt;h3&gt;
  
  
  Parallel worktrees, one window
&lt;/h3&gt;

&lt;p&gt;Each task runs in its own git worktree, with its own pseudo-terminal via &lt;code&gt;node-pty&lt;/code&gt;, surfaced in the same window as columns, a grid, or a single pane. This is the part that replaces the &lt;code&gt;git worktree&lt;/code&gt; + tmux + a handful of &lt;code&gt;gh&lt;/code&gt; aliases that an engineer would otherwise script themselves. The agent for each terminal is whatever the registry hands back, so a column running Claude and a column running Gemini coexist without either knowing about the other.&lt;/p&gt;

&lt;h3&gt;
  
  
  Running the same work in two agents at once
&lt;/h3&gt;

&lt;p&gt;Because the registry decouples agent from task, the worktree Actions dropdown can spawn a sibling task in the &lt;em&gt;same&lt;/em&gt; worktree on a &lt;em&gt;different&lt;/em&gt; agent. You can hand the same change to two agents side by side and compare what they do — useful when you're still forming an opinion about which agent is better at a given kind of work.&lt;/p&gt;

&lt;p&gt;One sharp edge worth naming: running two Codex sessions concurrently can invalidate each other's rotating OAuth tokens. Klaussy warns you before it starts a second concurrent Codex session rather than letting it silently break. Codex's auth model, not a Klaussy choice — but the kind of thing the orchestration layer has to know about, which is exactly why the registry exists.&lt;/p&gt;

&lt;h3&gt;
  
  
  The PR review surface
&lt;/h3&gt;

&lt;p&gt;Separately from the terminals, Klaussy renders a GitHub PR without a local checkout: Files, Conversation, Checks, and AI Review tabs. The inline review composer batches comments and submits them in one round trip, and per-finding state (Ignore / Add to PR / Implement / Investigate / Ask) persists across sessions. One click materializes a PR into a worktree plus a task when you do want it locally. There's a built-in Monaco editor with LSP diagnostics so you can edit and commit straight from the diff.&lt;/p&gt;

&lt;p&gt;This is where the maturity gap matters most, so I'll be plain about it: the review actions, the CI-failure auto-debug, Implement, and Ask are most battle-tested on Claude. The non-Claude output parsers for those headless surfaces are documented but still being verified in the shipped code. The interactive terminal, agent switching, resume, and side-by-side work across all four agents today. The deep AI surfaces on Codex, Gemini, and Copilot are the path I trust least, and I'd rather you know that going in than discover it on a real PR.&lt;/p&gt;

&lt;h3&gt;
  
  
  Optional on-device autocomplete
&lt;/h3&gt;

&lt;p&gt;There's also inline tab-autocomplete that runs entirely on your machine via local Ollama, using &lt;code&gt;qwen2.5-coder:1.5b&lt;/code&gt; at roughly 100ms latency. Nothing leaves the laptop per keystroke. It's opt-in and costs about a 2 GB download (the Ollama runtime plus the model weights); without it you get a free word-based completer. This is the one piece of the app that does its own inference instead of delegating to your agent CLI.&lt;/p&gt;

&lt;h2&gt;
  
  
  A quick demo
&lt;/h2&gt;

&lt;p&gt;The setup before first launch is real and worth stating plainly. You need Node.js 18+, the GitHub CLI authenticated, and at least one of the four supported agent CLIs installed and authenticated:&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;# Illustrative — Klaussy surfaces install commands in a setup dialog;&lt;/span&gt;
&lt;span class="c"&gt;# it can detect missing CLIs but cannot bootstrap your auth.&lt;/span&gt;
npm i &lt;span class="nt"&gt;-g&lt;/span&gt; @anthropic-ai/claude-code   &lt;span class="c"&gt;# or @openai/codex,&lt;/span&gt;
                                     &lt;span class="c"&gt;# @google/gemini-cli, @github/copilot&lt;/span&gt;
gh auth login
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once a worktree is open, picking an agent and spawning a sibling task on a second agent both happen from the worktree's Actions dropdown — no config files, no per-project agent setup. The agent you choose becomes the global default and sticks across restarts until you change it.&lt;/p&gt;

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

&lt;p&gt;A few things are honestly incomplete:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Multi-agent maturity is uneven.&lt;/strong&gt; Running, switching, resuming, and side-by-side work on all four agents. The deeper AI surfaces (PR review, Implement, CI-debug, Ask) are most proven on Claude and still being verified on Codex, Gemini, and Copilot. Treat Claude as the battle-tested path today.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The built-in flow prompts are still Claude-flavored.&lt;/strong&gt; The Plan/Debug/Review slash-command bodies were written for Claude. They run on the other agents but aren't tuned to them yet. Per-agent tuning is a follow-up.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;It doesn't replace your agent.&lt;/strong&gt; Klaussy does not bundle and mark up agent access, you use your account that you already have with one of the supported agents. Klaussy is an developer productivity app.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There's no Klaussy server in any of this. Data flows from your own agent CLI to that agent's provider, from your own &lt;code&gt;gh&lt;/code&gt; to GitHub, and optionally to local Ollama. Pricing is a one-time $39 founder license (rising later), or $349 / $599 for 5 / 10 seats.&lt;/p&gt;

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

&lt;p&gt;Site and downloads: &lt;a href="https://www.klaussy.com/" rel="noopener noreferrer"&gt;klaussy.com&lt;/a&gt;&lt;br&gt;
Early-access discussion: &lt;a href="https://discord.gg/ZxNhsuMyYu" rel="noopener noreferrer"&gt;Discord&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you've tried wiring multiple agent CLIs into one workflow yourself, I'd genuinely like to know which agent you trust for which job — drop a comment.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>productivity</category>
      <category>showdev</category>
      <category>automation</category>
    </item>
  </channel>
</rss>
