> ## Documentation Index
> Fetch the complete documentation index at: https://bastani-feat-2159-curl-irm-installers.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Keybindings

# Keybindings

All keyboard shortcuts can be customized via `~/.atomic/agent/keybindings.json`. Each action can be bound to one or more keys.

The config file uses the same namespaced keybinding ids that Atomic uses internally and that extension authors use in `keyHint()` and injected `keybindings` managers.

Older configs using pre-namespaced ids such as `cursorUp` or `expandTools` are migrated automatically to the namespaced ids on startup.

After editing `keybindings.json`, run `/reload` in Atomic to apply the changes without restarting the session.

## Key Format

`modifier+key` where modifiers are `ctrl`, `shift`, `alt` (combinable) and keys are:

* **Letters:** `a-z`
* **Digits:** `0-9`
* **Special:** `escape`, `esc`, `enter`, `return`, `tab`, `space`, `backspace`, `delete`, `insert`, `clear`, `home`, `end`, `pageUp`, `pageDown`, `up`, `down`, `left`, `right`
* **Function:** `f1`-`f12`
* **Symbols:** `` ` ``, `-`, `=`, `[`, `]`, `\`, `;`, `'`, `,`, `.`, `/`, `!`, `@`, `#`, `$`, `%`, `^`, `&`, `*`, `(`, `)`, `_`, `+`, `|`, `~`, `{`, `}`, `:`, `<`, `>`, `?`

Modifier combinations: `ctrl+shift+x`, `alt+ctrl+x`, `ctrl+shift+alt+x`, `ctrl+1`, etc.

## All Actions

### TUI Editor Cursor Movement

| Keybinding id                | Default                            | Description                |
| ---------------------------- | ---------------------------------- | -------------------------- |
| `tui.editor.cursorUp`        | `up`                               | Move cursor up             |
| `tui.editor.cursorDown`      | `down`                             | Move cursor down           |
| `tui.editor.cursorLeft`      | `left`, `ctrl+b`                   | Move cursor left           |
| `tui.editor.cursorRight`     | `right`, `ctrl+f`                  | Move cursor right          |
| `tui.editor.cursorWordLeft`  | `alt+left`, `ctrl+left`, `alt+b`   | Move cursor word left      |
| `tui.editor.cursorWordRight` | `alt+right`, `ctrl+right`, `alt+f` | Move cursor word right     |
| `tui.editor.cursorLineStart` | `home`, `ctrl+a`                   | Move to line start         |
| `tui.editor.cursorLineEnd`   | `end`, `ctrl+e`                    | Move to line end           |
| `tui.editor.jumpForward`     | `ctrl+]`                           | Jump forward to character  |
| `tui.editor.jumpBackward`    | `ctrl+alt+]`                       | Jump backward to character |
| `tui.editor.pageUp`          | `pageUp`                           | Scroll up by page          |
| `tui.editor.pageDown`        | `pageDown`                         | Scroll down by page        |

### TUI Editor Deletion

| Keybinding id                   | Default                   | Description               |
| ------------------------------- | ------------------------- | ------------------------- |
| `tui.editor.deleteCharBackward` | `backspace`               | Delete character backward |
| `tui.editor.deleteCharForward`  | `delete`, `ctrl+d`        | Delete character forward  |
| `tui.editor.deleteWordBackward` | `ctrl+w`, `alt+backspace` | Delete word backward      |
| `tui.editor.deleteWordForward`  | `alt+d`, `alt+delete`     | Delete word forward       |
| `tui.editor.deleteToLineStart`  | `ctrl+u`                  | Delete to line start      |
| `tui.editor.deleteToLineEnd`    | `ctrl+k`                  | Delete to line end        |

### TUI Input

| Keybinding id       | Default       | Description        |
| ------------------- | ------------- | ------------------ |
| `tui.input.newLine` | `shift+enter` | Insert new line    |
| `tui.input.submit`  | `enter`       | Submit input       |
| `tui.input.tab`     | `tab`         | Tab / autocomplete |

### TUI Kill Ring

| Keybinding id        | Default  | Description                           |
| -------------------- | -------- | ------------------------------------- |
| `tui.editor.yank`    | `ctrl+y` | Paste most recently deleted text      |
| `tui.editor.yankPop` | `alt+y`  | Cycle through deleted text after yank |
| `tui.editor.undo`    | `ctrl+-` | Undo last edit                        |

### TUI Clipboard and Selection

| Keybinding id         | Default            | Description         |
| --------------------- | ------------------ | ------------------- |
| `tui.input.copy`      | `ctrl+c`           | Copy selection      |
| `tui.select.up`       | `up`               | Move selection up   |
| `tui.select.down`     | `down`             | Move selection down |
| `tui.select.pageUp`   | `pageUp`           | Page up in list     |
| `tui.select.pageDown` | `pageDown`         | Page down in list   |
| `tui.select.confirm`  | `enter`            | Confirm selection   |
| `tui.select.cancel`   | `escape`, `ctrl+c` | Cancel selection    |

### Application

| Keybinding id              | Default                       | Description                                                                                                                                       |
| -------------------------- | ----------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- |
| `app.interrupt`            | `escape`                      | Abort active or queued work and restore queued steering/follow-up messages to the editor; the session remains paused until an ordinary submission |
| `app.clear`                | `ctrl+c`                      | Interrupt active or queued work, or terminate an unresponsive interactive engine; once idle, clear the editor (press twice while idle to exit)    |
| `app.exit`                 | `ctrl+d`                      | Exit (when editor empty)                                                                                                                          |
| `app.suspend`              | `ctrl+z` (none on Windows)    | Suspend to background                                                                                                                             |
| `app.editor.external`      | `ctrl+g`                      | Open in external editor (`$VISUAL` or `$EDITOR`)                                                                                                  |
| `app.clipboard.pasteImage` | `ctrl+v` (`alt+v` on Windows) | Paste image from clipboard                                                                                                                        |
| `app.message.copy`         | `ctrl+x`                      | Copy the last assistant message (or the selected message in `/tree`)                                                                              |

When `app.clipboard.pasteImage` finds text rather than an image, Atomic inserts that clipboard text into the editor instead of reporting an image-paste failure.

A held paused queue by itself is idle for Ctrl+C handling. After an interruption settles, the next Ctrl+C clears the editor without releasing or dequeuing the hold, and a second quick idle press exits normally.

In interactive sessions the agent runs in a supervised engine child (see [Extensions](/extensions#interactive-callback-isolation)). Escape there requests the engine's cooperative cancellation and waits for it with no deadline; it never terminates or replaces the engine.

Both keys are recognized by their physical identity, not by the configured `app.clear` action, so rebinding `app.clear` cannot make Escape stop the engine or take the host route away from Ctrl+C.

Ctrl+C is the host's escape hatch whenever an engine-owned `ctx.ui.custom()` component or overlay holds input: those forward every key to the engine, so a component that never resolves would swallow Ctrl+C. Which component gets the press is decided per mount, in this order:

1. If the engine is provably not answering, the first press terminates and replaces it — a wedged child cannot run the component's own handler either. "Not answering" means the watchdog has declared it unresponsive, a cooperative abort has gone unanswered past the same one-second threshold, a replacement has been waiting for readiness past it, or a replacement failed. A failed replacement keeps Ctrl+C armed so another press can try again; Atomic never retries on its own.
2. Otherwise, if the component declared `handlesCtrlC` when it was mounted, it receives the press and keeps its own Skip, Close, or cancel behavior. The bundled workflow surfaces declare it. If the same component is still holding input on the next press, that press closes it.
3. Otherwise the first press closes that one component, exactly as if it had been cancelled: its `ctx.ui.custom()` promise resolves with `undefined`, the editor comes back, and the engine — along with everything else it has mounted or is running — is left alone.

`tui.select.cancel` still keeps Ctrl+C as local cancel inside host-native selectors, dialogs, input forms, and session pickers.

### Sessions

| Keybinding id                   | Default          | Description                            |
| ------------------------------- | ---------------- | -------------------------------------- |
| `app.session.new`               | *(none)*         | Start a new session (`/new`)           |
| `app.session.tree`              | *(none)*         | Open session tree navigator (`/tree`)  |
| `app.session.fork`              | *(none)*         | Fork current session (`/fork`)         |
| `app.session.resume`            | *(none)*         | Open session resume picker (`/resume`) |
| `app.session.togglePath`        | `ctrl+p`         | Toggle path display                    |
| `app.session.toggleSort`        | `ctrl+s`         | Toggle sort mode                       |
| `app.session.toggleNamedFilter` | `ctrl+n`         | Toggle named-only filter               |
| `app.session.rename`            | `ctrl+r`         | Rename session                         |
| `app.session.delete`            | `ctrl+d`         | Delete session                         |
| `app.session.deleteNoninvasive` | `ctrl+backspace` | Delete session when query is empty     |

### Models and Thinking

| Keybinding id             | Default        | Description                        |
| ------------------------- | -------------- | ---------------------------------- |
| `app.model.select`        | `ctrl+l`       | Open model selector                |
| `app.model.cycleForward`  | `ctrl+p`       | Cycle to next model                |
| `app.model.cycleBackward` | `shift+ctrl+p` | Cycle to previous model            |
| `app.thinking.cycle`      | `shift+tab`    | Cycle thinking level               |
| `app.thinking.toggle`     | `ctrl+t`       | Collapse or expand thinking blocks |

### Display and Message Queue

| Keybinding id          | Default     | Description                                                                                      |
| ---------------------- | ----------- | ------------------------------------------------------------------------------------------------ |
| `app.tools.expand`     | `ctrl+o`    | Collapse or expand tool and workflow-node detail in main chat or an attached workflow stage chat |
| `app.message.followUp` | `alt+enter` | Queue follow-up message                                                                          |
| `app.message.dequeue`  | `alt+up`    | Restore queued messages to editor                                                                |

### Tree Navigation

| Keybinding id                   | Default                   | Description                                                                    |
| ------------------------------- | ------------------------- | ------------------------------------------------------------------------------ |
| `app.tree.foldOrUp`             | `ctrl+left`, `alt+left`   | Fold current branch segment, or jump to the previous segment start             |
| `app.tree.unfoldOrDown`         | `ctrl+right`, `alt+right` | Unfold current branch segment, or jump to the next segment start or branch end |
| `app.tree.editLabel`            | `shift+l`                 | Edit the label on the selected tree node                                       |
| `app.tree.toggleLabelTimestamp` | `shift+t`                 | Toggle label timestamps in the tree                                            |
| `app.tree.filter.default`       | `ctrl+d`                  | Set tree filter to default view                                                |
| `app.tree.filter.noTools`       | `ctrl+t`                  | Toggle tree filter that hides tool results                                     |
| `app.tree.filter.userOnly`      | `ctrl+u`                  | Toggle tree filter that shows only user messages                               |
| `app.tree.filter.labeledOnly`   | `ctrl+l`                  | Toggle tree filter that shows only labeled entries                             |
| `app.tree.filter.all`           | `ctrl+a`                  | Toggle tree filter that shows all entries                                      |
| `app.tree.filter.cycleForward`  | `ctrl+o`                  | Cycle tree filter forward                                                      |
| `app.tree.filter.cycleBackward` | `shift+ctrl+o`            | Cycle tree filter backward                                                     |

### Scoped Models Selector

Used inside the scoped models selector (opened via `/scoped-models`).

| Keybinding id               | Default    | Description                                            |
| --------------------------- | ---------- | ------------------------------------------------------ |
| `app.models.save`           | `ctrl+s`   | Save current model selection to settings               |
| `app.models.enableAll`      | `ctrl+a`   | Enable all models (or all matching the current search) |
| `app.models.clearAll`       | `ctrl+x`   | Clear all models (or all matching the current search)  |
| `app.models.toggleProvider` | `ctrl+p`   | Toggle all models for the current provider             |
| `app.models.reorderUp`      | `alt+up`   | Move the selected model up in the cycle order          |
| `app.models.reorderDown`    | `alt+down` | Move the selected model down in the cycle order        |

## Custom Configuration

Create `~/.atomic/agent/keybindings.json`:

```json theme={null}
{
  "tui.editor.cursorUp": ["up", "ctrl+p"],
  "tui.editor.cursorDown": ["down", "ctrl+n"],
  "tui.editor.deleteWordBackward": ["ctrl+w", "alt+backspace"]
}
```

Each action can have a single key or an array of keys. User config overrides defaults.

On native Windows, `app.suspend` has no default binding because Windows terminals do not support Unix job control. If you bind it manually, Atomic shows a status message instead of suspending. In WSL, the normal Linux `ctrl+z`/`fg` behavior still applies.

### Emacs Example

```json theme={null}
{
  "tui.editor.cursorUp": ["up", "ctrl+p"],
  "tui.editor.cursorDown": ["down", "ctrl+n"],
  "tui.editor.cursorLeft": ["left", "ctrl+b"],
  "tui.editor.cursorRight": ["right", "ctrl+f"],
  "tui.editor.cursorWordLeft": ["alt+left", "alt+b"],
  "tui.editor.cursorWordRight": ["alt+right", "alt+f"],
  "tui.editor.deleteCharForward": ["delete", "ctrl+d"],
  "tui.editor.deleteCharBackward": ["backspace", "ctrl+h"],
  "tui.input.newLine": ["shift+enter", "ctrl+j"]
}
```

### Vim Example

```json theme={null}
{
  "tui.editor.cursorUp": ["up", "alt+k"],
  "tui.editor.cursorDown": ["down", "alt+j"],
  "tui.editor.cursorLeft": ["left", "alt+h"],
  "tui.editor.cursorRight": ["right", "alt+l"],
  "tui.editor.cursorWordLeft": ["alt+left", "alt+b"],
  "tui.editor.cursorWordRight": ["alt+right", "alt+w"]
}
```
