Skip to content

Extension guides

Tool and entry renderers

Transcript renderers replace the default presentation for one tool name or session-entry type. They present Pi data; they do not execute tools or write entries themselves.

Tool renderers

Add a renderer under the exact tool name registered with Pi. It receives the call immediately and an optional result once execution has produced one.

src/renderer.tsx
export default defineRenderer({
  apiVersion: 1,
  tools: {
    "db.query": ({ call, result }) => {
      const sql = String(call.arguments.sql ?? "");

      if (!result) return <QueryProgress sql={sql} />;
      if (result.isError) return <QueryError sql={sql} message={result.text} />;

      return <QueryResult sql={sql} rows={result.details} />;
    },
  },
});

Render the full lifecycle

  • Running: result is undefined. Keep the call identity and arguments visible while work is in flight.
  • Success: show the useful structured result, with raw text available when it helps explain the outcome.
  • Failure: result.isError is true. Make failure at least as clear as NativePi's default tool container.

Calls may restore from a session long after the package version that created them. Treat arguments and details defensively unless you have narrowed their generic types and preserve compatibility intentionally.

Tool types

interface ToolCall<Arguments extends Record<string, unknown>> {
  id: string;
  name: string;
  arguments: Arguments;
}

interface ToolResult<Details> {
  toolName: string;
  text: string;
  details?: Details;
  isError: boolean;
}

Entry renderers

Entry renderers are keyed by the top-level entry.type value stored in the Pi session. They receive the complete entry object and current renderer context.

export default defineRenderer({
  apiVersion: 1,
  entries: {
    compaction: ({ entry }) => (
      <CompactionSummary summary={String(entry.summary ?? "Session compacted")} />
    ),
  },
});

Pi entries created with pi.appendEntry(customType, data) have top-level type custom and carry their extension key inentry.customType. A renderer registered under custom must inspect that field and return a fallback for entries it does not recognize.