Files
pi-ask/docs/configuration.md
T

13 KiB

pi-ask configuration

This file is the source of truth for configuring @eko24ive/pi-ask.

When changing pi-ask settings:

  1. Edit the config file.
  2. Validate keymaps against the rules below.
  3. Run /reload or restart pi so the new config is picked up.

pi-ask treats this file as user-owned config. It does not rewrite or back up the file just because it was loaded, migrated, or found invalid. Settings toggled in /ask-settings are saved only when the file is writable; if saving fails, pi-ask reverts the toggle and shows the config path to edit manually.

Config file path

Default path:

~/.pi/agent/extensions/eko24ive-pi-ask.json

If the file does not exist yet, pi-ask attempts to create it with the current default settings the first time the ask flow is used. If the config location is read-only or managed outside pi-ask, pi-ask uses built-in defaults for the session and leaves disk unchanged.

Older pi-ask versions wrote this file at ~/.pi/agent/eko24ive-pi-ask.json. If that legacy file exists and the extensions config does not, pi-ask reads the legacy file as a fallback and leaves disk unchanged. If both files exist, pi-ask uses the extensions config and leaves the legacy root file untouched.

Config versions and migrations

schemaVersion identifies the persisted config shape. pi-ask migrates older supported schema versions forward in memory before validation. Migrations preserve existing user-provided values and add new fields from defaults when needed, but loading a config does not rewrite the file.

Unsupported future versions or invalid files are left unchanged and defaults are loaded for the current session. Fix the file, then run /reload or restart pi.

Config shape

{
  "schemaVersion": 5,
  "answer": {
    "extractionModels": [
      { "provider": "openai-codex", "id": "<model-id>" },
      { "provider": "github-copilot", "id": "<model-id>" },
      { "provider": "anthropic", "id": "<model-id>" }
    ],
    "extractionTimeoutMs": 30000,
    "extractionRetries": 1
  },
  "behaviour": {
    "autoSubmitWhenAnsweredWithoutNotes": false,
    "confirmDismissWhenDirty": true,
    "doublePressReviewShortcuts": true,
    "presentSingleAsMulti": false,
    "showFooterHints": true
  },
  "keymaps": {
    "global": { "dismiss": ["ctrl+c"], "settings": ["?"] },
    "main": {
      "confirm": ["enter"],
      "cancel": ["esc"],
      "toggle": ["space"],
      "changeQuestionType": ["t"],
      "nextTab": ["tab", "right"],
      "previousTab": ["shift+tab", "left"],
      "nextOption": ["down"],
      "previousOption": ["up"],
      "optionNote": ["n"],
      "questionNote": ["shift+n"]
    },
    "editor": {
      "submit": ["enter"],
      "close": ["esc"],
      "nextTabWhenEmpty": ["tab", "right"],
      "previousTabWhenEmpty": ["shift+tab", "left"],
      "nextOptionWhenEmpty": ["down"],
      "previousOptionWhenEmpty": ["up"]
    },
    "noteEditor": {
      "save": ["enter"],
      "close": ["esc"],
      "nextTabWhenEmpty": ["tab", "right"],
      "previousTabWhenEmpty": ["shift+tab", "left"],
      "nextOptionWhenEmpty": ["down"],
      "previousOptionWhenEmpty": ["up"]
    },
    "settingsModal": {
      "close": ["esc", "ctrl+c", "?"],
      "nextOption": ["down"],
      "previousOption": ["up"],
      "toggle": ["enter", "space"]
    }
  },
  "notifications": {
    "enabled": true,
    "channels": ["bell"]
  }
}

Answer extraction

These settings affect only the /answer command. Normal ask_user tool calls do not use an extraction model.

answer.extractionModels

  • type: array of { "provider": string, "id": string }
  • default: lightweight OpenAI Codex, GitHub Copilot, and Anthropic models
  • effect: /answer tries configured models in order and uses the first model with available auth
  • fallback: if no configured model is usable, /answer tries the current chat model after validating its auth

answer.extractionTimeoutMs

  • type: positive number
  • default: 30000
  • effect: per-attempt extraction timeout in milliseconds

answer.extractionRetries

  • type: integer from 0 to 3
  • default: 1
  • effect: number of retry attempts after the model omits ask_user, returns invalid tool arguments, or produces an invalid JSON text fallback; retries include the previous error and response as feedback

Behaviour

behaviour.autoSubmitWhenAnsweredWithoutNotes

  • type: boolean
  • default: false
  • effect: when enabled, a fully answered ask flow with no notes can auto-submit from the review tab

behaviour.confirmDismissWhenDirty

  • type: boolean
  • default: true
  • effect: when enabled, discarding a dirty ask flow requires a second cancel/dismiss action
  • the warning stays visible until the user changes tabs in the ask flow
  • dirty means there are saved answers/notes or unsaved editor draft text

behaviour.doublePressReviewShortcuts

  • type: boolean
  • default: true
  • effect: when enabled, review-tab number shortcuts (1, 2, 3) only trigger after pressing the same key twice
  • the review screen shows an inline hint and keeps the pending shortcut armed until another review shortcut is pressed or the user leaves the tab

behaviour.presentSingleAsMulti

  • type: boolean
  • default: false
  • effect: future ask flows render requested single questions as multi questions
  • result: the question keeps type: "single" and adds presentedType: "multi"; result text uses one compact note when any answered questions were presented differently
  • scope: this is a default presentation policy for new/replayed ask flows; it is not hot-applied to the current ask flow
  • current-flow override: use the configurable main-flow changeQuestionType hotkey (default t) to change the active question type live: non-preview questions toggle single <-> multi; preview questions toggle preview <-> multi
  • destructive confirmation: changing multi -> single with multiple selected answers requires pressing the type hotkey again; the pending confirmation has no timeout and clears when another navigation/action is used

behaviour.showFooterHints

  • type: boolean
  • default: true
  • effect: when disabled, the ask flow hides the footer keymap hints

Notifications

Notifications are best-effort external alerts emitted once per ask session, when the ask UI opens and is waiting for input.

notifications.enabled

  • type: boolean
  • default: true
  • effect: enables or disables external ask notifications
  • settings UI: this is the only notification field toggled individually by /ask-settings or ? in the ask flow

notifications.channels

  • type: array
  • default: ["bell"]
  • supported channels:
    • "bell" writes BEL (\u0007)
    • "osc9" writes an OSC 9 terminal notification
    • "osc777" writes an OSC 777 title/body notification
    • { "type": "command", "command": string } runs a shell command
  • effect: channels run in order; failures are ignored and never fail the ask flow
  • invalid channels are skipped; if none are valid, pi-ask falls back to ["bell"]

Notification text:

Question waiting: <label or prompt>

Command channels receive these environment variables:

ASK_NOTIFY_EVENT=question.waiting
ASK_NOTIFY_TITLE="pi ask"
ASK_NOTIFY_MESSAGE="Question waiting: <label or prompt>"

cmux example:

{
  "type": "command",
  "command": "cmux notify --title \"$ASK_NOTIFY_TITLE\" --body \"$ASK_NOTIFY_MESSAGE\""
}

Keymaps

keymaps is context-aware. Each action accepts either one key id string or an array of key id strings. Arrays are aliases: any listed key triggers the same action.

Defaults

"keymaps": {
  "global": {
    "dismiss": ["ctrl+c"],
    "settings": ["?"]
  },
  "main": {
    "confirm": ["enter"],
    "cancel": ["esc"],
    "changeQuestionType": ["t"],
    "toggle": ["space"],
    "nextTab": ["tab", "right"],
    "previousTab": ["shift+tab", "left"],
    "nextOption": ["down"],
    "previousOption": ["up"],
    "optionNote": ["n"],
    "questionNote": ["shift+n"]
  },
  "editor": {
    "submit": ["enter"],
    "close": ["esc"],
    "nextTabWhenEmpty": ["tab", "right"],
    "previousTabWhenEmpty": ["shift+tab", "left"],
    "nextOptionWhenEmpty": ["down"],
    "previousOptionWhenEmpty": ["up"]
  },
  "noteEditor": {
    "save": ["enter"],
    "close": ["esc"],
    "nextTabWhenEmpty": ["tab", "right"],
    "previousTabWhenEmpty": ["shift+tab", "left"],
    "nextOptionWhenEmpty": ["down"],
    "previousOptionWhenEmpty": ["up"]
  },
  "settingsModal": {
    "close": ["esc", "ctrl+c", "?"],
    "nextOption": ["down"],
    "previousOption": ["up"],
    "toggle": ["enter", "space"]
  }
}

Contexts

  • global: active in the main ask flow and editors; duplicates with those contexts are invalid
  • main: question and review flow
  • editor: custom answer editor
  • noteEditor: question/option note editor
  • settingsModal: /ask-settings and ? settings overlay

Allowed bindings

Each action accepts any pi-tui key id string, as long as it is:

  • supported by pi-tui
  • not a fixed numeric shortcut (1 through 9)
  • not duplicated within the same context
  • not duplicated between global and main, editor, or noteEditor

Examples of valid bindings:

  • esc
  • ctrl+c
  • space
  • enter
  • n
  • shift+n
  • alt+f7
  • ctrl+[
  • ctrl+shift+p
  • super+k

Accepted alias normalization

Common aliases are normalized to canonical pi-tui-style strings.

Examples:

  • escape -> esc
  • return -> enter
  • control+c -> ctrl+c
  • Shift+N -> shift+n
  • pageup -> pageUp
  • pagedown -> pageDown

Fixed bindings

These are intentionally not configurable:

  • 1..9 triggers option/review shortcuts
  • when behaviour.doublePressReviewShortcuts is enabled, review-tab shortcuts 1, 2, and 3 require the same key twice
  • @ remains the file-reference affordance in editors

Invalid keymaps behavior

If configured keymaps are invalid:

  • valid behaviour, notifications, and answer settings still load
  • invalid keymaps fall back to default keymaps for the current session
  • ask remains usable
  • a warning notice is shown
  • after fixing the file, run /reload or restart pi

Invalid keymaps include:

  • missing one of the required contexts or actions
  • unsupported key syntax
  • duplicate bindings within one context
  • duplicate bindings between global and main, editor, or noteEditor
  • use of fixed numeric shortcuts (1 through 9)

Example custom config

{
  "schemaVersion": 5,
  "answer": {
    "extractionRetries": 1,
    "extractionTimeoutMs": 30000,
    "extractionModels": [
      { "provider": "openai-codex", "id": "<model-id>" }
    ]
  },
  "behaviour": {
    "autoSubmitWhenAnsweredWithoutNotes": true,
    "confirmDismissWhenDirty": true,
    "doublePressReviewShortcuts": true,
    "presentSingleAsMulti": false,
    "showFooterHints": false
  },
  "keymaps": {
    "global": {
      "dismiss": ["ctrl+c"],
      "settings": ["?"]
    },
    "main": {
      "confirm": ["ctrl+k"],
      "cancel": ["q"],
      "toggle": ["ctrl+t"],
      "changeQuestionType": ["t"],
      "nextTab": ["tab", "right"],
      "previousTab": ["shift+tab", "left"],
      "nextOption": ["down"],
      "previousOption": ["up"],
      "optionNote": ["x"],
      "questionNote": ["shift+x"]
    },
    "editor": {
      "submit": ["ctrl+k"],
      "close": ["q"],
      "nextTabWhenEmpty": ["tab", "right"],
      "previousTabWhenEmpty": ["shift+tab", "left"],
      "nextOptionWhenEmpty": ["down"],
      "previousOptionWhenEmpty": ["up"]
    },
    "noteEditor": {
      "save": ["ctrl+k"],
      "close": ["q"],
      "nextTabWhenEmpty": ["tab", "right"],
      "previousTabWhenEmpty": ["shift+tab", "left"],
      "nextOptionWhenEmpty": ["down"],
      "previousOptionWhenEmpty": ["up"]
    },
    "settingsModal": {
      "close": ["esc", "ctrl+c", "?"],
      "nextOption": ["j", "down"],
      "previousOption": ["k", "up"],
      "toggle": ["enter", "space"]
    }
  },
  "notifications": {
    "enabled": true,
    "channels": [
      {
        "type": "command",
        "command": "cmux notify --title \"$ASK_NOTIFY_TITLE\" --body \"$ASK_NOTIFY_MESSAGE\""
      }
    ]
  }
}

Agent editing rule

When editing this config for a user:

  • preserve unrelated fields
  • keep schemaVersion at 5
  • preserve answer.extractionModels as explicit provider/id pairs
  • keep answer.extractionRetries between 0 and 3
  • do not assign fixed numeric shortcuts (1 through 9) to configurable actions
  • do not create duplicate bindings within a context or between global and main, editor, or noteEditor
  • preserve existing notifications.channels unless the user asks to change notification targets
  • only toggle notifications.enabled unless the user asks to configure channels
  • use the settings reset action only when the user explicitly asks to restore pi-ask defaults
  • use a cmux notify command channel when the user asks for cmux notifications
  • after changing the file, tell the user to run /reload or restart pi