<?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: AlexTDev</title>
    <description>The latest articles on DEV Community by AlexTDev (@alextdev).</description>
    <link>https://dev.to/alextdev</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.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3828031%2F12ceefc8-6ae4-4ac1-80bf-304826d10a9d.jpg</url>
      <title>DEV Community: AlexTDev</title>
      <link>https://dev.to/alextdev</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/alextdev"/>
    <language>en</language>
    <item>
      <title>How I Automated Mermaid.js Upgrades with a Claude Code Skill</title>
      <dc:creator>AlexTDev</dc:creator>
      <pubDate>Sun, 05 Apr 2026 17:11:08 +0000</pubDate>
      <link>https://dev.to/alextdev/how-i-automated-mermaidjs-upgrades-with-a-claude-code-skill-e6g</link>
      <guid>https://dev.to/alextdev/how-i-automated-mermaidjs-upgrades-with-a-claude-code-skill-e6g</guid>
      <description>&lt;p&gt;I maintain an open-source IntelliJ plugin that bundles Mermaid.js. Every time Mermaid releases a new version, I need to update around ten files across a Kotlin codebase — lexer grammars, completion data, test fixtures, documentation. I know the process by heart, but knowing it doesn't make it less tedious. It's the same careful, detail-heavy work each time, and the kind where a single missed file means a debugging session you didn't plan for, or new features you silently skip without realizing.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Plugin
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://plugins.jetbrains.com/plugin/30432-mermaid-visualizer/" rel="noopener noreferrer"&gt;Mermaid Visualizer&lt;/a&gt; is a JetBrains IDE plugin that adds full Mermaid.js support: rendering inside Markdown preview, a standalone editor with live preview for &lt;code&gt;.mmd&lt;/code&gt; and &lt;code&gt;.mermaid&lt;/code&gt; files, syntax highlighting, code completion, inspections, navigation, and structure view. It crossed 2,000 downloads in about six weeks on the JetBrains Marketplace, which was a nice surprise for a solo project.&lt;/p&gt;

&lt;p&gt;The integration runs deep. The plugin bundles &lt;code&gt;mermaid.min.js&lt;/code&gt; (~2.9 MB) and renders diagrams via JCEF (Chromium embedded in the IDE). But it also has a JFlex lexer that knows every diagram type and keyword, a Grammar-Kit parser with PSI tree, contextual code completion that suggests the right arrows and keywords depending on which diagram you're writing, and inspections that catch mistakes. All of that means when Mermaid.js adds a new diagram type or changes syntax, the upgrade isn't just swapping a JavaScript file — it's updating the lexer, the completion catalogs, the test data, the documentation, and then verifying everything still works.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/Alex9583/MermaidVisualizer" rel="noopener noreferrer"&gt;GitHub repo&lt;/a&gt; if you want to look at the code.&lt;/p&gt;

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

&lt;p&gt;The first time I upgraded Mermaid.js, I did everything by hand. Read the changelog, figured out what was new, opened each file, made the edits, ran the tests, fixed what broke, ran them again. It took about three hours, and I still missed some new features from the release. I only noticed later when I went back to the changelog and realized I'd skipped a couple of new keywords.&lt;/p&gt;

&lt;p&gt;The second time, I used Claude to help. I walked it through the process step by step — "now open this file, add these entries here, now regenerate the lexer, now update the tests." It was faster and more thorough, but I was essentially being the orchestrator. I had to remember the sequence, remember which files to touch, remember that longer arrow patterns need to come before shorter ones in the JFlex grammar or longest-match breaks. Every piece of domain knowledge was in my head, and I had to give it to Claude sequentially.&lt;/p&gt;

&lt;p&gt;The core tension: the process is identical every time, but it demands attention to detail across many files with non-obvious ordering constraints. Miss one file and you get broken tests. Forget to regenerate the lexer after editing the grammar and you get a build that compiles fine but silently ignores your changes. It's the kind of work that's just tedious enough to be error-prone.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why a Skill, Not a Prompt
&lt;/h2&gt;

&lt;p&gt;Claude Code has a concept called skills — markdown files that live in your project and encode a reusable procedure. You invoke them with a slash command, and Claude follows the instructions. They're different from prompts in ways that matter for this kind of problem.&lt;/p&gt;

&lt;p&gt;A prompt is one-shot. You write it, use it, and if you need it again next month, you rewrite it — or dig through your conversation history hoping you saved it. A skill lives in the project repository, versioned alongside the code. When the project structure changes, you update the skill. It evolves with the codebase.&lt;/p&gt;

&lt;p&gt;More importantly, a skill encodes domain knowledge that would otherwise exist only in your head. The exact file paths. The line ranges where diagram types are defined in the lexer. The fact that the JFlex &lt;code&gt;KEYWORDS&lt;/code&gt; HashSet lives around lines 17-66 and new entries need a comment naming the diagram type. The ordering constraint on arrow patterns. None of that is obvious from reading the code cold — you'd have to explore, grep, build a mental model. The skill front-loads all of that.&lt;/p&gt;

&lt;p&gt;Skills also support conditional logic. A Mermaid.js release might add three new diagram types, or it might be just bug fixes. The skill adapts: if there are no new types, keywords, or arrows, it skips the lexer, completion data, and parser phases entirely and jumps straight to updating the bundled file and version references. A static prompt can't do that — or rather, it can suggest it, but it won't enforce it structurally.&lt;/p&gt;

&lt;p&gt;The critical insight is simple: skills are for recurring problems. If you do something once, a prompt is fine. If you'll do it again in four weeks, and again four weeks after that, encode it. A skill is a reproducible process you can invoke instantly. That's the core difference.&lt;/p&gt;

&lt;h2&gt;
  
  
  Anatomy of the Skill
&lt;/h2&gt;

&lt;p&gt;The skill has 11 phases, from changelog analysis through to a manual testing checklist. That might sound like overkill for "update a JavaScript file," but remember — this isn't just a file swap. It's a coordinated change across a lexer grammar, completion catalogs, test data, documentation, and a build pipeline.&lt;/p&gt;

&lt;p&gt;The structure is: analyze what changed, download the new version, update each affected layer of the codebase in dependency order, run the build, report results.&lt;/p&gt;

&lt;p&gt;Here's what makes it work.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Impact Classification
&lt;/h3&gt;

&lt;p&gt;Phase 0 starts with reading the changelog and classifying every change:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;| Category | Impact | Examples |
|---|---|---|
| New diagram types | HIGH — touches ~10 files | venn-beta, ishikawa-beta |
| New keywords for existing types | MEDIUM — touches ~4 files | set, union for venn |
| New arrow patterns | MEDIUM — touches ~4 files | half-arrowheads |
| Breaking changes | HIGH — varies | renamed types, removed syntax, API changes |
| Internal changes only | LOW — version refs only | perf improvements, bug fixes |
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is the decision engine. A bug-fix-only release skips most phases — download the new file, update version strings, build, done. A release with new diagram types triggers the full pipeline. The skill doesn't waste time on phases that don't apply, and it doesn't skip phases that do.&lt;/p&gt;

&lt;h3&gt;
  
  
  Precision in File Locations
&lt;/h3&gt;

&lt;p&gt;Phase 2 handles the JFlex lexer, and this is where precision matters:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gu"&gt;## Phase 2 — JFlex Lexer (IF new types/keywords/arrows)&lt;/span&gt;
File: src/main/grammars/Mermaid.flex
&lt;span class="gu"&gt;### 2a. Diagram types (YYINITIAL state, ~lines 100-130)&lt;/span&gt;
Add new diagram type strings to the alternation block. Keep grouped logically.
&lt;span class="gu"&gt;### 2b. Keywords (KEYWORDS HashSet, ~lines 17-66)&lt;/span&gt;
Add new keywords grouped under a comment naming the diagram type.
Only reserved words, NOT arbitrary identifiers.
&lt;span class="gu"&gt;### 2c. Arrow patterns (NORMAL state, ~lines 160-218)&lt;/span&gt;
Longer patterns MUST come BEFORE shorter ones (JFlex longest-match).
Variable-length arrows go before fixed-length.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Without this, Claude would have to search the codebase, figure out the lexer structure, and guess where to insert new entries. It might get it right. It might put a new arrow pattern after shorter ones and break longest-match. The skill eliminates that uncertainty.&lt;/p&gt;

&lt;p&gt;The line ranges use "~" because they shift as the file grows. They're landmarks, not GPS coordinates — close enough to orient, flexible enough to survive edits.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Verification Gate
&lt;/h3&gt;

&lt;p&gt;Phase 10 is short but non-negotiable:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gu"&gt;## Phase 10 — Build &amp;amp; Verify&lt;/span&gt;
./gradlew build then ./gradlew verifyPlugin.
Both must succeed. If tests fail: read, fix, re-run.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is what turns the skill from a checklist into a reliable process. It doesn't declare success until the build passes. If a test fails because a new diagram type wasn't added to a test fixture, Claude reads the failure, fixes it, and re-runs. The loop continues until green.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why It Works
&lt;/h3&gt;

&lt;p&gt;Looking across the whole skill, a few design choices carry the weight:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Explicit file paths and line ranges&lt;/strong&gt; remove ambiguity. The agent knows where to look without exploring.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Conditional phases with clear triggers&lt;/strong&gt; handle any type of release without wasted effort.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ordered dependencies&lt;/strong&gt; prevent cascading failures — the lexer is regenerated before completion data is updated, the parser before navigation, everything before tests.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Verification gates&lt;/strong&gt; ensure the process produces a working build, not just a set of edits.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Delegation&lt;/strong&gt; to existing tooling where it makes sense — &lt;code&gt;./gradlew updateMermaid&lt;/code&gt; handles the download, SHA-256 verification, and atomic file replacement. The skill doesn't reinvent that.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What I Changed Along the Way
&lt;/h2&gt;

&lt;p&gt;The first version of this skill was too vague. It said things like "update the lexer with new diagram types" without specifying where in the lexer or how. Claude made reasonable guesses, but reasonable guesses are wrong often enough to be a problem.&lt;/p&gt;

&lt;p&gt;The second version had better structure — numbered phases, file paths — but didn't handle variability well. What if the release has no new diagram types? What about breaking changes that rename existing syntax? It assumed every upgrade was the same shape, which they aren't.&lt;/p&gt;

&lt;p&gt;The third version added the conditional branching and the impact classification table. That was the version that started working reliably in one activation — invoke the skill, provide the changelog, let it run.&lt;/p&gt;

&lt;p&gt;I also had to refine the Gradle &lt;code&gt;updateMermaid&lt;/code&gt; task itself to integrate cleanly. The skill assumes that task handles download and integrity verification, so the task needed to actually be reliable — atomic writes, SHA-256 checks, clear error messages on failure.&lt;/p&gt;

&lt;p&gt;The lesson is familiar to anyone who writes code: you iterate. Expect two or three versions before a skill works the way you want. That's normal, not a failure.&lt;/p&gt;

&lt;h2&gt;
  
  
  Results
&lt;/h2&gt;

&lt;p&gt;Before the skill, a Mermaid.js upgrade took about 3 hours of focused work and I'd still miss things. With the skill, it takes 45 minutes to an hour, including running the full test suite and verifying the build.&lt;/p&gt;

&lt;p&gt;More importantly: zero missed features since adopting the skill. The impact classification in Phase 0 forces a thorough changelog review, and the per-phase file lists ensure nothing gets skipped. This matters because staying close to official Mermaid.js releases is the whole point of the plugin — one of the common criticisms of existing Mermaid plugins was lagging months behind upstream. The skill is what makes that goal sustainable as a solo dev, and I'll keep iterating on it to push that time down further.&lt;/p&gt;

&lt;h2&gt;
  
  
  Takeaways for Writing Your Own Skills
&lt;/h2&gt;

&lt;p&gt;If you're thinking about encoding one of your own processes as a skill, here's what I've learned:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Target recurring processes.&lt;/strong&gt; If you do something once, write a prompt. If you know you'll do it again, write a skill.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Be explicit about locations.&lt;/strong&gt; File paths, line ranges, section names. The less the agent has to search, the less it can get wrong.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Use conditional branching.&lt;/strong&gt; Real processes have variability. "IF new types exist, do X; otherwise skip to Y" handles that without separate skills for each scenario.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Include verification steps.&lt;/strong&gt; A skill that makes edits but doesn't check if they work is just a fancy TODO list. Build, test, lint — whatever your project needs.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Iterate.&lt;/strong&gt; Your first version will be too vague or too rigid. That's fine. Refine it after each use, the same way you'd refine code after a code review.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Keep it in the repo.&lt;/strong&gt; Version the skill alongside the code it operates on. When the code structure changes, the skill should change too.&lt;/p&gt;

&lt;h2&gt;
  
  
  One Last Thing
&lt;/h2&gt;

&lt;p&gt;If you work in JetBrains IDEs and want Mermaid diagram support, &lt;a href="https://plugins.jetbrains.com/plugin/30432-mermaid-visualizer/" rel="noopener noreferrer"&gt;give the plugin a try&lt;/a&gt;. But the broader point here isn't about Mermaid or IntelliJ — it's about recognizing when a recurring process is worth encoding.&lt;/p&gt;

&lt;p&gt;If you have a procedure that's always the same steps, always touches the same files, and always requires the same domain knowledge you keep in your head, that's a skill waiting to be written. The upfront cost is maybe an hour. The payoff compounds every time you invoke it.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://plugins.jetbrains.com/plugin/30432-mermaid-visualizer/" rel="noopener noreferrer"&gt;Plugin on JetBrains Marketplace&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/Alex9583/MermaidVisualizer" rel="noopener noreferrer"&gt;GitHub repository&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;If you found this helpful, you can &lt;a href="https://buymeacoffee.com/alextdev" rel="noopener noreferrer"&gt;buy me a coffee ☕&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>claude</category>
      <category>ai</category>
      <category>automation</category>
      <category>agentskills</category>
    </item>
    <item>
      <title>Agent Client Protocol (ACP): A New Standard for Bringing AI Coding Agents into Your IDE</title>
      <dc:creator>AlexTDev</dc:creator>
      <pubDate>Mon, 30 Mar 2026 06:15:00 +0000</pubDate>
      <link>https://dev.to/alextdev/agent-client-protocol-acp-a-new-standard-for-bringing-ai-coding-agents-into-your-ide-1k89</link>
      <guid>https://dev.to/alextdev/agent-client-protocol-acp-a-new-standard-for-bringing-ai-coding-agents-into-your-ide-1k89</guid>
      <description>&lt;p&gt;Using AI coding agents inside your IDE works but it's rarely as seamless as it should be. Some features of your favorite agent are missing in the plugin of your IDE compared to another (you can see the difference between Claude Code plugin in VSCode and IntelliJ). A new agent gets a lot of buzz, but there's no support for your editor yet. You make it work, but there's always friction somewhere.&lt;/p&gt;

&lt;p&gt;On the other side, agent developers face a different headache: they need to integrate into every IDE on the market. IntelliJ, VS Code, Zed, Neovim, and counting. Each one has its own API, its own extension format, its own quirks. And every time they ship an update, every plugin needs to follow — which it often doesn't or with a different experience.&lt;/p&gt;

&lt;p&gt;This is the exact same problem the software industry solved once before, with the Language Server Protocol. And the same solution is now emerging for AI agents: the &lt;strong&gt;Agent Client Protocol (ACP)&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;This article covers what ACP is, how it works under the hood, how it relates to MCP, and how you can use it today.&lt;/p&gt;




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

&lt;p&gt;Before LSP, every editor needed custom plugins for every programming language — autocompletion, go-to-definition, linting. It was an N×M integration problem. LSP turned it into N+M: language servers implement one protocol, editors support one protocol, everything just works.&lt;/p&gt;

&lt;p&gt;AI agents face the same N×M challenge. Every new agent needs a custom integration for every editor it wants to support. Every editor needs a custom integration for every agent it wants to offer. With 30+ agents and a dozen editors, that's hundreds of individual integrations — each one fragile, each one lagging behind the agent's latest release.&lt;/p&gt;

&lt;p&gt;ACP collapses this the same way LSP did. Agents implement one protocol. Editors adopt one protocol. A new agent immediately works in every compatible editor. A new editor immediately supports every compatible agent. No custom work, no vendor lock-in.&lt;/p&gt;




&lt;h2&gt;
  
  
  Who's behind it
&lt;/h2&gt;

&lt;p&gt;ACP was created by Zed Industries (the team behind the Zed editor) and launched in August 2025 with Google's Gemini CLI as the first reference implementation. In October 2025, JetBrains announced they would co-develop the protocol and bring ACP support to their entire IDE lineup. In January 2026, they jointly launched the ACP Agent Registry — a curated directory of agents installable in one click from any compatible editor.&lt;/p&gt;

&lt;p&gt;The protocol is open source under the Apache 2.0 license, hosted at &lt;a href="https://agentclientprotocol.com" rel="noopener noreferrer"&gt;agentclientprotocol.com&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The ecosystem has grown fast. Over 30 agents have adopted ACP, including Claude Code, Codex CLI, Gemini CLI, Cursor (which joined the registry in March 2026), Cline, Junie, GitHub Copilot, Kiro CLI, Kimi CLI, OpenCode, Augment Code, and more. On the editor side, Zed has native support, JetBrains IDEs support it from 2025.3 with full registry integration in 2026.1, and community plugins exist for VS Code, Neovim and Obsidian.&lt;/p&gt;




&lt;h2&gt;
  
  
  How ACP works under the hood
&lt;/h2&gt;

&lt;p&gt;The technical design is deliberately simple. ACP uses &lt;strong&gt;JSON-RPC 2.0 over stdio&lt;/strong&gt; — when you activate an agent, your editor spawns it as a subprocess and communicates through stdin/stdout pipes. No network configuration, no ports, no complex setup.&lt;/p&gt;

&lt;p&gt;The conversation follows a predictable sequence:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Initialize&lt;/strong&gt; — The editor sends an &lt;code&gt;initialize&lt;/code&gt; request declaring its capabilities (filesystem access, terminal, etc.). The agent responds with its own capabilities (image support, session loading, etc.).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"jsonrpc"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2.0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"method"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"initialize"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"params"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"protocolVersion"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"clientCapabilities"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"fs"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"readTextFile"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"writeTextFile"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"terminal"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"clientInfo"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"intellij-idea"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"version"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2026.1"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;2. New session&lt;/strong&gt; — The editor creates a session, passing the working directory and available MCP servers.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"jsonrpc"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2.0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"method"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"session/new"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"params"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"cwd"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"/home/user/my-project"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"mcpServers"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;3. Prompt&lt;/strong&gt; — The user sends a message. The agent streams back responses in real-time via JSON-RPC notifications — the editor can display progress token by token.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"jsonrpc"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2.0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"method"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"session/prompt"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"params"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"sessionId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"sess_abc123"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"content"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"text"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"text"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Refactor this controller"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}]&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The communication is &lt;strong&gt;bidirectional&lt;/strong&gt;: the editor sends prompts to the agent, but the agent can also request things back — reading a file, writing a file, running a terminal command. The editor mediates all access, keeping the user in control of what the agent can do.&lt;/p&gt;

&lt;p&gt;ACP reuses data types from MCP wherever possible, so structures like text content, diffs, and tool results follow established JSON schemas. Human-readable text defaults to Markdown.&lt;/p&gt;




&lt;h2&gt;
  
  
  ACP vs MCP: complementary, not competing
&lt;/h2&gt;

&lt;p&gt;This is the question everyone asks. The short answer: &lt;strong&gt;MCP connects agents to tools. ACP connects agents to editors.&lt;/strong&gt; They operate at different layers of the stack and are designed to work together.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;MCP (Model Context Protocol)&lt;/strong&gt; standardizes how agents access external tools and data sources — databases, APIs, file systems, web search. It answers the question: &lt;em&gt;what can the agent access?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;ACP (Agent Client Protocol)&lt;/strong&gt; standardizes how agents integrate into development environments — editors, IDEs, notebooks. It answers the question: &lt;em&gt;where does the agent live in your workflow?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;In practice, they compose naturally. When an ACP session starts, the editor can pass its configured MCP servers to the agent. The agent then uses MCP to access tools while communicating with the editor through ACP:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Editor ←— ACP (JSON-RPC/stdio) —→ Agent ←— MCP (JSON-RPC) —→ Tools &amp;amp; Data
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A concrete example: you're in IntelliJ with Gemini CLI connected via ACP. You ask it to analyze your database schema. Gemini uses MCP to query a connected PostgreSQL server, gets the schema, and sends the analysis back to IntelliJ through ACP — rendered inline in the AI chat panel. With IntelliJ 2026.1, agents can even access your IDE's configured data sources natively, making this kind of workflow seamless.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Don't confuse with IBM's ACP.&lt;/strong&gt; There's a separate protocol also called ACP — the Agent &lt;em&gt;Communication&lt;/em&gt; Protocol — created by IBM's BeeAI team for agent-to-agent communication. It has since merged with Google's A2A protocol under the Linux Foundation. It's a completely different thing solving a different problem (agents talking to each other, not agents talking to editors).&lt;/p&gt;




&lt;h2&gt;
  
  
  Using ACP in JetBrains IDEs
&lt;/h2&gt;

&lt;p&gt;ACP support landed in JetBrains IDEs with version 2025.3 and matured significantly with &lt;strong&gt;2026.1&lt;/strong&gt;, which brought the built-in ACP Registry, one-click agent installation, and expanded agent capabilities like database access and Git worktree support. It works across the entire lineup — IntelliJ IDEA, PyCharm, WebStorm, GoLand, and the rest. No JetBrains AI subscription is required.&lt;/p&gt;

&lt;h3&gt;
  
  
  From the ACP Registry (recommended)
&lt;/h3&gt;

&lt;p&gt;This is the easiest path and the one JetBrains is pushing forward:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Open the &lt;strong&gt;AI Chat&lt;/strong&gt; tool window&lt;/li&gt;
&lt;li&gt;Click the chat mode selector and choose &lt;strong&gt;Install From ACP Registry&lt;/strong&gt;  (or go to &lt;strong&gt;Settings | Tools | AI Assistant | Agents&lt;/strong&gt;)&lt;/li&gt;
&lt;li&gt;Browse the available agents — Cursor, Claude Agent, Codex, Gemini CLI, Kimi CLI, Augment Code, and many more&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Install&lt;/strong&gt; — the IDE downloads everything needed, including runtimes if required&lt;/li&gt;
&lt;li&gt;Select the agent from the dropdown in AI Chat and start prompting&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;That's it. The agent runs as a local subprocess. The registry handles updates automatically.&lt;/p&gt;

&lt;p&gt;On the Agents settings page, you can also configure MCP exposure:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Pass custom MCP servers&lt;/strong&gt; — exposes your configured MCP servers to installed agents&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pass IntelliJ MCP server&lt;/strong&gt; — gives agents access to the IDE's built-in MCP server (project structure, open files, data sources)&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Manual configuration
&lt;/h3&gt;

&lt;p&gt;For agents not in the registry or custom setups, you can still edit &lt;code&gt;~/.jetbrains/acp.json&lt;/code&gt; directly:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"default_mcp_settings"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"use_idea_mcp"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"use_custom_mcp"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"agent_servers"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"Gemini CLI"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"command"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"/path/to/gemini"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"args"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"--experimental-acp"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"env"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Restart your IDE, and the agent appears in the AI Chat selector.&lt;/p&gt;

&lt;h3&gt;
  
  
  What's new in 2026.1 specifically
&lt;/h3&gt;

&lt;p&gt;The 2026.1 release made ACP a first-class citizen in JetBrains IDEs. Beyond the registry, a few features stand out:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Database access for agents&lt;/strong&gt; — Codex, Claude Agent, and other ACP agents can query and modify your IDE's configured data sources natively.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Git worktrees&lt;/strong&gt; — Work in parallel branches and hand one off to an agent while you keep coding in another. A natural fit for agent-driven workflows.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cursor in the registry&lt;/strong&gt; — Cursor joined the ACP Registry in March 2026, bringing its agentic workflows directly into JetBrains IDEs.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Using ACP in Zed
&lt;/h2&gt;

&lt;p&gt;Zed has native ACP support and is where the protocol was born. The quickest way to get started: open the agent panel (&lt;code&gt;Cmd+?&lt;/code&gt; / &lt;code&gt;Ctrl+?&lt;/code&gt;), hit the &lt;code&gt;+&lt;/code&gt; button, and pick an agent — Gemini CLI, Claude Agent, and Codex are available out of the box.&lt;/p&gt;

&lt;p&gt;For additional agents, use the ACP Registry (&lt;code&gt;zed: acp registry&lt;/code&gt; in the command palette) or add them manually in your settings:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"agent_servers"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"My Custom Agent"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"custom"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"command"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"/path/to/agent"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"args"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"acp"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  What this changes in practice
&lt;/h2&gt;

&lt;p&gt;The practical impact is bigger than it might seem at first:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;For developers&lt;/strong&gt;, you're no longer choosing between "the IDE I love" and "the agent I want." Use PyCharm with Claude Code. Use IntelliJ with Cursor. Use Zed with Codex. Switch agents for different tasks without switching editors.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;For agent developers&lt;/strong&gt;, you implement ACP once and reach users across Zed, JetBrains, Neovim, VS Code, and every future client that adopts the protocol. No more maintaining editor-specific plugins that break with every release.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;For the ecosystem&lt;/strong&gt;, it creates healthy competition. Agents compete on intelligence and capability, not on which editors they happen to support. Editors compete on UX and developer experience, not on which agents they've managed to integrate.&lt;/p&gt;




&lt;h2&gt;
  
  
  Getting started
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Make sure your IDE supports ACP (JetBrains 2026.1+, Zed, or a community plugin for VS Code/Neovim)&lt;/li&gt;
&lt;li&gt;Open the ACP Registry from your IDE and install an agent in one click&lt;/li&gt;
&lt;li&gt;Or install manually from the &lt;a href="https://agentclientprotocol.com/get-started/agents" rel="noopener noreferrer"&gt;agents list&lt;/a&gt; and configure &lt;code&gt;acp.json&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Open the AI Chat panel and start using it&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The full protocol specification and SDK are at &lt;a href="https://agentclientprotocol.com" rel="noopener noreferrer"&gt;agentclientprotocol.com&lt;/a&gt;. The &lt;a href="https://www.jetbrains.com/help/ai-assistant/acp.html" rel="noopener noreferrer"&gt;JetBrains documentation&lt;/a&gt; covers IDE-specific setup in detail.&lt;/p&gt;

&lt;p&gt;ACP is still young — launched mid-2025, with JetBrains joining in October and the registry going live in January 2026. But with 30+ agents, Cursor on board, and the two biggest IDE ecosystems backing it, the trajectory is clear. This is the LSP moment for AI agents.&lt;/p&gt;




&lt;p&gt;If you found this helpful, you can &lt;a href="https://buymeacoffee.com/alextdev" rel="noopener noreferrer"&gt;buy me a coffee ☕&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>productivity</category>
      <category>agents</category>
      <category>llm</category>
    </item>
    <item>
      <title>How to Write Effective Agent Skills for Claude</title>
      <dc:creator>AlexTDev</dc:creator>
      <pubDate>Sat, 21 Mar 2026 22:27:16 +0000</pubDate>
      <link>https://dev.to/alextdev/how-to-write-effective-agent-skills-for-claude-2opb</link>
      <guid>https://dev.to/alextdev/how-to-write-effective-agent-skills-for-claude-2opb</guid>
      <description>&lt;p&gt;If you use Claude Code or claude.ai, you've probably caught yourself giving the same instructions over and over. "Use conventional commits." "Run the linter before committing." "Check for breaking changes." Every new conversation, you start from scratch.&lt;/p&gt;

&lt;p&gt;Agent Skills fix this. You package your instructions, conventions, and scripts into a reusable module that Claude picks up automatically.&lt;/p&gt;




&lt;h2&gt;
  
  
  What are Agent Skills?
&lt;/h2&gt;

&lt;p&gt;Skills are directories containing a &lt;code&gt;SKILL.md&lt;/code&gt; file with instructions, optional reference files, and optional scripts. Think of them as onboarding docs for Claude — reusable and automatically triggered when your request matches.&lt;/p&gt;

&lt;p&gt;Anthropic ships pre-built Skills (PowerPoint, Excel, Word, PDF). The real power is &lt;strong&gt;custom Skills&lt;/strong&gt;: your expertise, your conventions, your patterns.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Where they work:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Claude Code&lt;/strong&gt; — drop into &lt;code&gt;.claude/skills/&lt;/code&gt; (project) or &lt;code&gt;~/.claude/skills/&lt;/code&gt; (global). Auto-discovered.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;claude.ai&lt;/strong&gt; — upload as zip via Settings &amp;gt; Features (Pro/Max/Team/Enterprise).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Skills don't sync across surfaces — manage them separately.&lt;/p&gt;




&lt;h2&gt;
  
  
  How the loading works
&lt;/h2&gt;

&lt;p&gt;Skills use &lt;strong&gt;progressive disclosure&lt;/strong&gt; — they load in three stages, not all at once:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Metadata (always loaded)&lt;/strong&gt; — Claude sees only &lt;code&gt;name&lt;/code&gt; and &lt;code&gt;description&lt;/code&gt; from YAML frontmatter. ~100 tokens per Skill.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Instructions (when triggered)&lt;/strong&gt; — Claude reads &lt;code&gt;SKILL.md&lt;/code&gt; when your request matches. Instructions enter the context window.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Resources (as needed)&lt;/strong&gt; — Additional files and scripts are loaded only when referenced. Scripts are &lt;em&gt;executed&lt;/em&gt; via bash — their code never enters context, only the output.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This matters because every token in your Skill competes with conversation history. Understanding this mechanism is key to writing efficient Skills.&lt;/p&gt;




&lt;h2&gt;
  
  
  The practices that matter most
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Nail the description
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;description&lt;/code&gt; determines whether Claude picks up your Skill at all. Write in third person, be specific, include trigger words:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Good — Claude knows exactly when to use this&lt;/span&gt;
&lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="s"&gt;Reviews code changes, generates commit messages, and validates&lt;/span&gt;
  &lt;span class="s"&gt;diffs before committing. Use when the user asks to review code,&lt;/span&gt;
  &lt;span class="s"&gt;prepare a commit, write a commit message, or open a pull request.&lt;/span&gt;

&lt;span class="c1"&gt;# Bad — too vague to match reliably&lt;/span&gt;
&lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Helps with git stuff.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Constraints: &lt;code&gt;name&lt;/code&gt; is lowercase + hyphens only (max 64 chars), &lt;code&gt;description&lt;/code&gt; max 1024 chars, no XML tags in either.&lt;/p&gt;

&lt;h3&gt;
  
  
  Write for Claude, not for humans
&lt;/h3&gt;

&lt;p&gt;Claude already knows what commits and pull requests are. Don't explain basics — focus on &lt;strong&gt;your specific conventions&lt;/strong&gt;. If you wouldn't explain it to a senior dev joining your team, don't explain it to Claude.&lt;/p&gt;

&lt;h3&gt;
  
  
  Structure for progressive disclosure
&lt;/h3&gt;

&lt;p&gt;Keep &lt;code&gt;SKILL.md&lt;/code&gt; under 500 lines. Split detailed content into separate files referenced from the main file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gu"&gt;## Commit messages&lt;/span&gt;
Short version: &lt;span class="sb"&gt;`type(scope): description`&lt;/span&gt;
For detailed rules and examples, see &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;COMMIT_CONVENTIONS.md&lt;/span&gt;&lt;span class="p"&gt;](&lt;/span&gt;&lt;span class="sx"&gt;COMMIT_CONVENTIONS.md&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Claude loads &lt;code&gt;COMMIT_CONVENTIONS.md&lt;/code&gt; only when dealing with commits. Keep references &lt;strong&gt;one level deep&lt;/strong&gt; — nested chains (A → B → C) get partially read.&lt;/p&gt;

&lt;h3&gt;
  
  
  Use scripts for deterministic tasks
&lt;/h3&gt;

&lt;p&gt;Anything that should run the same way every time belongs in a script. They're more reliable than generated code, and more token-efficient since only the output enters context:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;Run &lt;span class="sb"&gt;`bash scripts/check_diff.sh`&lt;/span&gt; to get a diff summary.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Build feedback loops
&lt;/h3&gt;

&lt;p&gt;For quality-critical tasks, add validation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="p"&gt;1.&lt;/span&gt; Run &lt;span class="sb"&gt;`bash scripts/check_diff.sh`&lt;/span&gt;
&lt;span class="p"&gt;2.&lt;/span&gt; If warnings found, fix them
&lt;span class="p"&gt;3.&lt;/span&gt; Run again — only proceed when clean
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Control the thinking effort
&lt;/h3&gt;

&lt;p&gt;You can set how much reasoning Claude puts into your Skill via the &lt;code&gt;effort&lt;/code&gt; field in the frontmatter:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;reviewing-code&lt;/span&gt;
&lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Reviews code changes and generates commit messages.&lt;/span&gt;
&lt;span class="na"&gt;effort&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;max&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Values: &lt;code&gt;low&lt;/code&gt;, &lt;code&gt;medium&lt;/code&gt;, &lt;code&gt;high&lt;/code&gt;, &lt;code&gt;max&lt;/code&gt;. Use &lt;code&gt;max&lt;/code&gt; (opus only) for very complex tasks only because it consumes a lot of tokens. Use &lt;code&gt;low&lt;/code&gt; for straightforward, mechanical operations like formatting or file renaming. This directly controls Claude's thinking depth when executing the Skill.&lt;/p&gt;

&lt;h3&gt;
  
  
  Delegate to a subagent
&lt;/h3&gt;

&lt;p&gt;For complex Skills, you can have Claude spawn a subagent to handle the Skill in isolation. This keeps the main conversation's context clean and lets the Skill run with its own dedicated context window.&lt;/p&gt;

&lt;p&gt;Configure it in the frontmatter:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;reviewing-code&lt;/span&gt;
&lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Reviews code changes and generates commit messages.&lt;/span&gt;
&lt;span class="na"&gt;effort&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;high&lt;/span&gt;
&lt;span class="na"&gt;model&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;claude-sonnet-4-6&lt;/span&gt;
&lt;span class="na"&gt;allowed-tools&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Read, Bash, Grep&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When &lt;code&gt;model&lt;/code&gt; and &lt;code&gt;allowed-tools&lt;/code&gt; are specified, Claude delegates the task to a subagent running that model with only those tools. The main conversation receives the result without carrying the Skill's full execution context.&lt;/p&gt;




&lt;h2&gt;
  
  
  Anti-patterns to avoid
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Time-sensitive info&lt;/strong&gt; — "Before August 2025, use the old API" will rot. Use "current" and "legacy" sections.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Too many options&lt;/strong&gt; — Pick a default tool/library, mention one alternative for edge cases.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Assuming packages exist&lt;/strong&gt; — List install commands explicitly.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Deep reference chains&lt;/strong&gt; — Keep everything one link from SKILL.md.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Complete example: a code review Skill
&lt;/h2&gt;

&lt;p&gt;Here's a full Skill applying all the above practices.&lt;/p&gt;

&lt;h3&gt;
  
  
  Structure
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;code-review/
├── SKILL.md
├── COMMIT_CONVENTIONS.md
└── scripts/
    └── check_diff.sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  SKILL.md
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;reviewing-code&lt;/span&gt;
&lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="s"&gt;Reviews code changes, generates commit messages, and validates&lt;/span&gt;
  &lt;span class="s"&gt;diffs before committing. Use when the user asks to review code,&lt;/span&gt;
  &lt;span class="s"&gt;prepare a commit, write a commit message, check a diff, or&lt;/span&gt;
  &lt;span class="s"&gt;open a pull request.&lt;/span&gt;
&lt;span class="na"&gt;effort&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;high&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Below the frontmatter, the markdown body:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gh"&gt;# Code Review Assistant&lt;/span&gt;

&lt;span class="gu"&gt;## Review process&lt;/span&gt;
&lt;span class="p"&gt;
1.&lt;/span&gt; Run &lt;span class="sb"&gt;`bash scripts/check_diff.sh`&lt;/span&gt; to get an overview
&lt;span class="p"&gt;2.&lt;/span&gt; Analyze changes by category: breaking changes, new features,
   bug fixes, refactoring
&lt;span class="p"&gt;3.&lt;/span&gt; For each file, check: unrelated changes mixed in? Error handling?
   Edge cases? Docs on public methods?

&lt;span class="gu"&gt;## Commit messages&lt;/span&gt;

Conventional Commits: &lt;span class="sb"&gt;`type(scope): description`&lt;/span&gt;
Types: feat, fix, refactor, docs, test, chore, ci.

For detailed rules, see &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;COMMIT_CONVENTIONS.md&lt;/span&gt;&lt;span class="p"&gt;](&lt;/span&gt;&lt;span class="sx"&gt;COMMIT_CONVENTIONS.md&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;.

&lt;span class="gu"&gt;## PR preparation&lt;/span&gt;
&lt;span class="p"&gt;
1.&lt;/span&gt; Run &lt;span class="sb"&gt;`bash scripts/check_diff.sh`&lt;/span&gt; and fix any issues
&lt;span class="p"&gt;2.&lt;/span&gt; One logical change per commit
&lt;span class="p"&gt;3.&lt;/span&gt; PR description explains the "why", not the "what"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  COMMIT_CONVENTIONS.md
&lt;/h3&gt;

&lt;p&gt;Loaded only when Claude needs to write or review commit messages:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gh"&gt;# Commit Message Conventions&lt;/span&gt;

&lt;span class="gu"&gt;## Format&lt;/span&gt;

  type(scope): short description

  [optional body]
  [optional footer]

&lt;span class="gu"&gt;## Types&lt;/span&gt;
&lt;span class="p"&gt;
-&lt;/span&gt; feat: New user-visible feature
&lt;span class="p"&gt;-&lt;/span&gt; fix: User-visible bug fix
&lt;span class="p"&gt;-&lt;/span&gt; refactor: No behavior change
&lt;span class="p"&gt;-&lt;/span&gt; docs: Documentation only
&lt;span class="p"&gt;-&lt;/span&gt; test: Adding/updating tests
&lt;span class="p"&gt;-&lt;/span&gt; chore: Build, tooling, dependencies
&lt;span class="p"&gt;-&lt;/span&gt; ci: CI/CD changes

&lt;span class="gu"&gt;## Example&lt;/span&gt;

  feat(auth): add JWT token refresh endpoint

  Tokens auto-refresh 5 minutes before expiry.
  Closes #142
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  scripts/check_diff.sh
&lt;/h3&gt;

&lt;p&gt;Executed by Claude — only the output enters context:&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;#!/bin/bash&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"=== Staged changes summary ==="&lt;/span&gt;
git diff &lt;span class="nt"&gt;--cached&lt;/span&gt; &lt;span class="nt"&gt;--stat&lt;/span&gt; 2&amp;gt;/dev/null &lt;span class="o"&gt;||&lt;/span&gt; git diff &lt;span class="nt"&gt;--stat&lt;/span&gt;

&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;""&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"=== Looking for common issues ==="&lt;/span&gt;
&lt;span class="k"&gt;if &lt;/span&gt;git diff &lt;span class="nt"&gt;--cached&lt;/span&gt; &lt;span class="nt"&gt;-G&lt;/span&gt; &lt;span class="s2"&gt;"(console&lt;/span&gt;&lt;span class="se"&gt;\.&lt;/span&gt;&lt;span class="s2"&gt;log|debugger|print&lt;/span&gt;&lt;span class="se"&gt;\(&lt;/span&gt;&lt;span class="s2"&gt;)"&lt;/span&gt; &lt;span class="nt"&gt;--name-only&lt;/span&gt; 2&amp;gt;/dev/null | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-q&lt;/span&gt; .&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
    &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"WARNING: Debug statements found in:"&lt;/span&gt;
    git diff &lt;span class="nt"&gt;--cached&lt;/span&gt; &lt;span class="nt"&gt;-G&lt;/span&gt; &lt;span class="s2"&gt;"(console&lt;/span&gt;&lt;span class="se"&gt;\.&lt;/span&gt;&lt;span class="s2"&gt;log|debugger|print&lt;/span&gt;&lt;span class="se"&gt;\(&lt;/span&gt;&lt;span class="s2"&gt;)"&lt;/span&gt; &lt;span class="nt"&gt;--name-only&lt;/span&gt;
&lt;span class="k"&gt;fi

&lt;/span&gt;git diff &lt;span class="nt"&gt;--cached&lt;/span&gt; &lt;span class="nt"&gt;--stat&lt;/span&gt; 2&amp;gt;/dev/null | &lt;span class="nb"&gt;awk&lt;/span&gt; &lt;span class="s1"&gt;'$3 &amp;gt; 500 {print "WARNING: Large change - " $0}'&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"=== Done ==="&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Getting started
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Create a directory with a &lt;code&gt;SKILL.md&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Add YAML frontmatter (&lt;code&gt;name&lt;/code&gt;, &lt;code&gt;description&lt;/code&gt;, optionally &lt;code&gt;effort&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Write concise instructions in the body&lt;/li&gt;
&lt;li&gt;Drop into &lt;code&gt;.claude/skills/&lt;/code&gt; or upload as zip on claude.ai&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Start with a real problem you face repeatedly. A focused Skill that does one thing well beats a sprawling one every time.&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://platform.claude.com/docs/en/agents-and-tools/agent-skills/overview" rel="noopener noreferrer"&gt;official documentation&lt;/a&gt; covers the full spec, and the &lt;a href="https://platform.claude.com/docs/en/agents-and-tools/agent-skills/best-practices" rel="noopener noreferrer"&gt;best practices guide&lt;/a&gt; goes deeper on advanced patterns.&lt;/p&gt;




&lt;p&gt;If you found this helpful, you can &lt;a href="https://buymeacoffee.com/alextdev" rel="noopener noreferrer"&gt;buy me a coffee ☕&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>productivity</category>
      <category>agentskills</category>
      <category>agents</category>
    </item>
    <item>
      <title>I Built an Open-Source Mermaid Plugin for IntelliJ — Here's Why and What I Learned</title>
      <dc:creator>AlexTDev</dc:creator>
      <pubDate>Mon, 16 Mar 2026 22:03:38 +0000</pubDate>
      <link>https://dev.to/alextdev/i-built-an-open-source-mermaid-plugin-for-intellij-heres-why-and-what-i-learned-569a</link>
      <guid>https://dev.to/alextdev/i-built-an-open-source-mermaid-plugin-for-intellij-heres-why-and-what-i-learned-569a</guid>
      <description>&lt;p&gt;If you use Mermaid diagrams in JetBrains IDEs, you've probably noticed the official plugin hasn't kept up. Architecture diagrams, kanban boards, treemaps — a good chunk of the newer diagram types either render poorly or not at all.&lt;/p&gt;

&lt;p&gt;I ran into this problem in my own workflow. I use Mermaid a lot for technical documentation, and I had some of my diagrams broken in the Markdown preview. So instead of waiting for a fix that wasn't coming, I built my own plugin.&lt;/p&gt;

&lt;p&gt;Six weeks later, &lt;a href="https://plugins.jetbrains.com/plugin/30432-mermaidvisualizer" rel="noopener noreferrer"&gt;Mermaid Visualizer&lt;/a&gt; is on the JetBrains Marketplace at v1.4.0, open-source under Apache 2.0.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1ye1er8e795f4coinjjc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1ye1er8e795f4coinjjc.png" alt="The plugin listing on the JetBrains Marketplace" width="800" height="187"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Why build yet another plugin?
&lt;/h2&gt;

&lt;p&gt;I was looking for a concrete project to learn the IntelliJ plugin ecosystem from scratch. I had never built a plugin before, never touched JCEF, never published anything on the JetBrains Marketplace. Rather than building a throwaway exercise, I picked a real problem I was facing every day.&lt;/p&gt;

&lt;p&gt;The existing landscape looked like this:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;The official JetBrains Mermaid plugin&lt;/strong&gt; — closed-source, not fully functional with the new diagrams&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Mermaid Studio&lt;/strong&gt; — active and feature-rich, but commercial and proprietary&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There was a clear gap for an open-source, permissively licensed plugin running the latest version of Mermaid.js. That's the niche I went for.&lt;/p&gt;




&lt;h2&gt;
  
  
  What does it do?
&lt;/h2&gt;

&lt;p&gt;Mermaid Visualizer embeds Mermaid.js v11.13.0 directly inside the IDE. No CDN, no external dependencies — everything works offline.&lt;/p&gt;

&lt;h3&gt;
  
  
  Markdown preview integration
&lt;/h3&gt;

&lt;p&gt;Write a &lt;code&gt;mermaid&lt;/code&gt; block in any Markdown file and it renders as a diagram in the built-in preview. All 24+ diagram types are supported: flowcharts, sequence diagrams, class diagrams, ER diagrams, Gantt charts, architecture diagrams, kanban, mindmaps, and everything else Mermaid supports.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftakram608jtilp0butg1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftakram608jtilp0butg1.png" alt="A Markdown file with a mermaid block on the left, rendered diagram in the preview on the right" width="800" height="655"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Dedicated editor for &lt;code&gt;.mmd&lt;/code&gt; / &lt;code&gt;.mermaid&lt;/code&gt; files
&lt;/h3&gt;

&lt;p&gt;A split editor with live preview. You type on the left, the diagram updates on the right. Scroll sync keeps both sides aligned.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhfakm93r1rwsilxtdtm8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhfakm93r1rwsilxtdtm8.png" alt="The split editor with a flowchart or sequence diagram" width="800" height="254"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Export
&lt;/h3&gt;

&lt;p&gt;Hover over any diagram (in the Markdown preview or the standalone editor) and an overlay toolbar appears. Copy as SVG, copy as PNG, or save to file.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F82jgxlzhpsqsi94ovzkp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F82jgxlzhpsqsi94ovzkp.png" alt="The overlay toolbar visible on hover over a diagram" width="800" height="570"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Zoom and pan
&lt;/h3&gt;

&lt;p&gt;Ctrl + Scroll to zoom, click and drag to pan, fit-to-window, 1:1 view. Works the same in both contexts.&lt;/p&gt;

&lt;h3&gt;
  
  
  Syntax highlighting
&lt;/h3&gt;

&lt;p&gt;Keywords, diagram types, arrows, strings, comments, directives — all highlighted with configurable colors via the standard IntelliJ color scheme settings.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fy238fuzs0g4l6ipy0pjz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fy238fuzs0g4l6ipy0pjz.png" alt="A .mmd file showing syntax highlighting" width="782" height="398"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Settings
&lt;/h3&gt;

&lt;p&gt;Under &lt;code&gt;Settings &amp;gt; Tools &amp;gt; Mermaid&lt;/code&gt;: theme (auto/default/dark/forest/neutral), look (classic or hand-drawn), font family, max text size, debounce delay. Changes apply live without reloading.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fffkzvg0ijnr54b1i4kya.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fffkzvg0ijnr54b1i4kya.png" alt="The Settings" width="800" height="389"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Dark mode
&lt;/h3&gt;

&lt;p&gt;Detected automatically. Switch your IDE theme and the diagrams follow.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyr34l1aggj5ix3qnzc0a.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyr34l1aggj5ix3qnzc0a.png" alt="Diagram in dark mode" width="800" height="385"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdl6o1rv5vnp4vmbmpj6c.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdl6o1rv5vnp4vmbmpj6c.png" alt="Diagram in light mode" width="800" height="385"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  How it works under the hood
&lt;/h2&gt;

&lt;p&gt;The core idea is simple: let Mermaid.js do the rendering, inside the IDE's embedded Chromium browser (JCEF).&lt;/p&gt;

&lt;p&gt;The plugin bundles &lt;code&gt;mermaid.min.js&lt;/code&gt; (about 2.9 MB) and loads it into a JCEF browser instance via &lt;code&gt;loadHTML()&lt;/code&gt;. When you edit your diagram, the Kotlin side encodes the Mermaid source in base64, sends it to the browser through &lt;code&gt;executeJavaScript()&lt;/code&gt;, and Mermaid.js renders it to SVG. Communication back to Kotlin (for export, errors, scroll sync) goes through &lt;code&gt;JBCefJSQuery&lt;/code&gt; callbacks.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkczumb9lvcq4p2yn5yly.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkczumb9lvcq4p2yn5yly.png" alt="Execution diagram" width="800" height="197"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Each rendered diagram lives inside a &lt;strong&gt;Shadow DOM&lt;/strong&gt; to isolate its styles from the rest of the page. This matters especially in the Markdown preview where Mermaid's CSS could otherwise leak into your document.&lt;/p&gt;

&lt;p&gt;For the Markdown integration specifically, the plugin hooks into the Markdown plugin's &lt;code&gt;MarkdownBrowserPreviewExtension&lt;/code&gt; to inject its scripts and styles into the existing preview browser. It doesn't create a separate browser — it enhances the one that's already there.&lt;/p&gt;

&lt;p&gt;The settings propagation has two different paths depending on the context. In the standalone editor, config changes trigger a re-render via an application-level message bus topic. In the Markdown preview, the new config is pushed through the Markdown plugin's &lt;code&gt;BrowserPipe&lt;/code&gt; and JavaScript picks it up without a page reload.&lt;/p&gt;




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

&lt;p&gt;This was my first plugin, my first time publishing on the JetBrains Marketplace, and my first real encounter with several technologies. Here's what stood out.&lt;/p&gt;

&lt;h3&gt;
  
  
  JCEF is powerful but has sharp edges
&lt;/h3&gt;

&lt;p&gt;The browser must be created on the EDT. &lt;code&gt;loadHTML()&lt;/code&gt; is async, so you can't call &lt;code&gt;executeJavaScript()&lt;/code&gt; right after — you need &lt;code&gt;CefLoadHandler.onLoadEnd()&lt;/code&gt; to know when the page is ready. Resources loaded via &lt;code&gt;file://&lt;/code&gt; hit CORS restrictions, so inlining everything into &lt;code&gt;loadHTML()&lt;/code&gt; turned out to be the most reliable approach. And &lt;code&gt;onLoadEnd&lt;/code&gt; runs on CEF's IO thread, not the EDT, so you need to dispatch back for any shared state access.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Markdown plugin's API requires some caution
&lt;/h3&gt;

&lt;p&gt;The plugin integrates with the Markdown preview through &lt;code&gt;browserPreviewExtensionProvider&lt;/code&gt; — the official extension point exposed by the Markdown plugin. This lets me inject scripts and styles into the existing preview browser without creating a separate one.&lt;/p&gt;

&lt;p&gt;The approach is clean: the Markdown plugin renders &lt;code&gt;&lt;/code&gt;`&lt;code&gt;mermaid&lt;/code&gt; blocks as plain &lt;code&gt;&amp;lt;code class="language-mermaid"&amp;gt;&lt;/code&gt; elements, and my JavaScript picks them up, feeds them to Mermaid.js, and replaces them with rendered SVG diagrams. No need to override the rendering pipeline itself.&lt;/p&gt;

&lt;p&gt;I initially tried &lt;code&gt;CodeFenceGeneratingProvider&lt;/code&gt; which seemed like the more direct approach — intercept the code block and generate HTML server-side. But its &lt;code&gt;generateHtml()&lt;/code&gt; method is &lt;code&gt;@ApiStatus.Internal&lt;/code&gt; and gets flagged by the plugin verifier. The JavaScript-based approach turned out to be both simpler and more robust: it works with IncrementalDOM (live updates as you type), handles theme changes dynamically, and doesn't depend on any internal API.&lt;/p&gt;

&lt;h3&gt;
  
  
  Shadow DOM saved me a lot of headaches
&lt;/h3&gt;

&lt;p&gt;Mermaid.js generates SVGs with embedded &lt;code&gt;&amp;lt;style&amp;gt;&lt;/code&gt; tags. Without isolation, these styles bleed into the Markdown preview and break the layout. Wrapping each diagram in a Shadow DOM solved this cleanly.&lt;/p&gt;

&lt;h3&gt;
  
  
  Publishing on the Marketplace is straightforward
&lt;/h3&gt;

&lt;p&gt;The IntelliJ Platform Gradle Plugin handles most of the heavy lifting. Set up a &lt;code&gt;PUBLISH_TOKEN&lt;/code&gt;, run &lt;code&gt;./gradlew publishPlugin&lt;/code&gt;, and you're live. The review process was quick. I automated releases with GitHub Actions: push a version tag, and CI builds, publishes, and creates a GitHub Release.&lt;/p&gt;

&lt;h3&gt;
  
  
  Keeping Mermaid.js up to date needs a strategy
&lt;/h3&gt;

&lt;p&gt;The library is nearly 3 MB and gets frequent updates with new diagram types. I wrote a Gradle task (&lt;code&gt;updateMermaid&lt;/code&gt;) that pulls the latest version from npm, and a GitHub Actions workflow that checks for updates and opens an issue when a new version is available.&lt;/p&gt;




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

&lt;p&gt;The plugin covers the essentials — rendering, editing, export, zoom, settings. But there's more I want to build:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Code intelligence&lt;/strong&gt; — Autocompletion for node names, diagram keywords, arrow types. Inspections for undefined nodes, unused nodes, invalid syntax. This means writing a proper Grammar-Kit parser for the main diagram types.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Navigation&lt;/strong&gt; — Go-to-definition and Find Usages on node names. A Structure View showing the diagram hierarchy.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Live templates&lt;/strong&gt; — Snippets for common diagram skeletons (&lt;code&gt;mflow&lt;/code&gt; for flowchart, &lt;code&gt;mseq&lt;/code&gt; for sequence, etc.).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;ZenUML support&lt;/strong&gt; — It requires a separate module that isn't included in the standard Mermaid bundle.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I don't know how far I'll get, but the roadmap is there and I'm working through it.&lt;/p&gt;




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

&lt;p&gt;If Mermaid is part of your workflow in a JetBrains IDE, give it a try:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;JetBrains Marketplace&lt;/strong&gt;: &lt;a href="https://plugins.jetbrains.com/plugin/30432-mermaidvisualizer" rel="noopener noreferrer"&gt;Mermaid Visualizer&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;GitHub&lt;/strong&gt;: &lt;a href="https://github.com/Alex9583/MermaidVisualizer" rel="noopener noreferrer"&gt;Alex9583/MermaidVisualizer&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It works in any JetBrains IDE based on build 2025.3+ (IntelliJ IDEA, WebStorm, PyCharm, GoLand, etc.). Just install it and your &lt;code&gt;mermaid&lt;/code&gt; blocks will start rendering.&lt;/p&gt;

&lt;p&gt;It's open-source, it's free, and I'm actively working on it. If something is missing, broken, or could be better — open an issue or drop a comment. Your feedback helps me improve the plugin and learn the platform.&lt;/p&gt;




&lt;p&gt;If you want to support the project, you can &lt;a href="https://buymeacoffee.com/alextdev" rel="noopener noreferrer"&gt;buy me a coffee ☕&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>opensource</category>
      <category>kotlin</category>
      <category>mermaid</category>
      <category>javascript</category>
    </item>
  </channel>
</rss>
