# How to Create Custom Keybinding Modes in Flow Control

> Learn how to create custom keybinding modes in Flow Control using JSON namespace files. Define modes with inheritance and activation settings for enhanced control.

- Repository: [CJ van den Berg/flow](https://github.com/neurocyte/flow)
- Tags: how-to-guide
- Published: 2026-03-08

---

**Flow Control stores keybindings in JSON namespace files where modes are defined as subsections with inheritance, press/release arrays, and activation via the `input_mode` setting or the `f4` key cycle.**

The open-source terminal editor [Flow Control](https://github.com/neurocyte/flow) (neurocyte/flow) uses a hierarchical keybinding system that separates namespaces (JSON configuration files) from modes (contextual subsections within those files). Understanding this architecture allows you to define custom modes that inherit from existing ones and bind unique command sequences without modifying the core source code.

## Understanding Keybinding Namespaces and Modes

Flow Control organizes keybindings into **namespaces**—JSON files that contain multiple **modes**. A namespace corresponds to the `input_mode` configuration value (such as `flow`, `vim`, or `emacs`), while a mode represents a specific operational context like `normal`, `select`, or `mini/find`.

When the editor initializes, it loads the namespace file defined by `input_mode` and constructs runtime `BindingSet` structures for each mode. The `Namespace.load` function in `src/keybind/keybind.zig` (lines 71–115) handles this parsing using `std.json.parseFromSlice`, while `BindingSet.load` (lines 90–115) resolves inheritance chains.

## Locating and Creating Your Custom Keybinding File

Built-in namespaces reside in the source tree at `src/keybind/builtin/*.json`. For example, the default *flow* namespace is defined in [`src/keybind/builtin/flow.json`](https://github.com/neurocyte/flow/blob/main/src/keybind/builtin/flow.json). However, you should not edit these directly.

Instead, Flow Control uses the `get_or_create_namespace_config_file` function in `src/keybind/keybind.zig` (lines 22–32) to manage user-specific configurations. This helper checks the user config directory (`$XDG_CONFIG_HOME/flow/keys/`) for the requested namespace file. If the file does not exist, it copies the built-in JSON to the user directory as a starting point.

To begin creating a custom mode, ensure the namespace file exists in your user config directory by running the **"Edit keybindings"** command from the palette (implemented in `src/command.zig`), which opens the current namespace JSON file for editing.

## Defining a Custom Keybinding Mode

A custom mode is a top-level JSON object within the namespace file. The object name becomes the mode identifier, and it accepts several properties:

- **`inherit`** – Specifies a parent mode to inherit non-conflicting bindings from.
- **`on_match_failure`** – Defines behavior when a key sequence does not match (e.g., `"ignore"` or `"beep"`).
- **`press`** and **`release`** – Arrays of binding tuples in the format `[key-chord, command, ...args]`.

For example, to create a mode named `mycustom` that inherits from `normal` and binds **Ctrl+t** to `open_terminal`, add the following to your namespace file:

```json
"mycustom": {
    "inherit": "normal",
    "press": [
        ["ctrl+t", "open_terminal"]
    ]
}

```

The inheritance system, handled by `BindingSet.load`, merges parent bindings with child definitions, allowing you to override specific keys while retaining the base behavior of standard modes like `normal` or `select`.

## Activating and Testing Your Custom Mode

Once you save the namespace file, Flow Control automatically reloads the configuration on the next startup. To activate the mode immediately without restarting, use the **input-mode cycle** key (`f4` by default), which switches between available modes in the current namespace.

Alternatively, you can create a separate namespace entirely by copying the JSON file to a new name (e.g., [`mykeys.json`](https://github.com/neurocyte/flow/blob/main/mykeys.json)) in the user config directory and setting `input_mode = "mykeys"` in `$XDG_CONFIG_HOME/flow/config`. The `get_or_create_namespace_config_file` logic treats this as a distinct namespace, loading it independently from the built-in definitions.

## Summary

- Flow Control uses JSON **namespace** files stored in `$XDG_CONFIG_HOME/flow/keys/` to define keybindings, with individual **modes** as top-level objects within those files.
- The `get_or_create_namespace_config_file` function in `src/keybind/keybind.zig` automatically seeds user configurations from built-in templates located at `src/keybind/builtin/*.json`.
- Custom modes support **inheritance** via the `inherit` property, allowing you to extend base modes like `normal` without redefining every binding.
- Activation occurs through the `input_mode` configuration setting, the `f4` key cycle, or the **"Edit keybindings"** command palette entry.

## Frequently Asked Questions

### How do I inherit from multiple parent modes in Flow Control?

Flow Control supports the `inherit` property (singular) for direct parent mode inheritance. If you need to combine bindings from multiple sources, create a chain where your custom mode inherits from an intermediate mode that itself inherits from another parent. The `BindingSet.load` implementation in `src/keybind/keybind.zig` (lines 90–115) resolves these inheritance chains recursively.

### Where does Flow Control store user-defined keybinding files?

User-defined keybinding namespaces are stored in the `keys` subdirectory of the Flow Control configuration directory, typically `$XDG_CONFIG_HOME/flow/keys/` on Linux systems. The `get_or_create_namespace_config_file` function in `src/keybind/keybind.zig` (lines 22–32) manages these paths, automatically creating the directory structure and seeding initial files from built-in templates if they do not exist.

### Can I switch to my custom mode without restarting Flow Control?

Yes, you can activate custom modes immediately without restarting by using the input-mode cycle key (`f4` by default), which iterates through available modes in the current namespace. Alternatively, if you created a new namespace file entirely, you can force a reload by switching the `input_mode` setting in your configuration and triggering a mode change via the command palette or the `f4` cycle.

### What is the difference between a namespace and a mode in Flow Control?

A **namespace** is a complete JSON configuration file (such as [`flow.json`](https://github.com/neurocyte/flow/blob/main/flow.json) or [`vim.json`](https://github.com/neurocyte/flow/blob/main/vim.json)) that defines an entire keybinding scheme, selected by the `input_mode` configuration setting. A **mode** is a subsection within that namespace (such as `normal`, `insert`, or `mycustom`) that represents a specific operational context with its own set of key bindings. Namespaces are loaded by `Namespace.load` in `src/keybind/keybind.zig`, while modes are instantiated as `BindingSet` structures within those namespaces.