{"meta":{"title":"사용자 지정 기술","intro":"스킬은 Copilot의 기능을 확장하는 재사용 가능한 프롬프트 모듈입니다. 디렉터리에서 기술을 로드하여 특정 도메인 또는 워크플로에 대해 Copilot 특수한 기능을 제공합니다.","product":"GitHub Copilot","breadcrumbs":[{"href":"/ko/copilot","title":"GitHub Copilot"},{"href":"/ko/copilot/how-tos","title":"방법"},{"href":"/ko/copilot/how-tos/copilot-sdk","title":"코필로트 SDK"},{"href":"/ko/copilot/how-tos/copilot-sdk/features","title":"기능"},{"href":"/ko/copilot/how-tos/copilot-sdk/features/skills","title":"기술"}],"documentType":"article"},"body":"# 사용자 지정 기술\n\n스킬은 Copilot의 기능을 확장하는 재사용 가능한 프롬프트 모듈입니다. 디렉터리에서 기술을 로드하여 특정 도메인 또는 워크플로에 대해 Copilot 특수한 기능을 제공합니다.\n\n<!-- markdownlint-disable GHD046 GHD005 -->\n\n<!-- Suppressed: GHD046 (outdated release terminology), GHD005 (hardcoded data variable) -->\n\n## Overview\n\n스킬은 Copilot에 지침을 제공하는 Markdown 문서인 `SKILL.md` 파일을 포함하는 이름이 지정된 디렉터리입니다. 로드되면 기술의 콘텐츠가 세션 컨텍스트에 삽입됩니다.\n\n기술을 통해 다음을 수행할 수 있습니다.\n\n* 재사용 가능한 모듈로 도메인 전문 지식 패키지\n* 프로젝트 간에 특수한 동작 공유\n* 복잡한 에이전트 구성 정리\n* 세션당 기능 사용/사용 안 함\n\n## 기술 불러오기\n\n세션을 만들 때 기술을 포함하는 디렉터리를 지정합니다.\n\n<div class=\"ghd-codetabs\">\n<div class=\"ghd-codetab\" data-lang=\"typescript\" data-label=\"TypeScript\"><div class=\"ghd-codetab-fallback-label\" role=\"heading\" aria-level=\"3\">TypeScript</div>\n\n```typescript\nimport { CopilotClient } from \"@github/copilot-sdk\";\n\nconst client = new CopilotClient();\nconst session = await client.createSession({\n    model: \"gpt-5.4\",\n    skillDirectories: [\n        \"./skills/code-review\",\n        \"./skills/documentation\",\n    ],\n    onPermissionRequest: async () => ({ kind: \"approve-once\" }),\n});\n\n// Copilot now has access to skills in those directories\nawait session.sendAndWait({ prompt: \"Review this code for security issues\" });\n```\n\n</div>\n\n<div class=\"ghd-codetab\" data-lang=\"python\" data-label=\"Python\"><div class=\"ghd-codetab-fallback-label\" role=\"heading\" aria-level=\"3\">Python</div>\n\n```python\nfrom copilot import CopilotClient, PermissionDecisionApproveOnce\n\nasync def main():\n    client = CopilotClient()\n    await client.start()\n\n    session = await client.create_session(\n        on_permission_request=lambda req, inv: PermissionDecisionApproveOnce(),\n        model=\"gpt-5.4\",\n        skill_directories=[\n            \"./skills/code-review\",\n            \"./skills/documentation\",\n        ],\n    )\n\n    # Copilot now has access to skills in those directories\n    await session.send_and_wait(\"Review this code for security issues\")\n\n    await client.stop()\n```\n\n</div>\n\n<div class=\"ghd-codetab\" data-lang=\"go\" data-label=\"Go\"><div class=\"ghd-codetab-fallback-label\" role=\"heading\" aria-level=\"3\">Go</div>\n\n```golang\npackage main\n\nimport (\n    \"context\"\n    \"log\"\n    copilot \"github.com/github/copilot-sdk/go\"\n    \"github.com/github/copilot-sdk/go/rpc\"\n)\n\nfunc main() {\n    ctx := context.Background()\n    client := copilot.NewClient(nil)\n    if err := client.Start(ctx); err != nil {\n        log.Fatal(err)\n    }\n    defer client.Stop()\n\n    session, err := client.CreateSession(ctx, &copilot.SessionConfig{\n        Model: \"gpt-5.4\",\n        SkillDirectories: []string{\n            \"./skills/code-review\",\n            \"./skills/documentation\",\n        },\n        OnPermissionRequest: func(req copilot.PermissionRequest, inv copilot.PermissionInvocation) (rpc.PermissionDecision, error) {\n            return &rpc.PermissionDecisionApproveOnce{}, nil\n        },\n    })\n    if err != nil {\n        log.Fatal(err)\n    }\n\n    // Copilot now has access to skills in those directories\n    _, err = session.SendAndWait(ctx, copilot.MessageOptions{\n        Prompt: \"Review this code for security issues\",\n    })\n    if err != nil {\n        log.Fatal(err)\n    }\n}\n```\n\n</div>\n\n<div class=\"ghd-codetab\" data-lang=\"dotnet\" data-label=\".NET\"><div class=\"ghd-codetab-fallback-label\" role=\"heading\" aria-level=\"3\">.NET</div>\n\n```csharp\nusing GitHub.Copilot;\nusing GitHub.Copilot.Rpc;\n\nawait using var client = new CopilotClient();\nawait using var session = await client.CreateSessionAsync(new SessionConfig\n{\n    Model = \"gpt-5.4\",\n    SkillDirectories = new List<string>\n    {\n        \"./skills/code-review\",\n        \"./skills/documentation\",\n    },\n    OnPermissionRequest = (req, inv) =>\n        Task.FromResult(PermissionDecision.ApproveOnce()),\n});\n\n// Copilot now has access to skills in those directories\nawait session.SendAndWaitAsync(new MessageOptions\n{\n    Prompt = \"Review this code for security issues\"\n});\n```\n\n</div>\n\n<div class=\"ghd-codetab\" data-lang=\"java\" data-label=\"Java\"><div class=\"ghd-codetab-fallback-label\" role=\"heading\" aria-level=\"3\">Java</div>\n\n```java\nimport com.github.copilot.CopilotClient;\nimport com.github.copilot.rpc.*;\nimport java.util.List;\n\ntry (var client = new CopilotClient()) {\n    client.start().get();\n\n    var session = client.createSession(\n        new SessionConfig()\n            .setModel(\"gpt-5.4\")\n            .setSkillDirectories(List.of(\n                \"./skills/code-review\",\n                \"./skills/documentation\"\n            ))\n            .setOnPermissionRequest(PermissionHandler.APPROVE_ALL)\n    ).get();\n\n    // Copilot now has access to skills in those directories\n    session.sendAndWait(new MessageOptions()\n        .setPrompt(\"Review this code for security issues\")\n    ).get();\n}\n```\n\n</div>\n\n</div>\n\n## 기능 비활성화\n\n다른 사람을 활성 상태로 유지하면서 특정 기술을 사용하지 않도록 설정합니다.\n\n<div class=\"ghd-codetabs\">\n<div class=\"ghd-codetab\" data-lang=\"typescript\" data-label=\"TypeScript\"><div class=\"ghd-codetab-fallback-label\" role=\"heading\" aria-level=\"3\">TypeScript</div>\n\n```typescript\nconst session = await client.createSession({\n    skillDirectories: [\"./skills\"],\n    disabledSkills: [\"experimental-feature\", \"deprecated-tool\"],\n});\n```\n\n</div>\n\n<div class=\"ghd-codetab\" data-lang=\"python\" data-label=\"Python\"><div class=\"ghd-codetab-fallback-label\" role=\"heading\" aria-level=\"3\">Python</div>\n\n```python\nfrom copilot.session import PermissionHandler\n\nsession = await client.create_session(\n    on_permission_request=PermissionHandler.approve_all,\n    skill_directories=[\"./skills\"],\n    disabled_skills=[\"experimental-feature\", \"deprecated-tool\"],\n)\n```\n\n</div>\n\n<div class=\"ghd-codetab\" data-lang=\"go\" data-label=\"Go\"><div class=\"ghd-codetab-fallback-label\" role=\"heading\" aria-level=\"3\">Go</div>\n\n```golang\nsession, _ := client.CreateSession(context.Background(), &copilot.SessionConfig{\n    SkillDirectories: []string{\"./skills\"},\n    DisabledSkills:   []string{\"experimental-feature\", \"deprecated-tool\"},\n})\n```\n\n</div>\n\n<div class=\"ghd-codetab\" data-lang=\"dotnet\" data-label=\".NET\"><div class=\"ghd-codetab-fallback-label\" role=\"heading\" aria-level=\"3\">.NET</div>\n\n```csharp\nvar session = await client.CreateSessionAsync(new SessionConfig\n{\n    SkillDirectories = new List<string> { \"./skills\" },\n    DisabledSkills = new List<string> { \"experimental-feature\", \"deprecated-tool\" },\n});\n```\n\n</div>\n\n<div class=\"ghd-codetab\" data-lang=\"java\" data-label=\"Java\"><div class=\"ghd-codetab-fallback-label\" role=\"heading\" aria-level=\"3\">Java</div>\n\n<!-- docs-validate: skip -->\n\n```java\nimport com.github.copilot.rpc.*;\nimport java.util.List;\n\nvar session = client.createSession(\n    new SessionConfig()\n        .setSkillDirectories(List.of(\"./skills\"))\n        .setDisabledSkills(List.of(\"experimental-feature\", \"deprecated-tool\"))\n        .setOnPermissionRequest(PermissionHandler.APPROVE_ALL)\n).get();\n```\n\n</div>\n\n</div>\n\n## 기술 디렉터리 구조\n\n각 기술은 파일을 포함하는 명명된 하위 디렉터리입니다.`SKILL.md`\n\n```text\nskills/\n├── code-review/\n│   └── SKILL.md\n└── documentation/\n    └── SKILL.md\n```\n\n이 `skillDirectories` 옵션은 부모 디렉터리(예: `./skills`)를 가리킵니다. CLI는 즉시 하위 디렉터리의 모든 `SKILL.md` 파일을 검색합니다.\n\n### SKILL.md 형식\n\n`SKILL.md` 파일은 선택적 YAML 프런트매터가 있는 markdown 문서입니다.\n\n```markdown\n---\nname: code-review\ndescription: Specialized code review capabilities\n---\n\n# Code Review Guidelines\n\nWhen reviewing code, always check for:\n\n1. **Security vulnerabilities** - SQL injection, XSS, etc.\n2. **Performance issues** - N+1 queries, memory leaks\n3. **Code style** - Consistent formatting, naming conventions\n4. **Test coverage** - Are critical paths tested?\n\nProvide specific line-number references and suggested fixes.\n```\n\n프런트매터 필드:\n\n* **`name`**: 기술의 식별자입니다(`disabledSkills`와 함께 사용하여 이를 선택적으로 비활성화하는 데 사용됨). 생략하면 디렉터리 이름이 사용됩니다.\n* **`description`**: 기술이 수행하는 일에 대한 간단한 설명입니다.\n\nmarkdown 본문에는 기술이 로드될 때 세션 컨텍스트에 삽입되는 지침이 포함되어 있습니다.\n\n## 구성 옵션\n\n### SessionConfig 기술 필드\n\n| 언어      | Field               | Type           | Description      |\n| ------- | ------------------- | -------------- | ---------------- |\n| Node.js | `skillDirectories`  | `string[]`     | 기술을 로드하기 위한 디렉터리 |\n| Node.js | `disabledSkills`    | `string[]`     | 사용하지 않도록 설정하는 기술 |\n| Python  | `skill_directories` | `list[str]`    | 기술을 로드하기 위한 디렉터리 |\n| Python  | `disabled_skills`   | `list[str]`    | 사용하지 않도록 설정하는 기술 |\n| Go      | `SkillDirectories`  | `[]string`     | 기술을 로드하기 위한 디렉터리 |\n| Go      | `DisabledSkills`    | `[]string`     | 사용하지 않도록 설정하는 기술 |\n| .NET    | `SkillDirectories`  | `List<string>` | 기술을 로드하기 위한 디렉터리 |\n| .NET    | `DisabledSkills`    | `List<string>` | 사용하지 않도록 설정하는 기술 |\n\n## 모범 사례\n\n1. **도메인별로 구성** - 관련 기술 그룹화(예: `skills/security/`, `skills/testing/`)\n\n2. **프런트매터 사용** - 명확성을 위해 YAML 프런트매터 포함 `name` 및 `description` 포함\n\n3. **문서 종속성** - 기술에 필요한 도구 또는 MCP 서버에 유의하세요.\n\n4. **격리된 기술 테스트** - 기술을 결합하기 전에 기술 작동 확인\n\n5. **상대 경로 사용** - 환경에서 기술을 이식 가능한 상태로 유지\n\n## 다른 기능과 결합\n\n### 기술 + 사용자 지정 에이전트\n\n에이전트 `skills` 필드에 나열된 기술은 **즉시 미리 로드됩니다**. 시작 시 에이전트의 컨텍스트에 전체 콘텐츠가 삽입되므로 에이전트는 기술 도구를 호출할 필요 없이 즉시 기술 지침에 액세스할 수 있습니다. 스킬 이름은 세션 수준의 `skillDirectories`에서 조회됩니다.\n\n```typescript\nconst session = await client.createSession({\n    skillDirectories: [\"./skills/security\"],\n    customAgents: [{\n        name: \"security-auditor\",\n        description: \"Security-focused code reviewer\",\n        prompt: \"Focus on OWASP Top 10 vulnerabilities\",\n        skills: [\"security-scan\", \"dependency-check\"],\n    }],\n    onPermissionRequest: async () => ({ kind: \"approve-once\" }),\n});\n```\n\n> \\[!NOTE]\n> 스킬은 옵트인 방식이므로 `skills`가 생략되면 스킬 콘텐츠가 주입되지 않습니다. 하위 에이전트는 부모로부터 기술을 상속하지 않습니다. 에이전트별로 명시적으로 나열해야 합니다.\n\n### 기술 + MCP 서버\n\n기술은 MCP 서버 기능을 보완할 수 있습니다.\n\n```typescript\nconst session = await client.createSession({\n    skillDirectories: [\"./skills/database\"],\n    mcpServers: {\n        postgres: {\n            type: \"local\",\n            command: \"npx\",\n            args: [\"-y\", \"@modelcontextprotocol/server-postgres\"],\n            tools: [\"*\"],\n        },\n    },\n    onPermissionRequest: async () => ({ kind: \"approve-once\" }),\n});\n```\n\n## Troubleshooting\n\n### 기술이 로드되지 않음\n\n1. **경로 확인** - 기술 디렉터리 경로가 올바르고 파일이 있는 하위 디렉터리가 `SKILL.md` 포함되어 있는지 확인합니다.\n2. **권한 확인** - SDK가 디렉터리를 읽을 수 있는지 확인\n3. **SKILL.md 형식 확인** - markdown이 올바른 형식이고 YAML 프런트매터가 유효한 구문을 사용하는지 확인합니다.\n4. **디버그 로깅 활성화** - 스킬 로딩 로그를 보려면 `logLevel: \"debug\"`으로 설정\n\n### 기술 충돌\n\n여러 기술이 충돌하는 지침을 제공하는 경우:\n\n* `disabledSkills`를 사용하여 충돌하는 기술을 제외하십시오.\n* 겹치지 않도록 기술 디렉터리 다시 구성\n\n## 참고하십시오\n\n* [첫 번째 Copilot 기반 앱 빌드](/ko/copilot/how-tos/copilot-sdk/getting-started#create-custom-agents) - 전문 AI 페르소나 정의\n* [첫 번째 Copilot 기반 앱 빌드](/ko/copilot/how-tos/copilot-sdk/getting-started#step-4-add-a-custom-tool) - 사용자 고유의 도구 빌드\n* [GitHub Copilot SDK에서 MCP 서버 사용](/ko/copilot/how-tos/copilot-sdk/features/mcp) - 외부 도구 공급자 연결"}