7 min read
Ctrl+J: the newline shortcut agent TUIs don't tell you about

You want a multiline prompt in kiro-cli or the agent TUI: a list of requirements, a walkthrough of a diff, context that doesn’t fit in one sentence. You hit Enter and it submits halfway.

Ctrl+J inserts the line in almost any terminal, including tmux. Until you press it inside VS Code’s integrated terminal (or a fork like Cursor or Kiro IDE) and the panel disappears.

This post is short on purpose. It complements the IAG tooling map with a keyboard detail those CLIs barely document.

The trick

Enter submits. Ctrl+J inserts the newline.

ToolNewline (always)Others, if the terminal reports them
OpenCodeShift+Enter / Ctrl+Enter (the app intercepts them)(none)
Kiro CLICtrl+JShift+Enter, Alt+Enter; /editor opens $EDITOR
Cursor Agent (agent)Ctrl+J; \ then EnterShift+Enter; Option+Enter after /setup-terminal

Ctrl+J isn’t a shortcut Kiro invented. It’s the control character terminals have been emitting for decades. There is no other Ctrl+letter that does the same thing: J is the tenth letter of the Latin alphabet, and Ctrl+J is the only ASCII 10 (LF) byte. Ctrl+M is CR (the Enter that submits). Ctrl+I is Tab. There is no “Ctrl+K but for newline”.

What does exist are other combinations the TUI treats as “new line” without emitting LF:

ComboWhat goes down the wireWorks out of the box in
Ctrl+JLF (\n, ASCII 10)Any real terminal; in VS Code the workbench keeps it
\ + Enterbackslash then CR; the TUI turns it into a newlineCursor Agent, including tmux and the VS Code terminal
Shift+Entera modified-key sequence (not LF)iTerm2, Ghostty, Kitty, Warp, Zed
Alt+Enter / Option+Enterusually ESC+CR or another sequenceTerminal.app, Ghostty; VS Code only after setup

Shift+Enter and Alt+Enter are not Ctrl+J under another name. They depend on the emulator reporting the modifier. In gnome-terminal, in many IDEs, and inside tmux, Shift+Enter arrives as a plain Enter and submits the prompt. That’s why Cursor and Kiro docs call Ctrl+J (and, in Agent, \+Enter) the universal option.

Kiro documents /settings terminal to auto-configure Shift+Enter. Cursor documents /setup-terminal. Both end up writing an emulator keymap (in VS Code, a sendSequence) so that combo stops being a disguised Enter.

Why it works

Ctrl+letter isn’t OS magic. In the teletype / VT100 model, Ctrl plus a letter produces the byte letter & 0x1F: the matching control character.

ShortcutCharacterASCIIEquivalent
Ctrl+JLF10\n
Ctrl+MCR13Enter
Ctrl+IHT9Tab
Ctrl+[ESC27Escape
Ctrl+DEOT4EOF / close input
Ctrl+LFF12Clear screen (often)
Ctrl+HBS8Backspace (sometimes)

Enter is CR (Ctrl+M). Ctrl+J is LF. Kiro and Agent, in the TUI, treat LF as newline: if the editor eats Ctrl+J first, the input never sees it. OpenCode intercepts Shift+Enter at the application layer and doesn’t depend on that byte.

There are three layers, and any of them can keep the event:

Keyboard → terminal (bytes) → TUI (interpretation)

In a real emulator (WezTerm, Alacritty, iTerm2, GNOME Terminal) the three layers cooperate and Ctrl+J is LF. In an IDE’s integrated terminal the middle layer is the workbench: it decides whether the shortcut is its own or belongs to the process inside.

Linux and macOS behave the same in a real terminal. On Windows, Windows Terminal plus WSL, Git Bash, or SSH do too. PowerShell, cmd, and any GUI text field do not follow these rules: Ctrl+J is not LF there.

The clash in VS Code (and forks)

In Visual Studio Code, Ctrl+J (Cmd+J on macOS) is bound to workbench.action.togglePanel: show or hide the bottom panel. Cursor, Kiro IDE, and the rest of the forks inherit that keymap. If you run kiro-cli or agent inside that terminal, Ctrl+J never reaches the TUI. It reaches the workbench. The panel collapses.

On macOS the panel shortcut is usually Cmd+J, so Ctrl+J may already work in the integrated terminal. The ugly collision is Linux and Windows, where Ctrl+J is the panel toggle.

There is no second factory Ctrl+… that inserts LF and still uses Ctrl+J for the panel. In Cursor Agent you don’t need one: type \ and press Enter. I’ve checked it in Cursor’s integrated terminal: it inserts the line, doesn’t hide the panel, and doesn’t touch the keymap. (Agent’s docs also list it as working in tmux and over SSH.) In Kiro, without remapping, you’re left with /editor (opens $EDITOR) or pasting text that’s already multiline.

If you want Shift+Enter in that terminal, it isn’t free: you have to configure the IDE (/setup-terminal in Agent, /settings terminal in Kiro), which ends in a sendSequence. The rest of this section is that: give Ctrl+J’s LF back to the TUI, or send byte 10 with another key.

Let Ctrl+J reach the TUI

VS Code intercepts a list of commands when the terminal has focus (terminal.integrated.commandsToSkipShell). workbench.action.togglePanel is on that list. Remove it, and Ctrl+J is LF again for the process:

{
  "terminal.integrated.commandsToSkipShell": [
    "-workbench.action.togglePanel"
  ]
}

The panel still hides with Ctrl+` (the usual terminal shortcut). You only give up Ctrl+J while the cursor is in the terminal.

Send LF with another key

If you don’t want to touch the toggle, send the byte yourself. \u000a is LF (the same 10 as Ctrl+J). Don’t use \u000d: that’s CR, the Enter that submits the prompt.

{
  "key": "ctrl+enter",
  "command": "workbench.action.terminal.sendSequence",
  "args": { "text": "\u000a" },
  "when": "terminalFocus"
}

Pick a combo the IDE isn’t already using. Ctrl+Enter is sometimes taken; Alt+J or Ctrl+Shift+J are usually free. Same recipe in Cursor and Kiro IDE: the command has the same name.

You can also rebind Ctrl+J only when the terminal is focused to that sendSequence. Then Ctrl+J in the editor still folds the panel, and in the terminal it inserts a line. It’s still a keymap change; it’s the most precise one if you live in the IDE.

Don’t fight the IDE

If \+Enter isn’t enough or you’re on Kiro: open the TUI in WezTerm, Alacritty, or whichever emulator you already use. There Ctrl+J is LF and there’s no panel to hide. Pasting multiline text from the clipboard also works in almost every TUI.

The agent TUI and Cursor’s sidebar chat are not the same surface. This clash only shows up when the agent runs in the integrated terminal.

Closing

Enter submits because it’s CR. Ctrl+J inserts a line because it’s LF: there is no equivalent Ctrl+letter. Shift+Enter and Alt+Enter are TUI shortcuts, not terminal ones, and they fail where the emulator doesn’t report the modifier. In Agent, \+Enter fills that gap without fighting VS Code. Everywhere else, either you give LF back to the TUI, or you write the prompt where the editor doesn’t steal the keyboard.

Comments