최적 대상: 동시 사용자를 처리하는 SaaS 제품, 파트너 통합, 내부 플랫폼 및 백 엔드 서비스.
이 가이드를 사용하는 경우
빌드할 때 다음 가이드를 사용합니다.
- Copilot 지원 에이전트를 포함하는 다중 사용자 SaaS 제품
- Copilot Studio 또는 Fabric 스타일 패턴과 같은 파트너 통합을 위한 백 엔드
- 동시 사용자, 작업 영역, 테넌트 또는 요청을 처리하는 모든 서버
- 여러 SDK 클라이언트가 하나의 Copilot 런타임 프로세스에 연결하는 공유 런타임
이 가이드는 확장성 및 멀티 테넌시의 자매입니다. 토폴로지, 부하 분산 및 스토리지 패턴에 이 가이드를 사용합니다. SDK 수준 옵션 및 런타임 격리 선택에 대해서는 이 가이드를 사용합니다.
주요 SDK 옵션
| 옵션 | 다음 용도로 사용 | Notes |
|---|---|---|
mode: "empty" | 앰비언트 OS 도구 및 CLI 기본값을 사용하지 않도록 설정 | 다중 사용자 또는 공유 시나리오에 필요합니다. |
session | 유휴 세션 정리 | 장기 실행 프로세스에 대한 서버 쪽 시간 제한을 설정합니다. |
baseDirectory | 런타임 인스턴스별로 COPILOT_HOME 격리 | 기존 런타임에 연결할 때 무시됩니다. |
sessionFs | 세션 파일 시스템 스토리지를 로컬 디스크에서 다른 저장소로 라우팅 | 세션별 파일 시스템 공급자와 페어링합니다. |
Runtime | 이미 실행 중인 런타임 공유 | 언어 이름은 다양합니다. 아래 샘플을 참조하세요. |
| 세션별 GitHub 토큰 또는 공급자 | 요청하는 사용자에 대한 인증 범위 지정 | 단기 자격 증명에 회전 공급자를 사용하는 것이 좋습니다. 회전이 필요하지 않은 경우에만 정적 gitHubToken 을 사용합니다. |
콜백 지원 자격 증명은 인증을 참조하세요. 각 세션은 공급자 등록을 소유하므로 동시 세션은 콜백 상태를 공유하지 않고도 서로 다른 GitHub 호스트 및 계정을 사용할 수 있습니다.
mode: "empty"
mode: "empty" 기본적으로 선택적 Copilot CLI 동작을 사용하지 않도록 설정합니다. 다중 사용자 서버 모드에서는 애플리케이션이 세션에서 액세스할 수 있는 도구, MCP 서버, 기술 및 작업 영역 경로를 명시적으로 결정해야 하기 때문에 안전한 기준입니다.
공유 서버에는 기본값 mode: "copilot-cli" 을 사용하지 마세요. 이 모드는 CLI와 유사한 코딩 에이전트를 위한 것이며 앰비언트 호스트 파일 시스템 기능을 노출할 수 있습니다.
import { CopilotClient, RuntimeConnection } from "@github/copilot-sdk";
// baseDirectory and sessionIdleTimeoutSeconds apply when the SDK spawns the
// runtime. With RuntimeConnection.forUri(...) configure COPILOT_HOME and the
// idle timeout on the runtime process itself.
const client = new CopilotClient({
mode: "empty",
connection: RuntimeConnection.forUri(process.env.COPILOT_RUNTIME_URL!),
});
const session = await client.createSession({
sessionId: `user-${user.id}-${crypto.randomUUID()}`,
model: "gpt-5.4",
availableTools: ["custom:lookupOrder", "custom:createTicket"],
gitHubToken: user.githubToken,
});
from copilot import CopilotClient, RuntimeConnection
from copilot.session import PermissionHandler
client = CopilotClient(
mode="empty",
base_directory=f"/var/lib/my-app/copilot/{runtime_instance_id}",
session_idle_timeout_seconds=900,
connection=RuntimeConnection.for_uri(runtime_url),
)
await client.start()
session = await client.create_session(
session_id=f"user-{user.id}-{request_id}",
model="gpt-5.4",
available_tools=["custom:lookupOrder", "custom:createTicket"],
github_token=user.github_token,
on_permission_request=PermissionHandler.approve_all,
)
client := copilot.NewClient(&copilot.ClientOptions{
Mode: copilot.ModeEmpty,
BaseDirectory: fmt.Sprintf("/var/lib/my-app/copilot/%s", runtimeInstanceID),
SessionIdleTimeoutSeconds: 900,
Connection: copilot.URIConnection{URL: runtimeURL},
})
session, err := client.CreateSession(ctx, &copilot.SessionConfig{
SessionID: fmt.Sprintf("user-%s-%s", user.ID, requestID),
Model: "gpt-5.4",
AvailableTools: []string{"custom:lookupOrder", "custom:createTicket"},
GitHubToken: user.GitHubToken,
})
var client = new CopilotClient(new CopilotClientOptions
{
Mode = CopilotClientMode.Empty,
BaseDirectory = $"/var/lib/my-app/copilot/{runtimeInstanceId}",
SessionIdleTimeoutSeconds = 900,
Connection = RuntimeConnection.ForUri(runtimeUrl),
});
await using var session = await client.CreateSessionAsync(new SessionConfig
{
SessionId = $"user-{user.Id}-{requestId}",
Model = "gpt-5.4",
AvailableTools = ["custom:lookupOrder", "custom:createTicket"],
GitHubToken = user.GitHubToken,
});
// setCopilotHome and setSessionIdleTimeoutSeconds are ignored when
// setCliUrl is used; configure those on the runtime process instead.
var client = new CopilotClient(new CopilotClientOptions()
.setMode(CopilotClientMode.EMPTY)
.setCliUrl(runtimeUrl)
);
var session = client.createSession(new SessionConfig()
.setSessionId("user-" + user.id() + "-" + requestId)
.setModel("gpt-5.4")
.setAvailableTools(List.of("custom:lookupOrder", "custom:createTicket"))
.setGitHubToken(user.gitHubToken())
).get();
use std::path::PathBuf;
use github_copilot_sdk::{Client, ClientOptions, Transport};
use github_copilot_sdk::mode::ClientMode;
use github_copilot_sdk::types::SessionConfig;
let client = Client::start(
ClientOptions::new()
.with_mode(ClientMode::Empty)
.with_base_directory(PathBuf::from(format!(
"/var/lib/my-app/copilot/{runtime_instance_id}"
)))
.with_session_idle_timeout_seconds(900)
.with_transport(Transport::External {
host: runtime_host.to_string(),
port: runtime_port,
connection_token: None,
}),
).await?;
let session = client.create_session(
SessionConfig::default()
.with_session_id(format!("user-{}-{request_id}", user.id))
.with_model("gpt-5.4")
.with_available_tools(["custom:lookupOrder", "custom:createTicket"])
.with_github_token(user.github_token),
).await?;
sessionIdleTimeoutSeconds
비활성 세션이 자동으로 정리되도록 서버에서 설정합니다 sessionIdleTimeoutSeconds . 이렇게 하면 장기 실행 프로세스에서 좀비 세션을 방지하고 메모리 및 파일 시스템 압력을 줄일 수 있습니다.
| 언어 | 공용 옵션 |
|---|---|
| TypeScript | session |
| Python | session_idle_ |
| Go | Session |
| .NET | Session |
| java | set |
| 러스트 | with_session_ |
제품의 대화 수명과 일치하는 값을 사용합니다. 채팅 백 엔드의 경우 15~30분은 일반적으로 좋은 시작점입니다. 워크플로 에이전트의 경우 워크플로가 완료되면 더 긴 시간 제한 및 명시적 삭제를 사용합니다.
baseDirectory
baseDirectory은 런타임 인스턴스에 대해 COPILOT_HOME을 설정합니다. 프로세스, Pod, 작업자 또는 테넌트 경계당 런타임 상태, 자격 증명 및 세션 데이터를 격리하는 데 사용합니다.
const client = new CopilotClient({
mode: "empty",
baseDirectory: `/var/lib/my-app/copilot/runtime-${process.env.HOSTNAME}`,
sessionIdleTimeoutSeconds: 900,
});
런타임은 구성된 COPILOT_HOME 아래에 세션 상태를 저장하며, 여기에는 session-state/{sessionId}도 포함됩니다. 앱이 여러 런타임 인스턴스를 실행하는 경우 의도적으로 공유 스토리지를 사용하지 않는 한 각 인스턴스에 고유한 디렉터리를 제공합니다.
SDK가 RuntimeConnection.forUri(url)로 이미 실행 중인 런타임에 연결하면 baseDirectory는 SDK 클라이언트에 의해 무시됩니다. 대신 런타임 프로세스에서 COPILOT_HOME를 구성하세요.
sessionFs
sessionFs 는 사용자 지정 세션 파일 시스템 공급자를 등록하므로 세션 범위 파일 I/O가 런타임의 로컬 디스크 대신 애플리케이션 스토리지를 통해 라우팅될 수 있습니다. 로컬 디스크가 사용 후 삭제되거나, 세션 상태가 개체 스토리지에 있어야 하는 경우 또는 플랫폼이 테넌트 인식 스토리지 경로를 적용해야 하는 경우에 사용합니다.
const client = new CopilotClient({
mode: "empty",
sessionFs: {
initialCwd: "/workspace",
sessionStatePath: "/session-state",
conventions: "posix",
},
});
공급자 콜백을 노출하는 언어의 경우 클라이언트 수준에서 구성 sessionFs 하고 세션을 만들거나 다시 열 때 세션별 파일 시스템 처리기를 제공합니다. 지속성 개념 및 스토리지 장차는 세션 다시 시작 및 지속성 을 참조하세요.
런타임 소유의 영구 권한 선택도 세션 파일 시스템을 사용합니다. 공급자의 sessionStatePath 아래에서 permissions.json는 tool_approvals 및 allowed_directories와 함께 최상위 locations 맵을 유지하고, settings.json는 최상위 allowedUrls 및 sandbox를 저장하며, config.json는 최상위 trustedFolders를 저장합니다.
URL 승인은 settings.json에서만 읽습니다. config.json의 allowedUrls와 같은 레거시 사용자 설정 필드는 무시되고 호스트 동작과 일치합니다.
위치 키는 추가된 접두사 없이 정규화된 공급자 디렉터리 경로입니다. 확인은 호스트 파일 시스템을 검사하거나 호스트 Git 리포지토리를 검색하지 않고 공급자의 경로 규칙을 따릅니다.
/workspace 및 /workspace/sub은 서로 다른 위치 항목을 선택합니다.
런타임은 이러한 파일에 세션 ID 파티션을 추가하거나 공유 세분성을 변경하지 않습니다. 동일한 공급자 네임스페이스에서 동일한 파일에 액세스하는 세션은 기억된 권한을 공유합니다. 애플리케이션은 격리가 필요한 테넌트 또는 세션에 고유한 네임스페이스를 사용하고, 각 네임스페이스에 대한 액세스 권한을 부여하고, 다시 시작된 세션을 원래 네임스페이스에 다시 연결해야 합니다.
세션당 별도의 네임스페이스를 사용하면 영구 권한 부여는 새 세션에 대한 테넌트 차원의 권한 부여가 되는 대신 해당 세션이 다시 시작될 때도 유지됩니다. 세션 간에 승인을 공유하려면 다른 세션 상태를 별도로 유지하면서 동의 파일을 공유해야 합니다. 런타임은 동일한 공급자 엔드포인트 및 프로세스 내에서만 동의 업데이트를 직렬화합니다. 엔드포인트 또는 프로세스 간에 백킹 파일을 공유하는 애플리케이션은 동시 업데이트를 조정해야 합니다.
런타임은 변조 방지 스토리지 경계가 아니라 심층 방어를 위해 lexical approval-metadata 경로에 대한 직접적인 공급자 기반 파일 쓰기를 차단합니다. 공급자는 에이전트 파일 도구를 통해 승인 메타데이터에 쓰기 가능한 별칭(예: symlinks 또는 Windows 8.3 짧은 이름)을 노출해서는 안 됩니다. 셸 도구는 SessionFS를 통해 실행되지 않으며 해당 명령은 SessionFS의 가상 메타데이터 경로에 대해 확인되지 않습니다. 애플리케이션이 공급자의 기반 저장소를 셸 실행 또는 기타 임의 코드에 별도로 노출하는 경우 호스트는 해당 저장소를 보호해야 합니다.
세션 파일 시스템 승인 작업은 호스트의 permissions-config.json에 있는 기억된 권한, config.json의 URL 또는 샌드박스 설정, 또는 settings.json의 폴더 신뢰에서 기억된 권한을 가져오거나 이를 대신 사용하지 않습니다. 그들은 공급자가 승인받지 못했거나 오류를 보고하는 경우에도 이러한 호스트 파일을 업데이트하지 않습니다. 공급자 오류는 호스트 동의를 사용할 수 있다는 허가를 의미하지 않습니다. URL 거부 규칙은 권한 있는 기준으로 유지되며, 폴더 트러스트는 호스트 Git 검색 없이 공급자 경로를 사용합니다.
한 번 승인, 세션 동안 승인, 거부 및 세션 정책 변경은 기존 수명 및 이벤트 재생 동작을 유지합니다. 스토리지 라우팅은 그것들을 새 영구 권한 부여로 전환하지 않습니다. 승인 메타데이터와 동일한 테넌트 격리를 사용하여 지속성 권한 이벤트를 포함한 세션 기록을 보호합니다.
이 경계는 세션 파일 시스템 공급자를 사용하는 세션에만 적용됩니다.
copilot-cli가 없는 모든 SDK 애플리케이션은 sessionFs 및 empty 모드 모두에서 기억된 위치, 영구 URL 승인, 폴더 신뢰 및 샌드박스 설정에 대해 기존의 호스트 지원 지속성을 유지하며, 일반 CLI 세션도 마찬가지입니다.
확인된 공용 SDK 표면:
| 언어 | 클라이언트 수준 구성 | 세션별 제공자 |
|---|---|---|
| TypeScript | sessionFs | |
create / 공급자 콜백 | ||
| Python | session_fs | create_session_ |
| Go | SessionFS | Create |
| .NET | SessionFs | Create |
| 러스트 | with_session_ | with_session_ |
Java 현재 확인된 공용 sessionFs 옵션을 노출하지 않으므로 이 가이드에서는 Java sessionFs 샘플을 표시하지 않습니다.
RuntimeConnection.forUri(url)
여러 SDK 클라이언트가 이미 실행 중인 런타임을 공유해야 하는 경우 외부 런타임 연결을 사용합니다. 이는 런타임 프로세스가 요청 처리기와 별도로 관리되는 백 엔드 서비스에서 일반적입니다.
| 언어 | 외부 런타임 연결 |
|---|---|
| TypeScript | Runtime |
| Python | Runtime |
| Go | copilot.URIConnection{URL: url} |
| .NET | Runtime |
| java | setCliUrl(url) |
| 러스트 | Transport::External { host, port, connection_token } |
외부 런타임은 자체 프로세스 수준 인증 및 스토리지를 관리합니다. 사용자별 인증이 필요한 경우 createSession 또는 resumeSession에 세션별 토큰을 전달합니다.
세션당 gitHubToken
각 세션에서 gitHubToken 설정하여 요청 사용자에게 GitHub 인증 범위를 지정합니다. 이는 런타임 프로세스를 인증하는 클라이언트 수준 토큰과 다릅니다.
const session = await client.createSession({
sessionId: `user-${user.id}-support`,
model: "gpt-5.4",
availableTools: ["custom:*"],
gitHubToken: user.githubToken,
});
콘텐츠 제외, 모델 라우팅, 할당량 검사 및 사용자별 Copilot 액세스에 세션별 토큰을 사용합니다. 제품에서 의도적으로 서비스 계정 의미 체계를 사용하지 않는 한 사용자 간에 하나의 서비스 토큰을 공유하지 않습니다.
통합 ID
브랜드 에이전트를 빌드하는 파트너는 Mission Control 요청에 대한 통합 ID를 설정할 수 있습니다. 런타임은 GITHUB_COPILOT_INTEGRATION_ID를 읽고 모든 Mission Control 요청의 Copilot-Integration-Id HTTP 헤더에 이를 설정합니다.
GITHUB_COPILOT_INTEGRATION_ID=my-product-agent copilot --headless --port 4321
기본 통합 ID는 .입니다 copilot-developer-cli. 특성 및 라우팅과 같은 my-product-agent 안정적인 값을 사용합니다. 통합 ID는 현재 환경 변수에 의해서만 구성됩니다. 일류 SDK 옵션이 아닙니다.
SDK가 런타임을 생성하는 경우 클라이언트 환경 옵션을 통해 환경 변수를 전달합니다.
RuntimeConnection.forUri(url)로 연결하는 경우 런타임 프로세스 자체에 환경 변수를 설정합니다.
세션 수준 격리 보장
세션 수준 격리는 런타임이 전역 공유 상태가 아닌 세션으로 범위가 지정된 사용자별 모델 및 상태 정보를 유지한다는 것을 의미합니다.
| 표면 | 격리 동작 |
|---|---|
| 모델 목록 캐시 | 세션당. 모델 조회는 세션의 모델 목록 캐시를 사용합니다. |
| 세션 상태 | |
COPILOT_HOME/ 아래의 세션 ID당 | |
| GitHub 신원 | |
gitHubToken이(가) 세션에 설정된 경우 세션당. | |
| 도구 | |
mode: "empty"의 명시적, mode: "copilot-cli"의 암시적. | |
| 기술 | |
mode: "empty" 기본적으로 런타임 번들 기본 제공 기술은 사용할 수 없습니다. 호출자는 선택한 기본 제공을 허용하거나 사용자 지정 기술을 선택할 수 있습니다. | |
mode: "copilot-cli"의 앰비언트 | |
| 호스트 파일 시스템 | 호스트 도구를 사용할 수 있는 경우 런타임 프로세스에서 공유합니다. |
mode: "empty" 는 공유 런타임 패턴을 실행 가능하게 만드는 요소입니다. 애플리케이션이 등록하거나 허용하지 않는 한 앰비언트 OS 도구가 노출되지 않습니다. OS mode: "copilot-cli"파일 시스템 액세스는 호스트 프로세스를 통해 공유되므로 다중 사용자 서버 모드에 해당 모드를 사용하지 마세요.
mode: "empty"에서는 SDK가 기본적으로 런타임에 번들된 모든 기본 제공 스킬을 제외합니다(post-create/post-resume 옵션 패치에서 빈 installedPlugins 목록과 함께 빈 includedBuiltinSkills 목록을 보냅니다).
availableTools(또는 언어별 대소문자 표기)를 설정하여 선택한 내장 기능을 명시적으로 허용합니다. 이는 includedBuiltinSkills에서 선택한 런타임에 포함된 도구를 허용하는 것과 같습니다. 호출자는 기술을 사용하도록 설정하고 자체 기술 디렉터리를 가리키는 등 고유한 사용자 지정 기술을 옵트인할 수도 있으며, 이러한 기술은 계속 사용할 수 있습니다.
세션 상태는 COPILOT_HOME/session-state/{sessionId}를 통해 라우팅하지 않는 한 sessionFs 아래에 저장됩니다. 고유한 테넌트 또는 사용자 경계를 포함하는 고유한 세션 ID를 사용하고 세션을 다시 시작하거나 삭제하기 전에 액세스 제어를 적용합니다.
패턴 비교
| 패턴 | 사용 시기 | Trade-offs |
|---|---|---|
| 패턴 1: 사용자당 격리된 CLI | 사용자당 가장 강력한 격리 경계 또는 별도의 프로세스 자격 증명이 필요합니다. | 강력한 격리; 리소스 비용이 더 높습니다. |
| 확장성 및 멀티 테넌시을(를) 참조하세요. | ||
패턴 2: mode: "empty" 사용 공유 CLI | 앱이 도구, 인증 및 세션 ID를 제어하는 동안 하나의 런타임이 많은 사용자에게 서비스를 제공하려고 합니다. | 효율적이지만 신중한 도구 등록, 세션별 토큰, 그리고 애플리케이션 수준의 액세스 검사가 필요합니다. |
| 패턴 3: 하이브리드 | 컴퓨팅이 많은 작업을 클라우드 세션으로 라우팅하고 가벼운 작업을 로컬 세션으로 라우팅합니다. | 유연하지만 워크로드 라우팅 및 정책 처리가 필요합니다. |
| 클라우드 세션을(를) 참조하세요. |
패턴 2: mode: "empty" 사용 공유 CLI
이 패턴에서 모든 사용자는 백 엔드를 통해 하나의 런타임 풀에 연결합니다. 애플리케이션은 사용자 인증을 수행하고, 세션 ID를 선택하고, 세션에서 사용자의 GitHub 토큰을 전달하고, 명시적 도구 허용 목록을 제공합니다.

다음 규칙을 사용합니다.
- 항상
mode: "empty"에서 클라이언트 또는 런타임을 시작하세요. - 고유한 세션 ID를 사용하고 애플리케이션 데이터베이스에 소유권 메타데이터를 저장합니다.
- 세션 ID를 참조하는
resumeSession,deleteSession또는 모든 UI 작업을 수행하기 전에 소유권을 확인하세요. - 요청이 사용자로 실행되어야 하는 경우 세션당 전달
gitHubToken합니다. - 세션에 필요한 도구만 등록하고 원본으로 한정된 허용 목록(예:
custom:*또는mcp:search_docs.)을 선호합니다. sessionIdleTimeoutSeconds을 설정하고 완료된 워크플로 세션을 명시적으로 삭제합니다.
일반적인 문제
- 잊어버림
mode: "empty". 기본copilot-cli모드는 CLI 스타일 동작을 노출하며 앰비언트 도구를 통해 호스트 파일 시스템을 노출할 수 있습니다. - 설정하지 않음
sessionIdleTimeoutSeconds. 장기 실행 서버는 정리하지 않으면 유휴 세션을 누적할 수 있습니다. - 세션별 토큰을 전달하는 대신, 하나의
gitHubToken를 여러 사용자 간에 공유 - 백 엔드에서 소유권을 확인하지 않고 클라이언트에서 제공하는 세션 ID를 신뢰합니다.
- 기존 런타임에 연결하는 클라이언트에서 설정하고
baseDirectory런타임 스토리지를 이동할 것으로 예상합니다. 대신 런타임 프로세스를 구성합니다. - 각 도구가 사용자에게 적합한지 여부를 검토하지 않고와 같은
builtin:*광범위한 도구 패턴을 허용합니다.
참고하십시오
- 확장성 및 멀티 테넌시: 배포 토폴로지, 스토리지 패턴 및 격리 비교
- 백 엔드 서비스 설정: 헤드리스 서버 모드에서 런타임 실행
- BYOK(사용자 고유의 키 가져오기): 사용자 고유의 모델 공급자 자격 증명 사용
- 클라우드 세션: 선택한 작업을 클라우드 세션으로 라우팅
- 세션 다시 시작 및 지속성: 다시 실행 가능한 세션 상태 관리
- 기능: 도구, 이벤트, 후크 및 고급 SDK 기능