# How to Create Custom Chaos Experiment Scenarios for New Targets in ChaosBlade

> Learn to create custom chaos experiment scenarios for new targets in ChaosBlade. Implement the spec executor interface, define command specs, and register your executor.

- Repository: [ChaosBlade/chaosblade](https://github.com/chaosblade-io/chaosblade)
- Tags: how-to-guide
- Published: 2026-02-27

---

**To create custom chaos experiment scenarios for new targets in ChaosBlade, implement the `spec.Executor` interface with `Create`, `Destroy`, and optional `Query` methods, define a command model spec in `exec/<target>/spec.go`, and register the executor in [`cli/cmd/exp.go`](https://github.com/chaosblade-io/chaosblade/blob/main/cli/cmd/exp.go) using the `createExecutorKey` function.**

ChaosBlade models every chaos experiment as a **target → action → flags** triple. Extending the framework to support new infrastructure or services requires implementing the executor interface and registering your components in the CLI. This guide walks through the exact source code locations and implementation patterns used in the `chaosblade-io/chaosblade` repository to add a custom target like `myservice`.

## Step 1: Define the Command Model Spec

Create `exec/<target>/spec.go` to declare the target's metadata, default flags, and examples. This file must implement the `spec.ExpModelCommandSpec` interface, which provides the CLI with the target's name and usage information.

```go
package myservice

import "github.com/chaosblade-io/chaosblade-spec-go/spec"

type CommandModelSpec struct {
    spec.BaseExpModelCommandSpec
}

func NewCommandModelSpec() spec.ExpModelCommandSpec {
    return &CommandModelSpec{
        spec.BaseExpModelCommandSpec{
            ExpActions: []spec.ExpActionCommandSpec{},
            ExpFlags: []spec.ExpFlagSpec{
                &spec.ExpFlag{
                    Name: "endpoint",
                    Desc: "myservice endpoint (host:port)",
                },
            },
        },
    }
}

func (*CommandModelSpec) Name() string        { return "myservice" }
func (*CommandModelSpec) ShortDesc() string   { return "MyService experiment" }
func (*CommandModelSpec) LongDesc() string    { return "Chaos experiments for MyService" }
func (*CommandModelSpec) Example() string    {
    return "blade create myservice latency --delay 1000 --endpoint 127.0.0.1:8080"
}

```

The `Example()` method returns the command string users will run, while `ExpFlags` defines common flags available to all actions under this target.

## Step 2: Implement the Executor Interface

Create `exec/<target>/executor.go` to handle the actual chaos injection and cleanup. The executor must satisfy the `spec.Executor` interface defined in the ChaosBlade specification, which requires `Create`, `Destroy`, and optional `Query` methods.

```go
package myservice

import (
    "context"

    "github.com/chaosblade-io/chaosblade-spec-go/spec"
    "github.com/chaosblade-io/chaosblade-spec-go/log"
)

type Executor struct{}

// NewExecutor returns an executor that implements spec.Executor.
func NewExecutor() spec.Executor { return &Executor{} }

func (e *Executor) Name() string { return "myservice" }

func (e *Executor) SetChannel(c spec.Channel) {}

func (e *Executor) Create(ctx context.Context, model *spec.ExpModel) *spec.Response {
    // Parse flags from the experiment model
    delay := model.ActionFlags["delay"]
    endpoint := model.ActionFlags["endpoint"]
    
    // Insert real injection logic here (e.g., call myservice API)
    log.Infof(ctx, "Injecting latency %s ms to %s", delay, endpoint)
    return spec.ReturnSuccess("")
}

func (e *Executor) Destroy(ctx context.Context, model *spec.ExpModel) *spec.Response {
    // Cleanup logic to remove the chaos injection
    log.Infof(ctx, "Removing latency injection from %s", model.ActionFlags["endpoint"])
    return spec.ReturnSuccess("")
}

func (e *Executor) Query(ctx context.Context, model *spec.ExpModel) *spec.Response {
    // Optional: return current status of the experiment
    return spec.ReturnSuccess("")
}

```

The `Create` method receives an `ExpModel` containing parsed flags from the CLI and returns a `spec.Response` indicating success or failure.

## Step 3: Register the Target in the CLI

In [`cli/cmd/exp.go`](https://github.com/chaosblade-io/chaosblade/blob/main/cli/cmd/exp.go), register the executor so the `blade create` command can resolve it. The registration uses `createExecutorKey(target, actionTarget, action)` to build a unique lookup key for the `executors` map.

Add the following initialization code where target specs are loaded:

```go
myserviceSpec := myservice.NewCommandModelSpec()
myserviceExecutor := myservice.NewExecutor()

// Register the target command
ec.registerExpCommand(myserviceSpec, "")

// Map the specific action to the executor
ec.executors[createExecutorKey("myservice", "", "latency")] = myserviceExecutor

```

If your target implements dynamic spec loading, this registration happens automatically when the action command is created (see lines 65‑70 in [`cli/cmd/exp.go`](https://github.com/chaosblade-io/chaosblade/blob/main/cli/cmd/exp.go)). The `createExecutorKey` function concatenates the target name, action target, and action to generate the map key used by `GetExecutor`.

## Step 4: Create YAML Scenario Specifications

Write a YAML file describing your target's actions, flags, and matchers. The blade CLI reads these definitions from [`chaosblade.spec.yaml`](https://github.com/chaosblade-io/chaosblade/blob/main/chaosblade.spec.yaml), which is generated by merging all scenario files.

Create [`scenario/myservice.yaml`](https://github.com/chaosblade-io/chaosblade/blob/main/scenario/myservice.yaml):

```yaml
name: myservice
shortDesc: MyService experiment
longDesc: |
  Chaos experiments for MyService, such as injecting latency,
  CPU overload, or killing processes.
actions:
  - name: latency
    shortDesc: Add network latency
    longDesc: |
      Injects a fixed latency (ms) to the communication channel of the target
      MyService instance.
    flags:
      - name: delay
        desc: "latency in milliseconds"
        required: true
      - name: endpoint
        desc: "myservice endpoint (host:port)"
        required: true
    matchers: []   # optional, for complex targeting logic

```

Place this file in a scenario directory that will be processed by the spec builder tool.

## Step 5: Build and Test the Custom Target

Rebuild the aggregated specification to include your new target's YAML definitions. Run the spec merger tool from the repository root:

```bash
go run ./build/spec <scenario-dir> <target-dir>

```

For example, if your YAML is in `./scenario` and you want the output in the current directory:

```bash
go run ./build/spec scenario ./

```

This executes the merging logic in [`build/spec/spec.go`](https://github.com/chaosblade-io/chaosblade/blob/main/build/spec/spec.go), which writes the combined [`chaosblade.spec.yaml`](https://github.com/chaosblade-io/chaosblade/blob/main/chaosblade.spec.yaml) file containing all registered targets. The blade CLI reads this file at startup to populate available commands.

Test your implementation by creating an experiment:

```bash
blade create myservice latency --delay 2000 --endpoint 127.0.0.1:8080 --duration 30s

```

The CLI parses the flags, builds an `ExpModel` via `createExpModel` in [`exp.go`](https://github.com/chaosblade-io/chaosblade/blob/main/exp.go), looks up your executor using the generated key, and invokes the `Create` method with the experiment context.

## Summary

- **Define the spec**: Implement `spec.ExpModelCommandSpec` in `exec/<target>/spec.go` to declare target metadata and default flags.
- **Implement the executor**: Create `exec/<target>/executor.go` satisfying the `spec.Executor` interface with `Create`, `Destroy`, and `Query` methods.
- **Register with CLI**: Modify [`cli/cmd/exp.go`](https://github.com/chaosblade-io/chaosblade/blob/main/cli/cmd/exp.go) to register the spec and add the executor to the `executors` map using `createExecutorKey`.
- **Provide YAML specs**: Define actions and flags in YAML files processed by [`build/spec/spec.go`](https://github.com/chaosblade-io/chaosblade/blob/main/build/spec/spec.go) to generate [`chaosblade.spec.yaml`](https://github.com/chaosblade-io/chaosblade/blob/main/chaosblade.spec.yaml).
- **Rebuild specs**: Run `go run ./build/spec` to regenerate the master specification when adding or modifying YAML scenarios.

## Frequently Asked Questions

### What interface must a custom target executor implement?

Your executor must implement the `spec.Executor` interface from `chaosblade-spec-go`. This requires three methods: `Create(ctx context.Context, model *spec.ExpModel) *spec.Response` for injection logic, `Destroy` for cleanup and rollback, and `Query` for status checking. Each method receives the experiment model containing parsed CLI flags and must return a response indicating success or failure.

### How does ChaosBlade map CLI commands to executors?

The `GetExecutor` function in [`cli/cmd/exp.go`](https://github.com/chaosblade-io/chaosblade/blob/main/cli/cmd/exp.go) builds a lookup key using `createExecutorKey(target, actionTarget, action)`, which concatenates the target name, action target, and action into a unique string. This key retrieves the appropriate executor from the `ec.executors` map. When you run `blade create myservice latency`, the CLI generates the key for the `myservice` target and `latency` action, then invokes the matching executor's `Create` method.

### Where should YAML scenario files be placed for custom targets?

Place YAML files in any directory of your choice, then pass this directory as the first argument to the spec builder: `go run ./build/spec <scenario-dir> <output-dir>`. The tool merges all YAML files in the scenario directory into a single [`chaosblade.spec.yaml`](https://github.com/chaosblade-io/chaosblade/blob/main/chaosblade.spec.yaml) file that the blade CLI reads at runtime to discover available actions and their flags.

### Is rebuilding the spec required for every code change?

No. Rebuilding the specification via [`build/spec/spec.go`](https://github.com/chaosblade-io/chaosblade/blob/main/build/spec/spec.go) is only necessary when adding new YAML scenario files or modifying action definitions. Changes to Go source code in your executor or spec files require recompiling the `blade` binary itself, as the CLI loads executor implementations directly from compiled code, while the YAML specs provide metadata for CLI argument parsing.