프로비저닝(고급)
프로비저닝은 작업 트리 외부의 모든 항목, 즉 타입이 지정된 시크릿, 스킬 리포지토리, MCP 서버, 플러그인, 범용 지침 파일을 샌드박스 내부 에이전트에 전달하는 방법입니다. defineWorkspace()에 모두 선언하면 각 하네스 어댑터가 부트스트랩 시 자체 네이티브 형식으로 프로젝션하므로 에이전트가 Grok Build, Claude Code, Codex, OpenCode 중 무엇이든 동일한 정의가 작동합니다.
import {
bearer,
createSecrets,
defineWorkspace,
fileSkill,
gitSkill,
githubRepo,
mcpSkill,
} from '@tanstack/ai-sandbox'
const secrets = createSecrets({
GH: process.env.GH_TOKEN ?? '',
SENTRY: process.env.SENTRY_TOKEN ?? '',
})
defineWorkspace({
source: githubRepo({ repo: 'owner/repo', ref: 'main' }),
secrets,
skills: [
gitSkill({ repo: 'owner/tanstack-skills' }),
gitSkill({ repo: 'owner/private-skills', secret: secrets.GH }),
mcpSkill('my-mcp', {
url: 'https://mcp.example.com',
headers: { Authorization: bearer(secrets.SENTRY) },
}),
fileSkill({ path: '.agent-hints.md', content: '# Hints\nPrefer pnpm.' }),
],
plugins: ['@anthropic/plugin-foo'],
instructions: 'Always run `pnpm test` before proposing a change.',
})
타입 안전 시크릿
createSecrets는 일반 환경 값을 불투명한 SecretRef 토큰으로 변환합니다.
구성 전체에서 ref를 전달하며, 기반 문자열은 직렬화 가능한 모든 영역에 포함되지 않습니다.
import { createSecrets, defineWorkspace, githubRepo } from '@tanstack/ai-sandbox'
const secrets = createSecrets({
GH: process.env.GH_TOKEN ?? '',
SENTRY: process.env.SENTRY_TOKEN ?? '',
})
defineWorkspace({
source: githubRepo({ repo: 'owner/repo', ref: 'main' }),
secrets,
})
secrets는 워크스페이스에 선언됩니다. 생성, 재개 및
스냅샷 복원 시 샌드박스 계층이 이를 활성 핸들 환경으로 확인합니다.
프로바이더는 해당 값을 스냅샷, 샌드박스 저장소 또는 이벤트 로그에 기록하지 않습니다.
값이 유출되지 않는 이유
실제 문자열은 createSecrets가 반환하는 객체의 열거 불가능한 심볼 키 레지스트리에 보관됩니다. 접근하는 각 속성(secrets.GH)은 문자열이 아니라 SecretRef 토큰입니다. 레지스트리가 심볼 키이고 열거 불가능하므로 다음과 같습니다.
Object.keys(secrets), 스프레드 및JSON.stringify(secrets)는 값을 노출하지 않습니다.- 값은 스냅샷, 샌드박스 저장소 또는 이벤트 로그에 절대 기록되지 않습니다. 활성 샌드박스 환경을 구성할 때만 확인됩니다.
따라서 자격 증명을 영속화하지 않고도 재개 기록을 위해 워크스페이스 정의를 안전하게 해시하고, 영속화하고, 재생할 수 있습니다.
SecretRef가 허용되는 곳에 시크릿 전달
ref를 받는 모든 필드에 ref를 직접 전달합니다. 가장 명확한 예는
gitSkill 인증입니다. secret: secrets.GH를 전달하면 리포지토리를 복제할 때만 토큰이 확인됩니다.
import { createSecrets, defineWorkspace, gitSkill, githubRepo } from '@tanstack/ai-sandbox'
const secrets = createSecrets({ GH: process.env.GH_TOKEN ?? '' })
defineWorkspace({
source: githubRepo({ repo: 'owner/repo' }),
secrets,
skills: [gitSkill({ repo: 'owner/private-skills', secret: secrets.GH })],
})
헤더 값의 bearer(ref)
MCP 헤더 값에서는 ref를 직접 사용하거나 bearer(ref)로 감싸 확인 시점에
Bearer <value> 문자열을 만들 수 있습니다.
import { bearer, createSecrets, mcpSkill } from '@tanstack/ai-sandbox'
const secrets = createSecrets({
GH: process.env.GH_TOKEN ?? '',
SENTRY: process.env.SENTRY_TOKEN ?? '',
})
mcpSkill('my-mcp', {
url: 'https://mcp.example.com',
headers: {
Authorization: bearer(secrets.SENTRY), // resolves to "Bearer <value>"
'X-Token': secrets.GH, // resolves to the raw token value
},
})
스킬, 플러그인, MCP 서버
skills는 에이전트 환경에 기능을 프로비저닝하는 스킬 값 배열입니다. 서로 다른
종류의 기능을 나타내는 네 가지 빌더가 있습니다.
| 빌더 | 프로비저닝하는 항목 |
|---|---|
agentSkill | 이름이 지정된 공개 스킬입니다(이식 가능한 자리 표시자이며 Claude Code는 경고 후 건너뛰므로 대신 gitSkill을 사용합니다). |
gitSkill | 선택적 인증 및 복제 경로를 사용해 워크스페이스에 복제되는 스킬 리포지토리입니다. |
mcpSkill | URL 및 헤더가 있는 서드파티 MCP 서버입니다. |
fileSkill | 워크스페이스에 기록되는 임의의 파일입니다. |
import {
bearer,
createSecrets,
defineWorkspace,
fileSkill,
gitSkill,
githubRepo,
mcpSkill,
} from '@tanstack/ai-sandbox'
const secrets = createSecrets({
GH: process.env.GH_TOKEN ?? '',
SENTRY: process.env.SENTRY_TOKEN ?? '',
})
defineWorkspace({
source: githubRepo({ repo: 'owner/repo' }),
secrets,
skills: [
// Clone a public skill repo (preferred over agentSkill on Claude Code).
gitSkill({ repo: 'owner/tanstack-skills' }),
// Clone a private skill repo; `secret` is resolved from the secrets registry.
gitSkill({ repo: 'owner/private-skills', secret: secrets.GH }),
// Wire an MCP server with a resolved bearer token in the Authorization header.
mcpSkill('my-mcp', {
url: 'https://mcp.example.com',
headers: { Authorization: bearer(secrets.SENTRY) },
}),
// Write an arbitrary file into the workspace.
fileSkill({ path: '.agent-hints.md', content: '# Hints\nPrefer pnpm.' }),
],
plugins: ['@anthropic/plugin-foo'],
})
gitSkill 복제 경로
gitSkill은 리포지토리를 복제할 위치를 지정하는 선택적 into 필드를 받습니다. 이 필드는 샌드박스 내부의 절대 경로입니다. 기본값은
.tanstack-skills/<repo-basename>입니다. 부트스트랩은 복제 전에 부모 디렉터리를 생성합니다.
/workspace로 시작하는 경로는 이식 가능한 워크스페이스 루트를 사용합니다. 프로바이더는 해당 루트를 실제 작업 디렉터리에 매핑합니다. 프로바이더별 경로를 고정해야 할 이유가 없다면 into에 /workspace/...를 유지합니다.
import { createSecrets, defineWorkspace, gitSkill, githubRepo } from '@tanstack/ai-sandbox'
const secrets = createSecrets({ GH: process.env.GH_TOKEN ?? '' })
defineWorkspace({
source: githubRepo({ repo: 'owner/repo' }),
secrets,
skills: [
gitSkill({
repo: 'owner/private-skills',
secret: secrets.GH,
into: '/workspace/.skills/private',
}),
],
})
하네스별 프로젝션
부트스트랩 시 각 하네스 프로젝터는 이 값을 CLI의 네이티브 형식으로 매핑합니다.
| 하네스 | MCP 서버가 프로젝션되는 위치 |
|---|---|
| Claude Code | .mcp.json |
| Codex | .codex/config.toml |
| OpenCode | opencode.json |
각 프로젝터는 복제된 리포지토리에서 SKILL.md를 포함하는 폴더를 검색합니다. 중첩된 팩(skills/foo/SKILL.md)은 스킬 이름 foo 아래에 연결됩니다. 루트에 SKILL.md가 있는 평면 복제본은 복제본 이름을 사용합니다. ln -s를 직접 작성할 필요는 없습니다.
특정 CLI에 없는 개념(예: Codex의 plugins)은 예외를 발생시키는 대신 경고를 내보내고 조용히 건너뜁니다. Claude Code의 agentSkill도 마찬가지입니다. 이름만으로 공개 스킬을 설치할 신뢰할 수 있는 기본 기능이 없으므로 프로젝터가 경고하고 건너뜁니다. Claude Code에서 해당 스킬이 필요하면 gitSkill(또는 plugins 항목)을 우선 사용합니다. 이를 통해 하나의 이식 가능한 정의를 여러 하네스에서 사용할 수 있습니다. 모든 항목을 한 번 선언하면 각 에이전트가 이해하는 부분을 사용합니다.
이 MCP 서버는 에이전트가 연결할 서드파티 서비스입니다. 자체 앱의 호스트 도구를 에이전트에 연결하는 것은(호스트에서 다시 실행되는
execute()를 가진chat()서버 도구) 다른 메커니즘이며, 도구를 참조합니다.
AGENTS.md 및 하네스별 심볼릭 링크
instructions는 부트스트랩 중 워크스페이스 루트의 AGENTS.md에 기록되는 문자열입니다. 하네스별 대응 파일(CLAUDE.md, GEMINI.md)은 해당 파일을 가리키는 심볼릭 링크로 생성되며, 샌드박스 프로세스 계층에서 심볼릭 링크를 생성할 수 없으면 대신 복사본으로 기록됩니다. 어느 경우든 추가 구성 없이 지원되는 모든 CLI가 지침 내용을 네이티브하게 읽습니다.
import { defineWorkspace, githubRepo } from '@tanstack/ai-sandbox'
defineWorkspace({
source: githubRepo({ repo: 'owner/repo' }),
instructions: 'Always run `pnpm test` before proposing a change.',
})
에이전트가 항상 따르기를 원하는 지침에는
instructions를 사용합니다. 에이전트가 수행할 수 있는 작업과 허용, 확인 요청 또는 거부할 명령 및 기능을 제한하려면 대신 정책을 사용합니다.