# Write a Husk plugin

Canonical HTML: [Write a Husk plugin](https://getred.dev/docs/husk). Website source: `b212874eefaf200143affa21c770fbb8855a4f5c`. Documented Red release: v0.9.1. Installer source: `b86a2ca4b92e9547d3b174910c82db8a259f5171`.

Use Red's embedded Husk language to register commands, keep private state, and request editor-owned operations.

<a id="create-the-smallest-plugin"></a>

## Create the smallest plugin

Husk is Red's embedded scripting language. Place `hello.hk` in the `plugins` directory under Red's configuration directory, then register the filename in `config.toml`:

```toml
[plugins]
hello = "hello.hk"
```

```husk
#[red::command(
    name = "HelloWorld",
    title = "Say hello",
    category = "Example",
)]
fn hello_world() {
    red::execute("Print", "Hello from Husk");
}
```

The command is available as `:HelloWorld` and through the command palette.

<a id="keep-plugin-state"></a>

## Keep plugin state

```husk
struct PluginState {
    count: i64,
}

#[red::state]
fn initial_state() -> PluginState {
    return PluginState { count: 0 };
}
```

Read private state with `red::state()` and update named fields with `red::state_patch(...)`. Use declaration attributes for commands, fixed events, configuration, and lifecycle hooks; keep `red::on` for event names known only at runtime.

<a id="use-the-host-boundary"></a>

## Use the host boundary

| Function           | Purpose                                     |
| ------------------ | ------------------------------------------- |
| `red::execute`     | Request a fire-and-forget editor action     |
| `red::request`     | Request data and receive one typed callback |
| `red::on`          | Subscribe to an editor event                |
| `red::state`       | Read the plugin's private typed record      |
| `red::state_patch` | Update selected state fields                |
| `red::log`         | Write diagnostic information to Red's log   |

Red remains the owner of buffers, undo history, focus, confirmations, sessions, and filesystem reconciliation. Plugins request attributed operations through the versioned host API rather than changing editor state directly.

[Open the complete host API reference](https://github.com/codersauce/red/blob/eb5e2b6be15325abd12adbfac816f7844afff42c/docs/PLUGIN_API.md)

<a id="use-the-standalone-husk-cli"></a>

## Use the standalone Husk CLI

The Husk CLI is built separately from the Red editor binary:

```shell
cargo install --path crates/husk-cli
husk check script.hk
husk run script.hk
husk test path/to/package
husk repl
```

Standalone Husk grants no ambient filesystem, network, environment, process, clock, or random access. Embedders add capabilities explicitly.
