pi-ask-herdr
Pi extension that adds an ask_user tool and integrates with Herdr notifications/agent state.
Package details
Install pi-ask-herdr from npm and Pi will load the resources declared by the package manifest.
$ pi install npm:pi-ask-herdr- Package
pi-ask-herdr- Version
0.2.2- Published
- Jul 22, 2026
- Downloads
- 610/mo · 318/wk
- Author
- lesetong
- License
- MIT
- Types
- extension
- Size
- 36.5 KB
- Dependencies
- 0 dependencies · 4 peers
Pi manifest JSON
{
"extensions": [
"./index.ts"
]
}Security note
Pi packages can execute code and influence agent behavior. Review the source before installing third-party packages.
README
pi-ask-herdr
A Pi extension that adds an ask_user tool, with optional integration with
Herdr agent state.
Structure
index.ts # Pi auto-discovery entry point
src/
tool.ts # Tool registration and parameter schema
ui.ts # Batch question wizard (text, confirm, select, multiselect)
herdr.ts # Herdr event-bus integration
options.ts # Option normalization
types.ts # Shared TypeScript types
What it does
- Registers an
ask_usertool that asks the user one or more questions in a single call. Each question can be:- free-form text (
type: "text") - yes/no confirmation (
type: "confirm") - single choice from a list (
type: "select") - multiple choices from a list (
type: "multiselect")
- free-form text (
- All questions are answered inside one wizard UI:
- a progress header (
Question 2/4+ progress bar) when there are multiple questions - Enter submits and moves to the next question
- Esc steps back one layer (custom input → options → previous question)
- Ctrl+C cancels the whole batch immediately
- previously answered questions keep their answers when navigating back
- long option labels and descriptions wrap instead of being truncated, including continuous CJK text and long unbroken words
- a progress header (
- Agent-facing results stay compact (
1 -> answer), while the tool result UI retains each question alongside its answer for easy review. - For
selectandmultiselect, an "Other (custom)" option is always available so the user can type their own answer. - For
confirm, you can enable the same custom option with"allow_custom": true. - No extra slash command is registered — only the
ask_usertool. - When Pi runs inside a Herdr pane, it reports the pane state as
blockedwhile waiting, shows the pending question(s) as a sidebar token, and restores both after the user answers. (Herdr itself shows a notification for blocked panes, so the extension no longer sends its own.)
Install
From npm (recommended)
pi install npm:pi-ask-herdr
Then reload Pi with /reload.
From git
pi install git:github.com/leset0ng/pi-ask-herdr@v0.2.2
Manual
Copy or clone this directory into Pi's extensions folder:
# Global
cp -R pi-ask-herdr ~/.pi/agent/extensions/
# Or project-local
cp -R pi-ask-herdr .pi/extensions/
Then reload Pi with /reload, or test it directly with:
pi -e ~/.pi/agent/extensions/pi-ask-herdr/index.ts
Tool usage
A single question (one-element questions array):
{
"questions": [
{
"question": "Which database should we use?",
"type": "select",
"options": ["PostgreSQL", "SQLite", "MySQL"]
}
]
}
Multiple questions in one call:
{
"questions": [
{
"question": "Which database should we use?",
"type": "select",
"options": [
{ "label": "PostgreSQL", "description": "Full-featured relational database" },
{ "label": "SQLite", "description": "Zero-config file database" },
{ "label": "MySQL", "description": "Widely used open-source RDBMS" }
]
},
{
"question": "Which features should we enable?",
"type": "multiselect",
"options": ["dark mode", "notifications", "auto-save"]
},
{
"question": "Any additional notes?",
"type": "text"
}
]
}
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
| questions | object[] | yes | Questions to ask, in order (min 1). See per-question fields. |
| timeout | number | no | Total timeout in milliseconds for the whole batch |
Per-question fields:
| Name | Type | Required | Description |
|---|---|---|---|
| question | string | yes | The question to display |
| type | string | no | "text", "confirm", "select", "multiselect" (default: text) |
| options | string[] or object[] | no | Required when type is select or multiselect. Each item can be a string or { "label": string, "description"?: string } |
| default | string | no | Prefilled value for text input |
| allow_custom | boolean | no | For confirm: also offer "Other (custom)" |
Key bindings
| Key | Action |
|---|---|
| Enter | Submit current question and advance (on the last question: finish) |
| Esc | Step back one layer: custom input → options → previous question |
| Ctrl+C | Cancel the whole batch immediately (answers are discarded) |
| Space | Toggle an option in multiselect questions |
Herdr integration
The extension detects Herdr via the environment variables that Herdr injects into its panes:
HERDR_ENV=1HERDR_SOCKET_PATHHERDR_PANE_ID
If these are present, the extension:
- emits
herdr:blockedwithactive: truebefore prompting (the official Herdr Pi integration turns this into ablockedpane state, which Herdr surfaces as a notification) - reports the first pending question and remaining count as separate pane
metadata tokens while waiting, allowing Herdr to truncate the question as
the sidebar is resized while preserving
+N - emits
herdr:blockedwithactive: falseand clears the token after the user answers
Sidebar display
For one question the row shows the question text itself. For multiple questions,
Herdr renders the short count as a separate token, for example
❓ Which database should we use? · +2. Keeping $ask_count separate ensures
it remains visible while $ask is truncated responsively as the sidebar is
resized.
To render the tokens in Herdr's sidebar, add $ask and $ask_count to the same
agent row in ~/.config/herdr/config.toml, then run
herdr server reload-config:
[ui.sidebar.agents]
rows = [["state_icon", "workspace", "tab"], ["agent", "$ask", "$ask_count"]]
Without this config the token is simply not displayed; everything else works the same.
No extra configuration is required.
License
MIT