feat: align skill installs with the open agent skills standard#1
feat: align skill installs with the open agent skills standard#1chordpli wants to merge 5 commits into
Conversation
- Codex adapter installs to .agents/skills/ (native Codex skill discovery) instead of the deprecated .codex/prompts + .codex/scripts layout - namespace installed skills as q-<name> (directory + frontmatter name), normalized to the validators' ^[a-z0-9-]+$ requirement - normalize frontmatter on install: non-validator keys (version, scope, risk, outputs, ...) move under metadata: so Codex discovery accepts them - maintain managed skill-list blocks in CLAUDE.md / AGENTS.md - clean up legacy install layouts; sync reinstalls installs missing at the current layout - record installed file paths per skill in .quivo-lock.json
There was a problem hiding this comment.
Code Review
This pull request updates the skill installation layout for AI agents, transitioning Claude Code skills to .claude/skills/q-<name>/ and Codex CLI skills to .agents/skills/q-<name>/ (aligning with the open agent skills standard). It introduces a q- namespace prefix to prevent collisions, normalizes frontmatter keys by moving non-standard keys under metadata:, manages skill-list blocks in CLAUDE.md and AGENTS.md, and automatically cleans up legacy layouts. The review feedback highlights three key areas for improvement: handling potential OSError exceptions during legacy file cleanup to prevent command crashes, verifying registry existence during synchronization to avoid infinite sync loops for deleted/renamed skills, and catching yaml.YAMLError during frontmatter parsing to gracefully handle malformed YAML files.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
| if p.is_dir(): | ||
| shutil.rmtree(p) | ||
| removed.append(p) | ||
| elif p.exists(): | ||
| p.unlink() | ||
| removed.append(p) |
There was a problem hiding this comment.
cleanup_legacy 함수는 이전 버전의 quivo가 남긴 레거시 디렉토리나 파일을 정리하는 보조적인 역할을 합니다. 하지만 shutil.rmtree(p) 또는 p.unlink() 실행 중 권한 문제(PermissionError)나 파일 잠금 등으로 인해 OSError가 발생할 경우, 전체 quivo init 또는 quivo sync 명령이 중단(crash)될 수 있습니다. 레거시 정리는 실패하더라도 메인 설치/동기화 흐름에 영향을 주지 않도록 try-except OSError 블록으로 감싸서 예외를 안전하게 처리하는 것이 좋습니다.
| if p.is_dir(): | |
| shutil.rmtree(p) | |
| removed.append(p) | |
| elif p.exists(): | |
| p.unlink() | |
| removed.append(p) | |
| try: | |
| if p.is_dir() and not p.is_symlink(): | |
| shutil.rmtree(p) | |
| removed.append(p) | |
| elif p.exists() or p.is_symlink(): | |
| p.unlink() | |
| removed.append(p) | |
| except OSError: | |
| pass |
| for name, old_ver in installed.items(): | ||
| new_ver = latest.get(name) | ||
| if new_ver and new_ver != old_ver: | ||
| to_update.append((name, old_ver, new_ver)) | ||
| missing = any(not a.skill_md_path(name).exists() for a in adapters) | ||
| if (new_ver and new_ver != old_ver) or missing: | ||
| to_update.append((name, old_ver, new_ver or old_ver)) |
There was a problem hiding this comment.
만약 락파일(.quivo-lock.json)에 기록된 스킬이 업스트림 레포지토리나 레지스트리에서 삭제/이름 변경되어 all_registry에 존재하지 않는 경우, missing이 True가 되어 to_update에 추가됩니다. 하지만 all_registry에 없기 때문에 skills_to_install에서 제외되어 실제로는 설치되지 않고, 락파일에는 계속 남아있게 됩니다. 이로 인해 quivo sync를 실행할 때마다 매번 해당 스킬을 동기화하려고 시도하지만 아무 작업도 수행하지 않는 무한 루프(ghost sync loop) 상태에 빠지게 됩니다. 동기화 대상 스킬이 현재 레지스트리(all_registry)에 존재하는지 먼저 확인하고, 존재하지 않는 경우 경고 메시지를 출력하고 건너뛰도록 개선하는 것이 좋습니다.
for name, old_ver in installed.items():
if name not in all_registry:
console.print(f\"[yellow]Warning: Skill '{name}' is installed but not found in the registry. Skipping sync.[/yellow]\")
continue
new_ver = latest.get(name)
missing = any(not a.skill_md_path(name).exists() for a in adapters)
if (new_ver and new_ver != old_ver) or missing:
to_update.append((name, old_ver, new_ver or old_ver))| m = _FRONTMATTER_RE.match(content) | ||
| if not m: | ||
| return content | ||
| data = yaml.safe_load(m.group(1)) or {} |
There was a problem hiding this comment.
yaml.safe_load는 프론트매터(frontmatter)의 YAML 문법이 잘못되었을 경우 yaml.YAMLError 예외를 발생시킵니다. 외부 저장소나 로컬에서 잘못 작성된 SKILL.md 파일을 다운로드하거나 참조할 때, 이 예외가 처리되지 않으면 CLI 전체가 크래시(crash)될 수 있습니다. 예외를 안전하게 잡아내고(catch), 문법 오류가 있는 경우 원본 본문을 그대로 반환하거나 적절히 처리할 수 있도록 try-except 블록을 추가하는 것이 안전합니다.
| data = yaml.safe_load(m.group(1)) or {} | |
| try: | |
| data = yaml.safe_load(m.group(1)) or {} | |
| except yaml.YAMLError: | |
| return content |
- init/sync remove the previous install (every file recorded in .quivo-lock.json's per-skill manifests) before installing fresh, so layout/prefix convention changes never leave stale copies behind - hardcoded legacy-layout cleanup remains only as a fallback for locks written before the file manifest existed - sync always reinstalls all locked skills and uninstalls skills that were dropped from the skill source - lock now records internal skills too, and recorded paths that escape the target directory are ignored on removal - extract .quivo-lock.json helpers into quivo.lockfile
|
추가 커밋 e5eb33c: 레거시 정리 방식을 클린 재설치 개념으로 교체.
|
Extend quivo to install skills for 6 agents (up from 2).
New adapters:
- GeminiAdapter — .gemini/commands/v-<name>.md
- QwenAdapter — .qwen/commands/v-<name>.md
- WindsurfAdapter — .windsurf/workflows/v-<name>.md
- CursorAdapter — .cursor/skills/q-<name>/SKILL.md
(context: .cursor/rules/quivo-skills.mdc, alwaysApply: true)
Architecture:
- CommandsBaseAdapter: new abstract base for single-file slash-command
adapters (v- prefix). Strips YAML frontmatter, writes body + policy.
- BaseAdapter: gains context_file_mdc flag and install_display_name().
- context.py: update_context_file() now accepts mdc= (prepends MDC
frontmatter preamble to new files) and name_fn= (so GEMINI.md shows
v-<name>, CLAUDE.md shows q-<name>).
- AgentChoice: expanded to claude/codex/gemini/qwen/windsurf/cursor/both/all.
Interactive prompt updated; both stays as backward-compat claude+codex alias.
- _build_adapters(): centralised factory shared by init and sync.
- Per-adapter agents filtering: skills with agents: [...] are only installed
for listed agents.
- cleanup.py: legacy paths extended to cover all new adapter directories.
- skill.yamls: agents field updated to include all six agents.
요약
Codex CLI가 open agent skills 표준(agentskills.io)을 채택하면서 기존
.codex/prompts/+.codex/scripts/설치 레이아웃이 deprecated 되었고, 설치본이 Codex discovery에서 인식되지 않는 문제를 해결한다. spec-kit의 Codex integration(.agents/skills/speckit-<name>/SKILL.md, "Commands are deprecated")과 동일한 방향.변경 사항
설치 레이아웃
.agents/skills/q-<name>/에 SKILL.md 설치 (Codex가 CWD→레포 루트로 네이티브 스캔). frontmatter strip +# /<name>헤더 + sidecar 구조 제거q-prefix: 디렉토리명과 frontmattername:모두 네임스페이스 — 대상 프로젝트 자체 스킬과 충돌 방지. 호출명은/q-ripple(Claude),$q-ripple(Codex)^[a-z0-9-]+$에 맞게 정규화 (_→-등)BaseAdapter.install()하나로 통합Frontmatter 정규화
name/description/license/allowed-tools)만 top-level 유지version,scope,agents,risk,policy_injection,outputs)는 표준 자유 형식 키인metadata:아래로 이동 — 이게 없으면 Codex가 스킬을 invalid로 보고 discovery에서 제외함컨텍스트 파일 (spec-kit 차용)
CLAUDE.md/AGENTS.md에 마커로 구분된 스킬 목록 관리 블록 유지 (init/sync시 재생성, 마커 밖 내용 보존, 멱등)레거시 정리 + 매니페스트 (spec-kit 차용)
init/sync가 구버전 레이아웃(.codex/prompts|scripts, prefix 없는 디렉토리) 자동 제거 — 락파일에 기록된 quivo 관리 스킬만 대상sync에 missing 감지 추가: 버전이 같아도 현재 레이아웃에 설치본이 없으면 재설치 → 구버전 프로젝트가quivo sync한 번으로 수렴.quivo-lock.json에 스킬별 설치 파일 목록 기록 (향후 uninstall 기반)검증
scripts/test-skill.sh전체 통과 (스모크를 q- prefix·컨텍스트 파일 검증으로 강화)skills-v0.1.0) 번들 다운로드 →--agent both설치 → 설치본 6개 SKILL.md 전부 Codex validator 규칙(허용 키 집합, name 정규식, 디렉토리=name 일치) 통과sync마이그레이션 시나리오 통과 (구 경로 제거 → 새 경로 재설치 → 컨텍스트 파일 생성)CLAUDE.md사용자 내용 보존 + 관리 블록 멱등성 확인