I Made a CLI That Yells at Your Code Until It Gets an A

AI coding is great until your repo starts looking like it was assembled during a fire drill.

So I made this:

npx fix-hairball

It reviews your codebase, gives it a grade, fixes the worst parts, reviews it again, and keeps going until it gets an A.

Basically:

D -> C -> B -> A

but with more terminal output and fewer feelings.

Why?

Because AI agents love writing code.

They do not always love deleting code.

They will happily create:

  • a helper for the helper
  • a compatibility shim for code written 11 minutes ago
  • a 700-line test file
  • three “shared” abstractions used once
  • a function named like it has a mortgage

fix-hairball exists to run the cleanup loop on purpose.

What It Does

Under the hood, it runs:

npx commands-com quality --until A

It asks multiple AI reviewers what is wrong, synthesizes the useful complaints, splits the fixes into parallel tasks, applies them, runs checks, then does it again.

Very glamorous.

Mostly it deletes things.

The Philosophy

If code can be clean in 50 lines, it should not be 200.

If an abstraction exists only because yesterday’s abstraction got lonely, it should go.

If the repo has “legacy compatibility” for something created this morning, everybody needs a walk.

Try It

npx fix-hairball

It will not make you a better engineer.

But it may make your repo look like one was involved.


Arrowjet is now a Cross-Database Sync Tool in Python (PG, MySQL, Redshift)

I’ve been building Arrowjet, an open-source Python library for fast bulk data movement. It started as a Redshift speed tool, but it now supports PostgreSQL, MySQL, and cross-database transfers.

The latest addition: stateful sync that keeps tables in sync across databases.

The problem

Moving data between databases usually means writing custom scripts per source/destination pair. Add incremental logic, schema drift handling, retry on failure, and you’re maintaining a mini-ETL framework.

What sync does

One function call:

import arrowjet
from arrowjet_pro import sync

pg = arrowjet.Engine(provider="postgresql")
my = arrowjet.Engine(provider="mysql")

result = sync(
    source_engine=pg, source_conn=pg_conn,
    dest_engine=my, dest_conn=mysql_conn,
    table="orders",
    key_column="updated_at",  # incremental
)
# Sync SUCCESS: 12,000 rows (incremental)

It decides full vs incremental automatically based on previous state. Truncates destination on full sync. Validates row counts after. Retries with backoff on failure.

Schema-level sync

Sync an entire schema with filtering:

from arrowjet_pro import sync_schema

result = sync_schema(
    source_engine=pg, source_conn=pg_conn,
    dest_engine=my, dest_conn=mysql_conn,
    schema="public",
    exclude=["*_tmp", "*_backup"],
)
# Multi-table sync: ALL OK
#   Tables: 14/14 succeeded
#   Total rows: 2,340,000

YAML config for repeatable jobs

source:
  profile: my-postgres
destination:
  profile: my-mysql
defaults:
  mode: auto
  key_column: updated_at
  retry: 2
tables:
  - orders
  - users
  - name: products
    dest_table: product_catalog
    mode: full

CLI

arrowjet sync --table orders 
  --from-profile pg --to-profile mysql 
  --key-column updated_at

arrowjet sync --schema public 
  --from-profile pg --to-profile mysql 
  --exclude "*_tmp" --dry-run

Under the hood

All transfers use the fast path for each database:

  • PostgreSQL: COPY protocol (850x faster than INSERT)
  • MySQL: LOAD DATA LOCAL INFILE (6.6x faster)
  • Redshift: COPY/UNLOAD via S3

Arrow is the in-memory bridge between databases. No intermediate files, no serialization overhead.

Future

  • pip install arrowjet – bulk read/write/transfer, CLI, 3 database providers
  • pip install arrowjet-pro – sync, drift detection, schema auto-fix, alerting, operation log

GitHub: https://github.com/arrowjet/arrowjet PyPI: https://pypi.org/project/arrowjet/0.6.0/

The Decomposition Problem: Why Breaking Tasks into Agent-Sized Pieces Is Harder Than It Looks

The Decomposition Problem: Why Breaking Tasks into Agent-Sized Pieces Is Harder Than It Looks

Every operator who has worked with autonomous agents has experienced this: you carefully decompose a complex task into clean, discrete subtasks, hand them to an agent, and watch it reconstruct them into something that doesn’t resemble your original intent. The decomposition looked logical on your whiteboard. The execution looked logical from the agent’s perspective. But the output is wrong in ways that are hard to diagnose.

The problem isn’t the agent’s capability. It’s the decomposition itself.

Why Human Decomposition Fails

Human beings decompose tasks based on linear causality. We draw diagrams where A leads to B leads to C, and each step has a clear input-output relationship. This works perfectly for physical tasks and well-defined software workflows.

But agent tasks rarely have clean linearity. They have loops, feedback cycles, and implicit context that humans absorb unconsciously but agents must reconstruct explicitly.

Consider: you want an agent to “research competitor pricing and draft a pricing strategy memo.” You break this into steps: (1) gather competitor prices, (2) analyze pricing patterns, (3) draft recommendations. It sounds reasonable. But step 3 requires knowledge that isn’t in step 2’s output—things like your product’s positioning, your sales team’s discount patterns, your enterprise customers’ willingness to pay. The agent doesn’t know to pull this context unless you tell it to.

This is the decomposition problem: humans decompose tasks based on how tasks feel sequential. Agents decompose based on what’s actually in each data payload.

The Atomic Unit Fallacy

The instinct when things go wrong is to decompose further. Make the tasks smaller. More discrete. More atomic. This usually makes things worse.

When you break a task into units that are too small, you lose the coherence that makes the task tractable. A research subtask that says “find competitor pricing” is executable but lacks the guiding context of “find competitor pricing so we can identify underpriced segments.” Without that context, the agent optimizes for the wrong objective. It returns comprehensive pricing data instead of actionable pricing insights.

The agent’s cost function is implicit in how you phrase the task. Atomic tasks strip away the cost function.

The Thick Slice Principle

The better framing is thick slices rather than atomic units.

A thick slice contains:

  1. The objective — what decision this work informs
  2. The context — what background knowledge the agent needs
  3. The constraints — what success looks like, including what to avoid
  4. The output format — how the agent should structure its response

A thin slice contains only the action: “find competitor pricing.” A thick slice contains: “find competitor pricing for our top 5 rivals in the SMB segment, focusing on entry-level tiers and bundling patterns. I need this to inform a pricing decision next week. Return a structured comparison with per-feature pricing breakdown, not just list prices.”

Thick slices are more work upfront. They require you to think through what you actually need, not just what feels like the logical first step. But they dramatically reduce the reconstruction cost on the back end.

Failure Modes When Decomposition Goes Wrong

The most common failure mode isn’t task failure—it’s tangential success. The agent completes the decomposed subtasks with high fidelity, but the completion is irrelevant to the original goal. The research was thorough. The analysis was sound. The recommendations were confidently wrong for your specific market.

This happens because decomposed subtasks get their own optimization targets. Each subtask becomes “do this subtask well” rather than “move toward the original goal.” The agent loses sight of the forest for the trees, not because it’s stupid, but because you inadvertently made each tree a separate objective.

Another failure mode is context fragmentation. When tasks are broken into disconnected units, each unit loses the surrounding context. The agent working on step 7 doesn’t know what step 3 found, unless you explicitly wire that information flow. In human teams, this happens naturally through shared context and whiteboards. In agent systems, you have to build it explicitly.

The Decomposition Review

Before sending work to an agent, run a decomposition review. For each subtask, ask:

  1. Does this subtask have an explicit connection to the final goal, or only an implicit one?
  2. Is there context this subtask needs that lives in other subtasks?
  3. What would this subtask’s output look like if it were perfectly executed but irrelevant to the goal?
  4. What information does the next subtask need from this one that isn’t currently specified?

If you find gaps, thicken the slice. Add context. Add constraints. Add output specifications.

The goal isn’t to remove the need for agent judgment—it’s to give the agent the context it needs to exercise judgment correctly.

Breaking tasks into agent-sized pieces isn’t a sizing exercise. It’s a reasoning exercise. And most of us are doing it backwards.

Our 2026 Direction: AI and Classic Workflows in JetBrains IDEs

Two valid ways of writing code. One place to own it.

Quick version for AI-news-tired readers:

There are two ways developers create code now:

  1. The classic way: By typing, refactoring, debugging, and building up intent line by line.
  2. The new way: Through collaborating with AI – sometimes via autocomplete and other times by using an agent that can draft whole chunks of work.

We don’t think one is better than the other.

Our goal is to ensure both workflows can coexist inside JetBrains IDEs without hindering each other. In practice, this means that:

  • If you want to write code yourself, the IDE should be focused on code writing, and AI shouldn’t compromise the core coding experience.
  • If you want to generate code with AI (or delegate tasks to agents), the IDE should make that feel natural and powerful, both in terms of UX and functionality.

Either way, one thing doesn’t change: A human is responsible for the code that ships. And the best place to read, understand, and own that code is still the IDE.


What “AI in the IDE” means without the snake oil or hype

We’re not limiting this to one “official” workflow. The market is moving too fast for that – and developers are too diverse for a one-size-fits-all approach.

So when we say “AI in JetBrains IDEs”, we mean agentic added value: UX and features that become available as and when useful:

  • In the AI Chat tool window, as a chat-first workflow.
  • in the IDE terminal, where many developers already work with CLI tools.
  • In the new opt-in modes created for agentic systems, where you can run an agent and leave it to work for hours.

Think of it as follows: One IDE, with multiple AI-powered ways to get work done – picked by the user, shaped by the team, and constrained by real development expectations.


The AI strategy: Avoid vendor lock‑in and keep workflows compatible

If there’s one thing we’re confident about, it’s this: The “best” model, provider, or agent today won’t be the best forever – or perhaps even next month.

That’s why we’re deliberately building toward an IDE experience that does not depend on a single vendor’s roadmap.

Practically, that means our AI chat experience supports multiple ways to connect – depending on what’s allowed by providers’ terms, and what users actually want:

  • JetBrains AI-managed setup (with JetBrains AI subscription).
  • BYOK: Bring your own API key.
  • OAuth sign-in for supported provider accounts (where the provider supports it).
  • ACP agents: Connect external coding agents through a standard protocol.

One honest footnote: OAuth isn’t always available. If an agent provider doesn’t offer OAuth (or doesn’t offer it in a way an IDE can use), we can’t invent it.


Agent Client Protocol (ACP): “Bring your own agent”

ACP lets you connect external coding agents to JetBrains IDEs through a standard interface, so the IDE doesn’t need a bespoke integration for every agent. Agents can be installed from a curated registry (or configured manually), and the installed agents appear inside the AI chat. 

A practical example of one that people have been asking for is the Cursor agent. Cursor is already available as an AI agent inside JetBrains IDEs through ACP – you can select it from the agent picker and use its agentic workflow inside your JetBrains IDE. 

This is the shape we want:

  • You choose the agent that fits your workflow or team.
  • You keep working in the IDE you already rely on.
  • Classic IDE workflows don’t get shoved aside for “agent mode”.

“Professional coding with AI” means more responsibility

We’re not anti-AI. We’re anti-confusion.

There’s a kind of coding that’s optimized for disposable output – and it’s totally valid in the right context. But JetBrains IDEs are built for code that isn’t disposable, but rather for code that is intended for long-term use.

So here’s the principle we design for: Generated code should be treated like real code. That means it should be possible to:

  • Read it
  • Review it
  • Change it
  • Revert it when it’s wrong
  • Understand its impact on the codebase

In practice, our baseline expectation is boring (in the best possible sense):

  • Changes should be visible
  • Changes should be reversible
  • Your project isn’t left in a broken state (“no red code” is a pretty good starting point)

And yes, agents can edit many files. That can be a superpower – but only if you can fully inspect, understand, and correct the outcome. That’s where the IDE matters: It gives you visibility and control over the code produced by humans or AI.


AI on your terms: our product commitments

1. AI and classic modes live side by side 

Typing-first workflows and AI-first workflows are both valid. We’re not building for developer-replacement narratives, and we’re not building an IDE that nudges you into a single “approved” way of working. We respect both approaches. 

2. AI agents must respect the core IDE promise

Every push toward agents must keep the IDE’s core promise intact: deep code intelligence, safe refactoring, debugging, navigation, inspections, reviews – the stuff professional development is made of.

3. Zero vendor lock-in

Multiple activation pathways (subscription, BYOK, OAuth, where possible, and ACP agents) are not a “nice to have.” We are committed to ensuring your workflow is never tied to a single vendor.

4. Long-term utility over hype

If people keep using these workflows weeks later (real retention, real projects), that’s the signal. A lot of AI-driven workflows today are just hype (I’m talking about you, Ralph-loop). 

5. Prioritizing candid community feedback

We value the honesty of Reddit users, Marketplace reviewers, and community members who don’t owe us politeness. Those are exactly the people we want judging our progress.


AI will create a lot of code. That’s not a prediction anymore – it’s the reality in April 2026.

But someone still has to be responsible for that code. Someone still has to read it before it merges. And right now, agents can help you move fast – but they can’t carry the risk for you.

So our commitment is straightforward:

We’ll keep building AI workflows that speed up creation – and we’ll keep strengthening the IDE as the best place to review, understand, and own what gets shipped.

You decide how much AI you want. We’ll make sure both paths – AI-assisted and classic – work great together, but you can stay on the path you prefer.

React vs. React Native: The difference, and which is best for you

Choosing between React vs. React Native for your project can be confusing. Both JavaScript user interface (UI) libraries serve similar purposes and use the same syntax, but their differences are important. React is designed for building user interfaces for web front ends, while React Native helps you build native mobile apps for Android and iOS.

This article explains what React and React Native are and their differences, and provides context and information so that you can decide which to use for a particular project.

React and React Native are not the same thing

React and React Native are two distinct JavaScript libraries for developing user interfaces. While React serves as the foundation for React Native, they are not the same thing, and serve different purposes when developing user interfaces:

  • React is intended for building user interfaces for web applications that run in the browser. It lets you create reusable UI components using your own designs implemented using CSS, or using a pre-built user interface library.

  • React Native lets you use React to build mobile applications that look and behave like native applications. Rather than defining your own look and feel, it adopts the appearance of the native UI elements of the operating system (like buttons, lists, and inputs), while still letting you develop your own broader design using familiar React concepts and syntax.

Both libraries use the same core React syntax and component-based architecture.

Before deciding which JavaScript UI library to adopt for a project, it’s worth understanding each in detail. As React Native is built on React, the programming knowledge is transferable, so it’s less a matter of deciding which you will invest your time learning, and more about learning React and then identifying when it would be better to use React Native on a per-project basis.

What is React?

React is an open-source frontend JavaScript library that is developed specifically for building user interfaces for applications that run in a web browser. It lets you create reusable UI components (known as a component-based architecture), reducing the code you need to write and providing a consistent and efficient codebase.

React uses JSX, an extension to JavaScript that lets you include the HTML for your reusable UI components alongside their JavaScript in the same file, which some developers prefer as it makes your codebase easier to understand and navigate.

Another major feature of React is the virtual DOM: a representation of the HTML document displayed in the browser that you can manipulate programmatically, and that React then automatically syncs to the real DOM as shown to the user. This feature lets you use React to make dynamic pages that don’t have to reload to change their contents, with much less code than would be required if working from scratch.

Due to React’s lightweight nature, you can use it to provide as little or as much interactivity in a web page as needed, and you can add it to existing projects. Alternatives to React for web development include Vue.js and Angular. React is used by websites like Facebook, Instagram, and Netflix to power their user interfaces.

Below is an example of an HTML list rendered in React using JSX syntax:

// Import the React module
import React from 'react';

// Create the React component 
const App = () => {
    const items = ['Apple', 'Banana', 'Cherry']; // List data

    return (
        <div>
            <h1>Fruit List</h1>
            <ul> 
                {items.map((item) => (
                <li key={item}>{item}</li> /* Item names in the example array are unique strings, so they can be used as the key */
                ))}
            </ul>
        </div>
    );
};

export default App;

What is React Native?

React Native was developed so that React developers could create mobile apps with their existing React skill sets. It allows for efficient app development, as you can share much of your code between all of your web and native applications (Windows, iOS/iPadOS, and Android).

In addition to letting you leverage existing React skills, tools, and techniques to cover cross-platform native app development, React Native lets you build applications that look and feel like they were designed for each platform from the ground up.

Rather than building your own UI elements and interacting with a virtual DOM, you use React Native’s buttons, lists, panels, and other included components to create applications that look like, animate like, and conform to the host’s design system. Apps built with React Native include Discord, Uber, and Skype.

Below is an example of the same list as above, but implemented using React Native user interface elements:

// Import the React module as well as the React Native UI element modules for View, Text, and FlatList
import React from 'react';
import { View, Text, FlatList } from 'react-native';

// Create the React Component
const App = () => {
    const items = ['Apple', 'Banana', 'Cherry']; // Sample list data

    return (
        <View> 
        <Text style={{ fontSize: 24 }}>Fruit List</Text> 
        <FlatList 
            data={items}
            keyExtractor={(item, index) => item} // Item names in the example array are unique strings, so they can be used as the key
            renderItem={({ item }) => (
            <Text style={{ fontSize: 18 }}>{item}</Text> 
            )}
        />
        </View>
    );
};

export default App;

You’ll notice that while React and JSX syntax is used in both the React and React Native examples, the React example uses HTML elements like

and

    whereas the React Native example uses native UI components like and .

    The behavior of each example is the same, but the UI provided by React will require CSS to style it, whereas the React Native UI elements will automatically adopt the appearance of the mobile platform they are run on (it’s worth noting that you can alter the appearance of React Native components).

    What is React Native for Web?

    Web browsers don’t include native UI components for React Native to display. React Native for Web makes it possible to deploy React Native apps for delivery to web browsers by providing a set of web-compatible HTML UI components to use in place of the missing native components.

    This allows you to use React Native to build both mobile and web applications, and while React Native for Web isn’t a core part of React Native, it is widely supported and used by the React community, and is actively maintained.

    React Native for macOS and Windows

    It’s also possible to use it to develop desktop applications using React Native for Windows and React Native for macOS.

    When should you use React?

    You should use React to build user interfaces for your web development projects when you:

    Want to benefit from the component-based architecture and interactivity React provides.

    Are building web applications that will run in a web browser.

    Need to design bespoke interfaces with unique visual elements that differ from the visual style of the host operating system.

    When should you use React Native?

    You should use React Native when you:

    • Want to take your React skills and use them to build native mobile or desktop apps.
    • Require a consistent user interface that adopts the appearance of the host operating system.
    • Are building native apps that you will publish to the Apple App Store, Google Play, and Microsoft Store.
    • Are developing an application that doesn’t rely on HTML — React Native has no DOM, so everything must be constructed with React Native UI components.

    Choosing the best tools for your project

    React is a powerful user interface development tool, greatly streamlining the frontend development process. React Native builds on this by letting you use React to build native mobile apps as well as web apps, for full platform coverage using the same language and tools.

    However, that doesn’t mean React (or React Native) is necessarily right for your project: there are a number of other user interface libraries and technologies, each with their own use cases and advantages. In some cases, a full application framework may accelerate your development process by providing a code foundation and boilerplate functionality for your apps.

Field Learnings with OpenClaw and WhatsApp

Technical notes extracted by Claude from deploying an agentic WhatsApp bot to production (OpenClaw 2026.4.23). Focus on things not in the official docs or that cost hours of debugging.

High-Level Architecture

OpenClaw is a self-hosted agentic gateway that routes messages between:

  • Channels (WhatsApp via Baileys, Slack, Discord, Telegram, etc).
  • Agents (isolated objects with workspace, persona, model).
  • Tools via MCP (Model Context Protocol — standard protocol).

The main process is the gateway (Node 24, listens on :18789), which maintains a Baileys session per WhatsApp account and triggers agents on demand.

Config: JSON, Not YAML

The active config is ~/.openclaw/openclaw.json (under the node user, uid 1000). The env var OPENCLAW_CONFIG=/path/to/yaml is ignored by the gateway. The schema is huge (49.5k lines), validated via JSON Schema draft-07.

Useful commands:

openclaw config schema        # Full JSON Schema (stdout)
openclaw config get <path>    # read value
openclaw config set <path> <value> --strict-json [--dry-run] [--replace]
openclaw config set --batch-file /tmp/batch.json --strict-json

config set automatically creates a .bak before overwriting. A gateway restart is required to apply changes (docker restart openclaw-gateway).

Gotcha — . in paths: if the path contains . (e.g., a JID like 120363406566286319@g.us), the parser interprets it as an object separator. Workaround: set the entire object one level up (channels.whatsapp.groups, with value being a dict).

Inheritance Bug: Must Set on Both Channel + Account

channels.whatsapp.<X> is not inherited by channels.whatsapp.accounts.default.<X> during resolveMergedAccountConfig. Silent symptom: you set it on the channel, the value is “default” at runtime, and the gateway applies the fallback. Config changes must be duplicated:

{
  "channels.whatsapp.groupPolicy": "allowlist",
  "channels.whatsapp.accounts.default.groupPolicy": "allowlist",
  "channels.whatsapp.groupAllowFrom": [...],
  "channels.whatsapp.accounts.default.groupAllowFrom": [...]
}

groupAllowFrom Is a Sender List, Not a Group List

The name is misleading. groupAllowFrom is validated against senderE164 (the phone number of the message sender), via isNormalizedSenderAllowed(). It is not an allowlist by group.

There is no native group JID allowlist in OpenClaw. To restrict to a specific group, the options are:

  • Operational: the bot is in only one group.
  • Per user: list authorized phone numbers in groupAllowFrom. The bot responds when ONE of them speaks in ANY group (with default mention).
  • Combined: requireMention: true (default) everywhere, with an exception via groups.<JID>.requireMention: false for the main group.

WhatsApp in DinD

The <container_name> container is Docker-in-Docker. The Docker daemon that mounts volumes belongs to the outer host (<hostname>), not the inner container. Symptoms:

  • Bind-mounting a file creates a directory instead: the daemon looks for the file on its own filesystem, doesn’t find it, and creates an empty dir. Solution: package files in a thin Dockerfile via COPY (instead of bind mounts).
  • localhost doesn’t resolve in Alpine containers: use 127.0.0.1.
  • Binding 127.0.0.1:18789 on the host conflicts: use expose: instead of ports:. To access the UI externally: docker exec or port-forward via SSH.

Baileys Pairing

docker exec -it openclaw-gateway openclaw channels add --channel whatsapp
docker exec -it openclaw-gateway openclaw channels login --channel whatsapp

The second command opens an ASCII QR code in the terminal. It must be a TTY (docker exec -it + ssh -t if via SSH). Pair with the phone app under Linked Devices. Session is persisted in a Docker volume.

Session expires after a few days. Symptom: channels status --probe reports linked, connected, in:Xm ago but messagesHandled: 0. Common root cause: error 1006 from failed hydrating participating groups on connect. Solution: logout + login (new QR).

docker exec openclaw-gateway openclaw channels logout --channel whatsapp
docker exec -it openclaw-gateway openclaw channels login --channel whatsapp

After login, verify with directory groups list — if it returns the group list, hydration completed successfully.

append Skip Bug After Restart

Each gateway restart triggers a Baileys reconnect. Messages arriving during this window come with upsert.type === "append" (history sync). The code path in /app/dist/extensions/whatsapp/monitor-BXydC-6q.js around line ~967 checks:

const msgTsNum = msg.messageTimestamp != null ? Number(msg.messageTimestamp) : NaN;
if ((Number.isFinite(msgTsNum) ? msgTsNum * 1e3 : 0) < connectedAtMs - 60_000) continue;

If messageTimestamp is absent, the fallback 0 makes the comparison always true — skipping the message. Patch: change : 0 to : Date.now(). This is a manual edit in a dist file; it must be redone after each docker compose build. Issue tracker: openclaw/openclaw#19856.

groupAllowFrom Bug (issue #54613)

Multiple issues report “DMs work, groups don’t” or “messagesHandled stuck at 0 even when connected”. The actual cause is a combination of:

  • groupPolicy must be set on both channel + account (inheritance bug).
  • groupAllowFrom must contain E.164 sender numbers, not JIDs.
  • groups.<JID>.requireMention defaults to true and silently blocks in applyGroupGating if the message has no real mention (and WhatsApp Web doesn’t always mark mentions correctly).

Full workaround is documented in @pandeysoni’s comment on issue #54613.

Sessions and Conversation Context

OpenClaw has native sessions per channel+group. SessionKey:

agent:<agentId>:whatsapp:group:<JID>

Persisted in ~/.openclaw/agents/<agentId>/sessions/<uuid>.jsonl — JSONL with each turn (user message + tool calls + agent response). Consecutive messages in the same group share context, so “add 1 more” after “how much sugar does it have?” works.

To debug a conversation:

docker exec openclaw-gateway cat ~/.openclaw/agents/main/sessions/<uuid>.jsonl

MCP Transport: Legacy SSE, Not Streamable HTTP

OpenClaw 2026.4.x uses legacy HTTP+SSE for MCP, not Streamable HTTP (the newer protocol). The client sends a GET to the configured URL and expects a text/event-stream response with an event: endpoint handshake. Servers that return 405 on GET (common with Streamable HTTP-only stateless servers) fail with SSE error: Non-200 status code (405).

Solution: implement SSEServerTransport from @modelcontextprotocol/sdk alongside Streamable HTTP, exposing GET /sse (handshake) + POST /messages?sessionId=<id> (client messages). Configure MCP in OpenClaw pointing to /sse:

openclaw mcp set <name> '{"url":"http://host:port/sse"}'

Gateway Mode Is Required

gateway.mode must be set (local or remote). Without it, gateway start is blocked and openclaw doctor complains. The default is not populated — missing this once cost a full day of debugging.

Useful Debug Commands

# General status
openclaw doctor
openclaw channels status --probe

# View recent inbound/outbound
docker exec openclaw-gateway cat /tmp/openclaw/openclaw-$(date +%F).log | grep web-inbound | tail -5
docker exec openclaw-gateway cat /tmp/openclaw/openclaw-$(date +%F).log | grep web-auto-reply | tail -5

# MCP discovery
docker logs openclaw-gateway | grep bundle-mcp

# Heartbeat (check messagesHandled and lastInboundAt)
docker exec openclaw-gateway tail -3 /tmp/openclaw/openclaw-$(date +%F).log

# List groups visible to Baileys (after hydration)
openclaw directory groups list

Strategy for Debugging Silent Symptoms

When “messages aren’t arriving” and no log explains it, patch the dist file with console.error at critical points. The path is /app/dist/extensions/whatsapp/monitor-BXydC-6q.js (the hash in the filename changes with each release). Useful points to instrument:

  • handleMessagesUpsert (entry) — confirms Baileys delivers
  • normalizeInboundMessage null returns — ACL, recent outbound echo, status broadcast
  • enrichInboundMessage null return — unsupported format
  • claimRecentInboundMessage — dedup
  • enqueueInboundMessage — confirms entry into the pipeline

Back up first (cp file file.bak), then cp file.bak file to restore.

Recommendations for Other Deployments

  • Avoid DinD if possible. The outer host’s Docker daemon vs the container runs in different namespaces, and bind mounts break silently.
  • Use mcpServers from the start instead of proprietary TS plugins. MCP is the official path and is reusable (Claude Desktop, Cowork, etc. consume the same server).
  • Patch dist files carefully. Keep versioned backups; an OpenClaw upgrade will overwrite the files, losing patches. Consider forking the image with a multi-stage Dockerfile.
  • Baileys sessions are fragile. Schedule a preventive weekly restart (cron) and monitor messagesHandled in the heartbeat — if it stays at 0 for more than 1h while connected, it’s time to re-login.

Building or Buying: The Agentic Analytics Dilemma

Every company, when evaluating new tools, technologies, or infrastructure, eventually runs into the same question:

“Should we build this ourselves or buy a ready-made solution?”

The default answer is often: “We can do it ourselves.” And technically, that’s true.

But the real question isn’t whether it’s possible. It’s how fast and how efficiently you can get there. How long will it take to get something working? And more importantly, how long will it take to make it reliable, maintainable, and usable across the company?

Those are very different problems, and in the context of agentic analytics, the gap between them is especially wide.

We often start with the wrong question

Most build vs. buy discussions are approached with a narrow perspective:

“If we simply plug an LLM into our database and documentation, will that give us what we need?”

In early demo stages, this option often works surprisingly well. But it reduces the problem to a single dimension: evaluating model performance on a limited snapshot of data and context.

What it doesn’t capture is what happens next, once the system is used across teams, over time, in real workflows. Questions of consistency, reuse, maintainability, cost, and integration – all of which matter in production – are often overlooked at this stage, even though they ultimately determine whether the system succeeds or fails.

So the real question isn’t: “Can we make this work?”

It’s: “What does it take to make this work reliably across the business, over time?

Where most DIY approaches fail

In the early stages, DIY setups often look promising. You connect an agent to your warehouse, add some documentation, and run a few queries. The results can be impressive, especially compared to having no solution at all.

But the issues don’t show up in demos. They show up later as the scope expands and becomes more complex. They usually revolve around four main pitfalls commonly found in organizations.

1. Ambiguous business logic

DIY setups typically rely on documentation written in plain English, data catalogs, or a mix of both. These are quick to produce, but they leave room for interpretation, especially across teams that use different definitions for the same metrics.

Take a simple example: What does “active customer” actually mean?

Is it someone who logged in in the last 30 days, made a purchase, or holds an active subscription?

Without a formal definition, the agent has to guess the meaning. And those inferences are not stable; they shift depending on context, phrasing, or even the model’s behavior. Over time, this ambiguity accumulates and leads to inconsistent answers that often look correct but aren’t.

2. Answer quality is a context problem

It’s tempting to assume that better models will fix these issues. In reality, answer quality depends far more on the structure of the underlying context than on the model itself.

When metrics are defined in a structured and consistent way, queries become repeatable. The same question leads to the same result, grounded in the same logic.

Without that structure, each answer becomes a new interpretation. That’s why systems that perform well in controlled benchmarks can fail in production, where the same questions are asked repeatedly, by different people, in slightly different ways.

3. Two sources of noise

Agentic analytics sits at the intersection of two unavoidable sources of noise:

  • The first comes from how users ask questions. Natural language is flexible, and the same intent can be expressed in many different ways.
  • The second comes from how metrics are defined. When definitions are written in free-form text, they introduce ambiguity and inconsistency.

These two types of noise amplify each other. As both the questions and the definitions become more complex, the system becomes increasingly unstable – unless there is a clear, structured layer underneath.

4. Maintainability is the real bottleneck

This is where most DIY projects start to break down.

Even if the system works initially, it raises a series of difficult-to-answer questions as time progresses.

What happens when a metric definition changes? How do you correct inaccurate answers? How does the system evolve as new data sources or teams are added? And what happens when the person who built the original setup is no longer involved?

Beyond that, there are operational concerns: tracking usage and adoption, controlling cost per query, and monitoring answer quality over time.

At this point, the scope has expanded well beyond a simple agent. What started as a quick experiment has grown into a broader system encompassing a semantic layer, integrations, monitoring, and internal workflows. In practice, you are no longer building a tool; you are maintaining an internal product.

The hidden cost of “just building it”

What begins as a lightweight prototype quickly turns into a multi-surface system. It needs to integrate into communication tools like Slack or Teams, provide usable interfaces, expose APIs or MCP servers, manage permissions, and offer visibility into performance and usage.

Each of these components introduces its own complexity. And most teams don’t account for this upfront, discovering it gradually, once the system is already in use.

This pattern shows up again and again:

  • Month 1: A prototype works → strong internal excitement.
  • Month 3: Inconsistencies appear → more prompt tuning.
  • Month 6: Another team tries it → results don’t transfer.
  • Month 9: Maintenance becomes ad hoc.
  • Month 12: The team starts evaluating alternative platforms.

DIY approaches can work, but they rarely scale without significant ongoing investment.

What actually matters when deciding whether to build or to buy

When evaluating whether to build or buy, the decision usually comes down to a few core considerations:

  • How quickly can you define your business logic in a way that is unambiguous and reusable?
  • Will your approach remain flexible as your data stack evolves?
  • Can you ensure that answers remain consistent over time?
  • Does the system improve with usage, or require continuous manual effort?
  • And finally, who is responsible for building and maintaining the full stack around it?

These questions matter far more than whether a prototype works on day one.

Who should actually build

There are cases where building your own solution makes sense. Typically, these are large organizations with dedicated platform teams, the resources to maintain a semantic layer as a product, and a long-term commitment to developing internal tooling.

For most companies, however, that level of investment isn’t realistic.

In the end, the dilemma is simpler than it appears:

Do you want to build and maintain an internal product, or use an existing one?

And if you choose to buy, the more important question becomes whether the platform you choose will remain flexible, transparent, and maintainable over time.

About Databao

Databao is built around this exact problem: making agentic analytics reliable without requiring teams to build and maintain the entire system themselves.

It focuses on generating a structured semantic layer automatically, keeping it aligned with real usage, integrating directly into existing workflows, and ensuring consistency over time.

If you’re evaluating how to bring AI into your analytics stack, we’d be happy to explore the process with you and provide a proof of concept for your individual use case.

TALK TO THE TEAM

Popular Go Web Frameworks: A Practical Guide for Developers

According to the 2025 Go Developer Survey, 46% of Go developers use the language to build websites and/or web services. It’s therefore unsurprising that the topic of web frameworks frequently pops up in conversation and is often the subject of healthy debate.

The GoLand team enters the chat armed with data to answer the question: What are the most popular web frameworks for Go developers and why?

Do I even need a framework?

Developers from environments that rely heavily on frameworks, such as JavaScript, will naturally seek out frameworks to simplify or reduce their workload. Meanwhile, hardcore Gophers will reject external libraries and frameworks altogether as superfluous dependencies that ultimately make their work harder. Both sides are right to some extent; using Go’s standard library exclusively comes with its own set of pros and cons.

Reasons to use net/http

  • Robustness: Go famously has a “batteries included” approach, and the net/http package is no exception. Go’s standard library provides a solid foundation for building web services; in particular, it already includes routing, middleware composition via handlers, and an HTTP server implementation.
  • Simplicity: The standard HTTP package has no extra frills or dependencies. This means developers often write more boilerplate, but it also provides clear and predictable building blocks that can be composed however a project requires.
  • No dependencies: Some developers prefer to exclusively use net/http, so as to avoid external dependencies. Third-party libraries are only good as long as they’re maintained, and they can always introduce security risks and maintenance overhead. Especially in larger commercial projects, these limitations are often unacceptable.
  • Full control: Developers who stick with net/http have full control over their code and don’t have to pay the “overhead tax” for features they don’t use that come with the libraries.
  • Maintenance and growth: Go is regularly maintained by the Google team, and new features are added consistently, such as enhanced routing patterns in 1.22.
  • Standardization: Since every Go developer knows net/http (or so we hope), in commercial settings, this eliminates the need to learn new tools to become productive when a new developer is hired.

Reasons not to use net/http

  • Lack of built-in abstractions: It’s not that the standard library can’t handle complex scenarios; it’s that it can quickly turn into a nightmare for the engineer who has to provide instructions on how to handle them. Many developers turn to external libraries for the convenience they provide when it comes to routing or middleware management.
  • Productivity loss: As is often the case with Go, using standard solutions equals writing a lot of boilerplate code to stitch things together, which forces developers to work on mundane tasks, negatively affecting their productivity.

Whether you are convinced by the arguments for or against, the truth remains that – according to JetBrains State of Developer Ecosystem Report 2025 – as much as 32% of Go developers use net/http, and its popularity remains largely unchanged.

Most popular Go web frameworks

Unlike a lot of other languages – as is the case with Ruby and Rails or Python with Django or Flask – there isn’t one dominant framework that every Go developer would recognize and use. While stdlib remains a popular choice, our data shows that it has a formidable opponent, used by almost half of Go developers – Gin.

On top of that, in our analysis of The Go Ecosystem in 2025, we’ve identified the most widely used web frameworks to be Gin (48%), Gorilla (17%), Echo (16%), and Fiber (11%).

Now, let’s look at how they stack up against each other and against net/http and see if there is a clear winner when it comes to web frameworks for Go (spoiler alert: There isn’t 😉).

Gin

Gin is an HTTP web framework for building REST APIs, web applications, and microservices in Go. It offers middleware support, JSON validation, route grouping, error management, and built-in rendering. Gin is highly extensible and remains the top choice for Go developers as one of the fastest regularly maintained frameworks with a developer-friendly API. It has over 88,000 stars on GitHub and a sizable community around it, so you can expect to find a lot of examples and support from other developers when you run into trouble.

You can create a router engine in Gin with (gin.Default()) or without (gin.New()) middleware attached, depending on how much control you need. gin.Default() comes with logger and recovery middleware out of the box. Other middleware lives in the official gin-contrib collection, where you can find a CORS mechanism, as well as authentication, session manager, pprof, and other tools.

Gin’s creators boast that its “performance [is] up to 40 times faster than Martini”, though in 2026, this probably doesn’t indicate much. Thankfully, they also run their own benchmarks, allowing you to compare Gin’s performance against a number of more modern libraries as well. And while Gin is not the most performant in all scenarios (Aero actually takes that cake), the results are still very close to the top across the board. This is largely due to zero-allocation routing, which keeps the app memory usage stable even under high traffic.

Gin is an opinionated framework, which means it follows its own approach. For example, it uses gin.Context instead of the standard context.Context. It is still built on top of net/http, but if your code depends heavily on Gin-specific features, moving to another framework later may require extra work.

Pick Gin if you want a framework that:

  • Is familiar to most developers and thus easier to adopt.
  • Has community support and lots of learning resources, making onboarding and troubleshooting easier.
  • Provides simple, widely adopted patterns for easier development.

Echo

Echo is yet another high-performing and minimalist framework that has an HTTP router without dynamic memory allocation. It includes automatic TLS, support for HTTP/2, middleware, data binding and rendering, and various template engines. It’s also very extensible at various levels. It continues to grow in popularity, with 16% of Go developers declaring its use in 2025.

Echo has a broad catalog of official middleware that you will also find in other frameworks, such as CORS, JWT, and key authentication tools, as well as a logger and rate limiter.

Similarly to Gin, Echo is built on top of net/http, but it does deviate from it at times. For example, it uses Echo.context instead of context.Context. Also, Echo handlers use the signature func(echo.Context) error rather than http.HandlerFunc, but Echo provides adapters to integrate standard net/http handlers when needed.

Choose Echo if you:

  • Care about clean, centralized error handling and handlers that return errors.
  • Need a more structured, “batteries-included” framework.

Chi

Chi also claims to be a lightweight yet robust composable router for building Go HTTP services. Some would argue it’s not really a framework, but it’s still quite popular with Go developers, ranking as the fifth most popular alternative (used by 12% of developers in 2025).

Chi’s authors claim it offers “an elegant and comfortable design” for large REST APIs, and the framework itself is deconstructed into smaller parts. You can use the standalone core router or extend it with subpackages for middleware, rendering, and/or docgen. Other key features include full compatibility with net/http and no external dependencies. Chi uses standard Go handler types and middleware shape.

This means that Chi is compatible with all standard middleware, giving you more flexibility. Its optional middleware package includes a suite of core net/http tools, and on top of that, there are also extra middleware and other packages. Some noteworthy middleware options include: CORS, JWT auth, request logger, and rate limiter tools.

You can check Chi’s benchmarks here, though they are rather old.

It’s worth considering Chi if:

  • You want to stay close to the standard library: Some would argue there’s no point in even using Chi because you can achieve the same thing with net/http. If, however, you feel that a router would make your life easier, but you still want full compatibility with stdlib, Chi might be the choice for you.
  • You want more of a router than a full framework.

Fiber

Finally, there’s Fiber – a framework that JavaScript developers in particular will be very fond of, as it’s inspired by Express. It boasts robust routing, the ability to serve static files, API-readiness, a rate limiter, flexible middleware support, low memory footprint, support for template engines and WebSocket, and – you guessed it! – great performance. The Fiber team provides its own benchmarks here. It’s the last framework that’s been adopted by over 10% of developers according to our survey.

What differentiates Fiber from the other frameworks we’ve already discussed is that it’s built on a different HTTP engine – fasthttp. It can interoperate with net/http; however, the compatibility is provided through adapters and not through shared foundations. As Fiber’s architecture is fundamentally different from the standard library, choosing it locks you in more than other frameworks do, and migrating between Fiber and net/http frameworks typically requires more refactoring.

Considering Fiber’s architecture, it’s no surprise that it offers the broadest built-in toolbox of all the frameworks discussed. On top of that, it also has a whole host of third-party middleware maintained by the Fiber team or the community. Some of the most popular middleware options for Fiber are: a template engine, adaptor that converts net/http handlers to Fiber handlers and vice versa, Helmet integration, and key authentication tools.

Fiber is especially good for:

  • Developers with experience using Express.js: JavaScript developers who used Express before will feel right at home with Fiber because of the similarities.
  • Projects where performance is really crucial, even at the expense of idiomatic Go.

(Honorable mention) Gorilla

Strictly speaking, Gorilla is not a full-blown framework but rather a toolkit, and Gorilla/mux is just a router. But we include it on the list due to its enduring presence, with 17% of developers still using it in 2025. Even with a sharp decline in popularity compared to 2020, it’s still the third most popular choice (after Gin and net/http), despite the project no longer being actively maintained by the original team (the last update was in November 2023). While community forks continue development, most new projects today veer towards alternatives, such as Chi, or the improved routing features in Go’s standard library.

So how do they stack up?

net/http Gin Echo Chi Fiber
HTTP engine stdlib net/http net/http net/http fasthttp
Compatibility with net/http Native Partial  Partial Full Via an adapter
Maintenance Core Go Active Active Active Active
Performance High Very high High High Extremely high
Learning curve Low Low Medium Very low Medium
Standout features No dependencies; standardized solution Wide adoption; robust community support Clean error handling; “batteries-included” approach Closeness to stdlib; minimalist features Similarity to Express; extremely high performance
Dependencies None Moderate Moderate Very low Significant
Extensibility Very high Moderate – sometimes requires adaptation Moderate – requires wrapping Very high Low – mostly incompatible with standard middleware 
Ecosystem The largest and most mature; supported by Google Very mature with the largest community and adoption after net/http Mature with a strong community and long-term maintenance Mature with a sizeable community Younger framework, with a community that’s still expanding
Compatibility with net/http Native Opinionated, but built on net/http Built on top of net/http Designed around net/http – fully compatible Not directly compatible, built on fasthttp

Code samples

To show you how each framework handles API ergonomics, how verbose it is, and how it deviates from idiomatic Go, here’s a sample of the same API endpoint implemented in different frameworks.

net/http

// net/http
http.HandleFunc("/users", func(w http.ResponseWriter, r *http.Request) {
    json.NewEncoder(w).Encode(users)
})

Gin

// Gin
router.GET("/users", func(c *gin.Context) {
    c.JSON(200, users)
})

Echo

// Echo
e.GET("/users", func(c echo.Context) error {
    return c.JSON(200, users)
})

Chi

// Chi
r.Get("/users", func(w http.ResponseWriter, r *http.Request) {
    json.NewEncoder(w).Encode(users)
})

Fiber

// Fiber
app.Get("/users", func(c *fiber.Ctx) error {
    return c.JSON(users)
})

How can GoLand help web developers?

Using frameworks is not the only thing that can make your life easier; your IDE can help you stay productive as well, without locking you in. Here’s how using GoLand can help you as a web developer.

  • HTTP Client: With the HTTP Client plugin, you can create, edit, and execute HTTP requests directly in the GoLand code editor. This is especially useful when you are developing a RESTful web service or an application that interacts with one. This tool includes features like code highlighting, completion, folding, live templates, and language injections.
  • Endpoints tool: This window provides an aggregated view of client and server API used in your project for HTTP and WebSocket protocols. It can help you when you’re developing microservices, backend-frontend communication, and when you need to explore third-party APIs.

Frequently asked questions

What is the difference between Go’s standard library and a web framework?

Like in any other language, libraries are there to provide solutions to common problems and free up your time to focus on important work. While Go’s standard library, and net/http in particular, contain everything you need to build a production-ready web server, the libraries described in this article will help you avoid a lot of boilerplate and simplify common tasks such as routing, middleware composition, and request binding.

Why doesn’t Go have a single dominant web framework?

In the Go ecosystem, frameworks are optional rather than foundational. Many production services are built directly on top of net/http, while others use lightweight routers or frameworks to simplify common tasks.

Because the standard library is so robust, for many engineers, there isn’t really a good justification for using frameworks that require learning their syntax, create extra dependencies, and force regular updates. There isn’t a single dominant framework because none of them is superior to stdlib; they just offer different tradeoffs.

Are Go web frameworks necessary for production applications? Is net/http sufficient for building scalable APIs?

One of Go’s key differentiators is that, technically, you don’t need any external libraries for your application. Go’s standard library has everything you need, regardless of the scale of your project, and some hard-core Gophers stick to only that.

This is not to say that libraries are bad or useless – if they make your life easier and you’re aware of the tradeoffs, there’s really no reason not to use them.

What should I consider when choosing between Gin, Echo, Fiber, and Chi? Is one of them better for APIs or microservices?

While most Go web frameworks support common features such as routing, middleware, and JSON handling, they differ in architecture, ecosystem compatibility, and how closely they follow net/http. When deciding on the right one for you, focus primarily on what your team and project need.

  • If you’re looking for an established solution with a solid knowledge base that’s familiar to everyone, consider Gin.
  • If you need a more structured framework with centralized error handling, go for Echo.
  • If you’re after a lightweight router and need full compatibility with net/http, Chi is your best bet.
  • If you’re familiar with Express.js or you need extreme performance, even at the cost of compatibility, think about Fiber.

Does using Fiber limit compatibility with the Go ecosystem?

To a certain extent – yes, at least more than the other frameworks mentioned in this article. Because Fiber was designed around fasthttp, it had to make architectural trade-offs.

The biggest limitation is that you cannot use the vast library of generic Go middleware with Fiber out of the box. You therefore need to use middleware maintained by the Fiber team or employ an adapter (adaptor.FromHTTP), which introduces performance overhead and effectively defeats the reason to use Fiber in the first place.

[Livestream] TeamCity 2026.1: AI, Pipelines, and Enterprise CI/CD Improvements

TeamCity 2026.1 introduces a set of focused improvements that make your CI/CD more intuitive, intelligent, and enterprise-ready.

Join us for a live walkthrough of the latest updates, including support for both the Kotlin DSL and YAML in pipelines.

We’ll also introduce the new TeamCity CLI, which includes agent skills for popular AI coding agents like Claude Code, Codex, and JetBrains Junie. The TeamCity CLI helps developers run and manage TeamCity commands directly from the terminal. With added MCP support, it also connects TeamCity to leading AI tools across different environments.

📆 May 12 at 18:00 CEST

🔗 https://jb.gg/6u3izo

Register now

We’ll share how these changes fit into TeamCity’s broader evolution, including AI-assisted workflows and a more flexible pipeline experience, and what’s coming next on our roadmap.

Whether you’re already using TeamCity or exploring modern CI/CD approaches, this session will give you practical insights and a look at where TeamCity is heading.

Speaking to you

Daniel Gallo, Solutions Engineering Lead, TeamCity

Daniel is a Solutions Engineering Lead on the TeamCity team at JetBrains. With over 20 years of experience in the software development industry, he has held diverse roles, including Software Developer, Senior Systems Analyst, and Solutions Engineer. In his current role, Daniel works with customers worldwide, helping them understand TeamCity and optimize their CI/CD build pipelines.

Ernst Haagsman, Product Manager, TeamCity

Ernst is a Product Manager at JetBrains, where he works on strategy for TeamCity. In his time at JetBrains, he has worked on a range of developer tools and platforms, including IntelliJ IDEA, remote development, and IDE Services. With hands-on experience in software, DevOps, and working with enterprise customers, Ernst brings a practical perspective to improving developer workflows. Before joining JetBrains, he worked in the games industry.

Introducing the Skill Manager and Skill Repository

Install trusted skills once, then use them across agents and projects.

Two new features have just arrived in AI Assistant to address this issue: the skills manager and the skill repository. Together, they make skills easier to discover, trust, and reuse. Instead of keeping skills tied to one agent or project you can install them once and use them wherever they are needed while managing them from inside the IDE.

In practice, a skill gives an agent reusable capabilities for a specific task. The problem is that skills often stay tied to a single setup. They live with one agent, one repository, or one machine. Skills Manager changes that by making them reusable across projects and supported agents.For a quick introduction to what skills are, check out this great explanation from PyCharm Content Creator Kristel Cocoli.

Skills manager: One place to install, manage, and reuse skills

Skills are useful because they give agents reusable capabilities for specific developer tasks, whether that is debugging CI failures, working through PR comments, automating browser flows, or converting Java to Kotlin. The problem is that they often stay locked to a single setup.

Skills Manager fixes that by adding a new IDE layer for skill management. That means developers can install skills once inside the IDE and make them available across supported agents and across all projects opened in that IDE, instead of rebuilding the same setup over and over.

It also supports different ways of working depending on the task. Some skills belong at the IDE level, where they stay available across projects for an individual developer. Some belong at the project level, where they can travel with the repository and be shared through version control. Others are best kept agent-specific, tied to a dedicated workflow like CI triage, frontend work, or code review.

That is the core improvement: Skills Manager gives developers one place to discover recommended skills, choose the right scope for each one, and keep those skills available where the work actually happens.

Skill repository: A verified starting point

The skills manager makes skills easier to use. The skill repository makes them easier to get started with.

At launch, the repository gives you a JetBrains-filtered and verified list of skills, organized for easier discovery and reuse. Instead of building a collection from scratch or managing it by hand, you get a curated starting point with skills that are ready to be installed.

The repository is also designed to make adoption safer. New additions are screened to detect prompt injection, data exfiltration, and malicious code patterns. Attribution is preserved by using the skill’s own author metadata when available, or otherwise crediting the upstream maintainer or organization. That gives you a practical starting point you can trust, with useful skills, a safer adoption path, and clear credit to the people who created them.

Recommended skills to try first

Here are just a few examples from the repository that show the range of tasks where skills can be used to guide agents with improved accuracy. To view the full repository, check out this link: https://github.com/JetBrains/skills. 

  • React-best-practices –  Reusable React and Next.js guidance for writing, reviewing, and refactoring frontend code.
  • postgres-best-practicesPractical guidance for Postgres queries, schema design, performance, and security.
  • playwrightA structured way to automate and debug real browser flows.
  • pnpmBetter support for pnpm-based JavaScript projects, including workspaces and CI usage.
  • kotlin-tooling-java-to-kotlinSupport for disciplined migration from Java to idiomatic Kotlin.

Transparency and limitations

Skills Manager introduces an IDE-wide layer so developers can install skills once and make them available across supported agents and all projects opened within the IDE. That is the recommended default experience, but support is not universal yet.

  • Today, IDE-wide skill storage is supported in AI Assistant Chat for Codex and Claude Agent. Support for Junie and other ACP agents is coming.
  • For CLI workflows, the experience is different. CLI agents cannot use IDE-installed skills, so terminal-based workflows still rely on project-level or agent-specific installation.
  • Support also differs slightly between agents. Due to harness’ configuration Claude Agent can’t work with .agents folder and uses its own agent-specific location  (.claude folder), instead of the shared project location.
  • The repository will also keep expanding over time, including with more IDE-specific skills.

Get started

To get started, install the AI Assistant plugin in your JetBrains IDE. In the AI chat, click the + button and go to Skills to add, remove, and manage the skills that fit your workflow. Watch this video from JetBrains Developer Advocate Michelle Frost to see how installation works and which skills she recommends.