fos-blog/study
01 / 홈02 / 카테고리03 / 시리즈
01 / 홈02 / 카테고리03 / 시리즈

카테고리

  • AI 페이지로 이동
    • RAG 페이지로 이동
    • agent 페이지로 이동
    • claude-code 페이지로 이동
    • harness 페이지로 이동
    • llm 페이지로 이동
    • ops 페이지로 이동
    • practice 페이지로 이동
  • algorithm 페이지로 이동
    • Alias Method: 가중치 랜덤 선택을 전처리 O(n), 추출 O(1)로 바꾸기
    • Welford's Online Algorithm: 값을 저장하지 않고 평균과 분산 계산하기
  • architecture 페이지로 이동
    • distributed-systems 페이지로 이동
    • domain 페이지로 이동
    • evolution 페이지로 이동
    • patterns 페이지로 이동
  • database 페이지로 이동
    • milvus 페이지로 이동
    • mysql 페이지로 이동
    • opensearch 페이지로 이동
    • qdrant 페이지로 이동
    • redis 페이지로 이동
    • vespa 페이지로 이동
    • DB Connection Pool Saturation과 Thread Pool 격리
    • 커넥션 풀 크기는 얼마나 조정해야 할까?
    • MyBatis 기본기 — XML Mapper, resultMap, 동적 SQL, 운영 패턴 정리
    • MyBatis와 JPA/Hibernate 트레이드오프 — 레거시 백엔드를 다루는 시니어 관점
    • 한국어 형태소 분석기 Nori vs Lindera — OpenSearch에서 Milvus로 갈 때 어휘 검색은 유지되나
    • 정규화와 역정규화: 무결성과 조회 비용 사이의 선택
    • 벡터 DB 5종, 아키텍처는 어떻게 다른가
    • 벡터 DB 5종을 실제로 벤치마크했다 — 같은 recall에서 QPS는 얼마나 갈리나
    • 벡터 DB 어떻게 고를까 — OpenSearch · Milvus · Qdrant · Vespa · pgvector 비교
    • 벡터 DB를 실제로 도입한 사례 — 빅테크 프로덕션
  • devops 페이지로 이동
    • docker 페이지로 이동
    • k8s 페이지로 이동
    • Envoy Proxy
    • Graceful Shutdown
    • 종료 신호는 어디서 멈추는가
  • http 페이지로 이동
    • HTTP Connection Pool
    • HTTPS와 TLS: 핸드셰이크, 인증서, 종료 지점
  • java 페이지로 이동
    • concurrency 페이지로 이동
    • jdbc 페이지로 이동
    • spring 페이지로 이동
    • spring-batch 페이지로 이동
    • testing 페이지로 이동
    • Java 동시성 락 정리 — 커머스 메뉴/프로모션 정책 캐시 갱신 관점
    • JVM 튜닝 실전: 메모리 구조부터 Virtual Threads, GC 튜닝, 프로파일링까지
    • 로그에 traceId 남기기 — MDC 부터 OpenTelemetry 까지
    • Java StampedLock — 읽기 폭주에도 쓰기가 밀리지 않는 락
    • Virtual Thread와 Project Loom
  • javascript 페이지로 이동
    • typescript 페이지로 이동
    • AbortController
    • Async Iterator와 제너레이터
    • CommonJS와 ECMAScript Modules
    • 제너레이터(Generator)
    • Http Client
    • Node 백엔드 운영 패턴 — Streams 백프레셔, pipe/pipeline, 멱등성 vs 분산 락
    • Node.js
    • `setImmediate()`
  • kafka 페이지로 이동
    • Kafka 클러스터 아키텍처: Broker, KRaft Controller와 복제
    • Kafka 기본 개념: Topic, Partition, Offset과 Segment
    • Kafka 실전 설계: 파티션 전략, 컨슈머 그룹, 전달 보장, 재시도, 순서 보장 트레이드오프
    • Kafka 파티션·리밸런스·컨슈머 지연 운영
    • Kafka를 로그로 이해하기: 복제, 재처리, 상태와 데이터 통합
    • Spring Kafka 컨슈머 오프셋 커밋과 트랜잭션 정렬: AckMode, manual ack, 멱등 처리
  • linux 페이지로 이동
    • fsync — 리눅스 파일 동기화 시스템 콜
    • SSH forced command 로 배포 키가 실행할 수 있는 명령 제한하기
  • mlops 페이지로 이동
    • llm-serving 페이지로 이동
    • model-router 페이지로 이동
    • Python CUDA 버전 생태계 — nvidia-smi, nvcc, pip, conda가 다 다른 버전을 말하는 이유
    • GPU 컨테이너의 CUDA 버전 호환성 — nvidia-smi부터 이미지 다이어트까지
    • Kubernetes GPU 노드에서 /run tmpfs가 꽉 차서 Pod가 안 뜰 때
    • GPU·CUDA·MPS 기초 — 자바 백엔드 개발자가 처음 만나는 그림
    • Multi-process GPU 워크로드 — 자바 ThreadPool 사용자가 만나는 모델 차이
    • ML 서비스 성능 분석 워크플로 — 자바 백엔드 트러블슈팅과 다른 점
    • 한 GPU 를 여러 프로세스가 나눠 쓰기 — Time-Slicing 과 MPS
  • network 페이지로 이동
    • Connection reset by peer는 누가 보낸 걸까 — 리버스 프록시 홉마다 TCP 연결은 따로 논다
    • L2(스위치)와 L3(라우터)의 역할 차이
    • L4와 VIP(Virtual IP Address)
    • IP Subnet
  • observability 페이지로 이동
    • Observability 입문: 시니어 백엔드가 장애를 탐지하고 대응하는 방식
    • K8s 위 Spring Boot 앱의 메트릭 수집
  • python 페이지로 이동
    • Python async/await — CompletableFuture·Reactor 와 다른 점, 그리고 blocking I/O 함정
    • Python 의존성 관리 — Java Maven/Gradle 사용자가 만나는 첫 충격
    • FastAPI 기초 — Spring Boot 사용자가 빠르게 익히는 법
    • Java 개발자를 위한 Python 심화 — OOP·데코레이터·컨텍스트 매니저
    • PyTorch 기초 — 텐서, 디바이스, 그리고 모델 로딩이 무거운 이유
    • Java 개발자를 위한 Python 문법 핵심
    • ThreadLocal 에서 contextvars 로 — Python 의 요청 컨텍스트 전파
    • OCR 동작 원리 — Layout · Text · Post-process 3단계
    • Python 서버의 RSS가 줄지 않는 이유: CPython, gc.collect(), malloc_trim
  • rabbitmq 페이지로 이동
    • RabbitMQ Basics — 실전 백엔드 관점에서 정리하는 메시지 브로커 기본기
    • RabbitMQ vs Kafka — 백엔드 메시징 선택 기준과 실전 운영 관점
  • resume 페이지로 이동
    • 경험 및 경력기술서
    • 김병태 경력기술서
    • 김병태 포트폴리오
  • task 페이지로 이동
    • ai-service-team 페이지로 이동
    • nsc-slot 페이지로 이동
    • sb-dev-team 페이지로 이동
    • the-future-company 페이지로 이동
  • thinking 페이지로 이동
    • 자기주도 학습: 질문에서 시작해 글로 검증하기
    • 좋은 일을 넘어 중요한 일을 하는 법
FOS-BLOG · FOOTERall systems normal·v0.1 · 2026.04.27·seoul, kr
Ffos-blog/study

개발 학습 기록을 정리하는 블로그입니다. 공부하면서 기록하고, 기록하면서 다시 배웁니다.

visitors
01site
  • Home↗
  • Posts↗
  • Categories↗
  • Glossary↗
  • About↗
02policy
  • 소개/about
  • 개인정보처리방침/privacy
  • 연락처/contact
03categories
  • AI↗
  • Algorithm↗
  • DB↗
  • DevOps↗
  • Java/Spring↗
  • JS/TS↗
  • React↗
  • Next.js↗
  • System↗
04connect
  • GitHub@jon890↗
  • Source repositoryjon890/fos-study↗
  • RSS feed/rss.xml↗
  • Newsletter매주 1 회 · 한 편의 글→
© 2026 FOS Study. All posts MIT-licensed.
built with·Next.js·Tailwind v4·Geist·Pretendard·oklch
fos-blog/AI/스킬 문서는 반복 실행을 스크립트로 내리고 …
ai

스킬 문서는 반복 실행을 스크립트로 내리고 같은 지시를 한 곳에서만 소유하게 쓴다

스킬을 오래 쓰다 보면 SKILL.md 는 두 방향으로 부푼다. 매 실행마다 같은 셸 레시피가 본문에 들어 있고, 같은 규칙이 여러 절에 조금씩 다른 말로 반복된다. 이 글은 Claude Code 스킬 시스템에서 소개한 스킬 문서를 오래 유지하기 위한 두 가지 원칙을 정리한다. 하나는 반복 실행을 스크립트로 내리는 것이고, 다른 하나는 같은 지시를 한 곳에...

2026.10.02·6 min read·14 views

스킬을 오래 쓰다 보면 SKILL.md 는 두 방향으로 부푼다. 매 실행마다 같은 셸 레시피가 본문에 들어 있고, 같은 규칙이 여러 절에 조금씩 다른 말로 반복된다. 이 글은 Claude Code 스킬 시스템에서 소개한 스킬 문서를 오래 유지하기 위한 두 가지 원칙을 정리한다. 하나는 반복 실행을 스크립트로 내리는 것이고, 다른 하나는 같은 지시를 한 곳에서만 소유하게 하는 것이다.

사례는 모두 공개 저장소 fos-skills의 커밋 이력에서 가져왔다.

실행 코드는 scripts 에, 판단 문맥은 SKILL.md 에

자동화에는 성격이 다른 두 자산이 있다. 하나는 결정적으로 반복할 수 있는 실행이고, 다른 하나는 에이전트가 읽고 판단해야 하는 문맥이다. 두 자산을 서로 다른 파일에 두면 각자 따로 검토하고 고칠 수 있다.

자산맡는 일위치
반복 실행수집, 변환, 검증, 게시처럼 결정적으로 반복할 동작scripts/
판단 문맥언제 스크립트를 쓰고 어떤 근거로 분기할지SKILL.md
행동 경계워크스페이스 전체의 규칙과 문서 진입점AGENTS.md
데이터 구조와 되돌리기 어려운 결정결정의 이유와 최종 상태docs 와 ADR

분리하면 얻는 것은 네 가지다.

  • 에이전트가 긴 코드를 매번 다시 만들지 않고 같은 실행을 재사용한다.
  • 명령 구현을 바꿔도 판단 기준과 사용자 흐름을 독립적으로 검토할 수 있다.
  • 같은 지시를 여러 스킬에 복제해서 생기는 어긋남(drift)이 줄어든다.
  • 스크립트의 종료 코드와 산출물을 테스트할 수 있어, 자연어 지시보다 강한 검증 경계가 생긴다.

사례: 본문에 있던 셸 레시피를 스크립트로 내린다

fos-skills 의 docs-check 스킬은 2026-07-27 에 정적 검사를 별도 스크립트로 분리했다. 커밋 메시지가 적은 이유는 이렇다. SKILL.md 본문에 25줄짜리 셸 레시피 세 개가 들어 있어서, 모델이 매 실행마다 코드를 다시 옮겨 적었다는 것이다. 그 저장소의 스킬 작성 규칙은 다섯 줄을 넘고 매 실행마다 반복되는 코드는 분리하라고 정한다.

분리하는 과정에서 결함이 두 건 드러났고 함께 고쳤다.

  • 코드 스팬 안의 ~/path 를 취소선으로 오탐했다. 코드 블록과 코드 스팬을 검사에서 제외하도록 고쳤다.
  • grep -nP 는 기본 BSD grep 에서 지원되지 않아 공용 코어에 맞지 않았다. PCRE 없이 리터럴 매칭으로 바꿨다.

본문에 적혀 있을 때는 실행할 때마다 달라질 수 있는 코드였으므로 이런 결함이 드러나기 어려웠다. 스크립트로 내리자 한 번 고치면 모든 실행에 반영된다. 현재 이 검사는 docs-check/scripts/static_check.py 와 docs-check/tests/test_static_check.py 로 존재한다.

같은 판단은 다른 스킬에도 적용된다. planning 스킬이 어느 하위 프로젝트의 오버레이를 읽을지 정하는 규칙은 문서에 순서가 적혀 있고, 같은 순서를 scripts/overlay_paths.py 가 그대로 실행한다. 종료 코드가 0 이면 대상을 정했다는 뜻이고, 1 이면 사용자에게 물어야 하며, 2 이면 실행하지 못했다는 뜻이다. 문서는 종료 코드의 뜻과 그에 따른 행동만 설명하고, 판정 자체는 스크립트가 맡는다.

같은 지시는 한 곳에서만 소유한다

스킬 문서는 시간이 지나며 절이 늘어난다. 새 절을 추가하면서 기존 절의 내용을 요약해 다시 적으면 같은 규칙이 두 곳에 존재한다. 한쪽만 고치면 다른 쪽이 낡은 채 남고, 문서가 스스로 모순된다. 어느 쪽이 맞는지는 실행 시점에 판단이 갈린다.

판정 기준

  • 소유자를 정한다. 두 절이 같은 내용을 담고 있으면 더 구체적으로 다루는 쪽(절차 절이나 하위 reference)을 소유자로 정한다. 핵심 원칙 같은 상위 요약에서는 지운다. "통과 조건은 절차 절이 단일 소스다" 처럼 소유권을 밝히는 한 줄이 중복을 막는다.
  • 자기소개도 대상이다. "이 스킬은 공용 코어다" 같은 소개가 README 나 description 에 이미 있으면 본문 첫머리의 소개는 지운다.
  • 모델이 이미 아는 내용은 적을 값이 없다. git 의 기본 동작이나 자명한 도구 동작은 지시로 적지 않는다.
  • 끊긴 참조를 만들지 않는다. 소유자를 옮길 때 다른 곳이 그 절의 이름을 참조하고 있으면, 참조를 먼저 떼거나 그 줄이 혼자 읽히도록 흡수한 뒤에 지운다.
  • 옮긴 뒤에 내용이 그대로인지 확인한다. 절을 옮기거나 합칠 때 변경 전후를 정렬해 비교하면 내용은 그대로이고 위치만 바뀐 것인지 확인할 수 있다.

사례: 소유자를 지키는 정리 커밋

fos-skills 의 이력에는 이런 정리가 반복된다. content-preview 스킬은 2026-09-22 에 자기를 부르는 쪽의 이름을 적은 문장을 지웠다. 공용 스킬이라 어느 저장소에서 받았는지에 따라 부르는 쪽이 없을 수 있기 때문이다. 커밋 메시지의 기준은 "누가 가리키는지가 아니라 무엇을 소유하는지만 적는다" 였다. 같은 커밋은 스크립트의 동작을 다시 설명하던 한 줄도 지웠다. 바로 다음 줄이 그 스크립트가 소유한다고 말하고, 아래 출력 표가 이미 다루기 때문이다.

2026-09-21 에는 harness-cleanup 스킬의 조건부 절차를 참조 문서로 내렸다. 저장소 밖에서 돌릴 때만 필요한 절차가 불릿 하나 안에 25줄로 들어 있어서 매 실행마다 컨텍스트를 차지했기 때문이다. 본문에는 발동 조건과 읽을 경로만 남겼다.

옮기는 과정에서 지시가 빠질 수 있다

단일 소유권으로 정리하는 일에는 위험이 있다. 앞의 참조 문서 이동에서 읽기 전용 검토자가 지시 하나가 유실된 것을 찾았다. "상대경로가 어느 디렉터리를 전제하는지 함께 본다" 는 문장이 옮기는 과정에서 사라졌고, 뒤쪽에서 그것을 되짚던 "위에서 요구한" 이 가리킬 곳을 잃었다. 이 문장을 원래 절에 되돌리고, 되짚는 문장이 그 절의 이름을 부르게 고쳤다.

그래서 옮긴 뒤에는 작성자가 아닌 쪽이 읽어 확인한다. 옮긴 사람은 내용이 그대로라고 믿고 있어서 유실을 잘 보지 못한다.

스킬 사이에서도 소유권이 있다

소유권은 스킬 사이에도 적용된다. fos-skills 에서 두 스킬이 다른 스킬 번들에 있는 파일 경로를 자기 번들의 파일처럼 적은 일이 있었다. 끊긴 참조를 세는 검사기를 처음 만들자마자 이 결함이 잡혔다. 이 검사기는 아래 「스킬 문서 자체를 채점하기」 에서 다룬다.

스킬 문서 자체를 채점하기

스킬 문서가 나아졌는지 알려면 기준이 고정돼 있어야 한다. 기준값 없이 고치면 개선 여부를 나중에 측정할 수 없다. 문서의 품질은 기계로 셀 수 있는 축과 판단이 필요한 축으로 나눠서, 축마다 담당 도구를 다르게 둔다.

축담당재현성예
기계축스크립트항상 같은 값본문 줄 수, 끊긴 참조 수, 표기 위반 수
판단축독립 검토 에이전트한 점 안팎으로 흔들림지침 정렬, 강제력, 참조 무결성, 계층 분리

판단축은 작성자가 직접 매기지 않는다. 자기 산출물을 자기가 채점하면 후하게 나오기 때문이다. 채점은 작성과 다른 세션이나 에이전트가 한다.

사례: 기준점을 먼저 남기고 검사기가 첫 실행에서 결함을 찾는다

fos-skills 는 2026-07-27 에 이 구조로 채점 도구를 넣었다. 커밋 메시지는 도입 이유를 기준점 없이 고쳐 와서 개선 여부를 소급 측정할 수 없었던 것으로 적는다. 스크립트는 본문 분량, 끊긴 참조, 표기 위반을 세고, 채점표는 판단축 네 가지를 0점에서 3점으로 매겼다.

구조를 바꾸기 직전에 기준값을 남겨 두면 변경 뒤 줄 수가 달라졌을 때 지시 내용이 바뀐 것인지 순수한 이동인지 구분할 수 있다. 끊긴 참조 검사는 만들자마자 앞 절의 결함, 즉 다른 스킬 번들의 파일을 자기 번들 경로처럼 적은 두 곳을 찾았다.

소비하는 곳이 없으면 제거한다

이 채점 도구는 같은 저장소에서 2026-09-04 에 제거됐다. 커밋 메시지가 적은 이유는 누적 점수를 소비하는 곳이 없었다는 것이다. 점수를 보고 무언가를 바꾸는 사용처가 없으면 채점 도구는 유지할 값이 없다. 같은 판단이 하네스 회고는 새 문서로 쌓지 않고 종류에 맞는 기존 단일 소스에 환원한다에도 나온다.

정리

상황대응
본문에 다섯 줄이 넘는 셸 레시피가 매 실행마다 반복된다scripts/ 로 내리고 본문에는 종료 코드의 뜻과 행동만 둔다
같은 규칙이 두 절에 있다더 구체적인 절을 소유자로 두고 상위 요약에서 지운다
다른 스킬이 소유한 것을 설명하고 싶다설명을 다시 적지 않고 소유자를 가리킨다
절을 옮기거나 합쳤다작성자가 아닌 쪽이 지시가 유실되지 않았는지 확인한다
문서가 나아졌는지 알고 싶다기준값을 먼저 남기고, 기계축은 스크립트로, 판단축은 작성자가 아닌 쪽이 매긴다
on this page
  • 01실행 코드는 scripts 에, 판단 문맥은 SKILL.md 에
  • 사례: 본문에 있던 셸 레시피를 스크립트로 내린다
  • 02같은 지시는 한 곳에서만 소유한다
  • 판정 기준
  • 사례: 소유자를 지키는 정리 커밋
  • 옮기는 과정에서 지시가 빠질 수 있다
  • 스킬 사이에서도 소유권이 있다
  • 03스킬 문서 자체를 채점하기
  • 사례: 기준점을 먼저 남기고 검사기가 첫 실행에서 결함을 찾는다
  • 소비하는 곳이 없으면 제거한다
  • 04정리
tags
#study#insights

이런 글도

  • ai

    하네스 회고는 새 문서로 쌓지 않고 종류에 맞는 기존 단일 소스에 환원한다

    2026.10.02
  • ai

    에이전트가 배운 회피 패턴은 조건을 통과한 것만 파일로 쌓고 주기적으로 지운다

    2026.10.02
  • ai

    ADR 은 되돌리기 어려운 결정의 이유만 남기고, 대안 기각은 옵션마다 줄을 나눈다

    2026.10.02
  • ai

    여러 저장소가 쓰는 스킬은 도메인 중립 코어와 저장소별 오버레이로 나눈다

    2026.10.02

댓글 (0)