Skip to content

refactor: Claude 스킬·에이전트 시스템 표준화 및 회귀 방지 린트 도입#104

Merged
CaesiumY merged 13 commits into
mainfrom
refactor/claude-skills-standardization
Jul 3, 2026
Merged

refactor: Claude 스킬·에이전트 시스템 표준화 및 회귀 방지 린트 도입#104
CaesiumY merged 13 commits into
mainfrom
refactor/claude-skills-standardization

Conversation

@CaesiumY

@CaesiumY CaesiumY commented Jul 3, 2026

Copy link
Copy Markdown
Owner

Description

.claude/ 스킬 7개·에이전트 13개 시스템을 전면 표준화하고, 실버그 4건을 수정하며, 회귀 방지 린트를 CI에 편입합니다. 개선사항 중 런타임 무관한 것들은 Codex 미러(.agents/)에도 이식했습니다.

설계 제약: 산출물은 특정 모델에 의존하지 않습니다. 에이전트 model: 필드는 별칭(haiku/sonnet/opus)만 사용하며, 구체 모델 ID 하드코딩은 신규 린트가 CI에서 차단합니다.

버그 수정 (P0)

  • translate-writer: allowed-toolsEdit 누락 — Phase 3(Polish)이 Edit 적용을 지시하는데 권한이 없어 주력 파이프라인이 막힐 수 있던 문제
  • blog-writer: 에이전트 4개를 전부 subagent_type: "general-purpose"로 호출 — 전용 에이전트의 model/tools frontmatter가 로드되지 않던 버그. 직접 지정으로 교체
  • polish-agent: 자체 10개 패턴 번호가 28개 정본과 충돌(chore(deps): Bump object-path from 0.11.4 to 0.11.5 #2, #10의 의미가 서로 다름) — 정본 번호의 부분집합으로 재매핑
  • translation-verifier: WSL 스테일 절대경로(/home/wsl-agent/...)와 oh-my-claudecode 푸터 잔재 정리

표준화 (P1)

  • 스킬 frontmatter name 추가 및 키 순서 통일 (name → description → argument-hint → allowed-tools)
  • 사용자 게이트 표기를 ✋ GATE N — AskUserQuestion으로 통일 + "게이트 없이 진행 금지" 규칙 명시
  • 28개 번역투 패턴을 translation-patterns.md 단일 정본으로 통합 — reviewer의 임베디드 사본은 이미 드리프트가 발생한 상태였음. 차원 매핑(가중치·하드 임계값)도 정본으로 이관
  • 에이전트 13개 다듬기: 경계 판정 규칙(79 vs 80점), date -u 날짜 검증(미래 날짜 빌드 제외 예방), Windows 심링크 Read/생성 폴백, resume-specialist 프로젝트 컨텍스트·한국어 규칙 추가

자동화 (CI)

  • 신규 scripts/check-claude-assets.mjs: 스킬 frontmatter 완전성, subagent_type ↔ 에이전트 정의 대조(general-purpose 금지), .claude/ 참조 경로 실존, model 별칭 강제
  • CI Code standards & build 잡에 편입 (docs sync 다음 단계)

Codex 미러 이식

  • 런타임 무관 개선(패턴 정본화, 게이트 표기, 심링크 폴백 등)을 .agents/에 이식
  • Codex 규약(tools/model frontmatter 없음, @ 참조 없음, WebFetch 대신 "웹 조회") 보존
  • 에이전트 11개는 정규화 diff로 "규약 차이 외 동일" 검증 완료

Types of changes

  • Bug Fix (non-breaking change which fixes an issue)
  • New Feature (non-breaking change which adds functionality)
  • Documentation Update (if none of the other choices apply)
  • Others (any other types not listed above)

Checklist

  • I have read the Contributing Guide
  • I have added the necessary documentation (if appropriate)
  • Breaking Change (fix or feature that would cause existing functionality to not work as expected)

Further comments

리뷰어 참고:

  • 검증: node scripts/check-claude-assets.mjsnode scripts/check-agent-docs-sync.mjs 모두 통과. polish-agent는 실전 스모크 테스트로 검증했고, 이 과정에서 haiku가 "활용하다"를 #10으로 오기록하는 회귀를 발견해 어휘별 인라인 번호 표기로 수정 후 재검증 통과 (d115976)
  • 불가침 영역 준수: samples/ git 심링크, data/ 런타임 파일, .claude/agents/backup/, polish-reports/는 무변경
  • 커밋 12개는 Phase별 단독 커밋 — 문제 시 개별 git revert 가능 (특히 reviewer 임베디드 테이블 제거 커밋 4143b2a)
  • CLAUDE.md/AGENTS.md 미러 동기화 유지 확인 완료

Related Issue

Closes: #

CaesiumY added 12 commits July 3, 2026 02:11
- Phase 3이 Edit 적용을 지시하는데 allowed-tools에 Edit이 없어 권한 문제 발생 가능
- Phase 0/1/2/5의 에이전트 호출을 명시적 subagent_type 표기로 통일해
  전용 에이전트의 model/tools frontmatter가 확실히 로드되도록 함
general-purpose 경유 호출은 전용 에이전트의 model/tools frontmatter를 로드하지 않는 버그. style-analyzer, content-writer, content-reviewer, style-learner를 subagent_type으로 직접 지정하도록 수정.
polish-agent의 자체 10개 번호가 translation-patterns.md 정본 번호와 충돌해 리포트의 patterns_found ID가 모호했음. 정본 번호의 부분집합으로 재매핑하고, 28개 패턴 출처를 translation-reviewer.md에서 정본 파일로 교체. polish/polish-file의 예시 ID도 동기화.
사용 예시의 /home/wsl-agent 절대경로를 저장소 상대경로로 교체하고, 예시 Task 호출의 중복 model 파라미터를 제거해 frontmatter model 필드로 단일화. oh-my-claudecode 작성자 푸터 제거.
name → description → argument-hint → allowed-tools 순서로 6개 스킬 통일. agents-md-optimizer는 벤더링 파일로 이미 표준 충족이라 제외. 본문 변경 없음.
portfolio-strategy의 게이트 컨벤션을 표준으로 채택. translate-writer Phase 3/4, blog-writer Phase 3, polish-file Step 4에 게이트 라벨과 진행 금지 규칙을 명시해 어떤 모델이 실행해도 게이트를 건너뛰지 않도록 함.
translation-reviewer의 임베디드 패턴 테이블이 정본과 드리프트(패턴 7 예시 잔여 텍스트)를 일으켜 제거하고 필수 Read 지시로 교체. 차원 매핑(가중치, 하드 임계값)을 정본 파일 헤더로 이관. translation-verifier의 calibration 필수 Read 패턴과 동일 구조.
content-reviewer: 경계 판정 규칙(79 vs 80)과 종료 조건 체크리스트 추가, 번역투 검사를 정본 번호로 연결. content-writer: pubDatetime date -u 검증 규칙 추가(미래 날짜 빌드 제외 예방). content-translator: 번역투 표를 정본 번호로 재표기. style-analyzer/translation-style-analyzer: Windows 심링크 Read 폴백 규칙. resume-specialist: 프로젝트 데이터 소스, 한국어 출력, 사실 검증 규칙, 출력 형식 추가. 두 SKILL.md의 심링크 생성 단계에 git update-index 폴백 명시.
check-claude-assets.mjs: 스킬 frontmatter 필수 키와 name-디렉토리 일치, 에이전트 model 별칭(haiku/sonnet/opus) 강제(fable/claude-* 하드코딩 차단), subagent_type-에이전트 대조(general-purpose 금지), .claude 참조 경로 실존 검사. 게이트 회귀를 커밋 시점에 잡는다.
CLAUDE.md/AGENTS.md 미러 섹션에 check-claude-assets.mjs 린트 규칙 추가, Skills 섹션(CLAUDE.md)에 28개 패턴 정본 위치와 게이트 표기 규약 명시.
스모크 테스트에서 haiku가 활용하다를 #10으로 오기록하는 회귀 발견. 묶음 행 라벨에 어휘별 번호를 괄호로 병기(8(활용하다)·10(제공하다)·11(존재하다))하고 기록 규칙에 오답 경고를 추가. 동일 입력 재검증으로 #8 정상 기록 확인.
런타임 무관 개선 이식: 28개 패턴 정본화(차원 매핑 포함), polish-agent 패턴 ID 재매핑과 오기록 방지 규칙, 게이트 표기(GATE N), Windows 심링크 폴백, content-writer date -u 규칙, content-reviewer 경계 판정 규칙, resume-specialist 프로젝트 컨텍스트, translation-verifier 스테일 경로 정리. Codex 규약(tools/model frontmatter 없음, @ 참조 없음, WebFetch 대신 웹 조회, .agents/ 경로)은 유지. 에이전트 11개는 정규화 diff로 규약 외 동일 검증 완료. data/ 런타임 파일은 불변.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request standardizes translation patterns and agent/skill definitions across the repository, establishing a single source of truth for the 28 translation patterns and introducing explicit user gates. It also adds a new asset linter script, scripts/check-claude-assets.mjs, to enforce invariants on skill and agent frontmatter, model routing, and path references. Feedback on the new linter script suggests robustly handling quoted values in the frontmatter parser and refining the subagent_type regular expression to correctly match unquoted values and balanced quotes.

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.

Comment thread scripts/check-claude-assets.mjs Outdated
Comment on lines +61 to +62
const m = lines[i].match(/^([A-Za-z][A-Za-z0-9_-]*):\s*(.*)$/);
if (m) keys[m[1]] = m[2].trim();

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

프론트매터의 값(예: name 또는 model)이 따옴표(큰따옴표 또는 작은따옴표)로 감싸져 있는 경우, 파싱된 값에 따옴표가 그대로 포함되어 이후의 비교 검증(keys.name !== dir 또는 ALLOWED_MODELS.has(keys.model))이 실패할 수 있습니다.

프론트매터 값을 파싱할 때 양 끝의 따옴표를 안전하게 제거하도록 개선하는 것이 좋습니다.

    const m = lines[i].match(/^([A-Za-z][A-Za-z0-9_-]*):
*(.*)$/);
    if (m) {
      let val = m[2].trim();
      if ((val.startsWith('"') && val.endsWith('"')) || (val.startsWith("'") && val.endsWith("'"))) {
        val = val.slice(1, -1);
      }
      keys[m[1]] = val;
    }

Comment thread scripts/check-claude-assets.mjs Outdated
Comment on lines +138 to +142
const SUBAGENT_RE = /subagent_type["']?\s*[:=]\s*["'`]([A-Za-z0-9_-]+)["'`]/g;
for (const skillPath of skillFiles) {
const body = readFileSync(skillPath, "utf8");
for (const match of body.matchAll(SUBAGENT_RE)) {
const name = match[1];

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

현재 SUBAGENT_RE 정규식은 subagent_type의 값이 반드시 따옴표나 백틱으로 감싸져 있을 때만 매칭됩니다. 만약 YAML 프론트매터나 마크다운 본문에서 따옴표 없이 subagent_type: general-purpose와 같이 작성된 경우 이를 감지하지 못할 수 있습니다.

또한, 열린 따옴표와 닫힌 따옴표의 종류가 일치하는지(balanced quotes) 검증하는 것이 더 안전합니다. 정규식의 캡처 그룹과 역참조(\1)를 활용하여 따옴표가 없거나 일치하는 쌍으로 감싸진 경우를 모두 지원하도록 개선할 수 있습니다.

Suggested change
const SUBAGENT_RE = /subagent_type["']?\s*[:=]\s*["'`]([A-Za-z0-9_-]+)["'`]/g;
for (const skillPath of skillFiles) {
const body = readFileSync(skillPath, "utf8");
for (const match of body.matchAll(SUBAGENT_RE)) {
const name = match[1];
const SUBAGENT_RE = /subagent_type["']?\\s*[:=]\\s*(["'`]?)([A-Za-z0-9_-]+)\\1/g;
for (const skillPath of skillFiles) {
const body = readFileSync(skillPath, "utf8");
for (const match of body.matchAll(SUBAGENT_RE)) {
const name = match[2];

@claude

claude Bot commented Jul 3, 2026

Copy link
Copy Markdown

Review: refactor/claude-skills-standardization

Scope: this PR touches only .claude/, .agents/, CLAUDE.md/AGENTS.md, .github/workflows/ci.yml, and adds one new script (scripts/check-claude-assets.mjs). No application source code (.ts/.astro) is changed, so most of the usual review dimensions (perf, XSS/SQLi, runtime behavior) don't really apply here — I focused on the one piece of real code, scripts/check-claude-assets.mjs, and on whether the documented invariants actually hold across the full .claude/ tree it now lints.

Verification performed

I couldn't execute node scripts/check-claude-assets.mjs directly in this review sandbox (the local working tree here had several PR-touched files reverted to their pre-PR content relative to HEAD, which is a sandbox artifact, not something in your PR). To compensate, I manually traced the script's five checks against git show HEAD:... for every file it scans:

  • Skill frontmatter (name/description/allowed-tools, name == dirname): checked all 7 skills (blog-writer, polish, polish-file, portfolio-strategy, resume-specialist, translate-writer, agents-md-optimizer) — all pass.
  • Agent frontmatter (name/description/model, name == filename, model ∈ {haiku,sonnet,opus}): checked all 13 non-backup agents — all pass, including ones this PR doesn't touch (portfolio-reviewer, portfolio-strategist, style-learner, translation-learner).
  • subagent_type wiring: every literal subagent_type: "x" reference (blog-writer → style-analyzer/content-writer/content-reviewer/style-learner, translate-writer → translation-style-analyzer/content-translator/translation-reviewer/translation-verifier/translation-learner, portfolio-strategy → portfolio-strategist/portfolio-reviewer) resolves to a real agent. The described P0 fix (blog-writer's general-purpose bypass) is genuinely gone in the merged content.
  • Path references: spot-checked the referenced .claude/skills/.../data/*.md, .../references/*.md, and .../data/samples/ targets mentioned in the diff — all exist in the tree.

So functionally this looks correct and should pass CI as written.

Minor findings (non-blocking)

  1. subagent_type detection has blind spots (scripts/check-claude-assets.mjs, the SUBAGENT_RE check). It only matches the literal subagent_type: "x" / subagent_type="x" syntax. Several skills invoke their core agent through prose instead — e.g. .claude/skills/polish/SKILL.md ("Task 도구로 polish-agent 에이전트를 호출") and .claude/skills/resume-specialist/SKILL.md ("Task 도구로 resume-specialist 에이전트를 호출") — so the "no general-purpose bypass" and "agent must exist" invariants this lint is meant to guard aren't actually enforced for those two skills. Not a regression from this PR (they were already written that way), and not a CI failure risk, but worth knowing the guarantee is partial rather than blanket across all 7 skills. Might be worth a follow-up to standardize invocation phrasing so the regex catches all of them.

  2. Path-reference check only scans two file sets (skills' top-level SKILL.md and .claude/agents/*.md), not the references/*.md files underneath each skill (translation-patterns.md, ask-user-templates.md, report-schema.md, review-rubric.md, etc.). None of those currently contain broken .claude/... references, but since this PR's whole point is "reference files are the source of truth other files point to," a broken link inside a reference file would silently pass today. Might be worth widening pathSources to skills/*/references/**/*.md in a follow-up.

  3. Frontmatter parser is single-line-value only (parseFrontmatter) — it treats any key: rest-of-line pattern as a new top-level key. Fine today since every description: in this repo is a single (very long) line, but if a future edit switches to YAML block-scalar style (description: > with wrapped continuation lines), continuation lines starting with word: could be misparsed as new keys. Low risk given current conventions, not something this PR needs to fix.

Things I liked

  • The script mirrors the style/structure of the existing scripts/check-agent-docs-sync.mjs closely (header comment format, repoRoot resolution via fileURLToPath, CRLF-safe line splitting) — good consistency with prior art.
  • CLAUDE.md/AGENTS.md mirror sync: diffed both files' new lines and they're identical outside the documented allowed divergences, so check-agent-docs-sync.mjs should still pass.
  • The pattern-numbering unification (translation-patterns.md as single source of truth, polish-agent.md's remapped subset) is a real fix for a genuine drift bug (chore(deps): Bump object-path from 0.11.4 to 0.11.5 #2/Add claude GitHub actions 1755585605153 #10 meaning different things in different files) — the "정본 번호 기록 규칙" callout with the wrong-number example (활용하다 → #8, not #10) is a nice touch for an LLM-executed agent prone to exactly that mistake.
  • No security concerns: the new script only reads paths derived from its own repo-relative constants and from committed markdown content (fully trusted, non-adversarial input) — no shell-out, no network I/O, no untrusted input crossing a trust boundary.

Test coverage

No dedicated test for the new script, but that matches the existing precedent (check-agent-docs-sync.mjs also has no separate test — the "test" is the CI run itself). Not a blocker.

Overall: solid, well-scoped refactor with real bug fixes and a reasonable regression-prevention lint. The two coverage gaps above (#1, #2) don't block merge — they're follow-up material if you want the lint's guarantees to be airtight rather than best-effort.

claude-review: subagent_type 정규식 사각지대 해소(polish/polish-file/resume-specialist의 프로즈형 호출을 명시적 표기로 통일), 경로 검사 대상에 skills/*/references/*.md 추가. gemini: frontmatter 값의 YAML 따옴표 제거, subagent_type 비따옴표 표기도 매칭하도록 정규식 확장.
@CaesiumY

CaesiumY commented Jul 3, 2026

Copy link
Copy Markdown
Owner Author

@claude 리뷰 피드백을 반영했습니다 (커밋 8158dbc). 재리뷰 부탁드립니다.

반영 내역:

  • [claude merge: Update to version2 #1] polish/polish-file/resume-specialist의 프로즈형 에이전트 호출을 명시적 subagent_type 표기로 통일 — 린트 정규식이 7개 스킬 전부를 커버하게 됨
  • [claude chore(deps): Bump object-path from 0.11.4 to 0.11.5 #2] 경로 실존 검사 대상에 skills//references/.md 추가
  • [gemini] frontmatter 값의 YAML 따옴표 제거 처리, subagent_type 비따옴표 표기 매칭 확장

@claude

claude Bot commented Jul 3, 2026

Copy link
Copy Markdown

Claude finished @CaesiumY's task in 4m 18s —— View job


재리뷰 완료 ✅

커밋 8158dbc를 검증했습니다. git show 8158dbc로 실제 반영 diff를 확인하고, .claude/skills/{polish-file,polish,resume-specialist}/SKILL.md의 HEAD 커밋 내용과 scripts/check-claude-assets.mjs 전체를 직접 대조했습니다. (참고: 이번 세션의 로컬 워킹트리도 지난 리뷰 때와 동일하게 PR 변경 파일 일부가 pre-PR 상태로 되돌아가 있는 샌드박스 아티팩트가 있어 git show HEAD:<path>로 우회 확인했습니다. node 스크립트 직접 실행은 이 세션 권한상 차단되어 있어, 대신 CI 결과와 코드 대조로 검증을 대체했습니다.)

  • 커밋 8158dbc 변경사항 확인
  • scripts/check-claude-assets.mjs 정규식/파서 수정 검증
  • SKILL.md 3개 프로즈형 → 명시적 subagent_type 표기 확인
  • 경로 검사 대상 확장(skills/*/references/*.md) 확인
  • CI 실행 결과로 check-claude-assets.mjs / check-agent-docs-sync.mjs 통과 확인
  • 최종 리뷰 작성

검증 결과

  1. [claude #1] subagent_type 정규식 사각지대polish-file, polish, resume-specialist 세 SKILL.md 모두 HEAD 기준 (subagent_type: "polish-agent") / (subagent_type: "resume-specialist") 형태로 바뀌어 있고, 새 정규식 /subagent_type["']?\s*[:=]\s*["']?([A-Za-z0-9_-]+)["']?/g가 정확히 매치함을 직접 트레이스로 확인했습니다. 나머지 4개 스킬(blog-writer, translate-writer, portfolio-strategy)은 이미 명시적 표기였고, agents-md-optimizer는 애초에 Task/subagent 호출이 없는 스킬이라 이 불변식과 무관합니다 — 결과적으로 서브에이전트를 호출하는 6개 스킬 전부가 이제 정규식으로 커버됩니다.
  2. [claude #2] 경로 검사 확장referenceFilesskillDirs에서 references/ 하위 .md로 수집해 pathSources에 추가한 로직을 확인했습니다. 실제로 report-schema.md에 있던 `.claude/polish-reports/[slug]-[timestamp].json`가 플레이스홀더 절단으로 .claude/polish-reports/까지만 매치되고, 이 디렉터리가 실존함을 확인했습니다(허위 실패 없음). translation-patterns.md, ask-user-templates.md에는 .claude/ 경로 언급 자체가 없어 영향 없음.
  3. [gemini] frontmatter 따옴표 제거parseFrontmatter가 값의 앞뒤가 동일한 따옴표 쌍일 때만 벗기도록 구현되어 있고(length >= 2 가드로 빈 값 오작동 방지), 실제로 저장소에 존재하는 agents-md-optimizer/SKILL.md의 따옴표로 감싼 description 값(내부에 작은따옴표 다수 포함)에 대입해봐도 올바르게 바깥쪽 큰따옴표만 벗겨짐을 확인했습니다.
  4. [gemini] subagent_type 비따옴표 매칭 — 정규식이 여는/닫는 따옴표를 각각 독립적으로 optional 처리하는 방식으로 구현되어, gemini가 제안한 백레퍼런스 방식(따옴표 종류 일치 강제)과는 약간 다릅니다. 다만 저장소 내 실제 사용 사례(따옴표 없음/큰따옴표/백틱)는 모두 열고 닫는 기호가 일치하는 형태뿐이라 현재는 동작에 차이가 없는 사소한 구현 차이입니다 — 논블로킹.

CI: Code standards & build (22) job이 이 커밋에서 success로 완료되어(check-claude-assets.mjs, check-agent-docs-sync.mjs, lint, format, build, E2E 포함), 스크립트 실행 결과로도 회귀 없음이 뒷받침됩니다.

이전 리뷰에서 지적했던 두 가지 논블로킹 항목(프로즈형 호출 커버리지, references/ 경로 검사)이 정확히 요청대로 해소되었고, gemini의 두 제안도 의도대로 반영되었습니다. 추가로 병합을 막을 문제는 발견하지 못했습니다.
· Branch

@CaesiumY CaesiumY merged commit 43df77a into main Jul 3, 2026
2 checks passed
@CaesiumY CaesiumY deleted the refactor/claude-skills-standardization branch July 3, 2026 12:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant