From unity-assets
자연어 의도로 Unity 에셋 인덱스를 검색한다. LLM-as-Search dual-call (1차 multi-category 라우팅 + sub-intent 분해 → 2차 sub-intent별 retrieval). 기본 package-first drill-down, 2000+ 에셋 또는 index_depth=rich 시 map-reduce sliding chunks 자동 전환. 결과는 schemas/search-result.json.schema.json 형식으로 .claude/unity-asset-index/search-result.json에 atomic 저장. 후속 narrowing·학습 데이터 누적은 별도 `/unity-assets:pick` 스킬 참조.
How this skill is triggered — by the user, by Claude, or both
Slash command
/unity-assets:unity-assets-searchThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
자연어 의도를 받아 `<unity-project>/.claude/unity-asset-index/`의 인덱스를 직접 LLM에게 보여주고 후보 에셋을 confidence 점수와 함께 식별한다. embedding·벡터 DB 없이 dual-call 방식으로 multi-intent도 처리한다. 결과는 `search-result.json`으로 직렬화하여 `/unity-assets:build`(Orchestrator)가 소비한다.
자연어 의도를 받아 <unity-project>/.claude/unity-asset-index/의 인덱스를 직접 LLM에게 보여주고 후보 에셋을 confidence 점수와 함께 식별한다. embedding·벡터 DB 없이 dual-call 방식으로 multi-intent도 처리한다. 결과는 search-result.json으로 직렬화하여 /unity-assets:build(Orchestrator)가 소비한다.
CONVENTION.md를 계약 진실원으로 참조한다.
/unity-assets:search "<자연어 의도>" — 1회성 검색./unity-assets:pick 스킬 (skills/unity-assets-pick/SKILL.md). Search 결과의 후보 1개를 row-index로 선택하면 feedback.jsonl에 한 줄 append되어 다음 검색의 prompt hint로 활용된다..claude/unity-asset-index/{manifest.json, packages.jsonl, assets.jsonl} 존재.state.json::last_run보다 오래됨) 시 CRIT-SCH4 fallback 경로.{"status": "no_query", "reason": "<짧은 한글 사유>"}
manifest.json, assets.jsonl 존재 확인.assets.jsonl.mtime < state.json::last_run (조건상 부등호는 stale을 의미하지 않음 — 정확히는 둘이 일치해야 함; 불일치 시 stale)이면:
/unity-assets:reindex 사용자 직접 호출 권고..claude/unity-assets.yml 또는 기본값. 주요 키:
max_assets_in_context (기본 500) — 단일 LLM 호출에 받는 최대 row 수.index_depth (기본 minimal) — rich이면 map-reduce 강제 전환.1차 라우팅 prompt 조립 직전, 다음을 수행한다:
aliases 매핑에서 lookup. 정확 일치 + 부분 일치(token이 alias key를 포함하거나 그 반대) 모두 시도.--- Aliases hint ---
좀비: [zombie, undead, ghoul, enemy]
메뉴: [menu, ui, hud]
음악: [music, audio, bgm]
---
aliases.yml 부재·파싱 실패 시 fail-fast 하지 않고 경고 로그 1회 emit 후 hint 블록 생략하고 진행.이 hint는 routing subagent가 category_hint 및 subtype_hint 결정 시 한글 도메인 어휘를 영문 카테고리로 연결하는 데 사용된다.
<unity-project>/.claude/unity-asset-index/feedback.jsonl이 존재하면 routing prompt에 학습 hint를 첨부한다:
schemas/feedback-row.json.schema.json 통과해야 함. 파싱 실패·스키마 위반 행은 skip하고 stdout에 다음 한 줄 로그 emit (한 번만, 마지막 line 번호 기준):
[unity-assets:search] feedback row skipped: line <N>
picked_guid의 빈도 상위 3개를 추출.--- Past picks hint ---
sub_intent="좀비 적 캐릭터": [<guid1>, <guid2>, <guid3>]
sub_intent="메인 메뉴 UI": [<guid4>]
---
feedback.jsonl 부재 시도 동일하게 생략하고 정상 진행.이 hint는 routing이 sub_intent를 분해할 때 과거 사용자 선택 빈도 정보를 prompt 컨텍스트에 노출한다. 본격 confidence boost는 Wave 3 calibration에서 처리하며, 본 단계에서는 prompt hint 수준에 그친다.
단일 subagent 호출:
Task(
subagent_type="general-purpose",
model="sonnet",
prompt="<Aliases hint (있다면) + 라우팅 instructions + 사용자 쿼리>"
)
라우팅 instructions는 subagent에게 다음을 emit하도록 지시:
{"multi_category": <bool>, "sub_intents": [{"intent": "<자연어>", "category_hint": "<영문 또는 null>", "subtype_hint": "<Type/subtype 또는 null>"}, ...]}
schemas/search-routing.json.schema.json 형식 준수. 출력은 검증 후 다음 Step의 입력.
라우팅 instructions에는 다음 subtype 매핑 가이드를 추가한다:
메뉴 / HUD / UI / canvas → subtype_hint = "Sprite/ui" 또는 "Prefab/ui".배경 음악 / BGM / music → subtype_hint = "AudioClip/music".효과음 / SFX / sound-effect → subtype_hint = "AudioClip/sfx".앰비언스 / ambience / 환경 음향 → subtype_hint = "AudioClip/ambience".노멀맵 / normal map / _normal → subtype_hint = "Texture/normal-map".아이콘 / icon → subtype_hint = "Texture/icon" 또는 "Sprite/ui".스프라이트시트 / 타일시트 → subtype_hint = "Sprite/spritesheet".좀비 캐릭터 / 적 프리팹 / humanoid → subtype_hint = "Prefab/character".나무 / 바위 / 식생 / 환경 prop → subtype_hint = "Prefab/environment".wave config / spawn 설정 / ScriptableObject → subtype_hint 생략 (ScriptableObject는 taxonomy 밖).매핑이 모호하면 subtype_hint = null 또는 생략. emit된 값은 data/type-taxonomy.yml 기반 ^[A-Za-z]+/[a-z0-9-]+$ 패턴(asset-record.minimal.json의 type_subtype과 동일)을 준수해야 한다.
각 sub-intent에 대해 별도의 subagent 호출:
packages.jsonl을 모두 읽음 (보통 수십~수백 개로 컨텍스트 friendly).
subagent에게 packages.jsonl rows + sub-intent + category_hint 전달, top-K (보통 K=35) 패키지 선택 + 각 패키지의 1) 출력 요청.confidence (0
선택된 패키지의 package_id에 해당하는 assets.jsonl rows만 읽음. row 수가 max_assets_in_context 초과면 5.2로 fallback.
subagent에게 해당 rows + sub-intent + (있다면) subtype_hint 전달, 후보 에셋들의 {guid, path, confidence (0..1), reasoning (영어 풀-피델리티)} 출력 요청. reasoning은 영어 한 문장 이상.
subtype 필터 (CRIT-SCH6): subtype_hint가 sub-intent에 주어진 경우 subagent instructions에 다음을 추가한다:
type_subtype이 subtype_hint와 정확히 일치하는 후보만 우선 고려한다.type (예: Sprite/ui의 Sprite)의 다른 subtype 후보를 차순위로 보충한다.type 후보도 K 미만이면 마지막으로 type-무관 후보를 채워 K개를 채운다.reasoning에 명시한다 (예: "subtype 정확 일치", "같은 Sprite type 내 차순위").total_assets > 2000 OR index_depth == rich OR 단일 패키지 hit이 너무 많아서 5.1.3에서 max_assets_in_context 초과.assets.jsonl을 max_assets_in_context 단위로 chunk.[unity-assets:search] map-reduce 분기 활성 (assets=<N>, chunks=<M>) — CRIT-SCH2가 이 마커를 단언.Step 5.1 또는 5.2 완료 후 모든 sub-intent의 candidates 중 max confidence가 0.40 미만이면 다음 3단계를 순서대로 시도한다. 각 단계 진입 시 정확한 로그 마커를 stdout에 1회 emit한다 (문자열 그대로 복사·변형 금지 — CRIT-SCH7 테스트가 정확히 매칭).
단계 1 — top-K 확장: 5.1의 패키지 top-K를 3 → 5 → 8로 단계적으로 확장하며 retrieval 재시도. K 증분마다 5.1.2~5.1.4를 다시 호출. stdout 로그 마커 (K=현재 K 값을 정수로 치환):
[unity-assets:search] fallback stage 1: top-K expansion (K=<N>)
K=5 또는 K=8에서 confidence ≥ 0.40 후보가 1개 이상 발견되면 즉시 정상 결과로 종료한다. K=8까지 모두 < 0.40이면 단계 2로.
단계 2 — map-reduce 강제: 5.2 sliding chunks 분기를 강제 트리거 (트리거 조건 무시). stdout 로그 마커 (M=실제 chunk 개수를 정수로 치환):
[unity-assets:search] fallback stage 2: map-reduce forced (chunks=<M>)
map-reduce 결과의 max confidence ≥ 0.40이면 즉시 정상 결과로 종료. 여전히 < 0.40이면 단계 3으로.
단계 3 — no_match 출력: search-result.json에 다음을 작성하고 stdout 로그 마커 emit:
{
"manifest_version": "<현재 manifest.json::version>",
"status": "no_match",
"suggested_action": "reindex",
"groups": []
}
stdout 로그 마커:
[unity-assets:search] fallback stage 3: no_match (suggested_action=reindex)
계약 요약:
.claude/unity-assets.yml::fallback.max_stage (기본 3, 옵션 2)로 단계 2까지만 시도하도록 옵션 제공 (단계 2에서도 실패 시 즉시 단계 3 no_match로 점프, 단계 3 마커는 그대로 emit).groups: []는 schemas/search-result.json.schema.json의 status="no_match" 분기에서 허용됨.모든 sub-intent의 후보를 schemas/search-result.json.schema.json 형식으로 묶음:
{
"manifest_version": "<manifest.json::version 그대로 복사>",
"groups": [
{
"sub_intent": "<라우팅 출력의 intent와 동일>",
"candidates": [
{"guid": "...", "path": "...", "confidence": 0.83, "reasoning": "<영어 풀-피델리티>"},
...
]
},
...
]
}
reasoning 필드는 풀-피델리티 (CONVENTION.md §7) — subagent가 생성한 추론 텍스트를 1바이트도 절단·요약하지 말고 그대로 직렬화. maxLength 없음.
<.claude/unity-asset-index/search-result.json.tmp> 작성 → atomic rename으로 search-result.json 만듦.
stdout에 다음을 emit:
/unity-assets:pick으로 선택, 또는 /unity-assets:build "..."로 바로 진행./unity-assets:pick (별도 스킬)후속 narrowing은 skills/unity-assets-pick/SKILL.md 참조. 본 search 스킬은 search-result.json을 작성하기만 하고, pick은 row-index로 1개 후보를 선택하여 feedback.jsonl에 한 줄 append한다 (CRIT-SCH8). pick이 누적한 학습 데이터는 위 Step 4.0.5의 "Past picks hint"가 다음 검색에 활용한다.
<unity-project>/.claude/unity-asset-index/search-result.json{status: "no_query"} (CRIT-SCH3).max_assets_in_context 초과 → 자동 map-reduce 전환 (CRIT-SCH2).{status: "no_query"} 응답.data/aliases.yml lookup → routing prompt에 --- Aliases hint --- 블록 첨부. 골든 쿼리의 한글 키워드(좀비/검/숲/메뉴/음악 등) 100% 커버.subtype_hint 우선 순위 필터. search-routing.json.schema.json의 subtype_hint 필드(^[A-Za-z]+/[a-z0-9-]+$)를 통해 1차→2차 라우팅 정보 전달.{status:"no_match", suggested_action:"reindex"} 출력. 각 단계의 stdout 로그 마커 정확 일치 단언.Creates, edits, and optimizes skills for Claude Code, including drafting, evaluating with test prompts, iterating on performance, and improving skill descriptions for better triggering accuracy.
npx claudepluginhub v0o0v/unity-asset-skills