メモ
Copilot SDK は現在 テクニカル プレビューです。 機能と可用性は変更される場合があります。
アプリケーションを実装するときに、CLI セッションのさまざまな分離パターンと、同時実行セッションとリソースを管理する方法を検討してください。
**次の場合に最適です。** プラットフォーム開発者、SaaS ビルダー、および数人以上の同時実行ユーザーにサービスを提供するデプロイ。
セッション分離パターン
パターンを選択する前に、次の 3 つのディメンションを検討してください。
- 分離: どのセッションを誰が確認できますか?
- コンカレンシー: 同時に実行できるセッションの数はいくつですか?
- 永続性: セッションの存続期間はどれくらいですか?

パターン 1: ユーザーごとの分離 CLI
各ユーザーは、独自の CLI サーバー インスタンスを取得します。 これは最も強力な分離であり、ユーザーのセッション、メモリ、プロセスは完全に分離されています。

**使用するタイミング:**
- データの分離が重要なマルチテナント SaaS。
- 異なる認証資格情報を持つユーザー。
- SOC 2 や HIPAA などのコンプライアンス要件。
// CLI pool manager—one CLI per user
class CLIPool {
private instances = new Map<string, { client: CopilotClient; port: number }>();
private nextPort = 5000;
async getClientForUser(userId: string, token?: string): Promise<CopilotClient> {
if (this.instances.has(userId)) {
return this.instances.get(userId)!.client;
}
const port = this.nextPort++;
// Spawn a dedicated CLI for this user
await spawnCLI(port, token);
const client = new CopilotClient({
cliUrl: `localhost:${port}`,
});
this.instances.set(userId, { client, port });
return client;
}
async releaseUser(userId: string): Promise<void> {
const instance = this.instances.get(userId);
if (instance) {
await instance.client.stop();
this.instances.delete(userId);
}
}
}
パターン 2: セッション分離を使用した共有 CLI
複数のユーザーが 1 つの CLI サーバーを共有しますが、一意のセッション ID を介して分離されたセッションを持っています。 これはリソースでは軽くなりますが、分離が弱くなります。

**使用するタイミング:**
- 信頼されたユーザーが含まれた内部ツール。
- リソースに制約のある環境。
- 分離要件が低い。
const sharedClient = new CopilotClient({
cliUrl: "localhost:4321",
});
// Enforce session isolation through naming conventions
function getSessionId(userId: string, purpose: string): string {
return `${userId}-${purpose}-${Date.now()}`;
}
// Access control: ensure users can only access their own sessions
async function resumeSessionWithAuth(
sessionId: string,
currentUserId: string
): Promise<Session> {
const [sessionUserId] = sessionId.split("-");
if (sessionUserId !== currentUserId) {
throw new Error("Access denied: session belongs to another user");
}
return sharedClient.resumeSession(sessionId);
}
パターン 3: 共有セッション (コラボレーション)
複数のユーザーが同じセッション (Copilot との共有チャット ルームなど) と対話します。 このパターンでは、アプリケーション レベルのセッション ロックが必要です。

**使用するタイミング:**
- チーム コラボレーション ツール。
- コード共有レビューセッション.
- プログラミング アシスタントのペア。
メモ
SDK では、組み込みのセッション ロックは提供されません。 同じセッションへの同時書き込みを防止するには、アクセスをシリアル化する必要があります。
import Redis from "ioredis";
const redis = new Redis();
async function withSessionLock<T>(
sessionId: string,
fn: () => Promise<T>,
timeoutSec = 300
): Promise<T> {
const lockKey = `session-lock:${sessionId}`;
const lockId = crypto.randomUUID();
// Acquire lock
const acquired = await redis.set(lockKey, lockId, "NX", "EX", timeoutSec);
if (!acquired) {
throw new Error("Session is in use by another user");
}
try {
return await fn();
} finally {
// Release lock only if we still own it
const currentLock = await redis.get(lockKey);
if (currentLock === lockId) {
await redis.del(lockKey);
}
}
}
// Serialize access to a shared session
app.post("/team-chat", authMiddleware, async (req, res) => {
const result = await withSessionLock("team-project-review", async () => {
const session = await client.resumeSession("team-project-review");
return session.sendAndWait({ prompt: req.body.message });
});
res.json({ content: result?.data.content });
});
分離パターンの比較
| 各ユーザーに対する個別のCLI | 共有されたCLI + セッションの分離 | 共有セッション | |
|---|---|---|---|
| 隔離 | 完了 | 論理 | Shared |
| リソースの使用状況 | 高 (ユーザーあたりの CLI) | 低 (1 つの CLI) | 低 (1 つの CLI とセッション) |
| 複雑性 | 中程度 | 低 | 高 (ロックが必要です) |
| 認証の柔軟性 | ユーザーごとのトークン | サービス トークン | サービス トークン |
| 最適な用途 | マルチテナント SaaS | 内部ツール | コラボレーション |
水平スケーリング
ロード バランサーの背後にある複数の CLI サーバー
より多くの同時実行ユーザーにサービスを提供するには、ロード バランサーの背後で複数の CLI サーバー インスタンスを実行します。 任意の CLI サーバーが任意のセッションを再開できるように、セッション状態は 共有ストレージ 上にある必要があります。

// Route sessions across CLI servers
class CLILoadBalancer {
private servers: string[];
private currentIndex = 0;
constructor(servers: string[]) {
this.servers = servers;
}
// Round-robin selection
getNextServer(): string {
const server = this.servers[this.currentIndex];
this.currentIndex = (this.currentIndex + 1) % this.servers.length;
return server;
}
// Sticky sessions: same user always hits same server
getServerForUser(userId: string): string {
const hash = this.hashCode(userId);
return this.servers[hash % this.servers.length];
}
private hashCode(str: string): number {
let hash = 0;
for (let i = 0; i < str.length; i++) {
hash = (hash << 5) - hash + str.charCodeAt(i);
hash |= 0;
}
return Math.abs(hash);
}
}
const lb = new CLILoadBalancer([
"cli-1:4321",
"cli-2:4321",
"cli-3:4321",
]);
app.post("/chat", async (req, res) => {
const server = lb.getServerForUser(req.user.id);
const client = new CopilotClient({ cliUrl: server });
const session = await client.createSession({
sessionId: `user-${req.user.id}-chat`,
model: "gpt-4.1",
});
const response = await session.sendAndWait({ prompt: req.body.message });
res.json({ content: response?.data.content });
});
スティッキー セッションと共有ストレージ

**スティッキー セッションでは** 、各ユーザーが特定の CLI サーバーにピン留めされます。 共有ストレージは必要ありませんが、ユーザー トラフィックが大幅に変化すると、負荷分散が不均一になる可能性があります。
**共有ストレージ** を使用すると、任意の CLI で任意のセッションを処理できます。 負荷分散はより均等ですが、 `~/.copilot/session-state/`にはネットワークストレージが必要です。
垂直スケーリング
1 つの CLI サーバーのチューニング
1 つの CLI サーバーで、多数の同時セッションを処理できます。 重要なのは、リソースの枯渇を避けるためにセッション ライフサイクルを管理することです。

// Limit concurrent active sessions
class SessionManager {
private activeSessions = new Map<string, Session>();
private maxConcurrent: number;
constructor(maxConcurrent = 50) {
this.maxConcurrent = maxConcurrent;
}
async getSession(sessionId: string): Promise<Session> {
// Return existing active session
if (this.activeSessions.has(sessionId)) {
return this.activeSessions.get(sessionId)!;
}
// Enforce concurrency limit
if (this.activeSessions.size >= this.maxConcurrent) {
await this.evictOldestSession();
}
// Create or resume
const session = await client.createSession({
sessionId,
model: "gpt-4.1",
});
this.activeSessions.set(sessionId, session);
return session;
}
private async evictOldestSession(): Promise<void> {
const [oldestId] = this.activeSessions.keys();
const session = this.activeSessions.get(oldestId)!;
// Session state is persisted automatically—safe to disconnect
await session.disconnect();
this.activeSessions.delete(oldestId);
}
}
一時的セッションと永続的セッション

**エフェメラル セッション** は要求ごとに作成され、使用後に破棄されます。 これらは、ワンショット タスクやステートレス API に最適です。
**永続的なセッション** は名前が付けられ、再起動後も存続し、再開できます。 マルチターン チャットや長いワークフローに最適です。
一時的なセッション
app.post("/api/analyze", async (req, res) => {
const session = await client.createSession({
model: "gpt-4.1",
});
try {
const response = await session.sendAndWait({
prompt: req.body.prompt,
});
res.json({ result: response?.data.content });
} finally {
await session.disconnect();
}
});
永続的セッション
// Start a conversation
app.post("/api/chat/start", async (req, res) => {
const sessionId = `user-${req.user.id}-${Date.now()}`;
const session = await client.createSession({
sessionId,
model: "gpt-4.1",
infiniteSessions: {
enabled: true,
backgroundCompactionThreshold: 0.80,
},
});
res.json({ sessionId });
});
// Continue the conversation
app.post("/api/chat/message", async (req, res) => {
const session = await client.resumeSession(req.body.sessionId);
const response = await session.sendAndWait({ prompt: req.body.message });
res.json({ content: response?.data.content });
});
// Clean up when done
app.post("/api/chat/end", async (req, res) => {
await client.deleteSession(req.body.sessionId);
res.json({ success: true });
});
コンテナーのデプロイ
永続ストレージ付きのKubernetes
次の例では、任意のレプリカが任意のセッションを再開できるように、 PersistentVolumeClaim を共有する 3 つの CLI レプリカをデプロイします。
apiVersion: apps/v1
kind: Deployment
metadata:
name: copilot-cli
spec:
replicas: 3
selector:
matchLabels:
app: copilot-cli
template:
metadata:
labels:
app: copilot-cli
spec:
containers:
- name: copilot-cli
image: ghcr.io/github/copilot-cli:latest
args: ["--headless", "--port", "4321"]
env:
- name: COPILOT_GITHUB_TOKEN
valueFrom:
secretKeyRef:
name: copilot-secrets
key: github-token
ports:
- containerPort: 4321
volumeMounts:
- name: session-state
mountPath: /root/.copilot/session-state
volumes:
- name: session-state
persistentVolumeClaim:
claimName: copilot-sessions-pvc
---
apiVersion: v1
kind: Service
metadata:
name: copilot-cli
spec:
selector:
app: copilot-cli
ports:
- port: 4321
targetPort: 4321

実稼働チェックリスト
| 懸念 | レコメンデーション |
|---|---|
| セッションのクリーンアップ | 定期的なクリーンアップを実行して、TTL より古いセッションを削除します。 |
| ヘルスチェック | CLI サーバーに定期的に ping を実行します。応答しない場合は再起動します。 |
| ストレージ |
`~/.copilot/session-state/`の永続ボリュームをマウントします。 |
| シークレット | プラットフォームのシークレットマネージャー(Vault、Kubernetes Secrets など)を使用します。 | | 監視 | アクティブなセッション数、応答待機時間、エラー率を追跡します。 | | Locking | 共有セッション アクセスには Redis または同様を使用します。 | | シャットダウン | CLI サーバーを停止する前に、アクティブなセッションをドレインします。 |
制限事項
| 制限事項 | 詳細情報 |
|---|---|
| 組み込みのセッション ロックなし | 同時アクセス用にアプリケーション レベルのロックを実装します。 |
| 組み込みの負荷分散なし | 外部ロード バランサーまたはサービス メッシュを使用します。 |
| セッションの状態はファイル ベースです | マルチサーバーセットアップ用の共有ファイルシステムが必要です。 |
| 30 分間の無操作タイムアウト | アクティビティのないセッションは、CLI によって自動クリーンアップされます。 |
| CLI は単一プロセスです | スレッドではなく CLI サーバー インスタンスを追加してスケーリングします。 |
次のステップ
- コア サーバー側のセットアップについては、 バックエンド サービス用の Copilot SDK の設定 を参照してください。
- マルチユーザー認証については、 Copilot SDK での GitHub OAuth の使用 を参照してください。
- インストールと最初のメッセージについては、 Copilot SDK のはじめに を参照してください。