pi-blackbytes

Pi coding-agent extension that provides local search tools, locally-managed HTTP clients for the websearch / context7 / grep.app surfaces (replacing Pi's MCP-plugin dependency for these services), hashline-based editing, and delegated sub-agents for explo

Packages

Package details

extensionprompt

Install pi-blackbytes from npm and Pi will load the resources declared by the package manifest.

$ pi install npm:pi-blackbytes
Package
pi-blackbytes
Version
2.20.1
Published
Jun 9, 2026
Downloads
1,764/mo · 283/wk
Author
cuongntr
License
unknown
Types
extension, prompt
Size
570.4 KB
Dependencies
3 dependencies · 3 peers
Pi manifest JSON
{
  "extensions": [
    "./dist/index.js"
  ],
  "prompts": [
    "./prompts"
  ]
}

Security note

Pi packages can execute code and influence agent behavior. Review the source before installing third-party packages.

README

pi-blackbytes

Pi coding-agent extension that provides local search tools, locally-managed HTTP clients for the websearch / context7 / grep.app surfaces (replacing Pi's MCP-plugin dependency for these services), hashline-based editing, and delegated sub-agents for exploration, research, consultation, implementation, and code review.

Note on the wire protocol. web_search / web_fetch (Exa, Tavily) and docs_resolve / docs_query (Context7) are pure REST clients — no MCP involved. gh_search is also locally-managed (no Pi MCP plugin needed) but the upstream mcp.grep.app service still speaks MCP-over-HTTP, so the extension ships a small in-process MCP HTTP client just for that one tool. The user-facing benefit (extension owns auth, config, error handling, render) is the same for all three groups; the wire-level distinction matters only if you are debugging requests.

Overview

Blackbytes extends Pi with:

  • Bytes v2 system prompt overlay — capability-aware, per-model-family prompt with 15 sections covering identity, precedence, autonomy, investigation rules, session capabilities, skill-loading guidance, engineering boundaries, work defaults, tool-use protocol, verification contracts, careful-action gates, workflow guidance, markdown format, file references, and completion contracts. The Conditional Workflows section includes a metadata-driven delegation routing matrix built from typed SubAgentRoutingMetadata on each sub-agent declaration, with skill/workflow-aware General delegation triggers. Four provider variants: claude (semantic XML tags), gpt (Markdown + Parallel Execution Policy footer), gemini (numbered headings + worked examples), and kimi (terse instruction-dense Markdown).
  • Strict Librarian gatingdelegate_librarian requires ALL of (a) external information, (b) multiple independent sources or current-year authority, (c) direct tools individually insufficient — plus an explicit anti-pattern denylist.
  • Five builtin sub-agents — Explore (with Tour Mode for flow walk-throughs), Oracle (with long-context handling and high-risk self-check guardrails), Librarian, General, and Reviewer, each with typed declarations, typed routing metadata, runtime overlays, model fallback chains (read-only agents), per-model-family prompt variants (all five carry GPT-optimized prompt bodies), and per-agent timeout/model/reasoning configuration.
  • Typed routing metadata — each sub-agent declaration carries a SubAgentRoutingMetadata object with category, cost, useWhen, avoidWhen, and optional keyTrigger fields. This metadata drives the Bytes overlay routing matrix and the /blackbytes-status Sub-Agent Routing section, replacing hardcoded routing prose.
  • Delegation ROI tracking — in-memory session-scoped delegation log with per-agent metrics (call count, success rate, average duration, cost). Visible via /blackbytes-status.
  • Redacted artifact capture — opt-in per-agent persistence of large redacted sub-agent outputs to $PI_AGENT_DIR/blackbytes/artifacts/sub-agents/<YYYY-MM-DD>/<agent>-<HHmmssSSS>.md (512 KiB cap, 7-day retention). Surfaces the artifact directory, total count, and most recent artifact under /blackbytes-status Sub-Agent Diagnostics. Enable with sub_agents.<name>.artifactCapture: true.
  • Sequential chain executor (internal-only)src/sub-agents/chain.ts runs 1–5 existing sub-agents in order, threading each step's output into the next under a ## Previous step output heading. Reuses runNestedPi(), enforces a total timeout budget, and stops on first failure by default. No public delegate_chain tool in Phase 2 — chains are constructed in code.
  • look_at tool — multimodal image inspector that loads a primary image plus up to 3 references (PNG/JPG/GIF/WebP/BMP/SVG, 10 MB each) and embeds them as ImageContent blocks alongside the analysis objective.
  • Fluent file:// links — sub-agent output uses [relpath#L-L](file:///abs/path#L-L) links throughout.

pi-blackbytes vs raw Pi

Capability Raw Pi pi-blackbytes
System prompt Pi default Bytes v2 overlay (capability-aware, per-family)
Codebase exploration read/grep/glob + delegate_explore (parallel, scoped, fluent links, Tour Mode)
Reasoning consultation (manual) delegate_oracle (Effort estimate, self-contained reply)
External research (manual) delegate_librarian (strict gate, multi-source)
Code review (manual) delegate_reviewer (severity verdict, abstraction-fit eval)
Heavy implementation (manual) delegate_general (verification gates, AGENTS.md aware)
Image inspection (none) look_at (PNG/JPG/GIF/WebP/BMP/SVG, multi-image compare)
Edit workflow edit/write + hashline_edit (anchor-based)
Web/docs lookup (manual) web_search / web_fetch / docs_resolve / docs_query / gh_search
Delegation observability (none) Delegation ROI log (per-agent metrics, visible in /blackbytes-status)

Installation

pi install bun:pi-blackbytes

Quick start

Run the setup wizard after installation:

/setup-models

The wizard maps Blackbytes sub-agents to models that Pi already has available in its model registry. Provider credentials and model availability remain Pi-level concerns (for example /model, /login, or ~/.pi/agent/models.json); Blackbytes only stores per-sub-agent overrides in ~/.pi/agent/settings.json (or $PI_AGENT_DIR/settings.json).

Pi commands

Command Purpose
/setup-models Interactive per-agent model and thinking level configuration wizard with grouped provider picker, batch shortcuts, and summary confirmation
/blackbytes-status Interactive section-based status viewer with compact overview and drill-down into individual sections

Setup wizard

The /setup-models wizard maps Pi-available models to Blackbytes sub-agents and writes the result to blackbytes.sub_agents.<name>.model (and optionally .reasoningEffort) in ~/.pi/agent/settings.json.

Mapping modes

The wizard opens with three top-level modes:

Mode Behaviour
Per-agent Configure model and thinking level for each sub-agent in sequence
One-for-all Select a single model for all agents, then set reasoning mode
Clear all Remove all per-agent model and reasoning overrides

Per-agent mode

For each agent the wizard presents two consecutive picks — model, then thinking level — before advancing to the next agent. After the first agent is configured, two batch shortcuts appear at the top of subsequent selections:

  • ⬆ Apply <model> to all remaining agents — propagates the current model forward without prompting again
  • ⬆ Apply <level> to all remaining agents — propagates the current thinking level forward
  • ⏭ Skip thinking for all remaining agents — stops thinking configuration for all agents still to come

One-for-all mode

A single model is selected first, then the wizard asks how reasoning should be applied:

  • Same for all — one reasoning level applied to every agent
  • Per agent — step through each agent individually to set a reasoning level
  • Skip — no reasoning overrides are written

Grouped provider picker

When Pi's model registry contains more than 10 models, the model selection becomes a two-step flow:

  1. Provider list — each entry shows the provider name and model count (e.g., anthropic (8 models)). Selecting a provider drills into that group.
  2. Model list within provider — shows only models from the selected provider. Pressing Cancel at this step returns to the provider list rather than exiting the wizard.

When 10 or fewer models are available the two-step flow is skipped and all models appear in a single flat list.

Smart model ordering

Models chosen earlier in the same wizard session move to the top of the model list in subsequent agent selections, reducing scrolling when the same model is applied to multiple agents.

Summary confirmation

After all agents are configured a formatted summary table is displayed:

Agent       Model                       Thinking
─────────── ─────────────────────────── ────────
oracle      anthropic/claude-opus-4     high
general     openai/gpt-5.4              —
explore     (inherit host model)        —

The wizard prompts for confirmation before writing anything to settings.json. Cancelling at this step discards all selections.

/blackbytes-status viewer

Running /blackbytes-status opens an interactive section picker rather than printing the full output immediately.

Overview header

A compact summary line is always shown first regardless of which section is selected:

Tools: **10** enabled | Agents: **5** enabled | Skills: **2** enabled

Section picker

The picker presents 11 named sections plus a Show All option:

# Section Description
1 Enabled Tools Lists all registered tool names with their enabled/disabled state
2 Enabled Sub-Agents Lists builtin and YAML sub-agents with their enabled/disabled state
3 Sub-Agent Routing Typed routing metadata for each enabled sub-agent: category, cost, use-when/avoid-when hints, and key trigger
4 Enabled Skills Lists discovered Pi skills
5 Delegation ROI Session-scoped delegation metrics: per-agent call count, success rate, average duration, and accumulated cost
6 Sub-Agent Diagnostics Per-agent status, recent failures by kind, nested Pi availability, YAML warnings
7 Sub-Agent Snapshot Resolved per-agent config snapshot (model, reasoning, timeout, fallback chain)
8 YAML Diagnostics Skipped YAML sub-agent files and reasons
9 System Prompt Log Current system prompt logging configuration
10 Reserved / Unsupported Settings Settings accepted by schema but not yet functional (e.g. temperature)
11 Full Config (JSON) Raw blackbytes config object with secrets redacted
Show All Prints all sections in order

Selecting a numbered section prints the overview header followed by that section only. Selecting Show All or pressing Cancel prints the full output, preserving backward-compatible behaviour.

Prompt templates

Blackbytes bundles package-level Pi prompt templates that are available as slash commands after installation:

Template Purpose
/review-fresh-eyes Re-read recently changed code with fresh eyes, look for obvious bugs or confusion, and fix anything uncovered.
/update-docs Update README and other documentation so they describe the current project state.
/suggest-innovation Propose the single most valuable, innovative addition for the project.
/commit-and-push Commit changed files in logical groups with detailed commit messages and push, while skipping ephemeral files.

Configuration

Blackbytes reads the top-level blackbytes object from the Pi settings file.

{
  "blackbytes": {
    "disabled_tools": [],
    "disabled_sub_agents": [],
    "hashline_edit": { "strict_patch": true },
    "websearch": {
      "provider": "exa",
      "exa_api_key": "YOUR_EXA_KEY"
    },
    "context7": {
      "api_key": "YOUR_CONTEXT7_KEY"
    },
    "ui": {
      "bash_wrapper_enabled": true,
      "bash_max_preview_lines": 5,
      "bash_max_expanded_lines": 200,
      "bash_dim_output": false,
      "read_tool_display": "compact"
    },
    "system_prompt_log": {
      "enabled": false,
      "path": "~/.pi/logs/pi-blackbytes-system-prompts.jsonl",
      "capture_agent_start": true,
      "capture_provider_system": false,
      "include_nested": false,
      "dedupe": true
    },
    "sub_agents": {
      "oracle": {
        "model": "openai/gpt-5.4",
        "reasoningEffort": "high",
        "timeoutMs": 1200000,
        "fallbackModels": ["anthropic/claude-opus-4"],
        "executionMode": "sequential",
        "temperature": 0.2
      },
      "general": {
        "model": "openai/gpt-5.4"
      }
    }
  }
}

Supported keys

Key Type Meaning
disabled_tools string[] Disables specific public tool names for the entire session
disabled_sub_agents ("explore" | "oracle" | "librarian" | "general" | "reviewer")[] Disables delegate tools by agent name
hashline_edit boolean | { enabled?: boolean, strict_patch?: boolean } Enables hashline rewriting for Pi read/write tool results. Object form exposes strict_patch (default true) — lines payloads containing accidental LINE#ID| prefixes are rejected with [E_INVALID_PATCH]. Set strict_patch: false to restore the legacy silent-strip behaviour.
websearch.provider "exa" | "tavily" Selects the web backend. Defaults to exa when omitted.
websearch.exa_api_key string Exa credential. Overrides EXA_API_KEY when set.
websearch.tavily_api_key string Tavily credential. Overrides TAVILY_API_KEY when set.
context7.api_key string Context7 credential
ui { bash_wrapper_enabled?: boolean; bash_max_preview_lines?: number; bash_max_expanded_lines?: number; bash_dim_output?: boolean; read_tool_display?: "compact" | "preview" } Controls the built-in bash wrapper and built-in read display. Defaults: bash_wrapper_enabled=true, bash_max_preview_lines=5, bash_max_expanded_lines=200, bash_dim_output=false, read_tool_display="compact".
system_prompt_log.enabled boolean Opt-in full system-prompt capture to a JSONL file. Defaults to false because prompts may contain project context or secrets.
system_prompt_log.path string Optional log file path. Defaults to ~/.pi/logs/pi-blackbytes-system-prompts.jsonl; relative paths resolve against the current working directory.
system_prompt_log.capture_agent_start boolean Capture Pi's final effective system prompt at agent_start (after before_agent_start chaining). Defaults to true.
system_prompt_log.capture_provider_system boolean Also capture provider-serialized system/developer/systemInstruction fields at before_provider_request. Defaults to false; user messages are not logged by the extractor.
system_prompt_log.include_nested boolean Include nested sub-agent Pi sessions (PI_NESTED_DEPTH > 0). Defaults to false.
system_prompt_log.dedupe boolean Avoid repeated identical prompt entries per session/source/provider shape. Defaults to true.
sub_agents.<name>.model string Per-agent model override, preferably the canonical Pi model reference provider/model-id selected by /setup-models. Omit/clear to inherit the host Pi model.
sub_agents.<name>.reasoningEffort string Per-agent reasoning override passed to nested sessions
sub_agents.<name>.timeoutMs integer (1..3600000) Per-agent execution timeout in milliseconds. Builtin defaults: explore=600000, librarian=900000, oracle=1200000, general=1800000, reviewer=900000. YAML equivalent: timeout_ms.
sub_agents.<name>.fallbackModels string[] (max 5) Ordered list of fallback models tried on provider_or_model_unavailable failures. Read-only agents only (general and mutating YAML agents are ineligible). YAML equivalent: fallback_models.
sub_agents.<name>.executionMode "sequential" | "parallel" Per-agent tool execution mode override. "sequential" serializes tool calls within a batch; omitted uses Pi's default parallel behavior. YAML equivalent: execution_mode.
sub_agents.<name>.promptMode "static" | "append" RESERVED / PARTIALLY IMPLEMENTED - "static" (default) is the only safe value. "append" is accepted by the schema but throws at runtime ("not yet supported"). YAML equivalent: prompt_mode.
sub_agents.<name>.temperature number RESERVED / UNSUPPORTED - accepted by schema for forward-compatibility but NOT passed to the nested Pi CLI (Pi does not accept --temperature). Visible under "Reserved / Unsupported Settings" in /blackbytes-status.

Configuration notes

  • The settings file is strict JSON. Comments and trailing commas are not supported.
  • Per-agent config (model, reasoningEffort, reserved fields) is resolved once at session_start into an immutable snapshot. Changes to settings.json after startup take effect on the next session only.
  • Unknown keys inside blackbytes are preserved by the parser, so wizard-managed passthrough values can coexist with the validated Blackbytes settings.
  • disabled_tools uses public tool names such as hashline_edit or docs_query. Disabled tools are enforced through every nested delegate path - builtin agents, and both the default and allowlist/denylist forms of YAML agents.
  • disabled_sub_agents uses agent names, not tool names: explore, oracle, librarian, general, reviewer.
  • system_prompt_log is intentionally opt-in. The agent_start capture is the canonical Pi-effective prompt; provider capture is only for verifying serialization and extracts system-like fields instead of dumping the full provider payload.
  • temperature is accepted by the schema for forward-compatibility but is NOT applied. See /blackbytes-status → "Reserved / Unsupported Settings" for details.
  • All Blackbytes tools and sub-agents render through a single lightweight, borderless renderer; there is no on/off toggle. ui.bash_wrapper_enabled defaults to true, so the built-in bash tool also renders through the lightweight wrapper (set it to false to leave Pi's built-in bash untouched), while the built-in read renderer keeps displayed content anchor-free and preserves LINE#ID| anchors in conversation history.
  • ui.read_tool_display defaults to "compact", so collapsed read results render as one line with path/range and line-count summary; set it to "preview" to restore Pi's content preview (still with anchors hidden from the TUI).
  • ui.bash_max_preview_lines and ui.bash_max_expanded_lines bound the collapsed and expanded bash output previews; ui.bash_dim_output keeps preview text in muted toolOutput colour instead of regular text.
  • sub_agents.<name>.executionMode serializes or parallelizes tool calls within a batch. Use sequential when ordering matters; omit it to keep Pi's default parallel execution.

Tool surface

Tool result rendering

Every Blackbytes tool provides structured, scannable result rendering with three states:

State What the user sees
Running A muted status message indicating progress (e.g., Searching..., Fetching..., Scanning...)
Collapsed (default) A one-line summary with a (success) or (error) icon, followed by a brief summary and a ctrl+o to expand hint
Expanded (Ctrl+O) Full tool output in toolOutput color

Bundled local tools

Tool Icon Purpose
glob 📂 Fast file pattern matching with safety limits
ast_search 🌳 AST-aware structural search across 25 languages
ast_replace ✏️ AST-aware structural rewrite with dry-run default
hashline_edit LINE#ID-anchored file editing with snapshot semantics
look_at 👁️ Multimodal image inspector (PNG/JPG/GIF/WebP/BMP/SVG, up to 3 reference images)

Built-in Pi tools

When blackbytes.ui.bash_wrapper_enabled is true, Pi's built-in bash tool renders through a lightweight wrapper with shell highlighting, tail previews, capped expanded output, and footer metadata. The built-in read tool always uses the clean anchor-stripping renderer so LINE#ID| markers stay out of visible output while remaining in conversation history; collapsed read results are compact by default and render as a single line.

HTTP-backed tools

Tool Icon Purpose
web_search 🌐 Web search through Exa by default, or Tavily when configured
web_fetch 📥 Extract a URL through Exa/Tavily with direct HTTP fallback
docs_resolve 📚 Resolve a library/package to a Context7 ID
docs_query 📖 Query current library documentation and examples from Context7
gh_search 🔎 Search code patterns across public GitHub repositories

Delegate tools

Tool Icon Purpose
delegate_explore 🔭 Read-only codebase discovery and flow walk-throughs ("Where is X?", "How does Y work?")
delegate_oracle 🧠 Read-only high-reasoning consultation for difficult debugging or design questions
delegate_librarian 📚 Read-only docs, web, and cross-repository research
delegate_general Full-access execution for well-scoped multi-file implementation work
delegate_reviewer 📋 Read-only code reviewer for diffs, patches, and PRs; produces severity-classified findings (High/Medium/Low) and a Verdict

YAML sub-agents

User-defined sub-agents can be placed in $PI_AGENT_DIR/sub-agents/*.{yaml,yml} (defaulting to ~/.pi/agent/sub-agents/). Each file must define name, description, and system_prompt. Tool access is optional via either allowed_tools or denied_tools (mutually exclusive); when neither is provided the agent receives the default read/search/docs tool set.

Additional optional YAML fields: model, reasoning_effort, timeout_ms, mutability, prompt_mode, fallback_models, execution_mode, routing.

# ~/.pi/agent/sub-agents/deep-reviewer.yaml
name: deep-reviewer
description: Deep code review specialist
allowed_tools:
  - read
  - grep
  - glob
system_prompt: |
  You are a senior code reviewer.
timeout_ms: 180000          # per-agent timeout in ms (1..3600000)
fallback_models:            # read-only agents only; at most 5 entries
  - anthropic/claude-opus-4
  - google/gemini-2.5-pro
prompt_mode: static         # 'static' only; 'append' throws at runtime
execution_mode: sequential  # optional; sequential | parallel
routing:                    # optional typed routing metadata
  category: review           # exploration | reasoning | research | implementation | review
  cost: medium               # low | medium | high
  use_when:
    - "After significant implementation"
    - "Pre-merge code quality check"
  avoid_when:
    - "Trivial changes"
  key_trigger: "Deep code review"   # optional one-line summary

Key behaviors:

  • The default starting tool set for YAML agents is read/search/docs tools only. Listing any mutating tool (bash, edit, write, hashline_edit, ast_replace) in allowed_tools automatically promotes the agent to full-access mutability.
  • An optional mutability field can be set explicitly (read-only or full-access).
  • Conflicts with a builtin name or an earlier YAML file in the same directory are skipped with a diagnostic instead of causing a fatal error. All non-conflicting agents in the same directory still load.
  • Diagnostics (skipped files and reasons) appear in /blackbytes-status under ### YAML Sub-Agents.
  • disabled_tools is enforced on YAML agents the same as on builtins.
  • The optional routing field provides typed routing metadata for the /blackbytes-status Sub-Agent Routing section and the Bytes overlay. YAML agents without routing display a placeholder () in status output. Invalid routing values cause the file to be skipped with a diagnostic.
  • Routing field validation: category must be one of exploration, reasoning, research, implementation, review; cost must be low, medium, or high; use_when and avoid_when accept at most 6 entries of ≤ 60 characters each; the schema uses .strict() mode so unknown routing keys are rejected.

Sub-agent prompt system

Each builtin sub-agent receives a multi-layer system prompt:

  1. A runtime overlay prepended by the host (read-only agents: ~4 KB; General: ~8 KB safety overlay).
  2. The resolved persona prompt body, selected at execution time from either the default systemPrompt or a model-family-specific variant from systemPromptByFamily.

Prompt body resolution uses resolveSystemPromptBody() in src/sub-agents/prompt-builder.ts. When a nested model is explicitly configured via sub_agents.<name>.model, the model is classified into a ModelFamily (claude, gpt, gemini, kimi, other). If a matching family entry exists in systemPromptByFamily, that variant is used; otherwise the default systemPrompt applies. The parent session's cached model family is never consulted — only the explicitly configured nested model drives variant selection.

All five builtin sub-agents (Explore, Oracle, Librarian, General, Reviewer) carry GPT-optimized prompt variants (systemPromptByFamily.gpt) used only when the nested model is a GPT-family model (e.g. gpt-4o, o3-mini, o4-mini). The GPT variants follow OpenAI's GPT-5.x prompting guidance: outcome-first and shorter than the defaults, top-level # headings for prompt architecture with <xml> tags delimiting the semantic behavioural blocks (tool rules, search/review contracts, output specs, stop rules, citation policy), an explicit opener blacklist to suppress filler preambles, and fewer redundant negative rules. Each variant preserves the default persona's contract — read-only/full-access guarantees, tool allowlists, output formats (including the literal ## Findings / ### High / ## Verdict headings the host parses from Reviewer), no-fabrication and citation-precision rules, and verification-gate discipline.

Read-only sub-agent runtime overlay (~4 KB) — applied to Explore, Oracle, Librarian, and Reviewer via prependSystemPrompt. Contains:

  • Current date (ISO YYYY-MM-DD and current year), so date-sensitive queries always use the correct year
  • Working directory for the nested session
  • Final tool allowlist for that invocation (alphabetically sorted, secrets redacted)

The overlay is capped at ~4 KB, built by src/sub-agents/runtime-overlay.ts, and never injects delegation hints — nested sessions cannot spawn further sub-agents.

General agent safety overlay (~8 KB) — applied to General instead of the read-only overlay. Contains:

  • Current working directory
  • Finalized allowed tool list for that invocation
  • Enabled and disabled resource summary
  • Hard rules: no recursive delegation, no destructive git commands, no committing secrets, no introducing new dependencies, stay in task scope
  • Constraints derived from AGENTS.md (truncated, with secrets redacted)

General's persona prompt defers to the safety overlay for the authoritative tool list rather than maintaining a static tool-name list in the prompt text.

Oracle prompt guardrails

The Oracle default prompt includes two domain-specific guardrail sections:

  • Long-Context Handling — when input exceeds ~50 tool-result blocks or spans many files, Oracle anchors every factual claim to a specific file path and line range, labels inferred vs. verified items, and flags contradictions between code sections.
  • High-Risk Self-Check — before finalising any answer on architecture, security, or performance, Oracle re-scans reasoning for unstated assumptions, verifies the recommendation does not introduce new failure modes, and discloses any unread files it relied upon.

Routing metadata

Each builtin sub-agent declaration carries a routing field of type SubAgentRoutingMetadata:

export interface SubAgentRoutingMetadata {
  readonly category: "exploration" | "reasoning" | "research" | "implementation" | "review";
  readonly cost: "low" | "medium" | "high";
  readonly useWhen: readonly string[];     // max 6 items, each ≤ 60 chars
  readonly avoidWhen: readonly string[];   // max 6 items, each ≤ 60 chars
  readonly keyTrigger?: string;            // optional one-line summary
}

Builtin routing metadata:

Agent Category Cost Key Trigger
explore exploration medium Deep contextual grep across multiple files
oracle reasoning high Deep analytical reasoning on hard problems
librarian research high Multi-source external research requiring triangulation
general implementation high Heavy multi-file implementation with verifiable outcome
reviewer review medium Severity-classified code review with verdict

The Bytes overlay Conditional Workflows section uses buildOverlayRoutingMatrix() to render a concise one-line routing entry per enabled agent from this metadata. /blackbytes-status uses buildRoutingSummary() to display the full routing table including category, cost, use-when, and avoid-when details. Both helpers live in src/sub-agents/routing.ts, consume runtime SubAgentMeta[] (not builtin declarations directly), sort alphabetically for deterministic output, and produce placeholder entries for YAML agents without routing.

Sub-agent progress display

Delegate tools emit bounded, redacted onUpdate status events while the nested session runs. The TUI renders a live-updating display with two modes:

Collapsed view (default)

A single-line header showing real-time execution status:

✓ 🔭 explore · 12.5s · 8 calls · 2,048 chars · $0.031 · ctrl+o to expand

While a delegation is running:

⠹ 🔭 explore · 9.0s · 4 calls · 🔧 read …/sub-agents/render.ts

On failure:

✗ 🔭 explore · 1.4s · 2 calls · budget exhausted · ctrl+o to expand

Header elements (left to right):

  • Status indicator: a braille spinner (⠋⠙⠹⠸⠼⠴⠦⠧⠇⠏) animating at 10 fps while running, (success), (failure), or (cancelled / timed out) once complete. The status word (completed, failed, etc.) is omitted because the glyph carries the meaning.
  • Agent identity: the agent icon (🔭 explore, 🧠 oracle, 📚 librarian, ⚡ general, 📋 reviewer; for YAML-defined agents) followed by the bold agent name colored to match the status (red for failed, accent for running, success for completed).
  • Elapsed time: live-ticking wall-clock counter with progressive precision — <1ms, 47ms, 3.2s, 2m 7s, or 1h 12m.
  • Tool call count: total number of tool invocations by the sub-agent.
  • Current tool (running only): 🔧 read …/sub-agents/render.ts — the active tool name with a truncated argument summary. The wrench icon is accent-colored, the tool name uses the toolTitle token, and the argument hint is muted. Between calls (after one tool completes but before the next starts), the last finished tool is kept visible as ◷ <name> in muted color so the row never goes silent.
  • Output chars: total captured assistant output size.
  • Cost (when > 0): smart-formatted USD — <$0.001, $0.004, $0.420, $1.23, $42.05, or $1235.
  • Error hint (failed only): the first line of the failure message, stripped of any leading Error: prefix and clamped to 60 characters, rendered in red so the cause is visible without expanding.
  • Expand hint: ctrl+o to expand.

The model name is intentionally absent from the collapsed header — it appears in the expanded footer instead to keep the header scannable.

Expanded view (Ctrl+O)

When expanded, the header is followed by a tool activity timeline showing the last 30 tool invocations:

  [+5 earlier calls]
  ✓ read src/config/schema.ts (234ms)
  ✓ ast_search 'registerTool' (1.2s)
  ✓ bash grep -r "subagent" (847ms)
  ✓ read …/sub-agents/runner.ts (47ms)
  ▸ bash bun run build (running…)

Each entry shows a (completed, green) or (running, accent) icon, the tool name colored with the toolTitle token, an optional muted argument summary (path, command, query, etc.), and the execution duration. Sub-second tools display millisecond precision instead of 0.0s. Tool arguments are extracted from well-known parameter names (path, filePath, command, query, pattern, url, etc.) and truncated to 50 characters. Path-like arguments (path, filePath) are truncated from the left to preserve the filename and as many trailing parent segments as fit: /Users/invoker/Work/personal/pi-blackbytes/src/sub-agents/render.ts becomes …/sub-agents/render.ts rather than losing the filename to a tail-cut.

Below the timeline, the expanded view shows the assistant's output preview (while running) or the final result text (when complete), followed by a muted footer aggregate:

gemini-3-flash-preview · Tools: 12× read · 4× ast_search · 1× bash · $0.004

The footer carries the model name, a flattened tool-mix summary sorted by call count descending (ties broken alphabetically), and the smart-formatted cost. Any of the three is omitted when the corresponding data is unavailable; the entire footer is suppressed when nothing remains to display.

Design constraints

Raw nested-Pi stdout is not forwarded to the parent TUI. It contains the full nested conversation — reasoning tokens, tool calls, tool results, and final output — and dumping it would be noisy and may expose sensitive values from nested tool output.

The final delegate result remains a concise text block returned after the nested session completes. Progress updates are UI-only: they do not append intermediate nested output to the final tool result or to the parent model context.

Successful delegate output is bounded by boundReturnContent() in src/sub-agents/runner.ts (MAX_RETURN_CHARS, 24,576 chars) before it re-enters the parent context. The cap is tail-preserving and middle-eliding: it keeps the head and tail and inserts a [... truncated ...] marker in between, so a worker's trailing completion summary survives even when an outlier output (for example a worker dumping a whole file) would otherwise bloat the orchestrator's context. The threshold is large enough that normal structured summaries pass through untouched. Worker sub-agents are deliberately kept unaware of any token or context limit — resource pressure is handled structurally (isolation plus this output cap), never by signalling scarcity to the nested agent, since doing so degrades thoroughness.

The general worker closes its output with a fixed completion block delimited by === TASK COMPLETE === (Outcome / Changed Files / Verification / Failures), placed last so the tail-preserving cap retains it.

hashline_edit

hashline_edit works alongside Pi's native edit tool. It is optimized for precise, low-ambiguity edits by anchoring each mutation to a tagged line reference from read output, with a substring fallback (replace_text) for the cases where anchors are not needed.

Workflow

  1. Read the file first and copy the LINE#ID anchors.
  2. Build one hashline_edit call per file with all related edits batched together.
  3. Use replace, append, prepend, or replace_text against the copied anchors. The aliases insert_after, insert_before, and replace_range carry the same semantics with clearer intent.
  4. The success response includes an --- Updated anchors --- block (with ±3 lines of context) and a --- Diff preview --- block, so a follow-up edit nearby usually does not need a re-read round-trip.
  5. Re-read the file before issuing a second hashline_edit call when the structural change is large or when the previous response did not surface the anchors you need.

Operations

Op Anchors Semantics
replace pos; optional end for ranges Replace the targeted line (or [pos..end] inclusive range) with lines. lines: null deletes.
append optional pos Insert lines after pos. With no pos, appends at EOF.
prepend optional pos Insert lines before pos. With no pos, prepends at BOF.
insert_after required pos Alias for append with required pos. Missing pos rejects with [E_BAD_REF].
insert_before required pos Alias for prepend with required pos. Missing pos rejects with [E_BAD_REF].
replace_range required pos + end Alias for replace with required pos + end. Missing either rejects with [E_BAD_REF].
replace_text none (oldText + newText) Exact-unique substring edit. oldText must occur exactly once (LF only, multi-line allowed); zero matches → [E_NO_MATCH], multiple → [E_MULTI_MATCH] with the first three matching line numbers. Runs before anchored edits; overlap with an anchored range is rejected pre-mutation with [E_OVERLAP].

Properties

  • All edits in a single call refer to the original file snapshot.
  • lines: null deletes the targeted line or range.
  • Strict-patch rejection (default): lines payloads containing accidental LINE#ID| prefixes are rejected with [E_INVALID_PATCH] instead of silently stripped. The escape hatch is "hashline_edit": { "strict_patch": false }.
  • Atomic write with alias preservation: fresh-inode targets are written via temp+rename in the same directory; hard-linked files (nlink > 1) are written in place with O_TRUNC to preserve the alias chain; symlinks are followed to their canonical target so the link itself remains a symlink; the existing mode bits are restored on the new inode using an fchmod that bypasses the process umask. Non-regular-file targets are refused with [E_WRITE_FAILED].
  • Canonical-path mutation queue: concurrent edits that arrive via different symlink paths to the same inode serialise on the same key.
  • Optional postEditVerify: true per call: re-reads the file after the atomic write and compares byte-for-byte against the intended content. On mismatch, rolls back to the pre-edit bytes and returns [E_VERIFY_FAILED] with a compact line/column + windowed-byte divergence context. If rollback itself fails, the error message notes that the file may be partially corrupted.
  • delete: true removes the file (requires edits: []).
  • rename: <new path> writes to the new path and unlinks the old one.
  • When an anchor mismatch occurs, the tool returns the updated anchors around the affected lines for recovery.

Error codes

Every error is formatted as [CODE] message (optionally followed by a context block). The taxonomy:

Code Meaning
E_BAD_REF Anchor did not parse, or an alias was missing a required anchor.
E_HASH_MISMATCH Anchor parsed but its CID does not match the file's current content.
E_OUT_OF_RANGE Anchor's line number is outside the file.
E_INVALID_PATCH Payload shape is refused (e.g. a LINE#ID| prefix inside lines under strict mode).
E_OVERLAP Two or more edits target overlapping regions, or a replace_text span overlaps an anchored range.
E_NO_MATCH replace_text.oldText produced zero matches.
E_MULTI_MATCH replace_text.oldText produced more than one match.
E_WRITE_FAILED Filesystem write failed (EACCES / EPERM / ENOSPC / EROFS / non-regular-file refusal / unexpected).
E_NOT_FOUND Target file does not exist on the read path.
E_VERIFY_FAILED postEditVerify re-read did not match the intended bytes (the file is rolled back unless rollback itself fails).

Result rendering

Collapsed view shows ✓ <summary> · ctrl+o to expand for success and ✗ <summary> · ctrl+o to expand for errors. Expanded view renders the structured diffData returned alongside the response with ▌- (error colour) and ▌+ (success colour) gutter markers per changed range, width-clamped per line, so the diff is visible in both colour terminals and plain-text transcripts.

Delegation model

  • Explore locates files, symbols, and call sites in the local repository. In Tour Mode, it traces execution flows and returns numbered [file#L-L](file://…) steps with what · why annotations — use it when you need to understand how a flow works, not just where files live. Accepts an optional context parameter to scope the search.
  • Oracle handles hard architectural reasoning and elevated debugging. Includes long-context handling guardrails (anchoring claims to specific files when input is large) and a high-risk self-check (re-scanning for unstated assumptions before finalising architecture/security/performance answers). When the configured nested model is a GPT-family model, a GPT-optimized prompt variant with prose-first output and an explicit opener blacklist is used.
  • Librarian researches external APIs, official docs, and public code examples.
  • General executes large, well-defined implementation tasks with the session's enabled tool set. The routing metadata supports self-contained implementation units from loaded workflows or skills; when a workflow or skill defines atomic work units, each unit is delegated as a separate delegate_general call. The prompt defers to the runtime safety overlay for the authoritative tool list. When the configured nested model is a GPT-family model, a GPT-optimized prompt variant is used.
  • Reviewer reviews changed code—diffs, patches, and PR descriptions—and produces severity-classified findings (High/Medium/Low) with a Verdict. The caller must supply the diff or file list; the Reviewer cannot run git itself.

Nested delegation is limited to one level. Delegate sessions do not receive the delegate_* tools again, so recursion is blocked at runtime rather than by prompt text alone.

Model fallback

Read-only agents (explore, oracle, librarian, reviewer, and YAML agents that do not include mutating tools) support an optional fallbackModels chain. When the primary model returns a provider_or_model_unavailable failure, Blackbytes retries each model in the chain in order, all within a single shared timeout budget (minimum 1 s per attempt). No other failure kinds trigger a retry (timed_out, cancelled, failed, spawn_error, etc. are surfaced immediately). The attempted-models chain is appended to the user-visible failure message.

general is never fallback-eligible because its full-access mutability means partial retries could leave the workspace in an inconsistent state. YAML agents that include any mutating tool in allowed_tools are also ineligible.

Configure via JSON fallbackModels (array of strings, max 5, unique, non-empty) or YAML fallback_models. /blackbytes-status displays the fallback chain with separators; agents configured with fallbackModels but ineligible show an (ineligible) suffix.

Delegation ROI

Each delegation is logged to an in-memory, session-scoped log tracking:

  • Agent name
  • Start time and duration
  • Success/failure status
  • Tool call count and output size
  • Estimated cost (when available from usage tracking)

The log resets on each session restart. View the current session's delegation metrics via /blackbytes-statusDelegation ROI, which shows per-agent aggregates: call count, success rate, average duration, and accumulated cost.

Development

bun run check          # lint + typecheck + build + full test suite + package size
bun run lint
bun run typecheck
bun run build
bun run test
bun run check:size

bun run lint:fix
bun run format
bun run bench:startup
bun run bench:tool-result

Recommended verification order:

  1. bun run check
  2. For targeted iteration: bun run lintbun run typecheckbun run buildbun run test

Architecture summary

The extension bootstraps from src/index.ts and wires the core session handlers in src/bootstrap.ts:

  • session_start loads config, computes the enabled set, registers tools, registers delegate agents, and sets up the ✦ Bytes ✦ branding widget
  • before_agent_start renders the capability-aware Bytes v2 overlay, injects <available_resources>, and uses a minimal safe fallback if the enabled set is unavailable
  • agent_start captures Pi's final effective system prompt to the configured JSONL log when system_prompt_log.enabled is true
  • model_select caches the current model family for later requests
  • before_provider_request optionally captures provider-serialized system prompts when system_prompt_log.capture_provider_system is enabled
  • tool_result rewrites read/write results for the hashline workflow
  • session_shutdown flushes the buffered logger

Bytes prompt variants live under src/system-prompt/bytes/ (default.ts, gpt.ts, gemini.ts, kimi.ts) and are dispatched by model family resolved from the active model id. Nested delegate sessions are spawned by src/sub-agents/runner.ts with --no-session, --no-context-files, and (when reasoning is configured) --thinking <effort>.

Branding

A gradient ✦ Bytes ✦ badge renders right-aligned above the chat input editor in interactive mode. The badge uses fixed 24-bit RGB colors (violet → indigo → sky → cyan gradient, bold) and is independent of the active theme. It is not shown in print mode (-p) or JSON mode.

Troubleshooting

Websearch tools are unavailable

Check blackbytes.websearch.provider and the matching credential field:

  • Exa → blackbytes.websearch.exa_api_key
  • Tavily → blackbytes.websearch.tavily_api_key

Context7 tools are unavailable

Set blackbytes.context7.api_key.

A delegate or tool is missing

Check disabled_tools and disabled_sub_agents, then start a new session so the enabled set is recomputed.

ast_search / ast_replace fail immediately

Install ast-grep (sg) and ensure it is on PATH.