A Claude code plugin in an afternoon: What I learned

Plugins for AI coding tools sound like complex infrastructure. In practice, Markdown files and an HTTP API are sufficient.

listen Print view
White puzzle pieces on a blue background

(Image: Kenishirotie / Shutterstock.com)

12 min. read
By
  • Golo Roden
Contents

When someone says you should develop a plugin for an AI tool, most people think of SDKs, boilerplate code, and documentation that you have to read three times before finding the entry point. I had the same expectation when I decided a few weeks ago to build a plugin for Claude Code. Claude Code is Anthropic's command-line tool for AI-assisted software development, and for some time now, custom plugins can be developed for it and distributed via a marketplace.

the next big thing – Golo Roden
the next big thing – Golo Roden

Golo Roden ist Gründer und CTO von the native web GmbH. Er beschäftigt sich mit der Konzeption und Entwicklung von Web- und Cloud-Anwendungen sowie -APIs, mit einem Schwerpunkt auf Event-getriebenen und Service-basierten verteilten Architekturen. Sein Leitsatz lautet, dass Softwareentwicklung kein Selbstzweck ist, sondern immer einer zugrundeliegenden Fachlichkeit folgen muss.

The plugin I built integrates EventSourcingDB, a database specifically designed for Event Sourcing. For the sake of completeness: EventSourcingDB is a product of my company, the native web GmbH. However, this blog post is not about the database, but about what I learned while developing the plugin. The database merely serves as a concrete example to illustrate the insights.

Before I go into the plugin itself, a brief clarification is worthwhile. Because Claude Code plugins are not what you might expect when you hear the word “plugin.”

In the world of AI-assisted development tools, one standard has become particularly established in recent months: the Model Context Protocol, or MCP for short. MCP servers provide an AI model with tools that it can call. The model itself decides when which tool is useful and calls the corresponding function. There is already an MCP server for EventSourcingDB. MCP servers are powerful but require a certain infrastructure: you need a running server process, a transport layer, and a tool definition in JSON schema format.

Conference on AI-assisted software development in Mannheim
GenAI Summit, lines

(Image: TechSolution/Adobe Stock)

GenAI is fundamentally changing software development and has become established in the daily work of many developers. The AI tools not only take over tedious typing but also assist with complex tasks. However, to ensure secure and efficient code, one must also be aware of their risks.

The betterCode() GenAI Summit on June 11th will show which AI tools are suitable for which tasks and how AI integration works efficiently. It will also address the impact on the work of development teams.

Claude Code plugins follow a different approach. They extend Claude Code not through running processes, but through so-called skills (strictly speaking, a plugin can contain other things besides skills, but for my example, I'll limit myself to them). A skill is essentially a text file that explains to Claude Code how to perform a specific task. This sounds unspectacular at first, but it is remarkably effective. Instead of a programmatic interface, the model receives a natural language instruction that it interprets and executes. Plugins can be installed and distributed via a marketplace, making them easy for other developers to use.

What surprised me the most was the structure of a plugin. Or rather: how little structure is needed. The directory structure of the EventSourcingDB plugin, for example, looks like this:

/
  .claude-plugin/
    marketplace.json
  plugins/
    esdb/
      .claude-plugin/
        plugin.json
      skills/
        ping/
          SKILL.md
        write-events/
          SKILL.md
        read-events/
          SKILL.md
        ...

This is the entire structure. No SDK, no framework, no build step. At its core, a plugin consists of two things: a plugin.json and a collection of SKILL.md files.

Videos by heise

The plugin.json is the manifest. It defines the name, version, and a short description. For the EventSourcingDB plugin, it looks something like this:

{
  "name": "esdb",
  "version": "1.0.0",
  "description": "Interact with EventSourcingDB using its HTTP API",
  "author": {
    "name": "the native web GmbH",
    "email": "hello@thenativeweb.io"
  }
}

Each skill is in its subdirectory and consists of its SKILL.md file. This file begins with a frontmatter block containing the name and description, followed by the actual instructions in natural language:

---
name: ping
description: Check whether an EventSourcingDB instance is reachable.
---

# Ping

Send a GET request to $ESDB_URL/api/v1/ping to check whether
the EventSourcingDB instance is reachable. No authentication
is required for this endpoint. A successful response returns
HTTP 200 with the text "OK".

This is, in simplified form, the entire ping skill. Claude Code reads this description and implements it independently. It generates the HTTP call, sends it, and interprets the response. The actual logic is not in executable code, but in a precise description. The quality of the plugin therefore depends not on the quality of the code, but on the quality of the description.

On the level above is marketplace.json. It describes which plugins a marketplace offers. Claude Code has an official marketplace managed by Anthropic containing reviewed plugins. However, anyone can create their own marketplace. A GitHub repository with a marketplace.json in the .claude-plugin directory is sufficient. This was a crucial point for me: you are not dependent on a central instance but can also provide plugins internally or for your community without going through an approval process.

For someone like me, who has been developing software for over twenty years, this type of plugin development is a remarkable shift in perspective. Instead of thinking in functions and classes, you think in explanations and instructions. Instead of implementing an API, you describe an API. The ability to formulate precisely and unambiguously becomes the actual development competence.

So, what was the practical process? I started with an empty repository and the question of which interactions with EventSourcingDB I wanted to map. The database offers an HTTP API with a manageable number of endpoints: writing events, reading events, observing events, querying subjects, listing event types, executing EventQL queries, and registering schemas. There are also administrative functions like ping and API token verification.

For each of these endpoints, I created a separate skill. This sounds like a lot of work, but it wasn't. Firstly, each skill follows the same pattern: a brief description of its purpose, the relevant API endpoints with their parameters, authentication notes, and examples of typical calls and responses. The Markdown files are each between about 30 and 80 lines long. Secondly, I also used Claude Code for this: I didn't write the skills by hand, but described to Claude Code what I wanted to achieve and then had it generate the skills.

The first skill I created this way was the simplest: the ping skill mentioned above. This skill checks if an EventSourcingDB instance is reachable. The corresponding description includes little more than the API endpoint, the expected response, and a note that no authentication is required. Within minutes, the skill was ready, and Claude Code could use it.

What surprised me: It worked right away. No debugging, no trial and error, no hours of readjustment. Claude Code read the description, understood the task, and executed the HTTP call correctly. Encouraged by this quick success, I wrote the other skills in rapid succession. The plugin was complete after one afternoon.

This is not to give the impression that there were no challenges. Describing the skill for observing events required more care, because it involves a long-lived HTTP connection with NDJSON streaming. I had to explain to Claude Code that the connection remains open and continuously delivers data. But even that was a matter of the right wording, not the right implementation.

The completed plugin includes ten skills that cover almost the entire HTTP API of EventSourcingDB. Installation takes two steps. First, you add the marketplace:

/plugin marketplace add thenativeweb/claude-plugins

Then you install the plugin:

/plugin install esdb@thenativeweb

After that, the skills are available. Each skill has a namespace prefix derived from the plugin name and is called as a slash command. To check the reachability of an EventSourcingDB instance, for example, simply use:

/esdb:ping

For more complex interactions, you pass arguments in natural language. A call like:

/esdb:write-events Write an event of type “io.eventsourcingdb.library.book-acquired” for subject “/books/42” with data title “2001”, author “Arthur C. Clarke”

causes Claude Code to construct the appropriate HTTP request and send it to the database. The model interprets the natural language description, maps it to the API parameters, and outputs the result legibly. The same applies to EventQL queries, where Claude Code translates the query into the correct format based on the skill description.

Working on the skills for reading and observing events was particularly insightful. Both use the same endpoint but differ in their behavior: reading returns a finite set of events and closes the connection; observing keeps the connection open and streams new events in real-time. This distinction had to be clearly articulated in the description; otherwise, Claude Code wouldn't know when to close the connection and when not to.

This reveals an important pattern: the quality of a skill depends on how well you can describe the semantics of an action. It's not enough to list the technical parameters of an API call. You have to convey the why and the when to the model, not just the how. This is a different way of thinking than in classic programming, and it requires a different kind of diligence.

The plugin configuration is done via environment variables. The URL of the EventSourcingDB instance and the API token are set at startup, and the skills reference these values in their descriptions. This is also remarkably simple: no configuration files, no nested settings, no initialization logic.

What can be generalized from this experience? Three observations seem particularly relevant to me.

First: The barrier to entry for Claude Code plugins is remarkably low. Anyone who has an HTTP API and can describe it in natural language can build a plugin. No special programming skills are required, no understanding of compiler infrastructure, no experience with plugin architectures. The only prerequisite is the ability to precisely formulate what an action does, what inputs it expects, and what outputs it provides. This makes plugin development accessible to a broad group of developers.

Second: Skills as natural language descriptions are an unusually powerful concept. They allow domain-specific knowledge to be incorporated into an AI tool without writing a single line of executable code. This shifts the core competence: it's not the implementation that's crucial, but the understanding of the domain and the ability to express that understanding clearly. For teams working with technically complex systems, this is an interesting approach because it shortens the bridge between domain expertise and tool development.

Third: The line between plugins and MCP servers is blurring, and that's intentional. Plugins are well-suited for scenarios where an AI tool needs to use an existing API and the interaction is controlled via natural language. MCP servers are the better choice when programmatic control is needed, such as for complex authentication flows, stateful sessions, or bidirectional communication. Both approaches complement each other, and for many systems, it's worth offering both.

What impressed me most personally is the shift in perspective. For many years, I've been used to writing code that tells machines what to do. With a Claude Code plugin, on the other hand, I'm just writing natural language text that explains to a language model what it should do. Technically, this sounds like a small difference, but it feels like a big one. The question is no longer “How do I implement this?” but “How do I explain this so that it is understood?” This is comparable to an explanation you give to colleagues.

Anyone who wants to try out the plugin can find the source code on GitHub. Installation in Claude Code only requires the two commands mentioned above. EventSourcingDB can be used free of charge for up to 25,000 events, so there's nothing standing in the way of experimentation. Anyone who wants to build their own plugin for another API needs nothing more than an empty directory and the willingness to formulate precisely.

(rme)

Don't miss any news – follow us on Facebook, LinkedIn or Mastodon.

This article was originally published in German. It was translated with technical assistance and editorially reviewed before publication.