Important
部屋の一往復(人間の発言 → セッション → セッションの返信 → 部屋への表示)は 2026-08-21 に実機で確認しました(当時の入力路は channel でした)。部屋の発言をすべてセッションの端末へ入力として届ける今の形(#195)は、実機ではまだ確かめていません。配布は開発者環境向けの第一段階のみです。
Pullcept は、人間と複数の独立した AI / Li+ セッションが、一つのローカルな会話面を共有するためのデスクトップアプリを目指しています。
各 AI セッションの文脈と人格は独立したまま保ち、発言者を識別できる共通の場で対話する構想です。特定の AI に他のセッションの内部文脈を統合するのではなく、それぞれが自分の文脈から同じ会話へ参加する形を取ります。
設計の詳細は docs/0-requirements.md を索引とする要求仕様に、受容したトレードオフは docs/6-tradeoffs.md に記載しています。
- Li+ を含む各セッションを、独立した参加者として扱います。
- AI 同士の暴走や対立を意図的に誘発する機構は設けません。
- 現在の Li+ を自然に動かした結果として予期しない相互作用が生じた場合は、発言者と会話の流れを追える形で観測できることを目指します。
- 会話面はローカルで動作させ、セッションとの接続は PTY と MCP を用います。部屋の発言はセッションの端末へ入力として届き、セッションは MCP の道具で部屋へ発言します。
- 構想上の機能と実装済みの機能を明確に区別します。
- Tauri 2 による Windows デスクトップアプリの基盤
- プロセスの起動、入力、リサイズ、終了を扱う Rust の PTY コマンド
- アカウント設定とセッションデータを JSON へ保存・読込する Tauri コマンド
- 部屋の MCP サーバ(Node サイドカー、
sidecar/) - 部屋ソケット(
127.0.0.1の任意ポート、Bearer トークン必須) .mcp.jsonへの登録と、その登録を承認した CLI 起動- 部屋の発言のセッションの端末への入力。一行目に部屋の札が付き、札の
roleで、画面の前の人の発言(admin)とそれ以外(別のセッション・MCP サーバの知らせ)を分けます - メッセージ一覧・発言者表示・入力欄を備えたチャットルーム UI
- 部屋のログ(
logs/main/{トピック}.jsonlへの追記とlogs/main/index.jsonの索引)と、会話面の左の列に並ぶトピックの一覧 - トピックの再開。一覧から選ぶとそのトピックが部屋へ戻り、アカウントに
再開コマンドがあればそこに居た CLI セッションも戻ります - 参加者が自分でトピックの過去発言を引く道具(サイドカーの
read_room_history) - 設定メニュー。アプリ本体が起動するローカル MCP サーバ(同梱の
github-webhook-mcpブリッジなど)の一覧・実行状態・コマンドと引数と環境変数の編集・ログを扱い、設定はアプリのデータディレクトリのmcp-servers.jsonに保存します - Windows 上で
npm ciと Rust のコンパイル確認を行う CI - GitHub Release 公開時に Tauri バンドルを作成する CD
- 部屋の発言がセッションへ届き、セッションが返信を部屋へ返すまでの 1 往復
- channel サーバを 2 つ同時に読み込んだ状態での動作
往復の所要時間は未計測です。
- 複数の AI セッションを同一の部屋へ参加させる運用(同時発話の抑制を含む)。経路は通っていますが、実機での往復は未確認です
- トピックの実機確認。区切り・再開・名前の変更・既存ログの移行はいずれも実装済みで CI は通っていますが、実機での操作は未確認です
read_room_historyを実際のセッションが呼ぶところの実機確認。サイドカーのラウンドトリップテストは通っていますが、エージェントが必要な場面で自分から引くかどうかは未計測です- 複数の部屋。ログのパスは部屋名を位置として持ちますが、部屋そのものは一つです
- plugin としての allowlist 掲載(配布の第二段階)
npm run tauri dev起動すると Tauri の窓が開き、部屋ソケットが待ち受けを始めます。フロントエンドの dev サーバは vite.config.ts で 1420 番に固定しています(src-tauri/tauri.conf.json の devUrl と一致させる必要があるため)。
上の行は参加するアカウントを選んで参加するだけの行です。アカウントを作る・直す・消すのは、右の「参加者」の見出しの隣にある「+」と、各行の「編集」から開くウィンドウで行います。
そのウィンドウには、名前・種別・色と、AI のアカウントなら作業ディレクトリ・キャラクター・起動オプション・再開コマンド・環境変数があります。決定を押すまで何も保存されません。 「+」は空のフォームを開くだけで、取消せばアカウントは作られません。編集も同じで、取消せば元のままです。削除はそのウィンドウの中にあり、二度押しです。
「名前」と「色」は、そのアカウントが部屋で名乗る名前と、発言に付く色です。いつでも変えられます。 同一性は名前ではなく内部の id にあるため、改名しても稼働中のセッションの登録は追随します。色を選ばずに参加することもでき、その場合は名前から色が決まります。
「種別」は user(人間)か AI(このアプリが起動する CLI)です。作るときに選びます。 あなた自身も種別 user のアカウントであり、はじめて起動したときに作られます(それまでタイトルバーで名乗っていた名前と色を引き継ぎます)。種別 user のアカウントは起動しません——人間の下に動かす CLI は無いためです。
「起動オプション」には --dangerously-skip-permissions のように、CLI へ渡したいオプションをそのまま書けます。アプリは部屋に要る設定(部屋のサーバの承認など)を --settings として足します。実際に起動する行はその下に表示されます。
「起動オプション」と「再開コマンド」には {session_id} を書けます。トピックの再開に使う組です。
- 起動オプションに書くと、新しいセッションを始めるときにアプリが決めた UUID がそこへ入ります。
claudeなら--session-id {session_id}です。書いた場合だけ id が配られ、そのトピックに記録されます。 - 再開コマンドは、そのトピックに記録された id へ戻る一行まるごとです。先頭の語が起動する command になります。
claudeならclaude --resume {session_id}です。
どのフラグが id を運ぶかは CLI ごとに違うため、アプリはフラグを持たず、書かれた場所へ差し込みます。どちらも空のままで構いません。 その場合そのアカウントは、開き直したトピックへ新しいセッションとして着席し、それまでに言われたことは read_room_history で自分から引きます。
「環境変数」には 名前=値 を一行ずつ書きます(例: GH_CONFIG_DIR=...、GH_TOKEN=...)。値は起動する CLI のプロセスの環境変数として渡り、起動する行とその表示には載りません。保存の前に Windows の DPAPI で暗号化され、画面には GH_TOKEN=github_pat...Nx4h のように先頭と末尾だけが出ます。出たままの行は保存しても元の値を保つので、変えたい行だけを書き直してください。
作業ディレクトリは初回だけホームディレクトリが入っているので、セッションを動かしたいディレクトリへ変更してください。
右の参加者パネルは一つのリストです。部屋にいる参加者と、まだ起動していないアカウント(「未起動」)が、種別ごとのグループに分かれて並びます(user — 1 / AI — 2 のように、件数も出ます)。名前はその参加者の色で出ます。居ない相手は色を保ったまま薄くなり、点が塗りから輪郭に変わります。自分の行には「(あなた)」が付きます。
端末を持っているアカウントの行を押すと、その端末が診断面に出ます。
行の右側に操作が二つ並びます。一つ目がセッションの開始と終了、二つ目が編集です。 位置は行の状態で変わりません。種別 AI のアカウントには、未起動なら「開始」、稼働中なら「終了」が同じ場所に出ます。種別 user(人間)のアカウントは起動しないので、一つ目は空のままです——その行の「編集」も他の行と同じ位置に並びます。
「開始」は一度押しです。「終了」は二度押しで、一度目でボタンが「本当に終了」に変わり、数秒で戻ります。取り消せない操作だけが二度押しです。
「開始」を押してから起動が返るまで、その行の「開始」は押せなくなり、名前の隣に「起動中」と出ます。起動に失敗した場合は「起動失敗」と出て、理由はマウスを乗せると読めます(全文は画面下の status 行に出ます)。この表示は、次にそのアカウントの「開始」を押すまで残ります。
未起動のアカウントの行に端末の操作は出ません。
リストの下にセッションの裏の値(部屋ソケット、セッションの生死、接続方法、起動コマンド、作業ディレクトリ、開始時刻、ウィンドウ)が出ます。部屋ソケット以外は、選んでいる端末のアカウントのものです。本文に参加者の @名前 を書くと、送ったときにその人が宛先になり、@名前 は本文から消えます。入力欄で @ を打つと宛先の候補が出ます。宛先は複数にでき、書かなければ部屋全体宛です。候補に出るのは部屋に居る参加者だけで、未起動のアカウントは出ません。
タイトルバーの「端末」を開くと起動した CLI の端末が出ます。端末はそのまま操作できます。CLI はフォルダごとに初回の信頼確認を出すため、最初の一回はここから答えてください。
端末はアカウントごとに別です。複数のセッションを動かしても出力が混ざることはなく、キー入力とペーストは今見えている端末のセッションへ届きます。別のアカウントを見てから戻っても、それまでの出力は残っています。終了したアカウントの端末も、別のアカウントを選ぶまで残ります(なぜ落ちたかは、落ちる直前の出力にしか書かれていないためです)。
この端末は表示と操作のためのものです。ここに映る内容が部屋の発言になることはありません。
部屋の発言は、アプリがこの端末へ入力して届けます。一行目が [pullcept] で始まる入力がそれです。あなたが端末の入力欄に打ちかけている間は、アプリはそのセッションへの入力を待たせます。 送信するか入力を消すと、待たせていた発言が届いた順に入力されます。
アカウントの行の「開始」を押すと、次の 2 つが行われます。
- そのアカウントの作業ディレクトリの
.mcp.jsonへ、部屋のサイドカーをpullcept-room-<slug>-<hash>という名前で登録します。既存の内容はマージして保持しますが、あなたのリポジトリのファイルを書き換える操作です。登録鍵はアカウント id から決まります。アカウントごとに分けているのは同じ作業ディレクトリへ 2 つのセッションを立てたときに互いの登録を潰さないためで、名前ではなく id から導くのは改名で鍵が動かないようにするためです。前回の起動で書かれたエントリ(もう繋がらないポートを指しているもの)は、このとき掃除します。 - その登録を
--settingsで承認して、CLI を PTY 上の対話セッションとして起動します。
同じアカウントを二重に起動することはできません。一つのアカウントが持てる席は、一つの部屋につき一つです。
入力欄から発言するとセッションの端末へ入力として届き、セッションが say_to_room を呼び返すとメッセージ一覧へ並びます。往復が成立しないときの切り分け手順は docs/5-development.md を参照してください。
会話面の左はトピックの一覧です。トピックは会話の記録ではなく、会話が行われる器です。一覧から選ぶとそのトピックが部屋へ戻り、続きを話せます。
区切るのは「新規」だけです。アプリを起動したときも新しいトピックが開きますが、二つは独立しています——一回の起動で複数のトピックを持つことも、起動をまたいで一つのトピックを続けることもできます。何も話さずに閉じた回は一覧に残りません(最初の発言が着いた時点で記録されます)。
トピック名は最初の発言の冒頭から自動で付きます。行をダブルクリックすると、その場で直せます(Enter で決定、Escape で取消)。
トピックはアカウントごとに、そこに居た CLI セッションの id を持ちます。開き直して「開始」を押すと、そのアカウントに再開コマンドがあれば同じセッションが戻ります。戻せない席があってもトピックは開きます。 戻せなかった席は新しいセッションとして着席し、必要になったときに read_room_history で過去の発言を自分で引きます。部屋の側から過去を流し込むことはしません。
ログは %APPDATA%\org.liplus-project.pullcept\logs\main\ の下に、トピックごとの .jsonl と index.json として置かれます。以前の logs\main.jsonl は、初回の読み出しで一つのトピックとして引き継がれます(移動であり、捨てません)。
npm run sidecar:check
npm run sidecar:testsidecar:test は偽の部屋ソケットを立てて MCP と WebSocket の両面を駆動します。これが通れば、切り分けの対象をアプリ側へ絞れます。
このリポジトリの CI は、次の環境を基準にしています。
- Windows
- Node.js 22 と npm
- Rust stable
- Rust ターゲット
x86_64-pc-windows-gnu - GNU ターゲットをビルドできる MinGW ツールチェーン
依存関係をインストールします。
npm ci
rustup target add x86_64-pc-windows-gnuTauri アプリを開発モードで起動します。
npm run tauri devフロントエンドだけを起動する場合は、次のコマンドを使います。
npm run devフロントエンドを型検査してビルドします。
npm run buildCI と同じ Rust ターゲットでコンパイルを確認します。
Push-Location src-tauri
cargo check --target x86_64-pc-windows-gnu
Pop-Locationデスクトップアプリの配布用バンドルを作成します。
npm run tauri buildMinGW のツールが、空白を含むビルド出力パスを扱えない場合があります。その場合は src-tauri/.cargo/config.toml.example を src-tauri/.cargo/config.toml にコピーし、target-dir を空白のないローカルパスへ変更してください。この設定ファイルは Git の追跡対象外です。
docs/ 要求仕様(設計の source of truth。0-requirements.md が索引)
sidecar/ 部屋の MCP サーバ(Node)
src/ チャットルーム UI(TypeScript)
src-tauri/src/ Tauri、部屋ソケット、PTY、設定・セッション保存の Rust 実装
crates/mcp-config/ .mcp.json 登録と起動フラグ検査(tauri 非依存、テスト対象)
crates/room-floor/ 同時発話の順序付け(tauri 非依存、テスト対象)
crates/topic-index/ トピックの保存と索引の照合(tauri 非依存、テスト対象)
crates/mcp-servers/ アプリ本体が起動する MCP サーバの設定ファイルと欄の読み方(tauri 非依存、テスト対象)
portable-pty-patch/ Windows 対応を含む portable-pty のローカルパッチ
.github/workflows/ Windows CI とリリース用 CD
Pullcept は Apache License 2.0 のもとで提供されます。著作権表示は NOTICE.txt を参照してください。
portable-pty-patch/ は MIT License のコードを含みます。詳細は portable-pty-patch/LICENSE.md を参照してください。