키트 v2

키트 v2 (Kits v2)

v2 키트의 사용법, 구성, 사양을 알아볼게요.

출처: 문서

본문

V2 키트는 계속 지원돼요. 이 페이지는 v2 사용법, 구성, 사양을 다뤄요. sbx CLI로 새 키트를 개발한다면 v3 키트를 쓰세요.

claude, codex 같은 내장 단축어는 v2 키트를 선택하며 v2 mixin과도 여전히 동작해요. V3 워크로드와 mixin은 v1 또는 v2 키트와 결합할 수 없어요. V1도 계속 지원돼요.

참고 (Note): 이 기능은 Early Access 상태예요.

기존 키트 사용하기

v2 키트는 schemaVersion: "2"가 있는 spec.yaml과 선택적인 files/ 트리를 포함해요. 샌드박스 키트(sandbox kit)는 에이전트 환경을 정의하고, mixin은 그것에 도구나 구성을 추가해요. 에이전트 이름 대신 샌드박스 키트를 넘기고 --kit으로 mixin을 추가하세요:

$ sbx run ./my-agent --name my-project --kit ./team-config
$ sbx run claude --name claude-project --kit ./team-config

sbx run은 현재 디렉터리를 워크스페이스로 사용해요. 다른 디렉터리를 쓰려면 프로젝트 경로를 추가하세요. 에이전트를 실행하지 않고 만들려면 sbx create를 쓰고, 디렉터리를 마운트하려면 워크스페이스 경로나 .을 포함하세요. 참조는 로컬 디렉터리, ZIP 파일, OCI 아티팩트, Git URL이 될 수 있어요. 상대 경로는 ./ 또는 ../로 시작하세요. Docker Hub 키트는 docker.io/를 생략하고 <NAMESPACE>/<KIT>:<TAG>를 쓸 수 있어요. Git URL에서 ref는 리비전을, dir은 키트 디렉터리를 고른다. &를 포함하는 URL은 따옴표로 감싸세요:

$ sbx run "git+https://github.com/<ORG>/<REPOSITORY>.git#ref=<COMMIT>&dir=my-agent"

git+ssh:// URL은 로컬 SSH 에이전트와 Git 자격 증명으로 동작해요. 비공개 레지스트리는 Registry credentials 문서를 보세요.

--kit으로 하는 키트 선택은 생성 시점에 적용돼요. sbx kit add가 지원하는 제한된 갱신을 제외하고, 키트 세트를 바꾸려면 샌드박스를 다시 만드세요. 그 명령은 패키지, 이미지, 볼륨, 에이전트 히스토리를 보존하면서 샌드박스를 재시작해요. 실행 중인 샌드박스에서 키트를 제거할 순 없어요.

키트 소스 제한하기

소스 정책은 Restrict kit sources 문서를 보세요. kit.allowLocalKits는 v2 ZIP 파일도 통제해요.

내장 에이전트의 이미지 덮어쓰기

--template으로 내장 에이전트의 이미지를 바꾸면서 구성과 실행 명령은 유지할 수 있어요. 교체 이미지는 같은 에이전트를 지원해야 해요. 예를 들어 claude와 함께 쓰는 이미지에는 Claude Code가 설치돼 있어야 해요.

자체 실행 명령과 샌드박스 설정을 가진 환경을 정의하려면, v3 워크플로에 대해 에이전트 워크로드 빌드하기 문서를 보세요.

템플릿 고르기

Docker는 에이전트 이미지를 docker/sandbox-templates:<variant>로 배포해요. 에이전트와 일치하는 variant를 고르세요. 사용 가능한 variant는 Base images 문서를 보세요.

claude-code-docker처럼 -docker 접미사가 있는 variant는 샌드박스 안에서 컨테이너를 빌드·실행하기 위한 Docker Engine을 포함해요. 기본적으로 커스텀 템플릿을 지정하지 않으면 내장 에이전트가 이 variant를 써요.

샌드박스 안에 Docker가 필요 없으면 접미사 없는 variant를 고르세요. 리소스를 덜 쓰고 privileged 모드가 필요 없어요:

$ sbx run claude --template docker.io/docker/sandbox-templates:claude-code

--template 이미지 참조에는 레지스트리 도메인을 포함하세요. 키트 참조와 달리 템플릿 참조는 자동으로 docker.io를 붙여주지 않아요.

커스텀 템플릿 빌드하기

커스텀 템플릿을 빌드하려면 Docker Desktop이 필요해요.

실행할 에이전트에 대해 Docker가 제공하는 이미지를 확장하세요. 예를 들어 이 Dockerfile은 Claude Code 이미지에 Rust와 프로토콜 버퍼 도구를 추가해요:

FROM docker/sandbox-templates:claude-code
USER root
RUN apt-get update && apt-get install -y protobuf-compiler
USER agent
RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y

시스템 패키지는 root로 설치하고, 에이전트의 홈 디렉터리에 도구를 설치하기 전에 agent로 돌아가세요.

이미지를 빌드하고 레지스트리에 푸시하세요. <NAMESPACE>를 푸시 가능한 Docker Hub 네임스페이스로 바꾸세요:

$ docker build -t docker.io/<NAMESPACE>/my-template:v1 --push .

레지스트리 자격 증명과 로컬 빌드 이미지 로딩은 Load a template 문서를 보세요.

이미지로 샌드박스를 실행하세요:

$ sbx run claude --template docker.io/<NAMESPACE>/my-template:v1

이 이미지는 claude-code를 확장하므로 claude와 함께 쓰세요. codex 기반 이미지는 codex를, shell 기반 이미지는 shell을 써서 에이전트 없이 Bash를 여세요.

추가한 도구가 네트워크 접근을 필요로 하면, allow-all 정책을 쓰지 않는 한 그 도구가 쓰는 도메인을 샌드박스 네트워크 정책에 허용하세요:

$ sbx policy allow network "*.example.com:443,example.com:443"

키트 종류

kind: mixin

Mixin은 기존 샌드박스에 능력을 겹쳐 쌓아요. sandbox: 블록, extends:, mixins:를 선언해서는 안 돼요. Mixin은 requires:로 설계 대상 기본 에이전트를 고정할 수 있어요:

schemaVersion: "2"
kind: mixin
name: github-tools
requires:
  agent: claude

requires.agent는 기본 에이전트 이름 하나를 받아요. 키트 이름으로 검증되며 구성 중에 강제돼요.

kind: sandbox

샌드박스 키트는 완전한 에이전트를 정의해요. 루트 샌드박스는 sandbox: 블록을 선언해야 해요. extends:를 쓰는 샌드박스는 부모 이미지를 상속하고 자체 sandbox: 블록을 생략할 수 있어요:

schemaVersion: "2"
kind: sandbox
name: claude-safe
extends: claude

extends:는 샌드박스 전용이에요. 부모는 샌드박스 키트로 해석되어야 해요. mixins:도 샌드박스 전용이며 파서가 받아들이지만 런타임 구성 지원은 보류 중이에요.

최상위 필드

규범 문법은 v2 사양을 보세요.

필드 필수 설명
schemaVersion 예 사양 스키마 버전. 이 문법에는 "2"를 쓰세요.
kind 예 에이전트를 확장하는 키트는 mixin, 에이전트를 정의하는 키트는 sandbox.
name 예 고유 식별자. 소문자 영숫자에 하이픈, 1~64자.
version 아니요 키트 버전.
displayName 아니요 사람이 읽을 수 있는 이름.
description 아니요 짧은 설명.
sourceURL 아니요 소스 저장소 또는 문서 URL.
licenses 아니요 SPDX 라이선스 식별자.
locked 아니요 하위 키트가 덮어쓸 수 없는 점 경로.
security 아니요 컨테이너 보안 설정. security.privileged: true는 컨테이너를 privileged 모드로 실행해요.
args 아니요 키트를 불러올 때 제공되는 argument. 스키마 v2 전용.

키트는 agentInstructions, permissions, ports, credentials, environment, setup, volumes 같은 동작 블록도 선언해요.

Arguments

스키마 v2 키트는 argument를 선언하고 spec.yaml의 어디서나 또는 files/ 아래에서 ${{ kit.args.<name> }}로 참조할 수 있어요. 치환은 스펙을 디코딩하기 전에 일어나요.

args:
  version:
    default: latest
    description: Tool version to install
    pattern: '^(latest|[0-9]+\.[0-9]+\.[0-9]+)$'
  channel:
    default: stable
    enum: [stable, beta, nightly]
  target:
    required: true
    description: Build target

environment:
  variables:
    TOOL_VERSION: "${{ kit.args.version }}"

API 토큰, 비밀번호, 기타 비밀에 키트 argument를 쓰지 마세요. 민감한 값을 샌드박스에 제공하려면 Credentials를 쓰세요.

필드 설명
Argument 이름 문자 또는 밑줄로 시작하며 문자, 숫자, 밑줄, 하이픈만 포함.
default 호출자가 값을 제공하지 않을 때 쓸 문자열. required: true와 상호 배타적.
required 호출자가 값을 반드시 제공해야 할 때 true로 설정. default와 상호 배타적.
description 필수 값이 없을 때 보여주는 선택 도움말.
enum 허용 값의 선택 목록. pattern과 상호 배타적.
pattern 전체 값과 대조하는 Go RE2 정규식. enum과 상호 배타적.

각 argument는 빈 문자열 기본값을 포함한 default 또는 required: true 중 하나를 선언해야 해요.

argument 값은 문자열이지만 치환은 YAML 디코딩 전에 일어나요. 1.20 같은 값이 숫자로 디코딩되지 않도록 문자열 값 필드의 자리표시자를 따옴표로 감싸세요.

키트에 argument 넘기기

그 argument를 선언하는 모든 키트에 --kit-arg name=value를 쓰거나, 키트의 name을 접두사로 붙여 한 키트를 대상으로 해요. 범위 지정 값이 공유 값을 덮어써요:

$ sbx run ./my-agent --kit ./my-mixin --kit-arg channel=stable \
    --kit-arg my-mixin.channel=beta

--kit-args-file <FILE>은 name=value 항목을 읽고 빈 줄과 # 주석은 무시해요. 나중 파일이 이전 파일을 덮어쓰고, --kit-arg가 파일을 덮어써요. 반복되는 CLI 키는 마지막 값이 이겨요. 빠진 필수 값, 알 수 없는 argument, 선언되지 않은 자리표시자, 잘못된 값은 생성 전에 실패해요. 필요하면 같은 플래그를 sbx kit validate나 sbx kit inspect에 넘기세요. argument 값은 셸 히스토리에 남을 수 있고 argument 파일에 암호화 없이 저장돼요.

Sandbox 블록

sandbox:
  image: <image-ref>
  build:
    context: .
    dockerfile: Dockerfile
    args:
      AGENT_VERSION: "1.0.0"
    target: runtime
    platforms:
      - linux/amd64
  entrypoint: [my-agent, "--flag"]
  command:
    default: ["--task-mode"]
    interactive: []
  resources:
    cpu: 2
    memory: 4g
    gpu: "1"
필드 필수 설명
sandbox.image extends:를 생략할 때 Docker 이미지 참조.
sandbox.build 아니요 빌드 구성. 런타임 지원이 보류 중이므로 build:가 있는 키트는 image:도 설정해야 해요.
sandbox.entrypoint 아니요 문자열 배열의 고정 프로세스 접두사. 첫 요소가 에이전트 바이너리.
sandbox.command 아니요 모드별 argument 꼬리. default에는 리스트 축약을, default와 interactive가 있는 매핑을 쓰세요.
sandbox.resources 아니요 선택 CPU, 메모리, GPU 제약. 메모리는 4096m이나 4g 같은 바이트 크기 문자열을 써요.

유효 명령은 non-interactive 실행에서는 entrypoint + command.default, TTY 세션에서는 entrypoint + command.interactive예요. interactive를 생략하면 default로 폴백해요.

extends:를 쓰는 키트에서 sandbox.command는 부모 sandbox.entrypoint의 바이너리 뒤 플래그를 포함해 상속된 argument 꼬리 전체를 교체해요. 그 꼬리에 추가하지 않아요. 하위 키트가 필요한 모든 argument를 정의하세요. 예를 들어 --settings를 추가하는 claude의 하위 키트는 그 동작을 보존하려면 --dangerously-skip-permissions도 포함해야 해요.

에이전트의 컨테이너 이미지는 다음을 제공해야 해요:

  • 비밀번호 없는 sudo를 가진 UID 1000의 비-root agent 사용자.
  • agent가 소유한 /home/agent/ 홈 디렉터리.
  • sudo를 거쳐 보존되는 HTTP 프록시 환경 변수(HTTP_PROXY, HTTPS_PROXY, NO_PROXY).
  • 내장되거나 setup.install로 설치된 에이전트 바이너리.

이 기본 요구사항을 얻으려면 docker/sandbox-templates:shell-docker 위에 빌드하세요.

에이전트 지침

agentInstructions 아래에서 이 필드들을 선언하세요:

필드 설명
filename AI 프로필 파일 이름. kind: sandbox에서 의미 있고, kind: mixin에서는 경고와 함께 무시돼요.
content Markdown 지침. 샌드박스에서는 프로필에 인라인되고, mixin에서는 키트 메모리에 쓰여요.

mixin에서 엔진은 content를 <dir-of-AI-file>/kits-memory/<kit-name>.md에 쓰고 기본 AI 파일에 ## Kits 포인터 섹션을 추가해요. 이렇게 하면 각 mixin의 지침이 별도 파일에 유지돼요.

생성된 프로필은 샌드박스 안의 마운트된 워크스페이스의 상위 디렉터리에 있어요. 마운트 밖에 있으며 프로젝트의 지침 파일을 대체하지 않아요. 샌드박스 키트의 인라인 지침은 그 프로필로 직접 들어가요.

자격 증명

키트는 필요로 하는 자격 증명과 프록시가 그것을 아웃바운드 요청에 어떻게 주입하는지 선언해요. 호스트 검색 소스는 선언하지 않아요. 사용자가 비밀 저장소 또는 첫 실행 프롬프트로 값을 제공하고, credential binding이 사용을 승인해요. 키트는 임의의 호스트 환경 변수나 파일을 읽을 수 없어요.

credentials는 목록이며 각 항목이 service를 이름 짓고 하나 이상의 인증 메커니즘을 구성해요.

필드 설명
service 자격 증명 식별자. sbx secret set으로 저장한 값과 대조. 소문자 kebab-case.
description 선택. binding을 승인할 때 사용자에게 보여줌.
required 자격 증명을 에이전트에 필수로 표시. binding이 없으면 sbx가 경고하고 자격 증명을 보류한 채 시작. 기본 false.
provider 제공자 레지스트리용 예약. 경고와 함께 받아들이고 런타임 효과 없음.
apiKey API-key 주입(apiKey 참조).
oauth OAuth 가로채기(oauth 참조).

각 서비스는 apiKey, oauth, 또는 둘 다를 선언해야 해요. 둘 다 런타임에 해석되면 API 키가 우선하고 OAuth가 폴백 역할을 해요.

apiKey

필드 설명
name 자격 증명의 환경 변수 이름 (예: ANTHROPIC_API_KEY).
proxyManaged true면 sbx가 컨테이너 안의 name을 proxy-managed 센티넬로 설정. 기본 false.
inject[].domain 자격 증명을 주입할 도메인. permissions.network에도 허용돼야 해요.
inject[].header 프록시가 설정하는 HTTP 헤더 (예: x-api-key, Authorization).
inject[].format %s 자리표시자 하나가 있는 헤더 값 형식 (예: "%s" 또는 "Bearer %s"). scheme과 상호 배타적.
inject[].scheme 일반 인증 스킴 축약. bearer는 Authorization: Bearer ***로 확장되고, basic은 username이 필요. format과 상호 배타적.
inject[].username HTTP Basic 인증 사용자 이름 (예: Git over HTTPS의 x-access-token).

oauth

OAuth로 인증하는 에이전트(예: Claude Code)에서 프록시는 토큰 응답을 가로채서 실제 토큰을 센티넬로 바꾼 뒤 아웃바운드 요청에서 실제 토큰을 다시 넣어요. 기본적으로 토큰은 샌드박스에 들어가지 않아요. passthrough: true를 설정하면 센티넬 마스킹을 선택 해제하고 실제 토큰 응답을 샌드박스로 보내요.

필드 설명
tokenEndpoint.host / path 프록시가 가로채는 OAuth 토큰 엔드포인트.
sentinels.accessToken / refreshToken 실제 토큰 대신 컨테이너에 쓰는 센티넬 값.
credentialFile.path 컨테이너 안에서 자격 증명 파일을 쓸 위치 (~ 확장됨).
credentialFile.structure 선언적 JSON 형태. {{.AccessToken}}, {{.RefreshToken}}, {{.ExpiresAt}}, {{.Scopes}} 지원.
credentialFile.template Go 템플릿. {{.AccessToken}}, {{.RefreshToken}}, {{.ExpiresAt}}, {{.Scopes}}, {{.ScopesJSON}} 지원.
resourceHosts 프록시가 아웃바운드 요청에 토큰을 붙이는 API 호스트. 토큰 엔드포인트 호스트와 구분됨.
skipIfEnv 호환성용으로 받아들이지만 스키마 v2에서는 무시. v2 binding이 호스트 환경 변수보다 우선.
responseFields 프록시가 토큰 응답에서 읽는 기본 필드 이름을 덮어씀.
passthrough true면 프록시가 토큰을 센티넬로 바꾸는 대신 토큰 응답을 그대로 통과시킴.

credentialFile.structure는 credentialFile.template의 선언적 대안을 제공해요. 엔진이 잘 구성된 JSON으로 렌더링해요. 두 필드가 모두 설정되면 structure가 우선해요.

네트워크

네트워크 이그레스는 permissions.network 아래에 선언해요. 자격 증명은 더 이상 자체 도메인 매핑을 갖지 않아요. 프록시는 apiKey.inject가 나열한 도메인에만 자격 증명을 주입하고, 샌드박스가 닿는 모든 도메인은 여기서 허용돼야 해요.

필드 설명
permissions.network.allow 샌드박스가 닿을 수 있는 도메인.
permissions.network.deny 샌드박스가 닿지 못하도록 차단된 도메인. Deny가 allow보다 우선하며, 구성된 키트를 포함해.

allow와 deny 패턴:

패턴 예시 상태
정확한 호스트 api.example.com 강제됨
정확한 호스트와 포트 api.example.com:8080 강제됨
단일 라벨 와일드카드 *.example.com 강제됨
멀티 라벨 와일드카드 **.example.com 파싱됨; 강제 보류
포트 범위 api.example.com:80-443 파싱됨; 강제 보류
포트 와일드카드 api.example.com:* 파싱됨; 강제 보류
CIDR 10.0.0.0/8 파싱됨; 강제 보류

v1에서는 이것이 network: 블록(allowedDomains/deniedDomains, 그리고 serviceDomains/serviceAuth)이었어요. v2에서 그 필드들은 디코드 오류예요.

포트

ports를 항목 목록으로 선언해 샌드박스 서비스를 호스트에 노출해요:

필드 설명
container 컨테이너 포트, 1~65535.
protocol tcp 또는 udp. 비워 두면 한 패밀리를 공개함(아래 참조).
name 공개 포트 바인딩을 나열하는 도구가 표시하는 선택 라벨.

호스트 포트는 임시로 할당돼요. 서비스가 IPv6를 듣지 않으면 protocol을 비워 두세요. 빈 값은 IPv4(127.0.0.1)만 공개하는데, 이는 0.0.0.0에 바인딩된 서비스가 필요로 하는 값이에요. 반면 tcp는 127.0.0.1과 ::1 둘 다 공개해요. ::1로 도착한 클라이언트는 수락됐다가 샌드박스 안에 거기 듣는 것이 없으면 리셋돼요. 사용자는 sbx ports --publish <host>:<container>로 호스트 포트를 고정할 수 있어요.

환경

필드 설명
environment.variables 컨테이너에 직접 설정하는 키-값 쌍.

DASH_, SBX_, DOCKER_ 변수는 설정하지 말고, HOME, USER, SHELL, PATH, LD_PRELOAD, LD_LIBRARY_PATH를 덮어쓰지 마세요. 런타임이 이 이름들을 예약하며 덮어쓸 수 있어요.

설정

setup.install, setup.startup, setup.files는 여기 설명한 필드를 가진 명령이나 파일의 목록이에요.

실행 순서

샌드박스를 만들 때 키트 내용이 이 순서로 적용돼요:

  1. 네트워크 권한과 환경 변수.
  2. files/home/ 아래의 정적 파일.
  3. 선언 순서대로 setup.install 명령.
  4. setup.files 항목.
  5. setup.startup 명령은 각 샌드박스 시작에 등록됨.
  6. 워크스페이스가 준비된 후 files/workspace/ 아래의 정적 파일. --clone에서는 저장소가 클론된 후에.

스택된 키트에서 각 단계의 항목은 --kit 순서로 적용돼요. install 명령은 files/home/의 번들 파일을 소비할 수 있지만, files/workspace/나 setup.files의 것은 나중에 도착하므로 소비할 수 없어요.

sbx kit add는 샌드박스를 제자리에서 수정하는 대신 재생성해요. environment.variables, setup.install, permissions.network.allow로 제한된 mixin 키트를 지원하며, 이는 샌드박스 생성과 같은 순서를 따라요. 정적 파일, setup.startup, setup.files를 선언하는 키트는 거절해요. 그 필드를 쓰려면 키트로 샌드박스를 다시 만드세요.

install

키트 적용 시(샌드박스 생성 중 또는 sbx kit add를 통해) 동기적으로 실행돼요. 셸 문자열은 sh -c로 전달돼요.

키트 install 명령은 템플릿 이미지의 구성된 WORKDIR에서 시작해요. Docker가 제공하는 템플릿은 /home/agent/workspace를 쓰는데, 직접 마운트 또는 clone 모드 샌드박스의 기본 워크스페이스와 반드시 같지는 않아요. 현재 디렉터리로 워크스페이스 파일을 찾지 마세요. files/home/의 번들 자산에는 절대 경로를 쓰세요.

필드 기본값 설명
command — 셸 명령 문자열.
user "0" 실행할 사용자. "0" = root.
description — 사람이 읽을 수 있는 설명.

startup

모든 샌드박스 시작 시 실행돼요. 문자열 배열이며 셸이 해석하지 않아요.

필드 기본값 설명
command — 문자열 배열의 명령과 인자.
user "1000" 실행할 사용자. "1000" = agent.
background false 이 명령이 끝날 때까지 이후 startup 명령을 블록. true로 설정하면 기다리지 않고 이후 명령이 실행됨.
description — 사람이 읽을 수 있는 설명.

Startup 명령은 non-interactive예요. 에이전트가 붙기 전에 터미널 없이 실행되므로 사용자에게 프롬프트를 띄울 수 없어요(예: 대화형 aws login은 멈추거나 실패해요). 또한 에이전트의 entrypoint를 막지 않아요. startup 명령이 디스패치되면 background와 무관하게 에이전트가 시작돼요. false 값은 다음 명령을 실행하기 전에 startup 디스패처 안에서 기다려요. 에이전트 entrypoint를 지연시키진 않아요. 에이전트와 나란히 실행될 수 있는 작업에는 startup 명령을 쓰세요. 에이전트가 실행되기 전에 디스크에 있어야 하는 값은 setup.files를 쓰세요.

Startup 명령은 멱등(idempotent)이어야 해요. 모든 샌드박스 시작에 실행되고 컨테이너 재시작 시 재생되므로, 두 번째 호출에서 실패하거나 잘못 동작하는 명령은 재시작 경로를 깨뜨려요. 존재 확인으로 작업을 보호하고, insert 대신 upsert를 쓰고, 몇 번 실행하든 같은 종료 상태로 수렴하는 명령을 선호하세요.

files

샌드박스 시작 시 런타임 치환과 함께 쓰는 파일.

필드 기본값 설명
path — 절대 컨테이너 경로.
content — 파일 내용. ${WORKDIR}가 워크스페이스 경로로 확장됨.
mode "0644" 8진수 파일 권한.
onlyIfMissing false 파일이 이미 있으면 건너뜀.

런타임은 UID 1000의 에이전트 사용자로 이 파일들을 써요. 대상 경로는 그 사용자가 쓸 수 있어야 해요. /etc 같은 root 소유 경로에 쓰려면 기본적으로 root로 실행되는 install 명령을 쓰세요. 나중에 에이전트가 파일을 수정해야 하면 install 명령에서 소유권을 설정하세요.

셸 초기화와 서비스 로그

Docker 템플릿에서는 install 명령으로 /etc/sandbox-persistent.sh에 셸 초기화를 추가하세요. 기존 내용은 유지하고 완료 스크립트는 빼세요. 대화형·non-interactive Bash 명령이 이 파일을 소스하기 때문이에요. 백그라운드 서비스는 startup 출력을 파일로 리다이렉트하고 sbx exec로 읽으세요. 끝에 & 대신 background: true를 쓰세요.

정적 파일

my-kit/files/
├── home/ → /home/agent/
└── workspace/ → primary workspace path
키트 경로 컨테이너 목적지
files/home/ /home/agent/ (설정 파일, dotfile)
files/workspace/ 기본 워크스페이스 경로

상위 디렉터리는 자동으로 생성돼요. 기존 파일은 덮어써져요. 절대 경로와 경로 탐색 시퀀스(../../)는 거절돼요.

정적 파일은 linter 설정, 도우미 스크립트, 에이전트 스킬을 공급할 수 있어요. 예를 들어 Claude Code 프로젝트 스킬은 files/workspace/.claude/skills/<NAME>/SKILL.md에 있어요.

볼륨

volumes를 이 필드들을 가진 마운트 목록으로 선언해요:

필드 설명
path 필수 절대 컨테이너 경로.
type 블록 지원 볼륨이면 비우고, RAM 지원 스토리지면 tmpfs.
size 선택 바이트 크기 문자열.
mode 선택 8진수 권한.

볼륨은 샌드박스를 만들 때만 적용돼요. sbx kit add는 실행 중인 컨테이너에 볼륨을 붙일 수 없어요.

기존 에이전트 포크하기

샌드박스 키트(kind: sandbox)는 처음부터 완전한 에이전트를 정의해요. 가장 흔한 변형은 내장 에이전트의 포크예요. extends:로 부모의 완전한 구성을 상속하고 바꾸고 싶은 필드만 선언하세요. 이 예시는 내장 claude entrypoint를 교체해서 Claude Code가 승인 프롬프트를 우회하는 대신 수동 권한 모드를 쓰게 해요:

schemaVersion: "2"
kind: sandbox
name: claude-safe
displayName: Claude Code (with approval prompts)
description: Claude Code in manual permission mode

extends: claude

sandbox:
  entrypoint: [claude, "--permission-mode", "manual"]

하위 키트는 내장 이미지, 자격 증명, 네트워크 권한, 지속 볼륨, 설정, MCP 통합, 에이전트 지침, setup 항목, 환경 변수를 상속해요. 그것의 sandbox.entrypoint는 상속된 entrypoint를 교체해요.

샌드박스 키트를 내장 에이전트 이름 대신 넘겨 실행하세요:

$ sbx run ./claude-safe

내부 CA 인증서 설치하기

각 PEM 인코딩 루트 인증서를 .crt 확장자로 files/home/ 아래에 두세요. files/home/internal-ca.crt의 경우:

schemaVersion: "2"
kind: mixin
name: internal-ca
setup:
  install:
    - command: "install -m 0644 /home/agent/internal-ca.crt /usr/local/share/ca-certificates/internal-ca.crt && update-ca-certificates"
      user: "0"

이렇게 하면 시스템 신뢰 저장소가 갱신돼요. 여러 CA는 update-ca-certificates를 실행하기 전에 모든 인증서를 설치하세요.

샌드박스 관리 에이전트 구성

내장 에이전트 키트는 샌드박스 설정을 위해 다음 경로를 예약해요. 이 경로를 특정 기능에만 파일이 필요하더라도 샌드박스 관리로 취급하세요. 정적 파일, setup.files, install 명령으로 이 경로를 대상으로 하지 마세요. 이후 설정이 내용을 교체하거나 파일이 제거하는 설정에 의존할 수 있어요. 이 표에서 ~는 /home/agent예요.

내장 에이전트 키트 관리 구성 경로
claude ~/.claude.json, ~/.claude/settings.json, ~/.claude/.config.json
codex ~/.codex/config.toml
copilot ~/.copilot/config.json
cursor ~/.cursor/cli-config.json
devin ~/.config/devin/config.json, ~/.config/devin/mcp_config.json
gemini ~/.gemini/settings.json
kiro ~/.kiro/settings/mcp.json
opencode ~/.config/opencode/opencode.json

지원되면 별도의 설정 파일을 쓰세요. Claude Code는 --settings를, OpenCode는 OPENCODE_CONFIG를 받아요. 에이전트가 초기화 중에 읽어야 하는 설정에 setup.startup을 쓰지 마세요. startup 명령은 entrypoint를 막지 않아요.

패키징과 배포

sbx kit 하위 명령들은 키트를 검증, 검사, 배포해요:

  • sbx kit validate <path> — 키트 디렉터리나 ZIP이 올바른 형태인지 확인.
  • sbx kit inspect <path> — 키트 세부사항 표시. 기계 판독 가능 출력에는 --json 추가.
  • sbx kit pack <path> -o <file.zip> — 디렉터리를 공유용 ZIP으로 패키징.
  • sbx kit push <path> <ref> — OCI 레지스트리(예: ghcr.io/myorg/my-kit:1.0)에 배포.
  • sbx kit pull <ref> — 레지스트리에서 키트를 ZIP으로 작업 디렉터리에 내려받기.

Docker Hub에서 sbx kit pull과 sbx kit push는 sbx login의 세션을 사용해요. 다른 레지스트리는 sbx secret set --registry로 저장한 자격 증명을 선호해요. 두 명령 모두 Docker 자격 증명 저장소로 폴백하므로 docker login의 자격 증명도 동작해요.

키트 서명 및 확인

cosign 호환 Sigstore 서명으로 누가 키트를 승인했는지, 서명된 내용이 바뀌지 않았는지 확인해요. 서명은 기본적으로 keyless예요. 키 없는 서명을 인증서 신원과 OpenID Connect(OIDC) 발급자로 확인하세요:

$ sbx kit sign ./my-kit/
$ sbx kit verify \
    --certificate-identity [email protected] \
    --certificate-oidc-issuer https://accounts.google.com \
    ./my-kit/

키 기반 서명에는 ECDSA P-256 키 쌍을 쓰세요:

$ sbx kit sign --key cosign.key ./my-kit/
$ sbx kit verify --key cosign.pub ./my-kit/

로컬 디렉터리에서 sbx kit sign은 spec.yaml 옆에 kit.sig.bundle 파일을 써요. Git 저장소에서 불러온 키트를 소비자가 확인할 수 있도록 이 파일을 커밋하세요. OCI 키트에서는 서명이 OCI referrer로 저장돼요. OCI 키트는 푸시 후 서명하거나 푸시와 서명을 한 번에 할 수 있어요:

$ sbx kit push ./my-kit/ ghcr.io/myorg/my-kit:1.0 --sign

ZIP 키트는 검증 가능한 서명을 담을 수 없어요.

서명된 키트 요구하기

서명을 요구하기 전에 kit.trustedSigners를 신뢰하는 신원이나 키로 설정하세요. 그렇지 않으면 sbx가 Google의 OpenID Connect 발급자가 증명한 Docker 직원 신원을 신뢰하는 기본 정책을 사용해요. Keyless 정책은 인증서 신원과 OpenID Connect 발급자 둘 다 지정해야 해요:

$ sbx settings set kit.trustedSigners \
  '[{"identity":"[email protected]","issuer":"https://accounts.google.com"}]'
$ sbx settings set kit.requireSignature true

키 기반 서명을 신뢰하려면 정책을 공개 키 경로로 설정하세요:

$ sbx settings set kit.trustedSigners '[{"key":"/path/to/cosign.pub"}]'
$ sbx settings set kit.requireSignature true

kit.requireSignature가 true면 sbx는 서명되지 않은 키트, kit.trustedSigners와 일치하지 않는 서명, ZIP 키트를 거절해요. 이 정책은 키트를 로컬 디렉터리, Git 저장소, 또는 OCI 레지스트리에서 불러올 때 적용돼요.

서명은 spec.yaml과 키트의 files/ 내용을 다루지만, 이미지 태그나 install·startup 명령이 내려받는 내용 같은 변경 가능한 의존성은 다루지 않아요. 그 의존성이 변경 불가여야 하면 digest나 체크섬으로 고정하세요.

스키마 버전

스키마 v2는 Docker Sandboxes 0.36 버전부터 지원돼요. 이 페이지의 문법에는 schemaVersion: "2"를 쓰세요. 버전 "1"도 계속 허용돼요. V3는 전부 v3 워크로드와 mixin으로 만든 환경을 위한 별도 형식이에요. V3 키트는 v1 또는 v2 키트와 구성할 수 없어요. 그 워크플로는 Kits v3을 보세요.

schemaVersion: "2"로 마이그레이션할 때 v1 필드를 v2 대응으로 바꾸세요:

v1 v2
credentials.sources.<id> service가 있는 credentials: 목록 항목
network.allowedDomains / deniedDomains permissions.network.allow / deny
network.serviceDomains / serviceAuth credentials[].apiKey.inject
network.publishedPorts / publishedPorts 최상위 ports
독립 oauth: 블록 credentials[].oauth
oauth.skipIfEnv 받아들이지만 무시됨
environment.proxyManaged credentials[].apiKey.proxyManaged
memory / agentContext agentInstructions.content
kind: agent / agent: 블록 kind: sandbox / sandbox: 블록
sandbox.aiFilename agentInstructions.filename
sandbox.entrypoint.run sandbox.entrypoint
sandbox.entrypoint.args sandbox.command.default
sandbox.entrypoint.ttyArgs sandbox.command.interactive
tmpfs: type: tmpfs가 있는 volumes: 항목
volumes: (매핑 형태) volumes: 시퀀스 (- path: <path>)
commands: / commands.initFiles setup: / setup.files
settings: / kitDir / persistence 제거됨

자격 증명 검색도 v2에서 키트 밖으로 옮겨졌어요. 키트는 어떤 자격 증명이 필요하고 어떻게 주입할지만 선언하고, 각 값이 어디서 오는지는 사용자가 credential bindings를 통해 통제해요.

참고 (Note): mixins와 sandbox.build는 파서가 받아들이지만 런타임 지원은 보류 중이에요. sandbox.build를 설정하는 키트는 sandbox.image도 설정해야 해요.

환경을 v3로 옮기기

v3 워크로드를 선택하고, mixin을 변환하거나 교체하고, 다른 --name으로 별도 샌드박스를 만드세요. 내장 단축어 대신 명시적 워크로드 참조를 쓰세요. 선택한 모든 키트가 v3를 써야 해요.

schemaVersion만 바꾼다고 키트가 변환되진 않아요. 재사용 가능한 이미지 내용을 샌드박스 초기화와 분리하고, 런타임 능력을 선언하세요:

V2 표면 V3 대응
kind: sandbox Dockerfile 레시피가 있는 kind: workload
sandbox.image Dockerfile FROM
sandbox.entrypoint, sandbox.command, environment.variables Dockerfile ENTRYPOINT, CMD, ENV
extends 구성용 mixin, 또는 자체 descriptor가 있는 파생 워크로드 이미지
setup.install 재사용 가능한 내용은 Dockerfile RUN; 샌드박스 초기화는 lifecycle install
setup.startup 및 setup.files Lifecycle capability startup과 files
setup.files[].onlyIfMissing: true Lifecycle files[].overwrite: false
자동 files/home/ 및 files/workspace/ 주입 Dockerfile COPY, 런타임 마운트가 제공하는 목적지는 lifecycle hooks로
permissions.network 및 credentials 네트워크 정책과 자격 증명 capability
agentInstructions Agent-context capability

런타임 설정과 capability 선언을 변환할 때 v3 authoring guidance를 따르세요. 배포된 v3 구성 요소를 설정과 결합하려면 키트 세트를 쓰세요. 기본 이미지에서 에이전트 환경을 다시 빌드하려면 에이전트 워크로드 빌드하기 문서를 따르세요. 기존 샌드박스를 실행하면 기록된 구성을 유지해요. 키트 구성을 마이그레이션하지 않아요.

더 알아보기 (Learn more)

  • v3 키트, Restrict kit sources, Base images, Registry credentials, Load a template, v2 사양, Kits v3, v3 authoring guidance, 키트 세트, 에이전트 워크로드 빌드하기, credential bindings 문서를 참고하세요.