6 ファイル変更 +128 -78

この更新の概要

/terminal-setup コマンドの対応エディタに Cursor や Windsurf、Zed が追加され、各環境での Shift+Enter 設定がより容易になりました。フック機能では、サブコマンド単位での実行判定を可能にする if フィールドの挙動や、SessionStart と CwdChanged を組み合わせた環境変数の永続化手法が詳しく解説されています。macOS での Option キー活用や tmux 連携、フルスクリーンモードによる表示のちらつき防止など、ターミナル環境の最適化ガイドが大幅に拡充されました。対話モードの改善として undo 機能(uキー)の追加や、大規模なテキストを貼り付けた際の挙動に関する注意喚起も含まれています。

commands +2 -2

/terminal-setup の対象に Cursor や Windsurf、Zed などのエディタが追加され、/theme の自動設定に関する説明が更新されました。

@@ -92,8 +92,8 @@ In the table below, `<arg>` indicates a required argument and `[arg]` indicates
| `/tasks` | List and manage background tasks. Also available as `/bashes` |
| `/team-onboarding` | Generate a team onboarding guide from your Claude Code usage history. Claude analyzes your sessions, commands, and MCP server usage from the past 30 days and produces a markdown guide a teammate can paste as a first message to get set up quickly |
| `/teleport` | Pull a [Claude Code on the web](/en/claude-code-on-the-web#from-web-to-terminal) session into this terminal: opens a picker, then fetches the branch and conversation. Also available as `/tp`. Requires a claude.ai subscription |
| `/terminal-setup` | Configure terminal keybindings for Shift+Enter and other shortcuts. Only visible in terminals that need it, like VS Code, Alacritty, or Warp |
| `/theme` | Change the color theme. Includes an `auto` option that follows your terminal's dark or light mode, light and dark variants, colorblind-accessible (daltonized) themes, and ANSI themes that use your terminal's color palette |
| `/terminal-setup` | Configure terminal keybindings for Shift+Enter and other shortcuts. Only visible in terminals that need it, like VS Code, Cursor, Windsurf, Alacritty, or Zed |
| `/theme` | Change the color theme. Includes an `auto` option that matches your terminal's light or dark background, light and dark variants, colorblind-accessible (daltonized) themes, and ANSI themes that use your terminal's color palette |
| `/tui [default\|fullscreen]` | Set the terminal UI renderer and relaunch into it with your conversation intact. `fullscreen` enables the [flicker-free alt-screen renderer](/en/fullscreen). With no argument, prints the active renderer |
| `/ultraplan <prompt>` | Draft a plan in an [ultraplan](/en/ultraplan) session, review it in your browser, then execute remotely or send it back to your terminal |
| `/ultrareview [PR]` | Run a deep, multi-agent code review in a cloud sandbox with [ultrareview](/en/ultrareview). Includes 3 free runs on Pro and Max, then requires [extra usage](https://support.claude.com/en/articles/12429409-extra-usage-for-paid-claude-plans) |
env-vars +1 -1

CLAUDE_ENV_FILE 変数が Bash コマンド実行前に同一プロセス内で読み込まれ、エクスポートされた変数がコマンドに反映される仕組みが明文化されました。

@@ -151,7 +151,7 @@ Claude Code supports the following environment variables to control its behavior
| `CLAUDE_CONFIG_DIR` | Override the configuration directory (default: `~/.claude`). All settings, credentials, session history, and plugins are stored under this path. Useful for running multiple accounts side by side: for example, `alias claude-work='CLAUDE_CONFIG_DIR=~/.claude-work claude'` |
| `CLAUDE_ENABLE_BYTE_WATCHDOG` | Set to `1` to force-enable the byte-level streaming idle watchdog, or set to `0` to force-disable it. When unset, the watchdog is enabled by default for Anthropic API connections. The byte watchdog aborts a connection when no bytes arrive on the wire for the duration set by `CLAUDE_STREAM_IDLE_TIMEOUT_MS`, with a minimum of 5 minutes, independent of the event-level watchdog |
| `CLAUDE_ENABLE_STREAM_WATCHDOG` | Set to `1` to enable the event-level streaming idle watchdog. Off by default. For Bedrock, Vertex, and Foundry, this is the only idle watchdog available. Configure the timeout with `CLAUDE_STREAM_IDLE_TIMEOUT_MS` |
| `CLAUDE_ENV_FILE` | Path to a shell script that Claude Code sources before each Bash command. Use to persist virtualenv or conda activation across commands. Also populated dynamically by [SessionStart](/en/hooks#persist-environment-variables), [CwdChanged](/en/hooks#cwdchanged), and [FileChanged](/en/hooks#filechanged) hooks |
| `CLAUDE_ENV_FILE` | Path to a shell script whose contents Claude Code runs before each Bash command in the same shell process, so exports in the file are visible to the command. Use to persist virtualenv or conda activation across commands. Also populated dynamically by [SessionStart](/en/hooks#persist-environment-variables), [CwdChanged](/en/hooks#cwdchanged), and [FileChanged](/en/hooks#filechanged) hooks |
| `CLAUDE_REMOTE_CONTROL_SESSION_NAME_PREFIX` | Prefix for auto-generated [Remote Control](/en/remote-control) session names when no explicit name is provided. Defaults to your machine's hostname, producing names like `myhost-graceful-unicorn`. The `--remote-control-session-name-prefix` CLI flag sets the same value for a single invocation |
| `CLAUDE_STREAM_IDLE_TIMEOUT_MS` | Timeout in milliseconds before the streaming idle watchdog closes a stalled connection. For the byte-level watchdog on the Anthropic API: default and minimum `300000` (5 minutes); lower values are silently clamped to absorb extended thinking pauses and proxy buffering. For the event-level watchdog: default `90000` (90 seconds), no minimum. For third-party providers, requires `CLAUDE_ENABLE_STREAM_WATCHDOG=1` |
| `DISABLE_AUTOUPDATER` | Set to `1` to disable automatic updates |
hooks-guide +18 -6

direnv 等を利用した環境変数の永続化に SessionStart と CwdChanged を併用する手順が追加され、if フィールドによる Bash サブコマンドの判定ロジックが詳述されました。

@@ -285,17 +285,27 @@ The matcher filters by configuration type: `user_settings`, `project_settings`,
Some projects set different environment variables depending on which directory you are in. Tools like [direnv](https://direnv.net/) do this automatically in your shell, but Claude's Bash tool does not pick up those changes on its own.
A `CwdChanged` hook fixes this: it runs each time Claude changes directory, so you can reload the correct variables for the new location. The hook writes the updated values to `CLAUDE_ENV_FILE`, which Claude Code applies before each Bash command. Add this to `~/.claude/settings.json`:
Pairing a `SessionStart` hook with a `CwdChanged` hook fixes this. `SessionStart` loads the variables for the directory you launch in, and `CwdChanged` reloads them each time Claude changes directory. Both write to `CLAUDE_ENV_FILE`, which Claude Code runs as a script preamble before each Bash command. Add this to `~/.claude/settings.json`:
```json
{
"hooks": {
"SessionStart": [
{
"hooks": [
{
"type": "command",
"command": "direnv export bash > \"$CLAUDE_ENV_FILE\""
}
]
}
],
"CwdChanged": [
{
"hooks": [
{
"type": "command",
"command": "direnv export bash >> \"$CLAUDE_ENV_FILE\""
"command": "direnv export bash > \"$CLAUDE_ENV_FILE\""
}
]
}
@@ -304,6 +314,8 @@ A `CwdChanged` hook fixes this: it runs each time Claude changes directory, so y
}
```
Run `direnv allow` once in each directory that has an `.envrc` so direnv is permitted to load it. If you use devbox or nix instead of direnv, the same pattern works with `devbox shellenv` or `devbox global shellenv` in place of `direnv export bash`.
To react to specific files instead of every directory change, use `FileChanged` with a `matcher` listing the filenames to watch, separated by `|`. To build the watch list, this value is split into literal filenames rather than evaluated as a regex. See [FileChanged](/en/hooks#filechanged) for how the same value also filters which hook groups run when a file changes. This example watches `.envrc` and `.env` in the working directory:
```json
@@ -315,7 +327,7 @@ To react to specific files instead of every directory change, use `FileChanged`
"hooks": [
{
"type": "command",
"command": "direnv export bash >> \"$CLAUDE_ENV_FILE\""
"command": "direnv export bash > \"$CLAUDE_ENV_FILE\""
}
]
}
@@ -604,7 +616,7 @@ For full matcher syntax, see the [Hooks reference](/en/hooks#configuration).
The `if` field requires Claude Code v2.1.85 or later. Earlier versions ignore it and run the hook on every matched call.
The `if` field uses [permission rule syntax](/en/permissions) to filter hooks by tool name and arguments together, so the hook process only spawns when the tool call matches. This goes beyond `matcher`, which filters at the group level by tool name only.
The `if` field uses [permission rule syntax](/en/permissions) to filter hooks by tool name and arguments together, so the hook process only spawns when the tool call matches, or when a Bash command is too complex to parse. This goes beyond `matcher`, which filters at the group level by tool name only.
For example, to run a hook only when Claude uses `git` commands rather than all Bash commands:
@@ -627,9 +639,9 @@ For example, to run a hook only when Claude uses `git` commands rather than all
}
```
The hook process only spawns when the Bash command starts with `git`. Other Bash commands skip this handler entirely. The `if` field accepts the same patterns as permission rules: `"Bash(git *)"`, `"Edit(*.ts)"`, and so on. To match multiple tool names, use separate handlers each with its own `if` value, or match at the `matcher` level where pipe alternation is supported.
The hook process only spawns when a subcommand of the Bash command matches `git *`, or when the command is too complex to parse into subcommands. For compound commands like `npm test && git push`, Claude Code evaluates each subcommand and fires the hook because `git push` matches. The `if` field accepts the same patterns as permission rules: `"Bash(git *)"`, `"Edit(*.ts)"`, and so on. To match multiple tool names, use separate handlers each with its own `if` value, or match at the `matcher` level where pipe alternation is supported.
`if` only works on tool events: `PreToolUse`, `PostToolUse`, `PostToolUseFailure`, `PermissionRequest`, and `PermissionDenied`. Adding it to any other event prevents the hook from running.
`if` only works on tool events: `PreToolUse`, `PostToolUse`, `PostToolUseFailure`, and `PermissionRequest`. Adding it to any other event prevents the hook from running.
### Configure hook location
hooks +6 -4

if 条件が Bash の入力コマンドをサブコマンド単位で評価することや、複雑なコマンドの場合の実行挙動について追記されました。

@@ -48,7 +48,7 @@ The table below summarizes when each event fires. The [Hook events](#hook-events
### How a hook resolves
To see how these pieces fit together, consider this `PreToolUse` hook that blocks destructive shell commands. The `matcher` narrows to Bash tool calls and the `if` condition narrows further to commands starting with `rm`, so `block-rm.sh` only spawns when both filters match:
To see how these pieces fit together, consider this `PreToolUse` hook that blocks destructive shell commands. The `matcher` narrows to Bash tool calls and the `if` condition narrows further to Bash subcommands matching `rm *`, so `block-rm.sh` only spawns when both filters match:
```json
{
@@ -99,7 +99,7 @@ The `PreToolUse` event fires. Claude Code sends the tool input as JSON on stdin
The matcher `"Bash"` matches the tool name, so this hook group activates. If you omit the matcher or use `"*"`, the group activates on every occurrence of the event.
The `if` condition `"Bash(rm *)"` matches because the command starts with `rm`, so this handler spawns. If the command had been `npm test`, the `if` check would fail and `block-rm.sh` would never run, avoiding the process spawn overhead. The `if` field is optional; without it, every handler in the matched group runs.
The `if` condition `"Bash(rm *)"` matches because `rm -rf /tmp/build` is a subcommand matching `rm *`, so this handler spawns. If the command had been `npm test`, the `if` check would fail and `block-rm.sh` would never run, avoiding the process spawn overhead. The `if` field is optional; without it, every handler in the matched group runs.
The script inspects the full command and finds `rm -rf`, so it prints a decision to stdout:
@@ -202,7 +202,7 @@ This example runs a linting script only when Claude writes or edits a file:
`UserPromptSubmit`, `Stop`, `TeammateIdle`, `TaskCreated`, `TaskCompleted`, `WorktreeCreate`, `WorktreeRemove`, and `CwdChanged` don't support matchers and always fire on every occurrence. If you add a `matcher` field to these events, it is silently ignored.
For tool events, you can filter more narrowly by setting the [`if` field](#common-fields) on individual hook handlers. `if` uses [permission rule syntax](/en/permissions) to match against the tool name and arguments together, so `"Bash(git *)"` runs only for `git` commands and `"Edit(*.ts)"` runs only for TypeScript files.
For tool events, you can filter more narrowly by setting the [`if` field](#common-fields) on individual hook handlers. `if` uses [permission rule syntax](/en/permissions) to match against the tool name and arguments together, so `"Bash(git *)"` runs when any subcommand of the Bash input matches `git *` and `"Edit(*.ts)"` runs only for TypeScript files.
#### Match MCP tools
@@ -264,11 +264,13 @@ These fields apply to all hook types:
| Field | Required | Description |
| :- | :- | :- |
| `type` | yes | `"command"`, `"http"`, `"prompt"`, or `"agent"` |
| `if` | no | Permission rule syntax to filter when this hook runs, such as `"Bash(git *)"` or `"Edit(*.ts)"`. The hook only spawns if the tool call matches the pattern. Only evaluated on tool events: `PreToolUse`, `PostToolUse`, `PostToolUseFailure`, `PermissionRequest`, and `PermissionDenied`. On other events, a hook with `if` set never runs. Uses the same syntax as [permission rules](/en/permissions) |
| `if` | no | Permission rule syntax to filter when this hook runs, such as `"Bash(git *)"` or `"Edit(*.ts)"`. The hook only spawns if the tool call matches the pattern, or if a Bash command is too complex to parse. Only evaluated on tool events: `PreToolUse`, `PostToolUse`, `PostToolUseFailure`, and `PermissionRequest`. On other events, a hook with `if` set never runs. Uses the same syntax as [permission rules](/en/permissions) |
| `timeout` | no | Seconds before canceling. Defaults: 600 for command, 30 for prompt, 60 for agent |
| `statusMessage` | no | Custom spinner message displayed while the hook runs |
| `once` | no | If `true`, runs once per session then is removed. Only honored for hooks declared in [skill frontmatter](#hooks-in-skills-and-agents); ignored in settings files and agent frontmatter |
The `if` field holds exactly one permission rule. There is no `&&`, `||`, or list syntax for combining rules; to apply multiple conditions, define a separate hook handler for each. For Bash, the rule is matched against each subcommand of the tool input after leading `VAR=value` assignments are stripped, so `if: "Bash(git push *)"` matches both `FOO=bar git push` and `npm test && git push`. The hook runs if any subcommand matches, and always runs when the command is too complex to parse.
#### Command hook fields
In addition to the [common fields](#common-fields), command hooks accept these fields:
interactive-mode +7 -6

macOS 標準ターミナルや各エディタでの Shift+Enter 対応状況が整理され、新しい操作として undo (uキー) が追加されました。

@@ -13,8 +13,8 @@ Keyboard shortcuts may vary by platform and terminal. Press `?` to see available
**macOS users**: Option/Alt key shortcuts (`Alt+B`, `Alt+F`, `Alt+Y`, `Alt+M`, `Alt+P`, `Alt+T`) require configuring Option as Meta in your terminal:
- **iTerm2**: settings → Profiles → Keys → set Left/Right Option key to "Esc+"
- **Terminal.app**: settings → Profiles → Keyboard → check "Use Option as Meta Key"
- **iTerm2**: Settings → Profiles → Keys → General → set Left/Right Option key to "Esc+"
- **Apple Terminal**: Settings → Profiles → Keyboard → check "Use Option as Meta Key"
- **VS Code**: set `"terminal.integrated.macOptionIsMeta": true` in VS Code settings
See [Terminal configuration](/en/terminal-config) for details.
@@ -66,12 +66,12 @@ See [Terminal configuration](/en/terminal-config) for details.
| Method | Shortcut | Context |
| :- | :- | :- |
| Quick escape | `\` + `Enter` | Works in all terminals |
| macOS default | `Option+Enter` | Default on macOS |
| Shift+Enter | `Shift+Enter` | Works out of the box in iTerm2, WezTerm, Ghostty, Kitty |
| Control sequence | `Ctrl+J` | Line feed character for multiline |
| Option key | `Option+Enter` | After enabling [Option as Meta](/en/terminal-config#enable-option-key-shortcuts-on-macos) on macOS |
| Shift+Enter | `Shift+Enter` | Native in iTerm2, WezTerm, Ghostty, Kitty, Warp, Apple Terminal |
| Control sequence | `Ctrl+J` | Works in any terminal without configuration |
| Paste mode | Paste directly | For code blocks, logs |
Shift+Enter works without configuration in iTerm2, WezTerm, Ghostty, and Kitty. For other terminals (VS Code, Alacritty, Zed, Warp), run `/terminal-setup` to install the binding.
Shift+Enter works without configuration in iTerm2, WezTerm, Ghostty, Kitty, Warp, and Apple Terminal. For VS Code, Cursor, Windsurf, Alacritty, and Zed, run `/terminal-setup` to install the binding.
### Quick commands
@@ -160,6 +160,7 @@ In vim normal mode, if the cursor is at the beginning or end of input and cannot
| `>>` | Indent line |
| `<<` | Dedent line |
| `J` | Join lines |
| `u` | Undo |
| `.` | Repeat last change |
### Text objects (NORMAL mode)
terminal-config +94 -59

ターミナルの不具合解決ガイドとして大幅に再構成され、Shift+Enter 設定、tmux 連携、フルスクリーンモード、Vim モードの詳細が包括的に説明されています。

@@ -3,106 +3,141 @@ title: terminal-config
source: https://code.claude.com/docs/en/terminal-config.md
---
# Optimize your terminal setup
# Configure your terminal for Claude Code
> Claude Code works best when your terminal is properly configured. Follow these guidelines to optimize your experience.
> Fix Shift+Enter for newlines, get a terminal bell when Claude finishes, configure tmux, match the color theme, and enable Vim mode in the Claude Code CLI.
### Themes and appearance
Claude Code works in any terminal without configuration. This page is for when something specific is not behaving the way you expect. Find your symptom below. If everything already feels right, you do not need this page.
Claude cannot control the theme of your terminal. That's handled by your terminal application. You can match Claude Code's theme to your terminal via the `/theme` command. Select `auto` in the theme picker to have Claude Code follow your terminal's dark or light mode automatically.
- [Shift+Enter submits instead of inserting a newline](#enter-multiline-prompts)
- [Option-key shortcuts do nothing on macOS](#enable-option-key-shortcuts-on-macos)
- [No sound or alert when Claude finishes](#get-a-terminal-bell-or-notification)
- [You run Claude Code inside tmux](#configure-tmux)
- [Display flickers or scrollback jumps](#switch-to-fullscreen-rendering)
- [You want Vim keys in the prompt](#edit-prompts-with-vim-keybindings)
For additional customization of the Claude Code interface itself, you can configure a [custom status line](/en/statusline) to display contextual information like the current model, working directory, or git branch at the bottom of your terminal.
This page is about getting your terminal to send the right signals to Claude Code. To change which keys Claude Code itself responds to, see [keybindings](/en/keybindings) instead.
### Line breaks
## Enter multiline prompts
You have several options for entering line breaks into Claude Code:
Pressing Enter submits your message. To add a line break without submitting, press Ctrl+J, or type `\` and then press Enter. Both work in every terminal with no setup.
- **Quick escape**: Type `\` followed by Enter to create a newline
- **Ctrl+J**: Sends a line feed character, which works as a newline in any terminal without configuration
- **Shift+Enter**: Works out of the box in iTerm2, WezTerm, Ghostty, and Kitty
- **Keyboard shortcut**: Set up a keybinding to insert a newline in other terminals
In most terminals you can also press Shift+Enter, but support varies by terminal emulator:
#### Set up Shift+Enter with /terminal-setup
| Terminal | Shift+Enter for newline |
| :- | :- |
| Ghostty, Kitty, iTerm2, WezTerm, Warp, Apple Terminal | Works without setup |
| VS Code, Cursor, Windsurf, Alacritty, Zed | Run `/terminal-setup` once |
| Windows Terminal, gnome-terminal, JetBrains IDEs such as PyCharm and Android Studio | Not available; use Ctrl+J or `\` then Enter |
Run `/terminal-setup` within Claude Code to automatically configure Shift+Enter for VS Code, Alacritty, Zed, and Warp.
For VS Code, Cursor, Windsurf, Alacritty, and Zed, `/terminal-setup` writes Shift+Enter and other keybindings into the terminal's configuration file. If it reports a conflict such as `Found existing VSCode terminal Shift+Enter key binding`, remove that entry from the terminal's own keybindings file, for example VS Code's `keybindings.json`, and run the command again. Run `/terminal-setup` directly in the host terminal rather than inside tmux or screen, since it needs to write to the host terminal's configuration.
The `/terminal-setup` command is only visible in terminals that require manual configuration. If you're using iTerm2, WezTerm, Ghostty, or Kitty, you won't see this command because Shift+Enter already works natively.
If you are running inside tmux, Shift+Enter also requires the [tmux configuration below](#configure-tmux) even when the outer terminal supports it.
#### Set up Shift+Enter in tmux
To bind newline to a different key, or to swap behavior so Enter inserts a newline and Shift+Enter submits, map the `chat:newline` and `chat:submit` actions in your [keybindings file](/en/keybindings).
Inside tmux, `Shift+Enter` submits instead of inserting a newline unless extended key reporting is enabled. Add these lines to `~/.tmux.conf`, then run `tmux source-file ~/.tmux.conf` to reload your configuration:
## Enable Option key shortcuts on macOS
```text
set -s extended-keys on
set -as terminal-features 'xterm*:extkeys'
```
Some Claude Code shortcuts use the Option key, such as Option+Enter for a newline or Option+P to switch models. On macOS, most terminals do not send Option as a modifier by default, so these shortcuts do nothing until you enable it. The terminal setting for this is usually labeled "Use Option as Meta Key"; Meta is the historical Unix name for the key now labeled Option or Alt.
Claude Code requests extended keys at startup, but tmux ignores the request unless `extended-keys` is set to `on`. The `terminal-features` line tells tmux that your outer terminal can send these sequences.
Open Settings → Profiles → Keyboard and check "Use Option as Meta Key".
#### Set up Option+Enter on macOS
If you accepted Claude Code's first-run prompt that offered "Option+Enter for newlines and visual bell", this is already done. That prompt runs `/terminal-setup` for you, which enables Option as Meta and switches the audio bell to a visual screen flash in your Apple Terminal profile.
On macOS, you can use Option+Enter as the newline keybinding in Terminal.app, iTerm2, and the VS Code terminal after enabling the Option-as-Meta setting.
Open Settings → Profiles → Keys → General and set Left Option key and Right Option key to "Esc+".
1. Open Settings → Profiles → Keyboard
2. Check "Use Option as Meta Key"
Add `"terminal.integrated.macOptionIsMeta": true` to your VS Code settings.
1) Open Settings → Profiles → Keys
2) Under General, set Left/Right Option key to "Esc+"
For Ghostty, Kitty, and other terminals, look for an Option-as-Alt or Option-as-Meta setting in the terminal's configuration file.
Set `"terminal.integrated.macOptionIsMeta": true` in VS Code settings.
## Get a terminal bell or notification
### Notification setup
When Claude finishes a task or pauses for a permission prompt, it fires a notification event. Surfacing this as a terminal bell or desktop notification lets you switch to other work while a long task runs.
When Claude finishes working and is waiting for your input, it fires a notification event. You can surface this event as a desktop notification through your terminal or run custom logic with [notification hooks](/en/hooks#notification).
Claude Code sends a desktop notification only in Ghostty, Kitty, and iTerm2; every other terminal needs a [Notification hook](#play-a-sound-with-a-notification-hook) instead. The notification also reaches your local machine over SSH, so a remote session can still alert you. Ghostty and Kitty forward it to your OS notification center without further setup. iTerm2 requires you to enable forwarding:
#### Terminal notifications
Go to Settings → Profiles → Terminal.
Kitty and Ghostty support desktop notifications without additional configuration. iTerm 2 requires setup:
Check "Notification Center Alerts", then click "Filter Alerts" and enable "Send escape sequence-generated alerts".
1. Open iTerm 2 Settings → Profiles → Terminal
2. Enable "Notification Center Alerts"
3. Click "Filter Alerts" and check "Send escape sequence-generated alerts"
If notifications still do not appear, confirm that your terminal application has notification permission in your OS settings, and if you are running inside tmux, [enable passthrough](#configure-tmux).
If notifications aren't appearing, verify that your terminal app has notification permissions in your OS settings.
### Play a sound with a Notification hook
When running Claude Code inside tmux, notifications and the [terminal progress bar](/en/settings#global-config-settings) only reach the outer terminal, such as iTerm2, Kitty, or Ghostty, if you enable passthrough in your tmux configuration:
In any terminal you can configure a [Notification hook](/en/hooks-guide#get-notified-when-claude-needs-input) to play a sound or run a custom command when Claude needs your attention. Hooks run alongside the desktop notification rather than replacing it. Terminals such as Warp or Apple Terminal rely on a hook alone since Claude Code does not send them a desktop notification.
The example below plays a system sound on macOS. The linked guide has desktop notification commands for macOS, Linux, and Windows.
```json ~/.claude/settings.json theme={null}
{
"hooks": {
"Notification": [
{
"hooks": [{ "type": "command", "command": "afplay /System/Library/Sounds/Glass.aiff" }]
}
]
}
}
```
## Configure tmux
When Claude Code runs inside tmux, two things break by default: Shift+Enter submits instead of inserting a newline, and desktop notifications and the [progress bar](/en/settings#global-config-settings) never reach the outer terminal. Add these lines to `~/.tmux.conf`, then run `tmux source-file ~/.tmux.conf` to apply them to the running server:
```bash ~/.tmux.conf theme={null}
set -g allow-passthrough on
set -s extended-keys on
set -as terminal-features 'xterm*:extkeys'
```
Without this setting, tmux intercepts the escape sequences and they do not reach the terminal application.
The `allow-passthrough` line lets notifications and progress updates reach iTerm2, Ghostty, or Kitty instead of being swallowed by tmux. The `extended-keys` lines let tmux distinguish Shift+Enter from plain Enter so the newline shortcut works.
Other terminals, including the default macOS Terminal, do not support native notifications. Use [notification hooks](/en/hooks#notification) instead.
## Match the color theme
#### Notification hooks
Use the `/theme` command, or the theme picker in `/config`, to choose a Claude Code theme that matches your terminal. Selecting the auto option detects your terminal's light or dark background, so the theme follows OS appearance changes whenever your terminal does. The available themes are built in; there is no custom theme file. Claude Code does not control the terminal's own color scheme, which is set by the terminal application.
To add custom behavior when notifications fire, such as playing a sound or sending a message, configure a [notification hook](/en/hooks#notification). Hooks run alongside terminal notifications, not as a replacement.
To customize what appears at the bottom of the interface, configure a [custom status line](/en/statusline) that shows the current model, working directory, git branch, or other context.
### Reduce flicker and memory usage
## Switch to fullscreen rendering
If the display flickers or the scroll position jumps while Claude is working, switch to [fullscreen rendering mode](/en/fullscreen). It draws to a separate screen the terminal reserves for full-screen apps instead of appending to your normal scrollback, which keeps memory usage flat and adds mouse support for scrolling and selection. In this mode you scroll with the mouse or PageUp inside Claude Code rather than with your terminal's native scrollback; see the [fullscreen page](/en/fullscreen#search-and-review-the-conversation) for how to search and copy.
Run `/tui fullscreen` to switch in the current session with your conversation intact. To make it the default, set the `CLAUDE_CODE_NO_FLICKER` environment variable before starting Claude Code:
```bash Bash and Zsh theme={null}
CLAUDE_CODE_NO_FLICKER=1 claude
```
```powershell PowerShell theme={null}
$env:CLAUDE_CODE_NO_FLICKER = "1"; claude
```
```json ~/.claude/settings.json theme={null}
{
"env": {
"CLAUDE_CODE_NO_FLICKER": "1"
}
}
```
If you see flicker during long sessions, or your terminal scroll position jumps to the top while Claude is working, try [fullscreen rendering](/en/fullscreen). It uses an alternate rendering path that keeps memory flat and adds mouse support. Run `/tui fullscreen` to switch in your current conversation.
## Paste large content
### Handling large inputs
When you paste more than 10,000 characters into the prompt, Claude Code collapses the input to a `[Pasted text]` placeholder so the input box stays usable. The full content is still sent to Claude when you submit.
When working with extensive code or long instructions:
The VS Code integrated terminal can drop characters from very large pastes before they reach Claude Code, so prefer file-based workflows there. For very large inputs such as entire files or long logs, write the content to a file and ask Claude to read it instead of pasting. This keeps the conversation transcript readable and lets Claude reference the file by path in later turns.
- **Avoid direct pasting**: Claude Code may struggle with very long pasted content
- **Use file-based workflows**: Write content to a file and ask Claude to read it
- **Be aware of VS Code limitations**: The VS Code terminal is particularly prone to truncating long pastes
## Edit prompts with Vim keybindings
### Vim Mode
Claude Code includes a Vim-style editing mode for the prompt input. Enable it through `/config` → Editor mode, or by setting the [`editorMode`](/en/settings#global-config-settings) global config key to `"vim"` in `~/.claude.json`. Set Editor mode back to `normal` to turn it off.
Claude Code supports a subset of Vim keybindings that can be enabled via `/config` → Editor mode. To set the mode directly in your config file, set the [`editorMode`](/en/settings#global-config-settings) global config key to `"vim"` in `~/.claude.json`.
Vim mode supports a subset of NORMAL-mode motions and operators, such as `hjkl` navigation and `d`/`c`/`y` with text objects. See the [Vim editor mode reference](/en/interactive-mode#vim-editor-mode) for the full key table. Vim motions are not remappable through the keybindings file.
The supported subset includes:
Pressing Enter still submits your prompt in INSERT mode, unlike standard Vim. Use `o` or `O` in NORMAL mode, or Ctrl+J, to insert a newline instead.
- Mode switching: `Esc` (to NORMAL), `i`/`I`, `a`/`A`, `o`/`O` (to INSERT)
- Navigation: `h`/`j`/`k`/`l`, `w`/`e`/`b`, `0`/`$`/`^`, `gg`/`G`, `f`/`F`/`t`/`T` with `;`/`,` repeat
- Editing: `x`, `dw`/`de`/`db`/`dd`/`D`, `cw`/`ce`/`cb`/`cc`/`C`, `.` (repeat)
- Yank/paste: `yy`/`Y`, `yw`/`ye`/`yb`, `p`/`P`
- Text objects: `iw`/`aw`, `iW`/`aW`, `i"`/`a"`, `i'`/`a'`, `i(`/`a(`, `i[`/`a[`, `i{`/`a{`
- Indentation: `>>`/`<<`
- Line operations: `J` (join lines)
## Related resources
See [Interactive mode](/en/interactive-mode#vim-editor-mode) for the complete reference.
- [Interactive mode](/en/interactive-mode): full keyboard shortcut reference and the Vim key table
- [Keybindings](/en/keybindings): remap any Claude Code shortcut, including Enter and Shift+Enter
- [Fullscreen rendering](/en/fullscreen): details on scrolling, search, and copy in fullscreen mode
- [Hooks guide](/en/hooks-guide): more Notification hook examples for Linux and Windows
- [Troubleshooting](/en/troubleshooting): fixes for issues outside terminal configuration