HVE Core 에이전트 라이브러리를 VS Code Local harness에서 Copilot 에이전트 harness로 마이그레이션
README 링크에서 발견 · today
31개 에이전트와 37개 지침을 스킬, 도구 별칭으로 이동
What they did
저자는 HVE Core 에이전트 라이브러리를 VS Code의 Local chat harness에서 Copilot agent harness로 마이그레이션했다. 여기서는 `#file:` import가 전혀 로드되지 않고, `applyTo` 지침이 실행 중인 에이전트에 연결되지 않으며, subagent는 커스텀 지침을 받지 못하고, Copilot은 `handoffs`, `agents`, prompt 파일을 무시한다. 저자는 에이전트에 공급하기 위한 목적으로만 존재하던 지침을 대체하기 위해 네 개의 공유 skill(`disclaimer-language`, `untrusted-content-boundary`, `planner-identity`, `engagement-report-conventions`)을 만들고, 다른 에이전트 전용 프로토콜(RAI, privacy, ADR identity, TM7/VEX 생성, 코드 리뷰 diff 계산, 커뮤니티 상호작용, commit/merge 규칙)을 에이전트가 이미 참조로 사용하던 skill로 옮겼다. 이제 31개 에이전트가 `skills:` 목록을 통해 skill을 미리 로드하며, 다섯 개의 단계 기반 planner는 세션 시작 시 `planner-identity`를 이름으로 활성화한다. 더 이상 `#file:`을 사용하는 에이전트는 없다. Subagent는 미리 로드된 skill 또는 부모의 dispatch prompt에서 규칙을 받는다. 플러그인은 항상 켜져 있는 규칙 제공을 중단했으며, 남은 37개 지침 모두 `applyTo`를 갖는다. 에이전트는 `handoffs`, `agents`, `argument-hint`를 제거했고, frontmatter 스키마는 이제 이를 거부한다. 도구 목록은 Copilot 별칭(`read`, `edit`, `search`, `execute`, `web`, `agent`, 그리고 `skill`과 `ask_user`)을 사용한다. 본문은 Local 도구를 이름으로 언급하는 대신 평이한 표현으로 다시 작성되었다. 도구 쪽도 뒤따랐다. `lint:frontmatter`는 폐기된 필드를 거부하고(JSON Schema `not` 학습), cold-start 예산은 미리 로드된 skill을 계산에 포함하며, `lint:artifact-portability`는 `#file:`을 표시하고, eval 의존성 매핑은 `skills:` 목록을 따른다. 설정에서 `chat.*Locations`가 제거되었고, `.vscode/mcp.json.sample`은 이식 가능한 `.mcp.json.sample`이 되었으며, 문서와 설치 프로그램은 이제 다섯 가지 설치 경로 전반에서 플러그인을 앞세운다.
How it went
마이그레이션은 `origin/main`에 대한 타깃형 preflight와 함께 breaking change로 반영되었습니다. 네 개의 후속 커밋으로 CI 발견 사항을 수정했습니다: `lint:asset-docs`가 플래그한 스텁 Example usage 섹션 채우기, 슬라이드 번들 소스 제목 수정(22/22 deck 테스트 통과), 접근성 크롤이 4.32:1에서 실패한 후 WCAG AA(5.3:1)를 위해 라이트 Prism 문자열 토큰을 `#c9105f`로 상향, 그리고 Agent Eval Plan이 중단된 후 세 개의 공유 스킬에 대한 eval stimuli 추가. 스위트 총계는 87개 스킬에 걸쳐 338개 stimuli입니다. Docs 빌드, 맞춤법 검사, markdown/table lint, validate:docs 모두 통과합니다.
Worth knowing
이는 명시적인 breaking change입니다. 16개의 instruction 파일이 `.github/instructions/`와 플러그인에서 빠지고, 에이전트는 `handoffs`, `agents`, `argument-hint`를 잃게 되므로 다운스트림 사용자는 자신의 설정을 업데이트해야 합니다. PR 본문이 testing 섹션에서 문장 중간에 잘려 있어, 마지막 커밋의 최종 검증 상태가 완전히 설명되지 않습니다. 마이그레이션은 다시 바뀔 수 있는 Copilot harness 동작(skill 사전 로딩, tool alias)에 의존합니다. Eval 커버리지를 위해 13개의 stimulus를 수동으로 재태깅하고 7개를 제거해야 했으므로, behavior-conformance 커버리지의 형태가 달라졌습니다.
Wiring
(1) `#file:` 사용 현황과 에이전트 전용 지침 목록화; (2) 공유 스킬을 만들고 프로토콜을 기존 스킬 내 참조로 이동; (3) 31개 에이전트 전부에 `skills:` 사전 로드 목록을 추가하고 단계별 플래너를 이름 기반 활성화로 전환; (4) 에이전트 frontmatter에서 `handoffs`/`agents`/`argument-hint`를 제거하고 JSON Schema가 `not`을 사용해 이를 거부하도록 업데이트; (5) 도구 목록을 Copilot 별칭으로 변환하고, 이름 로딩 에이전트에는 `skill`을, 대화형 에이전트에는 `ask_user`를 추가; (6) 본문을 평이한 언어로 재작성; (7) 린트 스크립트(`lint:frontmatter`, 콜드 스타트 예산, `lint:artifact-portability`)와 eval 의존성 매핑을 `skills:`를 따르도록 업데이트; (8) `.vscode/settings.json`에서 `chat.*Locations` 제거, `mcp.json.sample`을 이식 가능한 `mcpServers` 형태로 이름 변경, 개인용 `.mcp.json`을 gitignore에 추가; (9) 문서, 설치 프로그램 스킬, 참조 카탈로그 업데이트. 설정은 `.github/agents/`, `.github/skills/`, `.github/instructions/`, `evals/`, `scripts/linting/`, `.vscode/`, `docs/`에 걸쳐 변경됩니다.
Try it yourself
# Copilot Agent Harness Audit
## 1. `#file:` imports in `.github/agents/` and `.github/skills/`
Every `#file:` reference found in agent and skill markdown:
| File | Import | Target exists? | Notes |
|---|---|---|---|
| `.github/agents/planner.agent.md` | `#file:../instructions/typescript.instructions.md` | yes | Duplicates a repo-wide instruction |
| `.github/agents/planner.agent.md` | `#file:../skills/planning/SKILL.md` | yes | Should be a `skills:` preload, not an inline import |
| `.github/agents/reviewer.agent.md` | `#file:../instructions/review-checklist.instructions.md` | yes | Agent-only checklist |
| `.github/agents/reviewer.agent.md` | `#file:../skills/diff-review/SKILL.md` | yes | Should be a `skills:` preload |
| `.github/agents/implementer.agent.md` | `#file:../instructions/testing.instructions.md` | yes | Overlaps with shared testing instruction |
| `.github/agents/implementer.agent.md` | `#file:../skills/tdd/SKILL.md` | yes | Should be a `skills:` preload |
| `.github/agents/triager.agent.md` | `#file:../instructions/triage-labels.instructions.md` | yes | Agent-only |
| `.github/agents/triager.agent.md` | `#file:../skills/issue-triage/SKILL.md` | yes | Should be a `skills:` preload |
| `.github/skills/planning/SKILL.md` | `#file:../../instructions/typescript.instructions.md` | yes | Skill pulling a global instruction — redundant |
| `.github/skills/diff-review/SKILL.md` | `#file:../../instructions/review-checklist.instructions.md` | yes | Skill pulling an agent-only instruction — inverted dependency |
| `.github/skills/tdd/SKILL.md` | `#file:../../instructions/testing.instructions.md` | yes | Same inversion |
| `.github/skills/issue-triage/SKILL.md` | `#file:../../instructions/triage-labels.instructions.md` | yes | Same inversion |
**Pattern:** every agent imports its own skill via `#file:` instead of declaring it in `skills:`, and every skill imports an instruction file that is really agent-scoped. The dependency graph is inverted in both directions.
## 2. Instruction files without `applyTo`
| File | Scope today | Recommendation |
|---|---|---|
| `.github/instructions/review-checklist.instructions.md` | none | Add `applyTo: "**/*.{ts,tsx,py}"` — it's a code-review checklist, not agent-only |
| `.github/instructions/triage-labels.instructions.md` | none | Add `applyTo: ".github/ISSUE_TEMPLATE/**"` — only relevant to issue templates |
| `.github/instructions/testing.instructions.md` | none | Add `applyTo: "**/*.{test,spec}.{ts,tsx,py}"` |
| `.github/instructions/typescript.instructions.md` | none | Add `applyTo: "**/*.{ts,tsx}"` |
| `.github/instructions/python.instructions.md` | none | Add `applyTo: "**/*.py"` |
Without `applyTo`, Copilot loads these into every chat turn — the main source of context bloat in this repo.
## 3. Agent frontmatter fields Copilot ignores
| Field | Where used | Status |
|---|---|---|
| `handoffs` | `planner.agent.md`, `triager.agent.md` | Ignored — Copilot has no handoff primitive |
| `agents` | `planner.agent.md` | Ignored — sub-agent lists aren't read |
| `argument-hint` | `implementer.agent.md`, `reviewer.agent.md` | Ignored — no argument-hint support |
These are Claude/Cursor-style fields that leaked into the Copilot harness. They should be removed and linted against.
## 4. Agent-only instructions — disposition
| Instruction | Currently used by | Proposal | Rationale |
|---|---|---|---|
| `review-checklist.instructions.md` | reviewer agent + diff-review skill | **Promote to shared instruction** with `applyTo` | It's a general code-review checklist; the skill should reference it, not own it |
| `triage-labels.instructions.md` | triager agent + issue-triage skill | **Reference inside `issue-triage` skill** | Only meaningful during triage; keep it out of the global instruction set |
| `testing.instructions.md` | implementer agent + tdd skill | **Promote to shared instruction** with `applyTo` on test files | Applies to any test authoring, not just the implementer |
| `typescript.instructions.md` | planner agent + planning skill | **Promote to shared instruction** with `applyTo` on TS files | Already global in spirit; the `#file:` import is redundant |
| `python.instructions.md` | (unused by agents) | **Keep as shared instruction** | Already correctly scoped once `applyTo` is added |
| Inline "planning heuristics" block in `planner.agent.md` | planner only | **Move into `planning` skill** | It's reusable planning guidance, not agent identity |
| Inline "diff summary format" block in `reviewer.agent.md` | reviewer only | **Move into `diff-review` skill** | Output format belongs with the skill that produces it |
| Inline "commit message style" block in `implementer.agent.md` | implementer only | **Delete** | Duplicates `CONTRIBUTING.md`; drift risk |
## 5. Rewritten tool lists (Copilot aliases)
Replace Claude-style tool names (`Read`, `Edit`, `Bash`, `Grep`, `Glob`, `WebFetch`, `Task`, `Skill`, `AskUserQuestion`) with Copilot aliases.
**`planner.agent.md`**
```yaml
tools: [read, search, web, ask_user]
skills: [planning]
```
**`reviewer.agent.md`**
```yaml
tools: [read, search, execute, ask_user]
skills: [diff-review]
```
**`implementer.agent.md`**
```yaml
tools: [read, edit, search, execute, ask_user]
skills: [tdd]
```
**`triager.agent.md`**
```yaml
tools: [read, search, web, agent, ask_user]
skills: [issue-triage]
```
Notes:
- `agent` is only granted to `triager` because it delegates to sub-agents for issue classification.
- `skill` is not listed per-agent — it's implied by the `skills:` preload list.
- `web` is dropped from `implementer` and `reviewer`; neither needs live fetch.
## 6. `skills:` preload lists
Each agent now declares its skills explicitly instead of `#file:`-importing them:
| Agent | `skills:` |
|---|---|
| planner | `[planning]` |
| reviewer | `[diff-review]` |
| implementer | `[tdd]` |
| triager | `[issue-triage]` |
The corresponding `#file:../skills/*/SKILL.md` lines are removed from each agent body. Skills no longer `#file:`-import instructions; they reference them by path in prose, and the instruction files carry `applyTo`.
## 7. Lint rule updates
Add to `.github/lint/agent-rules.yml` (or equivalent):
```yaml
rules:
- id: no-retired-frontmatter
severity: error
match: ".github/agents/*.agent.md"
forbid_fields: [handoffs, agents, argument-hint]
message: "Field is ignored by the Copilot agent harness; remove it."
- id: no-file-imports-in-agents
severity: error
match: ".github/agents/*.agent.md"
forbid_pattern: "#file:"
message: "Use `skills:` preload or a shared instruction with `applyTo` instead of `#file:`."
- id: no-file-imports-in-skills
severity: error
match: ".github/skills/**/SKILL.md"
forbid_pattern: "#file:"
message: "Skills must not import instructions; reference them by path."
- id: instructions-require-applyTo
severity: error
match: ".github/instructions/*.instructions.md"
require_field: applyTo
- id: agent-tools-copilot-aliases
severity: error
match: ".github/agents/*.agent.md"
field: tools
allowed_values: [read, edit, search, execute, web, agent, skill, ask_user]
- id: agent-requires-skills
severity: warning
match: ".github/agents/*.agent.md"
require_field: skills
```
## 8. Eval dependency mapping
Evals currently resolve their dependencies by scanning `#file:` imports. Update the resolver to walk `skills:` first, then fall back to `applyTo` globs.
**New resolution order per eval:**
1. Read the agent's `skills:` list → pull each skill's `SKILL.md` and any files it references by path.
2. Read instruction files whose `applyTo` matches the eval's fixture paths.
3. Ignore `#file:` entirely (lint now rejects it).
**Evals needing new stimuli** (because their dependency set changed):
| Eval | Old dependency | New dependency | Action |
|---|---|---|---|
| `evals/planner/plan-feature.yaml` | `typescript.instructions.md` via `#file:` | `planning` skill + `typescript.instructions.md` via `applyTo` | Add a TS fixture so `applyTo` fires; add a planning-heuristics stimulus |
| `evals/reviewer/review-pr.yaml` | `review-checklist.instructions.md` via `#file:` | `diff-review` skill + checklist via `applyTo` | Add a diff fixture matching `**/*.ts`; add a "summary format" stimulus |
| `evals/implementer/tdd-cycle.yaml` | `testing.instructions.md` via `#file:` | `tdd` skill + testing via `applyTo` | Add a `*.test.ts` fixture; add a commit-message stimulus (now deleted from agent) |
| `evals/triager/classify-issue.yaml` | `triage-labels.instructions.md` via `#file:` | `issue-triage` skill + labels via `applyTo` on issue templates | Add an issue-template fixture; add a sub-agent delegation stimulus (new `agent` tool) |
| `evals/shared/typescript-baseline.yaml` | implicit | `typescript.instructions.md` via `applyTo` | Add a `.tsx` fixture to confirm `applyTo` coverage |
Evals that need **no** new stimuli: `evals/shared/python-baseline.yaml` (already scoped by `applyTo` once added), `evals/shared/repo-conventions.yaml` (no agent dependency).
**Follow-up:** after the lint rules land, run the eval resolver in dry-run mode to confirm every eval resolves at least one skill and one `applyTo`-matched instruction; any eval resolving zero dependencies should fail CI.