Skip to content

Latest commit

 

History

202 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

@pure/pi-tool-display

License Platform

A pure TUI display wrapper for the Pi coding agent.

This extension is derived from MasuRii/pi-tool-display.

@pure/pi-tool-display keeps tool rows compact, renders trustworthy tool-provided diffs, and improves the native user prompt box without changing tools, model context, messages, or sessions.

image image image

Why the rendering-only architecture matters

Earlier tool-display integrations commonly replaced or wrapped executable tool definitions to gain control of their presentation. That made behavior depend on extension registration order: two extensions targeting the same built-in tool could overwrite each other, wrap stale definitions, change ownership, or lose settings when tools were registered late or reloaded.

@pure/pi-tool-display instead attaches at Pi's final tool-row rendering seam. It does not re-register tools, wrap execute, replace schemas, change the active tool set, or mutate model/session data. The original extension remains the tool owner and continues to control execution; this extension only chooses how the existing call and result are displayed.

This separation provides practical advantages:

  • No executable-tool ownership conflicts with extensions that customize Bash, MCP, permissions, background tasks, or other tools
  • No registration-order race between this extension and the tool producer
  • No execution or schema drift caused by cloning or wrapping tool definitions
  • Reload-safe rendering without stacking wrappers or leaving stale registrations behind
  • Fail-open compatibility: unsupported host shapes or renderer failures keep Pi's native rendering and execution
  • Explicit third-party integration through display-only adapters that never expose or mutate executable definitions

Features

  • Compact built-in tool rendering for read, grep, find, ls, bash, edit, and write
  • Opt-in MCP-style rendering with hidden, summary, and preview modes through custom tool overrides
  • Opt-in custom tool overrides for noisy extension tools, defaulting to generic rendering unless kind: "mcp" is selected
  • Adaptive edit/write diffs with split or unified layouts, syntax highlighting, inline emphasis, and narrow-pane width clamping
  • Trustworthy diff rendering only from explicit patches or before/after data already supplied by the tool; missing diffs are never reconstructed
  • Progressive collapsed diff hints that shorten automatically on small terminal widths instead of overflowing
  • Hashline-anchor diff gutters that preserve LINE#HASH labels from anchored read/edit output when those lines are rendered in diffs
  • Three presets: opencode, balanced, and verbose
  • Optional native user message box with markdown-aware rendering, configurable Theme-token border color, and safer ANSI/background handling
  • Configurable tool-row separators for every tool, with dashed/solid styles and Theme-token colors
  • Per-tool display toggles that never change tool ownership or execution
  • Explicit third-party rendering through customToolOverrides or producer adapters; MCP-like tools are never auto-detected for styling
  • Capability-aware RTK settings that appear only when the optimizer is available
  • Adapter API for renderer consumers through the @pure/pi-tool-display/tool-display-api-consumer subpath export

Installation

Local extension folder

Place this folder in one of Pi's auto-discovery locations:

# Global default (when PI_CODING_AGENT_DIR is unset)
~/.pi/agent/extensions/pi-tool-display

# Project-specific
.pi/extensions/pi-tool-display

Git repository

pi install git:github.com/liuli195/pi-tool-display@v0.1.0

Usage

Interactive settings

Open the settings modal:

/tool-display

The modal exposes the day-to-day controls most people change regularly:

  • preset profile
  • read and grep/find/ls output modes
  • preview line count
  • Bash output, command, and error modes with their line limits
  • diff layout and indicator modes
  • RTK compaction hints (when RTK is available)
  • native user message box toggle and border color
  • tool separator toggle, dashed/solid style, and color

JSON-only controls include the extension master switch, debug logging, built-in and custom-tool selection, the fallback output mode for explicit MCP producer adapters, expanded preview limit, split-width threshold, collapsed logical diff-line limit, diff wrapping, and truncation hints.

Direct commands

/tool-display show                    # Show the current display-policy summary
/tool-display reset                   # Reset to the default opencode preset
/tool-display preset opencode         # Apply opencode preset
/tool-display preset balanced         # Apply balanced preset
/tool-display preset verbose          # Apply verbose preset

Tool display adapter API

Other extensions that declare @pure/pi-tool-display as a direct dependency can opt into its rendering without depending on load order by importing the consumer helper:

import { registerRendererAdapter } from "@pure/pi-tool-display/tool-display-api-consumer";

const dispose = registerRendererAdapter({
  id: "my-extension:mcp",
  toolName: "my_mcp_tool",
  kind: "mcp",
});
// Dispose during extension shutdown or reload.
dispose();

Registration is display-only, deterministic, disposable, and does not expose or mutate the executable tool definition, schema, ownership, active state, or execution. Retain the returned disposer even when registering before pi-tool-display loads: after the pending intent is drained, that same disposer delegates to the live registration and remains idempotent before or after the drain.

The deprecated decorateToolForDisplay(tool, adapter) migration facade registers the same display intent and returns the exact original tool unchanged. Its registration lasts only for the current pi-tool-display load epoch; repeated calls for the same tool and adapter ID in that epoch replace the previous intent, and consumers must call it again after reload. New integrations should retain the disposer from registerRendererAdapter instead.

Compatibility

Supported Pi releases are 0.81.1 and later stable versions. The release matrix currently qualifies 0.81.1, 0.82.0, and the development runtime as representative points.

Versions below 0.81.1 and prerelease version strings are not supported. The peer dependency range and Host Adapter gate accept stable releases from 0.81.1 onward; the qualification matrix does not limit that support range.

Older, prerelease, or incompatible private TUI shapes emit one concise debug diagnostic and keep Pi's native rendering and execution.

Presets

Preset Read Output Search Output Explicit MCP Adapter Default Bash Output Preview Lines Bash Lines
opencode hidden hidden hidden opencode 8 10
balanced summary count summary summary 8 10
verbose preview preview preview preview 12 20
  • opencode (default): minimal inline-only display; tool results stay collapsed
  • balanced: compact summaries with line counts and match totals; bash shows line count only
  • verbose: larger previews for read/search/MCP/bash output

Bash Output Modes

Mode Behavior
opencode Classic collapsed output using the bashCollapsedLines visual-row limit with expansion hint
summary Shows only line count (e.g., "↳ 3 lines returned") — no output displayed
preview Shows actual output lines using previewLines limit

Configuration

Runtime configuration is stored at:

Default global path: ~/.pi/agent/extensions/pi-tool-display/config.json
Actual global path: $PI_CODING_AGENT_DIR/extensions/pi-tool-display/config.json when PI_CODING_AGENT_DIR is set

A starter template is included at config/config.example.json.

Project-local config

Trusted projects can override global display settings by placing a config.json in their project-local extension directory:

<project>/.pi/extensions/pi-tool-display/config.json

Project-local config is read-only and only loaded when isProjectTrusted() is active (i.e., when the user has approved project-local files). It overlays the global config: any fields defined in the project config override the corresponding global values. Write operations through /tool-display always save to the global config.

The .pi directory name uses Pi's CONFIG_DIR_NAME constant and is not hardcoded.

Configuration options

Option Type Default Description
enabled boolean true Master switch; set to false and reload to disable the extension
debug boolean false Opt-in file logging for extension diagnostics; preserved by /tool-display saves
builtInToolDisplays object all true Enable display formatting for each built-in tool
customToolOverrides object {} Explicit opt-in rendering rules for non-built-in extension tools
enableNativeUserMessageBox boolean true Enable bordered user prompt rendering
enableToolSeparator boolean true Add one separator after every tool row
toolSeparatorStyle string "dashed" Separator style: dashed or solid
toolSeparatorColor string "borderMuted" Separator Theme token: border, borderAccent, borderMuted, accent, muted, or dim
userMessageBorderColor string "border" USER box border Theme token from the same supported set
readOutputMode string "hidden" hidden, summary, or preview
searchOutputMode string "hidden" hidden, count, or preview
mcpOutputMode string "hidden" Fallback hidden, summary, or preview mode for explicitly registered MCP producer adapters; it does not discover or opt tools into rendering
previewLines number 8 Lines shown in collapsed preview mode
expandedPreviewMaxLines number 4000 Max expanded visual rows for non-Diff previews; for Diff it caps logical Diff lines
bashOutputMode string "opencode" opencode (collapse), summary (line count), or preview (show lines)
bashCollapsedLines number 10 Visual rows shown for collapsed Bash output in opencode mode
bashCommandMode string "preview" Bash command display: full, summary, or preview
bashCommandPreviewLines number 3 Visual command lines shown in preview mode; Ctrl+O expands the full command
bashErrorOutputMode string "preview" Failed Bash output: full, summary, or preview; the failure header always remains visible
bashErrorPreviewLines number 3 Visual error lines shown in preview mode; Ctrl+O expands the error output
diffViewMode string "auto" auto, split, or unified
diffIndicatorMode string "bars" bars (vertical indicators), classic (+/- markers), or none
diffSplitMinWidth number 120 Minimum width before auto mode prefers split diffs
diffCollapsedLines number 24 Logical diff content lines shown when collapsed; headers, metadata, and wrapped continuations do not consume the limit
diffWordWrap boolean true Wrap long diff lines when needed
showTruncationHints boolean false Show truncation indicators for compacted output
showRtkCompactionHints boolean false Show RTK compaction hints when RTK metadata exists

Built-in display selection

Use builtInToolDisplays to select which built-in rows this extension formats:

{
  "builtInToolDisplays": {
    "read": true,
    "grep": true,
    "find": true,
    "ls": true,
    "bash": true,
    "edit": true,
    "write": true
  }
}

Set an entry to false to keep Pi's native renderer. Changes made through /tool-display apply immediately; manual config.json edits require /reload. Display selection never changes tool ownership, activation, definitions, or execution. Legacy registerToolOverrides input remains supported and is not rewritten merely by loading it.

Custom tool overrides

Use customToolOverrides when another extension registers a noisy top-level tool and you want pi-tool-display to compact its result output. Custom overrides are explicit opt-in only: unlisted or disabled tools keep their original renderers, and native call renderers are preserved by default.

{
  "customToolOverrides": {
    "ide_find_symbol": {
      "enabled": true,
      "kind": "generic",
      "outputMode": "summary"
    },
    "custom_mcp_gateway": {
      "enabled": true,
      "kind": "mcp",
      "outputMode": "preview"
    }
  }
}

Each entry supports:

Field Type Default Description
enabled boolean true Whether pi-tool-display should decorate this custom tool
kind string "generic" generic for plain compact output, or mcp for MCP-style call labels and result handling
outputMode string "summary" hidden, summary, or preview for this custom tool's result output
overrideCallRenderer boolean false Replace the tool's native call renderer with the generic or MCP call renderer

Boolean shorthand is also accepted:

{
  "customToolOverrides": {
    "ide_find_symbol": true,
    "noisy_tool_to_leave_alone": false
  }
}

Notes:

  • Built-in tool names (read, grep, find, ls, bash, edit, write) are ignored here; use builtInToolDisplays for those.
  • With overrideCallRenderer: true, generic call rendering shows the tool name and argument count.
  • With overrideCallRenderer: true, mcp call rendering understands MCP proxy-style arguments such as tool, server, search, describe, and connect.
  • Overrides are selected at render time, so they work regardless of tool registration or extension load order.

Example config

{
  "enabled": true,
  "debug": false,
  "builtInToolDisplays": {
    "read": true,
    "grep": true,
    "find": true,
    "ls": true,
    "bash": true,
    "edit": true,
    "write": true
  },
  "customToolOverrides": {
    "ide_find_symbol": {
      "enabled": true,
      "kind": "generic",
      "outputMode": "summary"
    },
    "custom_mcp_gateway": {
      "enabled": true,
      "kind": "mcp",
      "outputMode": "preview"
    }
  },
  "enableNativeUserMessageBox": true,
  "enableToolSeparator": true,
  "toolSeparatorStyle": "dashed",
  "toolSeparatorColor": "borderMuted",
  "userMessageBorderColor": "border",
  "readOutputMode": "summary",
  "searchOutputMode": "count",
  "mcpOutputMode": "summary",
  "previewLines": 12,
  "expandedPreviewMaxLines": 4000,
  "bashOutputMode": "opencode",
  "bashCollapsedLines": 15,
  "bashCommandMode": "preview",
  "bashCommandPreviewLines": 3,
  "bashErrorOutputMode": "preview",
  "bashErrorPreviewLines": 3,
  "diffViewMode": "auto",
  "diffIndicatorMode": "bars",
  "diffSplitMinWidth": 120,
  "diffCollapsedLines": 24,
  "diffWordWrap": true,
  "showTruncationHints": false,
  "showRtkCompactionHints": false
}

Debug logging

Debug logging is disabled by default. Set debug to true in the extension root config.json only when collecting diagnostics; missing or non-true values are treated as false. When enabled, diagnostics are appended to debug/debug.log under a runtime-created debug/ directory, and no debug output is written to the terminal.

Rendering notes

Edit and write diffs

edit and write results use the same diff renderer. In auto mode the extension chooses split or unified layout based on available width. Collapsed and expanded limits count logical Diff content lines, so headers, trusted omission metadata, and wrapped continuations do not consume the body budget. The extra omission hint reports the omitted visual Diff lines.

Partial edit calls can render a diff only from explicit old/new text supplied by the call. write calls show neutral content summaries unless the tool supplies trustworthy diff evidence. Rendering never reads the workspace to reconstruct a preimage or infer create/overwrite semantics.

When diff input includes Pi anchored read lines such as 12#AB:content, the renderer treats the anchor as line metadata and displays the LINE#HASH label in the gutter while keeping the content aligned for split, unified, and compact diff layouts.

Write summaries

When content is available, write call summaries include line count and byte size information inline so you can quickly see the size of the pending write before expanding the result.

Native user message box

When enabled, user prompts render inside a bordered box using Pi's native user message component. The renderer preserves markdown content more safely and normalizes ANSI/background handling to avoid odd nested background artifacts. userMessageBorderColor selects one of six stable Pi Theme foreground tokens; the user title keeps its accent styling.

Tool separators

When enableToolSeparator is enabled, every tool row—including partial updates and otherwise-native third-party tools—ends with one width-safe separator. toolSeparatorStyle selects dashed or solid, while toolSeparatorColor selects one of border, borderAccent, borderMuted, accent, muted, or dim. Separators are presentation-only and do not change tool renderers or execution.

Capability detection

The extension does not probe tool metadata to identify MCP tools. MCP-style rendering is enabled only by an exact customToolOverrides entry or an explicit producer adapter.

RTK controls remain capability-aware:

  • RTK optimizer available: the modal exposes an RTK compaction-hints toggle
  • RTK optimizer unavailable: the RTK control is hidden and RTK compaction hints are disabled

This keeps the RTK UI aligned with the current environment. Explicit producer adapters may still register dynamically; unconfigured tools remain native.

Troubleshooting

Reload safety

/reload is fully supported. On reload, the extension removes its display patches, timers, and Adapter registrations before reinstalling the current display policy. It never re-registers tools. No manual cleanup is needed.

Display conflicts

Set builtInToolDisplays.<tool> to false to retain Pi's native renderer for that built-in. Display selection is independent of the executable tool's owner. Modal changes apply immediately; manual JSON edits require /reload. Use /tool-display show to inspect the effective display state.

Config not loading

If your settings are not being applied:

  1. Check that the global Pi tool-display config exists (default: ~/.pi/agent/extensions/pi-tool-display/config.json, respects PI_CODING_AGENT_DIR)
  2. Make sure the JSON is valid
  3. Run /tool-display show to inspect the current display-policy summary

MCP or custom tool rendering not appearing

Add the exact third-party tool name under customToolOverrides. Use kind: "generic" for ordinary tools and kind: "mcp" for MCP proxy or direct tools. MCP tools are not detected or intercepted separately.

RTK setting missing

The RTK control appears only when the optimizer is available. MCP-style tools are configured manually under customToolOverrides; there is no auto-detected MCP control.

Project structure

pi-tool-display/
├── index.ts                         # Extension entrypoint for Pi auto-discovery
├── src/
│   ├── index.ts                     # Bootstrap and extension registration
│   ├── capabilities.ts              # RTK capability detection
│   ├── config-command.ts            # Single lazy /tool-display registration entry
│   ├── config-modal.ts              # /tool-display settings UI and command handling
│   ├── config-store.ts              # Config load/save and normalization
│   ├── disposable.ts                # Reload-safe cleanup registry for display patches and timers
│   ├── diff-renderer.ts             # Edit/write diff rendering engine
│   ├── line-width-safety.ts         # Width clamping helpers for narrow panes
│   ├── pi-host-adapter.ts           # Supported Pi host-shape qualification
│   ├── presets.ts                   # Preset definitions and matching
│   ├── render-utils.ts              # Shared rendering helpers
│   ├── tool-display-resolver.ts     # Pure display-policy resolution
│   ├── tool-display-runtime.ts      # Reload-safe renderer runtime
│   ├── tool-execution-patch.ts      # Final tool-row display seam
│   ├── tool-overrides.ts            # Built-in, MCP, and custom display renderers plus Adapter API
│   ├── types.ts                     # Shared config and type definitions
│   ├── user-message-box-markdown.ts # Markdown extraction for user message rendering
│   ├── user-message-box-native.ts   # Native user message box registration
│   ├── user-message-box-patch.ts    # Safe native render patching helpers
│   ├── user-message-box-renderer.ts # User message border renderer
│   ├── user-message-box-utils.ts    # ANSI/background normalization helpers
│   ├── write-display-utils.ts       # Write summary helpers
│   └── zellij-modal.ts              # Modal UI primitives
├── config/
│   └── config.example.json          # Starter config template
└── tests/
    ├── ansi-utils.test.ts           # ANSI utility tests including foreground RGB preservation
    ├── bash-display.test.ts         # Deterministic Bash display tests
    ├── capabilities-edge.test.ts    # Capability detection edge cases
    ├── config-modal.test.ts         # Config modal tests
    ├── custom-tool-overrides.test.ts # Opt-in custom tool override tests
    ├── debug-logger-edge.test.ts    # Debug logger edge cases
    ├── diff-renderer-ansi.test.ts   # ANSI/background handling tests for diff rendering
    ├── diff-renderer-edge.test.ts   # Diff renderer edge case tests
    ├── diff-renderer-width.test.ts  # Width and background coverage tests for diff rendering
    ├── index-integration.test.ts    # Integration tests for extension lifecycle
    ├── presets-edge.test.ts         # Preset edge case tests
    ├── reload-behavior.test.ts      # Reload-safe cleanup and re-registration tests
    └── tool-ui-utils.test.ts        # Utility tests for user message and diff helpers

Development

# Type check
npm run build

# Run the local real-runtime contract (missing optional runtimes are skipped)
npm run test:contract:local

# Standard local verification (missing optional Pi runtimes are skipped)
npm run check
npm run test:contract:local
npm run build
git diff --check

# Strict runtime qualification (requires every runtime root below)
PI_RUNTIME_DEV_ROOT=/path/to/pi-dev \
PI_RUNTIME_0_81_1_ROOT=/path/to/pi-0.81.1 \
PI_RUNTIME_0_82_0_ROOT=/path/to/pi-0.82.0 \
npm run test:contract:required

License

MIT

About

Compact tool call rendering, diff visualization, and output truncation extension for Pi coding agent. Hides, collapses, and truncates verbose tool output for cleaner TUI display.

Resources

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages