Export the kit's host-neutral rules to every harness entrypoint file (AGENTS.md, GEMINI.md) so non-Claude-Code harnesses (Codex, OpenCode, Copilot, Gemini CLI, Pi, Hermes) follow the same discipline. Use when a repo is worked by more than one agent harness, or after changing rules/. Trigger with /harness-export.
Installs into .claude/skills of the current project.
Are you the author of Harness Export?
Add the live security badge to your README. It updates with every re-scan.
[](https://www.skillsdirectory.com/skills/this-hw-harness-export-hiway-kit)
---
name: harness-export
description: Export the kit's host-neutral rules to every harness entrypoint file (AGENTS.md, GEMINI.md) so non-Claude-Code harnesses (Codex, OpenCode, Copilot, Gemini CLI, Pi, Hermes) follow the same discipline. Use when a repo is worked by more than one agent harness, or after changing rules/. Trigger with /harness-export.
disable-model-invocation: true
---
# Harness Export — 규범을 하네스 중립으로 내보내기
이 킷의 규범(`rules/*.md`)은 **Claude Code의 SessionStart 훅으로만** 주입된다.
그런데 Orca·Paseo 같은 ADE에서는 한 레포에 Claude Code와 Codex·OpenCode·Pi를
**동시에** 붙여 굴린다. 그 순간 레포의 절반은 이 킷의 규율 밖에서 동작한다.
이 스킬은 규범을 **각 하네스가 읽는 진입점 파일**로 내보내 그 구멍을 메운다.
| 전달 형태 | 대상 | 경로 |
| --- | --- | --- |
| 세션형 + 킷 훅 | Claude Code | SessionStart 훅이 **자동 주입** — 이 스킬 불필요(단 `CLAUDE.md` 없는 프로젝트는 아래) |
| 세션형, 킷 훅 = 주입·포맷(마켓플레이스 설치·훅 신뢰 승인 후) | Codex | **`AGENTS.md`** — 신뢰 승인 전과 **디렉토리(ZIP) 설치**(훅이 빠진다)에선 이것이 유일한 경로. 승인 후엔 훅 주입과 **이중 도달**(아래) |
| 세션형, 킷 훅 미탑재 · 플러그인 `rules/` 미도착 | Antigravity (agy) | **`AGENTS.md` + `GEMINI.md` 둘 다 읽는다** — 플러그인 설치로는 규범이 오지 않는다(실측). **이중 로드**(아래) |
| 세션형, 킷 훅 미탑재 | OpenCode · Copilot CLI · Cursor | **`AGENTS.md`** |
| 세션형, 킷 훅 미탑재 | Gemini CLI | **`GEMINI.md`**(기본 파일명 — `AGENTS.md` 는 `context.fileName` 으로 지정할 때만) |
| **API 성 호출**(세션 아님) | 래퍼가 모델을 함수처럼 부르는 레인 | **`--stdout` 으로 뽑아 프롬프트에 싣는다** |
하네스별 실측 기록(버전·날짜)은 킷 레포의 `packaging/targets.json` 관측 키가 소유한다.
**내용은 같다** — 규범이 하네스 중립이므로 블록도 sha 도 하나이고 파일만 여럿이다.
한 파일에만 내보내면 나머지 하네스는 규율 밖에서 돈다.
> **`CLAUDE.md` 는 의도적으로 뺐다.** Claude Code 는 이 킷의 SessionStart 훅이 규범을
> 직접 주입한다 — 파일로 또 실으면 같은 규범이 두 번 들어간다. 세션 시작 주입 훅이
> **돌지 않는** 하네스만 파일이 필요하다.
>
> **같은 규범이 두 번 들어가는 곳 — 셋 다 알고 감수한다:**
>
> | 하네스 | 왜 두 번인가 | 그래도 두는 이유 |
> | --- | --- | --- |
> | Codex | 훅 신뢰 승인 후 세션 시작 주입 훅(portable 규범만) + `AGENTS.md` | 승인 **전**·ZIP 설치에선 `AGENTS.md` 가 유일한 경로 — 폴백을 잃는 것이 중복보다 나쁘다 |
> | Antigravity | `AGENTS.md`·`GEMINI.md` 를 둘 다 읽는다 | Gemini CLI 는 `GEMINI.md` 만 읽으므로 둘 다 필요하다. 얇은 `GEMINI.md`(`@./AGENTS.md`)는 Gemini CLI 런타임 실측 전이라 채택하지 않았다 |
> | Claude Code 2.1.277+ | **`CLAUDE.md` 가 없는 프로젝트**에서는 `AGENTS.md` 를 직접 읽는다 → 훅 주입과 겹친다 | `CLAUDE.md` 가 있으면 겹치지 않는다. 겹침을 훅이 피하는 방안은 별도 결정이다 |
>
> 블록이 크므로 두 번이면 컨텍스트 비용도 두 배다. 진입점을 줄이고 싶으면 `--entrypoints` 로
> 실제 쓰는 하네스의 파일만 남겨라.
진입점 목록을 바꾸려면 `--entrypoints AGENTS.md,GEMINI.md,OTHER.md` 로 덮어쓴다.
### API 성 호출 레인 — 파일이 개념적으로 없다
래퍼가 모델을 **함수처럼** 부르는 레인(분류·라우팅·스카우트 등)에는 세션도 진입점
파일도 없다. 규범은 **호출자가 프롬프트에 실어야** 도달한다:
```bash
NORMS="$(python3 "$EH" --stdout)" # 캐시하고 sha 로 갱신 판단
# → system 프롬프트 앞에 붙여 호출
```
**레인별로 켜라.** 규범 블록은 수천 토큰이다. 분류·라우팅처럼 응답이
수백 토큰인 레인에 매번 실으면 비용이 본문을 압도한다. 코드 생성·결정 산출처럼
**규율이 결과를 바꾸는 레인**에만 싣는다.
**전부 싣거나 아무것도 싣지 마라.** 티어별로 잘라도 절감이 10% 미만이고, 블록의
"정직한 한계" 표(*"이 규범은 강제 장치가 아니라 규율 문서다"*)는 **훅이 아예 없는
이 레인에서 더 중요하다** — 토큰을 아끼려고 그 사실을 지우면 모델이 집행이 있다고
오해한다.
## 사용 시점
| 상황 | 실행 |
| --- | --- |
| 레포를 두 개 이상의 하네스가 만진다 | `/harness-export` 1회 → 생성된 진입점 파일 전부 커밋 |
| `rules/*.md`를 고쳤다 | 재생성 (안 하면 다른 하네스가 옛 규범을 읽는다) |
| CI/게이트에서 최신 여부만 확인 | `--check` |
## 절차
### 소비자(플러그인 설치) 환경 — 기본 경로
구현은 **플러그인 안**에 있다(`<플러그인 루트>/tools/export_harness.py`).
설치한 프로젝트에는 킷 레포의 개발용 래퍼가 없으므로 이 경로를 쓴다.
> **`$CLAUDE_PLUGIN_ROOT`를 그대로 신뢰하지 마라.** 이 변수는 스킬의 셸 컨텍스트에
> **설정돼 있지 않을 수 있다** — Codex 의 모델 셸 환경에는 없다(실측), Claude Code 에서도
> 비어 있을 수 있다. 빈 값이면 `python3 "/tools/export_harness.py"`가 되어 **파이썬이**
> 파일 없음으로 종료코드 2를 내는데, 이 도구의 2는 "SKIPPED"라서 **원인을 오보고**하게 된다.
> `~/.claude` 캐시만 뒤지는 폴백도 Codex 전용 머신에서는 죽은 경로다.
>
> **`$EH`(이 도구의 경로)는 킷 도구 탐색 규약으로 해석한다** — 순서와 명령은
> `skills/plan-task/references/task-tools-fallback.md` 의 *킷 도구 탐색* 절이 소유한다
> (이 스킬은 복제하지 않는다). 찾을 도구 이름은 `export_harness.py` 다. 끝내 못 찾으면
> 추측하지 말고 사용자에게 플러그인 경로를 물어 `--plugin-root` 로 넘긴다.
```bash
# 1) $EH 해석 — 위 규약대로 (못 찾으면 여기서 멈춘다)
# 2) 현재 프로젝트(git 최상위)의 AGENTS.md·GEMINI.md 갱신
python3 "$EH"
# 3) 드리프트 검사만 (기록하지 않음)
python3 "$EH" --check
# 4) 규범 블록을 표준출력으로 — **API 성 호출 레인의 유일한 경로**
python3 "$EH" --stdout
# 5) 다른 프로젝트 대상
python3 "$EH" --target /path/to/project
```
`--plugin-root`를 **명시**했는데 그 경로에 `rules/`가 없으면 자동 탐색으로 폴백하지
않고 **실패**한다(SKIPPED 가 아니다). 지정한 것과 다른 레포의 규범을 내보내고 성공을
보고하는 사고를 막는다.
명시하지 않으면 **스크립트 자기 위치**가 1순위이고(플러그인 캐시에서도 불변),
환경변수는 그 다음이다 — 셸에 남은 다른 플러그인의 값이 남의 규범을 내보내지 않도록.
### 이 킷 레포에서만 — 개발용 래퍼 (소비자 프로젝트에는 없다)
```bash
./scripts/export-harness.sh # 내보내기
./scripts/export-harness.sh --check # 드리프트 검사 (게이트가 쓰는 명령)
```
## exit code
**표는 `python3 "$EH" --help` 가 소유한다**(모듈 docstring 의 `exit code:` 절을 그대로
보여 준다). 여기 복제하지 않는다 — 복제본은 실제로 낡았었다(명시 `--plugin-root` 실패를
exit 2 로, 사라진 분류 딕셔너리를 현행으로 적고 있었다).
읽을 때 지킬 것 둘: **0 이 아니면 stderr 의 원인을 읽는다**(재생성으로 안 고쳐지는 종류가
있다) · **SKIPPED 와 "conventions 블록 건너뜀"을 성공으로 위장하지 않는다.**
## 불변식 [건너뛰기 금지]
1. **마커 블록 밖 불가침.** 대상의 `AGENTS.md`에서 `<!-- kit:begin ... -->` ~
`<!-- kit:end -->` 밖은 생성기가 절대 건드리지 않는다. 마커가 없는 사용자 파일은
덮어쓰지 않고 **append**한다. 이 규율을 깨는 수정은 consumer-first 위반이다.
2. **자기신고 sha를 믿지 않는다.** `--check`는 마커의 sha뿐 아니라 **블록 전문**을
생성 결과와 대조한다. sha만 보면 마커 줄을 그대로 둔 채 안쪽을 지워도 초록이 되고,
이 도구가 막겠다고 선언한 상황이 그대로 게이트를 통과한다.
3. **요약 금지.** 이식 대상 룰은 **원문 그대로** 실린다. 규범을 요약하면 원문과
의미가 갈리고, 갈린 규범은 규범이 아니다.
4. **분류 누락은 실패.** 룰은 자기 frontmatter 에 `portable: true|false`(사유는
`portable_reason:`)와 `tier:` 를 **선언**한다 — 생성기는 그것을 읽기만 한다. 미선언이면
실패한다. 분류가 룰 파일 안에 있으므로 룰을 지우면 분류도 함께 사라진다(별도 등재표가
없으니 "유령 엔트리"도 생길 수 없다).
## 마커 규약 — 자기 AGENTS.md에 마커를 *설명*하려면
블록으로 인정되는 마커는 **줄 전체를 차지하고 메타가 정확한 형식일 때뿐**이다:
| | 형식 |
| --- | --- |
| 여는 마커 | `<!-- kit:begin rules-v<버전> sha256:<64자리 hex> -->` (그 줄에 다른 내용 없음) |
| 닫는 마커 | `<!-- kit:end -->` (그 줄에 다른 내용 없음) |
**왜 이렇게 좁은가.** 2.14.0까지는 마커를 관대한 패턴으로 찾았다. 그러자 자기
`AGENTS.md`에 "이 블록이 뭔지" 설명해 둔 소비자에게 재생성을 돌렸을 때, 인용된 두
마커 **사이의 사용자 문장이 침묵 속에 삭제**되고 exit 0이 났다 — 그리고 그 뒤
`--check`는 green을 돌려줘 흔적조차 남지 않았다(2.14.1에서 수정). 이 도구의 대상
파일이 하필 "에이전트에게 규약을 설명하는 문서"라는 점에서 최악의 조합이었다.
따라서 문서에 마커를 인용할 때는 **문장 안에 인라인으로** 쓴다:
- ✅ `` 이 구간은 `<!-- kit:begin … -->` 로 시작한다. `` — 줄 앵커에 걸리지 않아 안전
- ❌ 마커만 한 줄로 적은 예시(코드 펜스 안 포함) — 형식이 정확하면 **진짜 블록으로
인정**되고, 형식이 어긋나면 "손상된 마커"로 **exit 1** 거부된다
거부는 파괴가 아니다 — 생성기는 추측해서 고치지 않고 그 줄을 사람에게 넘긴다.
## 다중 하네스 패키지와의 관계
킷은 Codex·Antigravity 용 **네이티브 플러그인 매니페스트**로도 배포된다. 둘은 **대체가 아니라
상보 관계**다:
- 이 스킬(`AGENTS.md`)은 **규범 텍스트**를 어느 하네스에서든 읽히는 자유형식 파일로 실어
나른다 — 플러그인 설치 여부와 무관하게 동작한다.
- 네이티브 패키지는 **스킬·컴포넌트**를 그 플랫폼의 설치 메커니즘으로 실어 나른다:
- **Codex 마켓플레이스 설치** — 스킬 + 훅(세션 시작 주입·자동 포맷, 훅 신뢰 승인 후).
- **Codex 디렉토리(ZIP) 설치** — **스킬만**. 디렉토리 심사가 훅을 받지 않아 ZIP 에서 뺀다.
- **Antigravity** — **스킬만**. 플러그인 `rules/` 는 런타임에 도착하지 않고(실측 — 공식
문서는 `rules/` 를 나열하지만 런타임과 다르다), 에이전트는 인식되지 않는다(원인은
에이전트 frontmatter 의 `model:` 값 — 실측).
**규범은 Claude Code 를 뺀 어느 하네스에서도 플러그인 설치만으로 보장되지 않는다.** Codex 는
세션 시작 훅(마켓플레이스 설치 + 신뢰 승인 후에만 돈다) 아니면 이 스킬로만, Antigravity·
Gemini CLI 는 **이 스킬로만** 전달된다 — `/harness-export` 로 만든 진입점 파일이 유일한 경로다.
## 이식되지 않는 것 (정직한 한계)
차단·검증 훅(`protect-sensitive`·`stop-validator`), 서브에이전트 정의 전부, 그리고 Claude
Code 프리미티브에 종속된 규범(frontmatter `portable: false`)은 이식되지 않는다. 생성물이 그
목록과 사유를 표로 남긴다. (Codex 도 PreToolUse 차단 자체는 된다 — 실측. 이식하지 않은 것은
Codex 의 도구 페이로드를 읽는 파서가 없어서이지 Codex 가 못 막아서가 아니다.)
**다른 하네스에서 이 킷은 규율 *문서*로 동작하지 강제 *장치*로 동작하지 않는다.**
강제가 필요하면 그 하네스의 네이티브 수단(pre-commit, CI)에 같은 검사를 건다.
## 게이트
소비자 프로젝트라면 `python3 "$EH" --check` 를 자기 CI·pre-commit 에 걸어라 — 진입점 파일이
규범보다 낡으면 막힌다. (이 킷 레포는 스스로 도그푸딩한다 — 그 레포의 완료 게이트와 CI 가
같은 `--check` 를 돈다.)