opencode-map
← guides/

Custom commands and keybinds in opencode

IntermediateLast updated: Oct 21, 2026

Two small surfaces with outsized payoff: custom slash commands package repeatable prompts, and keybinds remap the TUI to your hands.

Custom slash commands

Drop a markdown file in .opencode/commands/ (project) or ~/.config/opencode/commands/ (global). The filename becomes the command name:

---
description: Run tests with coverage
agent: build
model: anthropic/claude-3-5-sonnet-20241022
---

Run the full test suite with coverage report and show any failures.
Focus on the failing tests and suggest fixes.

Run it in the TUI:

/test

Frontmatter sets command options; the body is the prompt template. Custom commands sit alongside built-ins like /init, /undo, /redo, /help — and a custom command with the same name overrides the built-in.

You can also define commands in opencode.json under the command key, where template is required:

{
  "command": {
    "test": {
      "template": "Run the full test suite with coverage report and show any failures.",
      "description": "Run tests with coverage"
    }
  }
}

Template placeholders

  • $ARGUMENTS — the full argument string: /component Button expands Button into the template.
  • $1, $2, $3… — positional arguments, for multi-slot templates like Create a file named $1 in $2 with content: $3.
  • !`command` — run a shell command in the project root and inject its output into the prompt:
---
description: Review recent changes
---

Recent git commits:
!`git log --oneline -10`

Review these changes and suggest any improvements.
  • @file — pull a file’s content into the prompt automatically: Review the component in @src/components/Button.tsx.

Command options

Key Effect
template The prompt sent to the LLM. Required in JSON config; the file body supplies it in Markdown.
description Shown in the TUI when you pick the command.
agent Which agent executes it (default: current agent). A subagent target triggers a subagent invocation.
subtask true forces a subagent invocation even for mode: primary agents — keeps your main context clean. false disables it.
model Per-command model override.

Pin agent: plan on a review command for a guaranteed read-only pass over a diff.

Keybinds: tui.json

TUI keybinds live in tui.json — not opencode.json, where the legacy keybinds key is deprecated and auto-migrated (see the configuration guide). The map is action name → binding:

{
  "$schema": "https://opencode.ai/tui.json",
  "leader_timeout": 2000,
  "keybinds": {
    "leader": "ctrl+x",
    "session_new": "<leader>n",
    "session_compact": "<leader>c",
    "agent_cycle": "tab",
    "app_exit": "ctrl+c,ctrl+d,<leader>q"
  }
}
  • Leader key — ctrl+x by default; press it, then the shortcut (ctrl+x then n = new session). leader_timeout sets the wait in ms. Use <leader> in your own binds to avoid terminal conflicts.
  • Value forms — one shortcut, a comma-separated list of fallbacks, an array, or an object with key, event, preventDefault, fallthrough for advanced cases.
  • Unbind — set an action to "none" (or false) to disable it.

Useful actions:

Action Default What it does
agent_cycle / agent_cycle_reverse tab / shift+tab Switch primary agent
session_new, session_list, session_compact <leader>n, <leader>l, <leader>c Session management
session_interrupt escape Stop the running response
session_child_first / session_parent <leader>down / up Enter / leave subagent sessions
model_list, agent_list <leader>m, <leader>a Model and agent pickers

The full action list is in the keybinds doc. One gotcha: some terminals don’t send Shift+Enter — the doc has per-terminal fixes, including Windows Terminal.

v2 differences

The v2 commands doc renames a few things: the JSON key is commands (plural), and subtask is a deprecated alias of subagent — subagent: true runs the command in a background child session. Nested directories namespace commands: .opencode/commands/team/review.md runs as /team/review. Stored templates no longer expand @file refs — attach files when invoking instead. On name collisions project commands override global ones, and command files hot-reload on save. Keybinds also move: in v2 they live in ~/.config/opencode/cli.json under keybinds — the value forms are the same (objects with key, event, preventDefault, fallthrough) but command ids switch from snake_case to dot-notation (app_exit→app.exit, input_paste→prompt.paste), and leader_timeout becomes a top-level leader.timeout sibling. See the v1↔v2 mapping.

Further reading