mcpField
P
pi-coding-agent

pi-coding-agent

github.com/mizchiエージェントワークフロー416130 回インストール1 週間前に更新
リポジトリ

pi-coding-agent について

pi-coding-agentは、TypeScriptやNodeのスクリプト、サービスからエージェントセッションを作成するSDKです。ストリーミング出力、カスタムツール、ツールセットの制限に対応し、専用エージェントや自動化処理に利用できます。

主な機能

  1. 01Nodeスクリプトからのセッション作成
  2. 02エージェント出力のストリーミング
  3. 03組み込みツールの選択と制限
  4. 04呼び出し可能なカスタムツールの定義
  5. 05リソースローダーによる拡張とプロンプトの設定

活用シーン

  1. 01専用のTypeScript CLIエージェントの構築
  2. 02Nodeサービスやジョブランナーへの組み込み
  3. 03スクリプト処理での一度限りのエージェント実行
  4. 04読み取り専用または特定領域のツールへの制限

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/mizchi/skills --skill pi-coding-agent

インストール後、Claude Code で/pi-coding-agentを入力して読み込まれたか確認します。

同梱ファイルREADME.md

詳細

pi-coding-agent

@mariozechner/pi-coding-agent (upstream) は、pi の対話型 TUI と、フル機能の SDK を提供します。SDK を使うと、Node 20.6+ の任意のスクリプトからエージェントセッションを起動し、出力をストリーミングし、ツールの適用範囲を設定したり、独自のツールを追加したりできます。CLI をフォークする必要はありません。

使用する場面

  • TypeScript / Node で単一目的のエージェント CLI を構築する場合(チャット製品ではないもの)
  • より大きな Node サービスやジョブランナー内で pi をラップする場合
  • スクリプトのパイプラインにエージェントの推論を組み込む場合(一度だけ実行し、完了時に終了する)
  • 読み取り専用または特定のドメインに制限されたツールセットが必要な場合
  • エージェントが呼び出せるカスタムツール(deploy、query_db、…)を追加したい場合

次の場合は、このスキルを使わないでください。

  • pi を対話的に使いたいだけの場合 → CLI から pi を実行してください。SDK は不要です
  • ホストが Node ではない場合 → 代わりに pi --mode rpc(サブプロセス経由の JSON-RPC)を使用してください
  • Anthropic の公式 SDK のセマンティクスが必要な場合 → それは別パッケージの @anthropic-ai/claude-agent-sdk です

注意点(最初にお読みください)

症状原因解決方法
require() で ERR_PACKAGE_PATH_NOT_EXPORTED が発生するパッケージが ESM 専用です("type": "module"、CJS を含まない exports マップ)ESM(import)を使用するか、tsx / --experimental-strip-types で実行してください
ツールが誤ったディレクトリを基準にパスを解決するビルド済みの readTool / bashTool は、インポート時の process.cwd() をキャプチャしますカスタムの cwd と明示的な tools の両方を渡す場合は、ファクトリー形式の createCodingTools(cwd) / createReadTool(cwd) を使用してください
session.prompt(...) が「stream in progress」をスローする前のストリームが実行中に、再度 prompt() を呼び出しています{ streamingBehavior: "steer" } または "followUp" を渡すか、session.steer() / session.followUp() を使用してください
ANTHROPIC_API_KEY を設定しているのに認証エラーが発生するAuthStorage はランタイムのオーバーライド → auth.json → 環境変数の順に読み込みます。古い ~/.pi/agent/auth.json が環境変数を上書きしている可能性があります保存済みの認証情報を削除するか、createAgentSession() の前に authStorage.setRuntimeApiKey("anthropic", key) を呼び出してください
ストリーミング中に何も表示されない購読を忘れているか、text_delta だけを処理していて、モデルが思考のみを出力していますmessage_update を購読し、text_delta と(必要に応じて)thinking_delta の両方を処理してください
拡張機能が pi -e ./ext.ts では読み込まれるが、通常の実行では読み込まれない-e は一度限りの指定であり、そのファイルは自動検出ディレクトリにありません~/.pi/agent/extensions/<name>.ts(グローバル)または <project>/.pi/extensions/<name>.ts(プロジェクト)に移動するか、settings.json の extensions: [...] に登録してください
インストールした pi パッケージが、実行時に Cannot find module '@mariozechner/pi-coding-agent' で失敗するpeerDependencies ではなく dependencies に記載しています5 つのコアパッケージ(@mariozechner/pi-{ai,agent-core,coding-agent,tui}、typebox)は "*" の範囲で peerDependencies に指定し、バンドルしてはいけません。pi は読み込み時にこれらを提供します
pi install は成功したが、推移的な依存関係が見つからないデフォルトで npm install --omit=dev が使用されるため、実行時に devDependencies が存在しませんインポートを dependencies に移すか、カスタムの npm ラッパーが必要な場合は settings.json で npmCommand を設定してください
拡張機能の変更が反映されないTUI が前回の読み込み結果をキャッシュしていますpi 内で /reload を実行してください(自動検出される場所にある拡張機能であれば、どれでも有効です)

インストール

pnpm add @mariozechner/pi-coding-agent
# Or one-off scripts:
npx tsx my-agent.ts

Node ≥ 20.6 と API キー(環境変数または ~/.pi/agent/auth.json)が必要です。

最小限のセッション

#!/usr/bin/env -S npx tsx
import {
  AuthStorage,
  ModelRegistry,
  SessionManager,
  createAgentSession,
} from "@mariozechner/pi-coding-agent";

const authStorage = AuthStorage.create();
const modelRegistry = ModelRegistry.create(authStorage);

const { session } = await createAgentSession({
  sessionManager: SessionManager.inMemory(), // no .jsonl on disk
  authStorage,
  modelRegistry,
});

session.subscribe((event) => {
  if (
    event.type === "message_update" &&
    event.assistantMessageEvent.type === "text_delta"
  ) {
    process.stdout.write(event.assistantMessageEvent.delta);
  }
});

await session.prompt(process.argv.slice(2).join(" ") || "Hello");

実行方法:

export ANTHROPIC_API_KEY=sk-ant-...
npx tsx my-agent.ts "Explain the layout of src/"

オプションなしの createAgentSession() も使用できます。~/.pi/agent/ と cwd から、ツール、スキル、拡張機能、デフォルトモデルを検出します。デフォルトから変更する必要がある場合にのみ、オプションを渡してください。

ツールセットの制限

SDK には、組み込みのツール配列と文字列による名前指定の両方が用意されています。読みやすいほうを使ってください。

import { createAgentSession, readOnlyTools } from "@mariozechner/pi-coding-agent";

// Array of tool objects (use process.cwd())
await createAgentSession({ tools: readOnlyTools });

// Or by name — equivalent, more concise
await createAgentSession({ tools: ["read", "grep", "find", "ls"] });

ツール名のカタログ:read、bash、edit、write、grep、find、ls。事前定義済みのセット:

セット内容
codingToolsread、bash、edit、write(デフォルト)
readOnlyToolsread、grep、find、ls
cwd × tools の落とし穴

事前構築済みのツールインスタンス(readOnlyTools、codingTools、readTool、bashTool、…)は、インポート時の process.cwd() を保持し、再バインドされません。カスタムの cwd と組み合わせると、エージェントは気づかないうちに誤ったディレクトリを読み込みます。

覚えておくべき組み合わせは次の3つです。

形式カスタムの cwd を指定した場合理由
tools: readOnlyTools(定数)NGインポート時の process.cwd() を保持します
tools: ["read", "grep", ...](文字列名)OKSDK が指定された cwd に基づいて、セッションごとに名前を解決します
tools: createReadOnlyTools(cwd)(ファクトリー)OKcwd を明示的にバインドします
tools を省略OKSDK がデフォルトのセットを選び、cwd をバインドします

ファクトリー群はすべての定数/インスタンスに対応しています。必要に応じて選んでください。

必要なもの…ファクトリー
cwd にバインドされた codingTools セットcreateCodingTools(cwd)
cwd にバインドされた readOnlyTools セットcreateReadOnlyTools(cwd)
cwd にバインドされた単一のツールcreateReadTool(cwd)、createBashTool(cwd)、createEditTool(cwd)、createWriteTool(cwd)、createGrepTool(cwd)、createFindTool(cwd)、createLsTool(cwd)
import {
  createAgentSession,
  createCodingTools,
  createReadOnlyTools,
  createGrepTool,
  createReadTool,
} from "@mariozechner/pi-coding-agent";

const cwd = "/path/to/project";

// Whole set, bound to cwd
await createAgentSession({ cwd, tools: createCodingTools(cwd) });
await createAgentSession({ cwd, tools: createReadOnlyTools(cwd) });

// Or hand-picked, bound to cwd
await createAgentSession({ cwd, tools: [createReadTool(cwd), createGrepTool(cwd)] });

// Or — equivalent and shorter — name-based, which the SDK rebinds per session
await createAgentSession({ cwd, tools: ["read", "grep", "find", "ls"] });

デフォルト以外の cwd と明示的な tools の値を両方渡す場合にのみ、この点を考慮する必要があります。tools をまったく指定しなければ、SDK が cwd にバインドされたデフォルトのセットを構築します。

カスタムツール

import { Type } from "typebox";
import { createAgentSession, defineTool } from "@mariozechner/pi-coding-agent";

const deployTool = defineTool({
  name: "deploy",
  label: "Deploy",
  description: "Deploy the current branch to staging",
  parameters: Type.Object({
    target: Type.Optional(Type.String({ description: "Target env (default: staging)" })),
  }),
  execute: async (_toolCallId, params) => {
    // Your logic. Must return { content: [...], details: {...} }.
    const target = params.target ?? "staging";
    return {
      content: [{ type: "text", text: `Deployed to ${target}` }],
      details: { target },
    };
  },
});

const { session } = await createAgentSession({
  customTools: [deployTool],
});

customTools は追加されるもので、指定した tools と統合されます。パラメーターには TypeBox を使用します。エージェントには JSON Schema の形式で表示され、execute には型付けされた params が渡されます。

カスタムシステムプロンプト

システムプロンプトを管理するのは createAgentSession() ではなく、ResourceLoader です。

import { DefaultResourceLoader, createAgentSession } from "@mariozechner/pi-coding-agent";

const resourceLoader = new DefaultResourceLoader({
  systemPromptOverride: () => "You are a senior SRE. Answer tersely.",
});
await resourceLoader.reload();

const { session } = await createAgentSession({ resourceLoader });

同じローダーが、スキル、プロンプトテンプレート、拡張機能、仮想的な AGENTS.md コンテキストファイルを追加する際のエントリーポイントにもなります。オプションの全一覧については、docs/sdk.md を参照してください。

拡張機能(プラグインシステム)

拡張機能は、pi が起動時に読み込む TypeScript モジュールです。SDK 経由で渡す customTools と比べて、拡張機能には次の特徴があります。

  • それを検出するすべての pi の呼び出しで再利用できます
  • ツールとコマンド(/foo)、ショートカット、フッターウィジェット、プロバイダー、カスタムレンダリングを登録できます
  • ライフサイクルイベントをインターセプトできます(ツール呼び出しのブロック、コンテキストの変更、コンパクションのカスタマイズ)
  • ctx.ui を介してユーザーにプロンプトを表示できます(選択/確認/入力/通知)

Pi は jiti を使用して .ts を直接読み込みます。コンパイルは不要です。

セキュリティ: 拡張機能はシステムの全権限で実行され、任意のコードを実行できます。信頼できるソースからのみインストールしてください。

自動検出される場所
パススコープ
~/.pi/agent/extensions/<name>.tsグローバル、単一ファイル
~/.pi/agent/extensions/<name>/index.tsグローバル、複数ファイル
.pi/extensions/<name>.tsプロジェクトローカル
.pi/extensions/<name>/index.tsプロジェクトローカル、複数ファイル

これに加えて、settings.json で宣言されたパスも対象です(下記のインストールセクションを参照)。自動検出される場所にある拡張機能は、TUI 内で /reload を実行するとホットリロードできます。

最小限の拡張機能

~/.pi/agent/extensions/greet.ts として保存します。

import type { ExtensionAPI } from "@mariozechner/pi-coding-agent";
import { Type } from "typebox";

export default function (pi: ExtensionAPI) {
  pi.on("session_start", async (_event, ctx) => {
    ctx.ui.notify("greet extension loaded", "info");
  });

  // Block dangerous bash commands
  pi.on("tool_call", async (event, ctx) => {
    if (event.toolName !== "bash") return;
    const cmd = event.input.command as string;
    if (/\brm\s+-rf?\b|\bsudo\b/.test(cmd)) {
      const ok = ctx.hasUI ? await ctx.ui.confirm("Dangerous", `Allow:\n${cmd}`) : false;
      if (!ok) return { block: true, reason: "blocked by greet extension" };
    }
  });

  pi.registerTool({
    name: "greet",
    label: "Greet",
    description: "Greet someone by name",
    parameters: Type.Object({ name: Type.String() }),
    async execute(_id, params) {
      return { content: [{ type: "text", text: `Hello, ${params.name}!` }], details: {} };
    },
  });

  pi.registerCommand("hello", {
    description: "Say hello",
    handler: async (args, ctx) => ctx.ui.notify(`Hello ${args || "world"}!`, "info"),
  });
}

どこにもインストールせずに試すには、次のようにします。

pi -e ./greet.ts
非同期ファクトリー(起動時の処理向け)

非同期のデフォルトエクスポートは、session_start が発生する前に完了を待機します。動的な設定(ローカル LLM のモデル一覧など)の取得に使用してください。

export default async function (pi: ExtensionAPI) {
  const res = await fetch("http://localhost:1234/v1/models");
  const { data } = (await res.json()) as { data: Array<{ id: string; context_window?: number; max_tokens?: number }> };

  pi.registerProvider("local-openai", {
    baseUrl: "http://localhost:1234/v1",
    apiKey: "LOCAL_OPENAI_API_KEY",
    api: "openai-completions",
    models: data.map((m) => ({
      id: m.id, name: m.id, reasoning: false, input: ["text"],
      cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
      contextWindow: m.context_window ?? 128000,
      maxTokens: m.max_tokens ?? 4096,
    })),
  });
}
SDK から拡張機能を読み込む

SDK コードでは、拡張機能は引き続き ResourceLoader が管理します。DefaultResourceLoader は上記と同じ自動検出ディレクトリを検出します。単発のパスには additionalExtensionPaths を、インラインファクトリーには extensionFactories を渡します。

import { DefaultResourceLoader, createAgentSession } from "@mariozechner/pi-coding-agent";

const resourceLoader = new DefaultResourceLoader({
  additionalExtensionPaths: ["/abs/path/to/my-ext.ts"],
  extensionFactories: [
    (pi) => pi.on("agent_start", () => console.log("[inline] agent starting")),
  ],
});
await resourceLoader.reload();

const { session } = await createAgentSession({ resourceLoader });
npm 依存関係を含む複数ファイルの拡張機能

npm パッケージを使用する拡張機能の場合は、その隣に package.json を配置します。

~/.pi/agent/extensions/my-ext/
├── package.json
├── package-lock.json
├── node_modules/
└── src/
    └── index.ts
// package.json
{
  "name": "my-ext",
  "dependencies": { "zod": "^3.0.0" },
  "pi": { "extensions": ["./src/index.ts"] }
}

ディレクトリ内で一度 npm install を実行します。pi はローカルの node_modules/ を通じてインポートを解決します。

サードパーティパッケージのインストール

pi パッケージは配布単位です。1 つ以上の拡張機能、スキル、プロンプトテンプレート、テーマをまとめます。pi install は settings.json に書き込み、次回起動時に pi がパッケージで宣言されたすべての内容を自動で読み込みます。

pi install npm:@foo/[email protected]           # npm, version-pinned
pi install npm:@foo/bar                 # npm, latest (re-pulled by `pi update`)
pi install git:github.com/user/repo@v1  # git, ref-pinned
pi install https://github.com/user/repo # raw URL also works
pi install ./local/package              # local path, not copied

pi list           # show installed
pi update         # pull all non-pinned packages
pi remove npm:@foo/bar

デフォルトでは、~/.pi/agent/settings.json(グローバル)を変更します。代わりに <project>/.pi/settings.json に書き込むには -l を使用します。このファイルをコミットすると、チーム全員の pi が起動時に不足しているパッケージを自動インストールします。

設定を保存せずにパッケージを試すには、次のようにします。

pi -e npm:@foo/bar
pi -e git:github.com/user/repo

-e は、現在の実行時のみ使用するために一時ディレクトリへインストールします。

生成される settings.json は次のようになります。

{
  "packages": [
    "npm:@foo/[email protected]",
    "git:github.com/user/repo@v1"
  ],
  "extensions": [
    "/absolute/path/to/local/extension.ts",
    "/absolute/path/to/local/extension/dir"
  ]
}

packages(配列):ソース別の pi パッケージです。extensions(配列):パッケージ化されていない拡張機能のパスです。どちらの配列も、パッケージ内で対象を絞り込むオブジェクト形式に対応しています。例:{ source: "npm:my-pkg", extensions: ["extensions/*.ts", "!extensions/legacy.ts"], skills: [], prompts: [...] }。

公開可能な pi パッケージを作成する

package.json に pi マニフェストを追加し、pi-package キーワードを付けると、pi.dev/packages で検出されるようになります。

{
  "name": "my-pi-pack",
  "version": "1.0.0",
  "keywords": ["pi-package"],
  "pi": {
    "extensions": ["./extensions"],
    "skills": ["./skills"],
    "prompts": ["./prompts"],
    "themes": ["./themes"]
  },
  "peerDependencies": {
    "@mariozechner/pi-coding-agent": "*",
    "@mariozechner/pi-ai": "*",
    "@mariozechner/pi-agent-core": "*",
    "@mariozechner/pi-tui": "*",
    "typebox": "*"
  },
  "dependencies": {
    "zod": "^3.0.0"
  }
}

pi フィールドを省略すると、pi は慣例のディレクトリ(extensions/、skills/、prompts/、themes/)から自動検出します。パス配列では glob と !negation を使用できます。

依存関係のルール — ここを間違えると、インストール時にパッケージが壊れます。

  • 5 つのコアパッケージ — @mariozechner/pi-coding-agent、@mariozechner/pi-ai、@mariozechner/pi-agent-core、@mariozechner/pi-tui、typebox — は "*" を指定して peerDependencies に含める必要があります。pi は実行時にこれらを提供します。バンドルするとモジュール ID の不整合が発生します(独自の defineTool は pi の defineTool ではありません)。
  • それ以外(zod、chalk など)は dependencies に含めます。pi は取得後に npm install --omit=dev を実行するため、実行時に devDependencies は利用できません。
  • 別の pi パッケージを埋め込むには、dependencies と bundledDependencies の両方に記載し、node_modules/<name>/... を通じてそのリソースを参照します。

プリントモード(ワンショットのパイプライン)

runPrintMode は pi -p と同様に動作します。プロンプトを送信し、結果をストリーミングして終了します。シェルパイプラインや CI タスクで役立ちます。

import {
  type CreateAgentSessionRuntimeFactory,
  SessionManager,
  createAgentSessionFromServices,
  createAgentSessionRuntime,
  createAgentSessionServices,
  getAgentDir,
  runPrintMode,
} from "@mariozechner/pi-coding-agent";

const createRuntime: CreateAgentSessionRuntimeFactory = async (
  { cwd, sessionManager, sessionStartEvent },
) => {
  const services = await createAgentSessionServices({ cwd });
  return {
    ...(await createAgentSessionFromServices({ services, sessionManager, sessionStartEvent })),
    services,
    diagnostics: services.diagnostics,
  };
};

const runtime = await createAgentSessionRuntime(createRuntime, {
  cwd: process.cwd(),
  agentDir: getAgentDir(),
  sessionManager: SessionManager.inMemory(),
});

await runPrintMode(runtime, {
  mode: "text", // "text" | "json"
  initialMessage: process.argv.slice(2).join(" "),
});

mode: "json" にすると、各ターンの出力が構造化された JSON エンベロープに切り替わります。別のプログラムにパイプで渡す場合に適しています。

実行中のストリームを操作する

session.prompt() はデフォルトで順次実行されます。実行中のターンに入力するには、次のようにします。

await session.steer("Stop and read README.md first");  // delivered after current tool calls
await session.followUp("Then summarise it");           // delivered after the agent finishes

どちらもファイルベースのプロンプトテンプレートを展開しますが、拡張機能コマンド(/...)は拒否します。ストリーミング中に session.prompt(text) を呼び出す場合は、{ streamingBehavior: "steer" | "followUp" } のいずれかを明示的に選択する必要があります。

適切なエントリーポイントの選び方

用途API
エンドツーエンドで制御する単発の CLI ツールcreateAgentSession() + SessionManager.inMemory()
ディスク上にセッションを永続化するSessionManager.create(cwd)(または .continueRecent、.open)
パイプに適したスクリプトを作成するrunPrintMode(runtime, { mode: "json" })
ドメインに合わせたカスタムツール(1つのプロセス内、コード内で定義)defineTool() + customTools: [...]
このマシン上のすべての pi の実行で共有するツール/コマンドpi.registerTool/pi.registerCommand を使用する ~/.pi/agent/extensions/<name>.ts の拡張機能
1つのプロジェクトに限定するツール/コマンド(コミットして共有)<project>/.pi/extensions/<name>.ts の拡張機能と、<project>/.pi/settings.json(-l を使用)
拡張機能/スキル/プロンプトをパッケージ化して共有するPi パッケージ:pi フィールドと pi-package キーワードを含む package.json
他の人のパッケージをインストールするpi install npm:<spec> または pi install git:<spec>(プロジェクトに限定する場合は -l を使用)
実行時にアクティブなセッションを置き換える(/new、/fork、/resume)createAgentSessionRuntime() を呼び出し、その後 runtime.newSession() などを実行します。置き換えるたびに再購読してください
別の言語からエージェントを操作するpi --mode rpc --no-session(stdio 経由の JSON-RPC)、SDK は不要

SDK と pi --mode rpc の比較

型安全性、プロセス内での制御、TypeScript で記述されたツールや拡張機能を登録する機能が必要な場合は、SDK を使用してください。ホストが Python、Go、Rust などの場合や、プロセス分離が必要な場合は、RPC モードを使用してください。どちらも同じエージェントを公開します。SDK では、内部状態やイベントストリームに直接アクセスできます。

参考資料

  • 上流の SDK ガイド — SDK の正式なリファレンス(スキル、設定、拡張機能のオプション、実行時の置き換え)
  • 拡張機能ガイド — イベントの全一覧、ExtensionAPI/ExtensionContext のインターフェース、カスタム UI コンポーネント
  • パッケージガイド — パッケージ化、pi install のソース、フィルタリング、スコープ/重複排除のルール
  • スキルガイド — エージェントが SKILL.md をどのように使用するか(このスキルリポジトリとは別)
  • 設定リファレンス — ~/.pi/agent/settings.json のスキーマ(コンパクション、リトライ、パッケージ、拡張機能)
  • examples/sdk/ — SDK のサンプル13件。node_modules/@mariozechner/pi-coding-agent/examples/sdk/ にもインストールされています
  • examples/extensions/ — 拡張機能のクックブック:permission-gate.ts、protected-paths.ts、git-checkpoint.ts、カスタムプロバイダー、カスタム UI など
  • RPC モード — Node.js 以外のホストから pi を呼び出す際の JSON プロトコル

コメント