# How to Add New Actions to Embabel Agents Without Modifying Existing Code

> Extend Embabel agents with new actions by creating a Tool JAR and registering it via Java ServiceLoader. Add custom functionality without altering existing agent code.

- Repository: [Embabel/embabel-agent](https://github.com/embabel/embabel-agent)
- Tags: how-to-guide
- Published: 2026-08-09

---

**You can add new actions to Embabel agents by creating a JAR that contains a class implementing the `Tool` interface annotated with `@Action` and registering it via the Java ServiceLoader mechanism in `META-INF/services/com.embabel.agent.api.tool.Tool`, which the `ActionRegistry` discovers at runtime without requiring any changes to the core agent codebase.**

The Embabel agent framework (`embabel/embabel-agent`) is built on a modular, plugin-based architecture that separates core orchestration logic from executable capabilities. This design allows developers to extend agent functionality by packaging new actions as standalone dependencies rather than forking or patching the existing source tree.

## Understanding the Embabel Agent Plugin Architecture

Embabel agents execute discrete operations called **actions**, which are discovered at runtime through the standard Java Service Provider Interface (SPI). The framework defines two critical contracts in the `embabel-agent-api` module:

- **`@Action` annotation**: Declares metadata (name, description) for the action in [`embabel-agent-api/src/main/java/com/embabel/agent/api/annotation/Action.java`](https://github.com/embabel/embabel-agent/blob/main/embabel-agent-api/src/main/java/com/embabel/agent/api/annotation/Action.java)
- **`Tool` interface**: Specifies the execution contract that all actions must fulfill in [`embabel-agent-api/src/main/java/com/embabel/agent/api/tool/Tool.java`](https://github.com/embabel/embabel-agent/blob/main/embabel-agent-api/src/main/java/com/embabel/agent/api/tool/Tool.java)

The `ActionRegistry` class in [`embabel-agent-core/src/main/java/com/embabel/agent/core/ActionRegistry.java`](https://github.com/embabel/embabel-agent/blob/main/embabel-agent-core/src/main/java/com/embabel/agent/core/ActionRegistry.java) bootstraps the agent's capability set by scanning the classpath for implementations of `Tool` using `ServiceLoader`, enabling true zero-touch extensibility.

## Step-by-Step Guide to Adding Custom Actions

### Create a New Maven Module

Start by creating a new Maven project that depends only on the Embabel agent API. This ensures your extension remains lightweight and decoupled from core implementation details.

```xml
<dependency>
    <groupId>com.embabel</groupId>
    <artifactId>embabel-agent-api</artifactId>
    <version>0.9.0</version>
</dependency>

```

### Implement the Tool Interface and Annotate with @Action

Create a public class with a no-arg constructor that implements `Tool` and is annotated with `@Action`. The annotation marks the class for discovery, while the interface enforces the `run(ActionContext ctx, ...)` contract.

```java
package com.mycompany.embabel.actions;

import com.embabel.agent.api.annotation.Action;
import com.embabel.agent.api.tool.Tool;
import com.embabel.agent.api.tool.ActionContext;

@Action(name = "summarizeText", description = "Summarizes a block of text using the LLM")
public class SummarizeTextAction implements Tool {

    @Override
    public Object run(ActionContext ctx, String text) {
        return ctx.llm().generateSummary(text);
    }
}

```

This implementation references the `ActionContext` to access shared services like the LLM client, demonstrating how actions integrate with the agent's execution environment.

### Register the Action via Java SPI

To make the implementation discoverable, create a service provider configuration file at `src/main/resources/META-INF/services/com.embabel.agent.api.tool.Tool`. List the fully qualified class name of your implementation:

```

com.mycompany.embabel.actions.SummarizeTextAction

```

The `ActionRegistry` loads these entries during agent initialization, instantiating each class via reflection and adding it to the available toolset.

### Deploy the Extension JAR

Build your module into a JAR file and place it on the application's classpath. When the Embabel agent starts, it automatically detects and registers your new action without requiring configuration changes or restarts of the core system.

## Complete Code Example: Creating a Custom Action

The following example demonstrates a concrete action that extracts email addresses from text, showing the full implementation pattern including the service descriptor.

### Action Implementation

```java
package com.mycompany.embabel.actions;

import com.embabel.agent.api.annotation.Action;
import com.embabel.agent.api.tool.Tool;
import com.embabel.agent.api.tool.ActionContext;
import java.util.regex.Pattern;
import java.util.List;
import java.util.stream.Collectors;

@Action(name = "extractEmails", description = "Extracts all email addresses from a block of text")
public class ExtractEmailsAction implements Tool {

    @Override
    public Object run(ActionContext ctx, String text) {
        return Pattern.compile("[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-z]{2,}")
                .matcher(text)
                .results()
                .map(match -> match.group())
                .collect(Collectors.toList());
    }
}

```

### Service Provider Descriptor

File: `src/main/resources/META-INF/services/com.embabel.agent.api.tool.Tool`

```

com.mycompany.embabel.actions.ExtractEmailsAction

```

### Maven Configuration

```xml
<project>
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.mycompany.embabel</groupId>
    <artifactId>embabel-custom-actions</artifactId>
    <version>1.0.0</version>

    <dependencies>
        <dependency>
            <groupId>com.embabel</groupId>
            <artifactId>embabel-agent-api</artifactId>
            <version>0.9.0</version>
        </dependency>
    </dependencies>
</project>

```

## How the ActionRegistry Discovers New Actions at Runtime

The `ActionRegistry` class leverages Java's `ServiceLoader` utility to maintain a registry of available tools. During the agent's boot sequence, the registry iterates over all providers found in `META-INF/services/com.embabel.agent.api.tool.Tool` across the classpath. For each discovered class, it instantiates the object using the default constructor and extracts the `@Action` metadata to build the action's public-facing interface. This architecture ensures that adding new capabilities is purely additive—deploying a new JAR extends the agent's functionality without invalidating existing configurations or requiring recompilation of the core framework.

## Summary

- **Implement the `Tool` interface** from `embabel-agent-api` and annotate your class with `@Action` to define new capabilities.
- **Register via Java SPI** by adding your class name to `META-INF/services/com.embabel.agent.api.tool.Tool`.
- **Package as a standalone JAR** with a dependency on `embabel-agent-api` and deploy to the classpath.
- **Rely on `ActionRegistry`** in `embabel-agent-core` to automatically discover and load your actions at startup without modifying existing source code.

## Frequently Asked Questions

### Do I need to modify the embabel-agent-core source code to add actions?

No. The framework is designed specifically to avoid source modifications. You create a separate JAR containing your action implementation and service descriptor, and the `ActionRegistry` discovers it automatically through the classpath scanning mechanism.

### What interface must my custom action implement?

Your class must implement `com.embabel.agent.api.tool.Tool`, which defines the `run(ActionContext ctx, ...)` method. This interface is located in [`embabel-agent-api/src/main/java/com/embabel/agent/api/tool/Tool.java`](https://github.com/embabel/embabel-agent/blob/main/embabel-agent-api/src/main/java/com/embabel/agent/api/tool/Tool.java).

### Can I add multiple actions in a single JAR?

Yes. You can package any number of action implementations into one JAR file. Simply list each fully qualified class name on a separate line in the `META-INF/services/com.embabel.agent.api.tool.Tool` file, or provide multiple service files if you prefer modular organization within the same archive.

### How does the agent handle action name collisions?

The `ActionRegistry` uses the `name` attribute from the `@Action` annotation as the unique identifier. If two implementations register with identical names, the later discovery order typically overrides the earlier registration, though production deployments should enforce unique naming conventions across extension modules to avoid ambiguity.