PiG Documentation

Guides and references for configuring, using, and extending PiG.

Keybindings

PiG reads keybindings from ~/.pig/agent/keybindings.json. The file is optional. If it is absent, PiG uses the defaults in this page. The action names and defaults are those of Pi 1.5.0 (Pi's keybindings reference).

Each entry maps one action to one key or a list of keys. To change a binding, write the action name and the keys you want:

{
  "app.tools.expand": "alt+o",
  "app.session.tree": ["ctrl+shift+t", "alt+shift+t"]
}

A binding in the file replaces the default for that action. It does not add to it. Bindings you do not name keep their defaults. Set an action to [] to leave the action with no key.

For validation and completion in your editor, add "$schema": "https://pi.dev/schemas/keybindings.schema.json" to the file. PiG ignores the $schema key when it loads the bindings. Pi 1.2.0 added this schema.

Set PIG_CODING_AGENT_DIR to read the file from a different directory. After you edit the file, run /reload to apply the change to the running session.

Use /hotkeys to list the keys that are active in the current session.

A custom tui.input.submit binding submits messages and slash commands through the normal interactive handler. Enabling PIG_DEBUG_KEYS does not change that binding.

If two actions claim the same key, PiG records the conflict and keeps both bindings. Both actions then answer that key, so give one of them a different key.

Worked example: move the tool-output key

Tool output longer than a few lines folds, and a hint names the key that expands it. Take this request, whose command prints 30 lines. PiG shows the last five and a hint with the key (checked on PiG; ctrl+o is the default):

 $ seq 1 30

 ... (25 earlier lines, ctrl+o to expand)
 26
 27
 28
 29
 30

Put this in ~/.pig/agent/keybindings.json, then type /reload (or start PiG again):

{
  "app.tools.expand": ["alt+o"]
}

The hint now names the new key, and the old key stops working:

 ... (25 earlier lines, alt+o to expand)

Pressing alt+o expands all 30 lines and prints Tool output: expanded. Pressing ctrl+o does nothing. /hotkeys lists the change as Alt+O | Toggle tool output expansion.

Choose a key that no other action uses. The key ctrl+e is the editor's "End of line", so a binding of app.tools.expand to ctrl+e leaves both actions on the key (checked: /hotkeys listed End/Ctrl+E and Ctrl+E | Toggle tool output expansion). PiG keeps both bindings and answers with both, which is rarely what you want. Pick an unused key, and check /hotkeys after every change.

Defaults

The keys below are the macOS defaults. Platform differences are listed after the tables.

Session control

Action
Default key
Effect
app.clearctrl+cClear editor
app.exitctrl+dExit when editor is empty
app.interruptescapeCancel or abort
app.session.deletectrl+dDelete session
app.session.deleteNoninvasivectrl+backspaceDelete session when query is empty
app.session.forknoneFork current session
app.session.newnoneStart a new session
app.session.renamectrl+rRename session
app.session.resumenoneResume a session
app.session.toggleNamedFilterctrl+nToggle named session filter
app.session.togglePathctrl+pToggle session path display
app.session.toggleSortctrl+sToggle session sort mode
app.session.treenoneOpen session tree
app.suspendctrl+zSuspend to background

Editing and messages

Action
Default key
Effect
app.clipboard.pasteImagectrl+vPaste files on macOS, images, or text from clipboard
app.editor.externalctrl+gOpen external editor
app.message.copyctrl+xCopy the selected message in /tree. In fullscreen mode with fullscreenCopyOnSelect set to false, copy the active selection. Otherwise copy the last assistant message. On OAuth sign-in screens, copy the sign-in URL
app.message.dequeuealt+upRestore queued messages
app.message.followUpalt+enterQueue follow-up message

macOS Terminal.app sends Option+Up as plain Up in its default profile, so app.message.dequeue (alt+up) never arrives there. Pi treats that Up as history recall: the queued message appears in the editor as a copy, stays queued, and is still sent. PiG differs in two ways (D228):

  • In Terminal.app (TERM_PROGRAM=Apple_Terminal), when the editor is empty, a message is queued and app.message.dequeue is bound to alt+up, plain Up runs app.message.dequeue. The queued-message hint then names Up. In every other state Up keeps Pi's behavior.
  • Everywhere else, when Up recalls history while a message is queued, PiG shows one dim line under the editor, once per run: That's a copy. The queued message still sends. <key> edits the queue. Here <key> is the key bound to app.message.dequeue. In tmux, over ssh, or in a terminal PiG does not know, the line also says how to map Option+Up to \033[1;3A in Terminal Settings > Profiles > Keyboard. Do not enable "Use Option as Meta key" for this: it makes Option+Up send Esc and then Up, and Esc aborts the turn.

Both differences apply to PiG's own editor only. An extension's custom editor keeps Pi's Up (D228).

Clipboard image helper commands reject stdout larger than 50 MiB. PiG cancels and joins an oversized helper instead of retaining its output. Unsupported image formats such as BMP are converted to PNG; a failed conversion produces no image.

Models

Action
Default key
Effect
app.model.cycleBackwardshift+ctrl+pCycle to previous model
app.model.cycleForwardctrl+pCycle to next model
app.model.selectctrl+lOpen model selector
app.models.clearAllctrl+xClear all models
app.models.enableAllctrl+aEnable all models
app.models.reorderDownalt+downMove model down in order
app.models.reorderUpalt+upMove model up in order
app.models.savectrl+sSave model selection
app.models.toggleProviderctrl+pToggle all models for provider
app.thinking.savectrl+sSave the selected thinking level as the default, in the thinking level selector

Display

Action
Default key
Effect
app.thinking.cycleshift+tabCycle thinking level
app.thinking.togglectrl+tToggle thinking blocks
app.tools.expandctrl+oToggle tool output

Session tree

Action
Default key
Effect
app.tree.editLabelshift+lEdit tree label
app.tree.filter.allctrl+aTree filter: show all entries
app.tree.filter.cycleBackwardshift+ctrl+oTree filter: cycle backward
app.tree.filter.cycleForwardctrl+oTree filter: cycle forward
app.tree.filter.defaultctrl+dTree filter: default view
app.tree.filter.labeledOnlyctrl+lTree filter: labeled entries only
app.tree.filter.noToolsctrl+tTree filter: hide tool results
app.tree.filter.userOnlyctrl+uTree filter: user messages only
app.tree.foldOrUpalt+left, ctrl+leftFold tree branch or move up
app.tree.toggleLabelTimestampshift+tToggle tree label timestamps
app.tree.unfoldOrDownalt+right, ctrl+rightUnfold tree branch or move down

Several actions share a key, such as ctrl+s for app.session.toggleSort, app.models.save and app.thinking.save. Each one applies only in its own selector, so they do not conflict.

Terminal UI actions

Actions named tui.* control the editor, lists, and the fullscreen transcript. Rebind them in keybindings.json the same way as app.* actions.

Cursor movement

Action
Default key
Effect
tui.editor.cursorUpupMove cursor up, or browse older history at the top
tui.editor.cursorDowndownMove cursor down, or browse newer history at the bottom
tui.editor.historyPreviousnoneSelect the previous prompt history entry
tui.editor.historyNextnoneSelect the next prompt history entry
tui.editor.cursorLeftleft, ctrl+bMove cursor left
tui.editor.cursorRightright, ctrl+fMove cursor right
tui.editor.cursorWordLeftalt+left, ctrl+left, alt+bMove cursor one word left
tui.editor.cursorWordRightalt+right, ctrl+right, alt+fMove cursor one word right
tui.editor.cursorLineStarthome, ctrl+aMove to line start
tui.editor.cursorLineEndend, ctrl+eMove to line end
tui.editor.jumpForwardctrl+]Jump forward to a character
tui.editor.jumpBackwardctrl+alt+]Jump backward to a character
tui.editor.pageUppageUp, ctrl+pageUpScroll the editor up one page
tui.editor.pageDownpageDown, ctrl+pageDownScroll the editor down one page

The dedicated history actions browse prompt history wherever the cursor is, and they take precedence over application actions on the same key.

Text editing

Action
Default key
Effect
tui.editor.deleteCharBackwardbackspaceDelete character backward
tui.editor.deleteCharForwarddelete, ctrl+dDelete character forward
tui.editor.deleteWordBackwardctrl+w, alt+backspaceDelete word backward
tui.editor.deleteWordForwardalt+d, alt+deleteDelete word forward
tui.editor.deleteToLineStartctrl+uDelete to line start
tui.editor.deleteToLineEndctrl+kDelete to line end
tui.editor.yankctrl+yPaste the most recently deleted text
tui.editor.yankPopalt+yCycle through deleted text after a yank
tui.editor.undoctrl+-Undo the last edit

Undo groups consecutive word characters. A space starts a new group, and each newline or paste is a separate edit. Undo restores the cursor and any large-paste content with the text. Submission clears the undo stack.

Consecutive word or line deletions accumulate in the kill ring. Typing or replacing the editor text ends that accumulation. Yank-pop replaces the last yank, including multiline text, and keeps the ring's rotated order.

Input and selection

During initial theme detection and managed-tool setup, submitting keeps the text in the editor and shows Startup is still in progress. Submit again after startup completes.

Action
Default key
Effect
tui.input.newLineshift+enter, ctrl+jInsert a new line
tui.input.submitenterSubmit input
tui.input.tabtabTab or autocomplete
tui.input.copyctrl+cCopy selection
tui.select.upupMove selection up
tui.select.downdownMove selection down
tui.select.pageUppageUpMove the selection up one page in a list
tui.select.pageDownpageDownMove the selection down one page in a list
tui.select.confirmenterConfirm selection
tui.select.cancelescape, ctrl+cCancel selection

PiG pages like Pi 1.5.0: PageUp and PageDown move the selection by one visible page in the select and settings lists, the open autocomplete list, and the model, session, tree, user-message, OAuth, scoped-models, llama.cpp and /mcp selectors, and the fullscreen transcript behind such a list does not scroll. The config selector also pages, but, as in Pi, it does not keep the fullscreen transcript from scrolling on those keys. The extension selector, the trust selector and the first-time setup dialog have no page keys and ignore them (Pi #7629).

Fullscreen transcript

These actions apply when tuiMode is fullscreen. They take precedence over editor actions that use the same key. While an overlay or a scrollable list such as autocomplete, /settings, or the model selector has focus, the scrolling and prompt-jump actions go to it instead of the transcript, so tui.select.pageUp and tui.select.pageDown move the list selection. Transcript search actions keep working.

Action
Default key
Effect
tui.altScreen.pageUppageUpScroll the transcript up one page
tui.altScreen.pageDownpageDownScroll the transcript down one page
tui.altScreen.halfPageUpnoneScroll the transcript up half a page
tui.altScreen.halfPageDownnoneScroll the transcript down half a page
tui.altScreen.lineUpnoneScroll the transcript up one line
tui.altScreen.lineDownnoneScroll the transcript down one line
tui.altScreen.previousPromptctrl+shift+up, ctrl+upJump to the previous prompt
tui.altScreen.nextPromptctrl+shift+down, ctrl+downJump to the next prompt
tui.altScreen.searchctrl+shift+fSearch the transcript
tui.altScreen.searchNextenter, ctrl+gSelect the next match while searching
tui.altScreen.searchPreviousshift+enter, ctrl+shift+gSelect the previous match while searching
tui.altScreen.searchCloseescapeClose transcript search
tui.altScreen.topctrl+homeScroll to the start of the transcript
tui.altScreen.bottomctrl+endScroll to the end of the transcript and follow new output

Platform differences

Some actions use a different key on each platform, because the terminal or the operating system reserves the macOS key. WSL uses the Windows keys, except that ctrl+z still suspends and alt+z undoes. PiG detects WSL from WSL_DISTRO_NAME or WSL_INTEROP.

Action
macOS
Linux
WSL
Windows
app.clipboard.pasteImagectrl+vctrl+valt+valt+v
app.suspendctrl+zctrl+zctrl+znone
app.message.dequeuealt+upalt+upalt+qalt+q
app.message.followUpalt+enteralt+enterctrl+qctrl+q
app.model.cycleBackwardshift+ctrl+pshift+ctrl+palt+palt+p
app.tree.foldOrUpalt+left, ctrl+leftctrl+left, alt+leftctrl+left, alt+leftctrl+left, alt+left
app.tree.unfoldOrDownalt+right, ctrl+rightctrl+right, alt+rightctrl+right, alt+rightctrl+right, alt+right
tui.editor.undoctrl+-ctrl+-alt+zctrl+z
tui.altScreen.previousPromptctrl+shift+up, ctrl+upctrl+shift+up, ctrl+upctrl+upctrl+up
tui.altScreen.nextPromptctrl+shift+down, ctrl+downctrl+shift+down, ctrl+downctrl+downctrl+down
tui.altScreen.searchctrl+shift+fctrl+shift+fctrl+fctrl+f

On native Windows, app.suspend has no default because Windows terminals do not support Unix job control. If you assign it, PiG shows a status message instead of suspending.

After ctrl+z, bg leaves the session stopped: PiG does not take the terminal back from the shell, and fg returns to it. Pi restarts its UI on bg and stops when its first terminal call fails (divergence D227).

Actions with no default key

These actions exist but have no key until you assign one. Reach them with their slash command, or bind them in keybindings.json.

Action
Slash command
app.session.fork/fork
app.session.new/new
app.session.resume/resume
app.session.tree/tree

Key names

Write a key as its name, or as modifiers joined to the name with +. The modifiers are ctrl, alt, shift and super, and you can combine them. Examples: ctrl+o, shift+ctrl+p, alt+enter, escape, ctrl+backspace, super+k.

The key names are:

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

A super binding needs a terminal that reports the modifier on its own, usually through the Kitty keyboard protocol.

A shifted symbol such as + matches the character the key produces, so ctrl++ responds under the Kitty keyboard protocol and modifyOtherKeys. Pi 1.1.0 did not match these bindings; Pi 1.5.0 does.

Terminals do not all report the same keys. If a binding does not respond, the terminal usually consumed the key before PiG saw it. See terminal setup.

Adapted from upstream Pi documentation · Upstream documentation ↗ · MIT License