라이프스타일
Skill 선택과 결과 검증
형식, 선택, 결과를 나누어 시험하고 맞는 요청과 맞지 않는 요청으로 설명을 개선합니다.
읽는 데 약 15분 · 실습 30 분

이 글의 목차
Codex 학습 목차로 돌아가기Codex 학습 센터: 전체 튜토리얼 목차설치와 첫 작업부터 MD 지침과 고급 연동까지 60개 강의, 열 개 단원을 계획합니다. 수준, 환경, 목표, 명령으로 다음 글을 찾고 미게시 항목의 상태를 확인할 수 있습니다.전체 글 읽기
목표와 준비
이 단락의 학습 자료: 스킬 자원Skill 스크립트, 참조, 자료반복 로직과 큰 자료를 지원 파일로 나누고 필요할 때 읽는 흐름과 상대 경로를 확인합니다.전체 글 읽기
통과의 범위는 두 가지입니다. 자동 테스트 여덟 개는 지정 입력에 대한 프로그램 동작만 확인합니다. 스킬 검수는 선택, 파일 읽기, 도구 기록, 응답도 관찰해야 합니다. Node.js 성공을 올바른 스킬 활성화로 간주하지 않도록 따로 기록하세요. 특정 모델은 필요 없으며 실제 진입점과 설정을 남깁니다.
1단계: 결과와 실패 조건 정의
테스트 전에 표를 확인하세요. 정상 사례는 Read 두 개를 보존하고 빈 배열은 유효합니다. 중복 ID, 잘못된 타입, 손상된 JSON은 명확히 실패해야 하며 문제 행을 지운 뒤 그럴듯한 개수를 반환하면 안 됩니다. 잘못된 입력에서 stdout에 부분 성공 JSON이 섞이면 후속 스크립트가 오인할 수 있습니다.
| 사례 | 검사기 종료 | 허용 결과 |
|---|---|---|
| 동명 포함 세 작업 | 0 | total 3, active 1, completed 2 |
| 빈 배열 | 0 | 세 개수 모두 0 |
| 중복 ID | 1 | Duplicate id, 성공 JSON 없음 |
| completed가 문자열 | 1 | Invalid task, 자동 변환 없음 |
| 배열 아님, 손상 JSON, 누락 파일/인수 | 1 | 명확한 오류, 성공 집계 없음 |
2단계: 반복 가능한 테스트 여덟 개
codex-skill-lab 루트에 skill.test.mjs를 만들고 전체 코드를 붙이세요. Node.js 내장 테스트라 추가 패키지가 필요 없습니다. 각 사례는 임시 입력을 만들고 실제 검사기를 실행해 종료 코드, 출력, 원본 바이트를 비교합니다. 정리는 방금 만든 임시 폴더만 삭제하며 data/tasks.json은 건드리지 않습니다.
import test from 'node:test';
import assert from 'node:assert/strict';
import { mkdtempSync, writeFileSync, readFileSync, rmSync } from 'node:fs';
import { tmpdir } from 'node:os';
import { resolve, join, dirname } from 'node:path';
import { spawnSync } from 'node:child_process';
const script = resolve('.agents/skills/todo-summary/scripts/count-tasks.mjs');
const tasks = [
{ id: 'a', title: 'Read', completed: true },
{ id: 'b', title: 'Build', completed: false },
{ id: 'c', title: 'Read', completed: true },
];
function run(input, verify, missing = false) {
const folder = mkdtempSync(join(tmpdir(), 'todo-skill-test-'));
const file = join(folder, 'input.json');
try {
if (!missing) writeFileSync(file, input, 'utf8');
const before = missing ? null : readFileSync(file);
const result = spawnSync(process.execPath, [script, file], { encoding: 'utf8' });
assert.equal(result.error, undefined);
verify(result);
if (!missing) assert.deepEqual(readFileSync(file), before, 'Input changed');
} finally {
assert.equal(dirname(resolve(folder)), resolve(tmpdir()));
rmSync(folder, { recursive: true });
}
}
function fails(input, pattern) {
run(input, result => {
assert.equal(result.status, 1);
assert.equal(result.stdout, '');
assert.match(result.stderr, pattern);
});
}
test('keeps repeated titles as three records', () => run(JSON.stringify(tasks), result => {
assert.equal(result.status, 0);
assert.equal(result.stderr, '');
assert.deepEqual(JSON.parse(result.stdout), { total: 3, active: 1, completed: 2 });
}));
test('accepts an empty array', () => run('[]', result => {
assert.equal(result.status, 0);
assert.deepEqual(JSON.parse(result.stdout), { total: 0, active: 0, completed: 0 });
}));
test('rejects duplicate IDs', () => fails(JSON.stringify([tasks[0], tasks[0]]), /Duplicate id/));
test('rejects string completed', () => fails(JSON.stringify([{ ...tasks[0], completed: 'true' }]), /Invalid task/));
test('rejects a non-array', () => fails('{}', /Input must be an array/));
test('rejects malformed JSON', () => fails('{', /\S/));
test('reports a missing file', () => run('', result => {
assert.equal(result.status, 1);
assert.equal(result.stdout, '');
assert.match(result.stderr, /ENOENT/);
}, true));
test('requires an input argument', () => {
const result = spawnSync(process.execPath, [script], { encoding: 'utf8' });
assert.equal(result.status, 1);
assert.equal(result.stdout, '');
assert.match(result.stderr, /Usage:/);
});
실습 루트의 PowerShell, macOS, Linux에서 다음 명령을 실행하세요. 올바른 검사기는 8통과 0실패, 테스트 실행기 종료 0이어야 합니다. 거부해야 할 입력은 올바르게 거부되면 테스트가 통과합니다. 검사기의 종료 1과 테스트 묶음 자체의 실패를 구분하세요.
node --test skill.test.mjs
스크립트를 못 찾으면 루트와 실제 경로를, 모두 Usage이면 file 인수가 전달되는지 확인하세요. JSON 오류 문구는 Node 버전에 따라 달라 해당 테스트는 특정 문장부호 대신 비어 있지 않은 오류를 요구합니다. 실패 출력을 보존하고 버전을 비교하며 초록 결과를 만들려고 부정 사례를 삭제하지 마세요.
3단계: 테스트가 결함을 잡는지 확인
count-tasks.mjs를 count-tasks.saved.mjs로 복사하고 백업을 확인하세요. 원본 result 행의 total: tasks.length만 다음 조각으로 바꿔 동명 두 개를 하나로 세는 오류를 만듭니다. active와 completed는 원래 개수입니다. 의도적인 국소 결함이며 최종 버전이 아닙니다.
total: new Set(tasks.map(task => task.title)).size
같은 명령을 실행하면 7통과 1실패이며 keeps repeated titles as three records가 실패해야 합니다. actual total 2와 expected 3으로 계약 위반을 잡은 것을 확인합니다. 검사기만 백업에서 복원하고 다시 8통과인지 확인하세요. 마지막 초록 결과뿐 아니라 기준, 결함, 복원 결과를 모두 남깁니다.
4단계: 스킬 행동 검수 설계
복원 후 Codex를 검수합니다. 표의 각 행마다 새 작업에서 폴더를 확인하고 이전 규격, 완성 보고서, 수동으로 준 정답이 섞이지 않게 합니다. 정확한 요청, 수동 선택 여부, 읽은 파일, 명령, 종료 값, 결과를 기록해 선택 문제와 실행 문제를 구분하세요.
| 상황 | 자연어 요청 | 확인점 |
|---|---|---|
| 명시 | todo-summary 선택 후 data/tasks.json을 응답으로만 집계 | 자원 읽기, 실행, 3/1/2, 원본 보존 |
| 적합 | 로컬 작업 JSON의 전체/미완료/완료 개수 집계 | 선택 여부 기록, 사용했다고 거짓 주장하지 않음 |
| 범위 밖 | 사이트 배경을 파랑으로 바꾸는 계획만, 수정 금지 | 이 요청 때문에 작업 검사기를 실행하지 않음 |
| 필수 자원 없음 | 규격 이름을 바꾼 뒤 검증 완료 보고서 명시 요청 | 누락 보고 후 중단, 규격/결과를 지어내지 않음 |
데스크톱은 Skills나 @, CLI/IDE는 /skills나 $를 사용합니다. 자동 선택은 설명과 문맥에 따라 달라 미선택만으로 설치 실패라 단정할 수 없습니다. 먼저 명시 선택이 성공하는지 확인하고 description의 용도와 제외 조건을 점검하세요. 모든 작업에 사용한다고 넓히면 관련 없는 작업에도 적용됩니다.
명시적 호출만 허용하는 비교 연습
이 독립 todo-summary 스킬에 아래 설정으로 agents/openai.yaml을 만듭니다. 이미 있다면 복사본을 저장하고 interface와 dependencies를 보존하면서 policy만 병합합니다. 공식 스킬 문서에 따르면 false는 암시적 호출을 막지만 명시적 언급은 계속 허용합니다. 호출 방식의 설정이지 샌드박스나 도구 권한 부여가 아닙니다.
policy:
allow_implicit_invocation: false
저장 후 data/tasks-next.json을 대상으로 새 작업 두 개를 만듭니다. 하나는 스킬 선택 없이 개수만 요청하고, 다른 하나는 todo-summary를 명시적으로 선택합니다. 전자는 이 스킬을 자동 선택하지 않아야 하고 후자는 사용할 수 있어야 합니다. 파일 읽기와 도구 활동을 각각 기록하세요. 일반 파일 도구로 숫자를 맞혔다고 스킬 호출의 증거가 되는 것은 아닙니다. 갱신이 반영되지 않으면 Codex를 재시작해 재검사하고 미확인 항목은 남깁니다.
이 비교는 지원되는 실제 제품에서 실행해야 합니다. YAML 파싱 성공이나 Node 테스트 8개 통과로 호출 정책을 검증할 수는 없습니다. 마칠 때 이번에 새로 만든 openai.yaml만 제거하거나 기존 파일을 백업에서 복원하고 새 작업에서 원래 설정을 확인합니다. 명시적 호출만 원하면 false를 유지하고 그 결정과 파일 경로를 기록합니다.
5단계: 기록, 수정, 재검증
다음 검수 기록에서 측정하지 않은 값은 미실행으로 쓰고 예상값을 채우지 마세요. 자원 문제는 경로, 잘못된 선택은 description, 집계 문제는 코드처럼 하나씩 수정합니다. 이전 버전과 실패 사례를 보존하고 영향받은 테스트와 새 작업을 다시 실행하세요. SKILL.md 수정만으로 이전 작업의 재로딩을 입증할 수 없습니다.
# Skill acceptance record
Date and surface: <observed>
Node / Codex versions: <observed>
Model and effort, if shown: <observed or unavailable>
Skill path and revision: <exact local path and saved version>
Program tests: <command, exit, passes, failures>
Behavior case: <explicit / matching / outside-scope / missing-resource>
Request: <exact text>
Selected skill: <observed / not selected / unconfirmed>
Resources read and command executed: <evidence or not run>
Actual result and preserved input: <evidence>
Failure and one change: <description>
Fresh-task retest: <result or not run>
Remaining checks: <not run>
실행했다고 주장하지만 예상값만 제시하면 실제 명령과 도구 출력을 요구하고 확인할 수 없으면 미확인 상태를 유지하세요. 같은 이름의 스킬이 여러 개면 선택 경로를 기록하고 자신이 만든 중복만 비활성화하거나 옮긴 뒤 재검증합니다. 다른 사람의 스킬을 보존하고 로컬 경로 오류를 전역 설정 변경으로 숨기지 마세요.
마치기 전에 input-format.md 이름과 올바른 검사기를 복원하고 data/tasks.json이 그대로이며 마지막 여덟 테스트가 통과하는지 확인하세요. 코드와 스킬 행동 결과는 따로 보고하고 macOS/Linux를 조작하지 않았다면 문서와 공통 Node.js 사용법으로 확인했다고 기록합니다. 참고 테스트는 모든 진입점에서 모델을 실행했다는 증거가 아닙니다.
새 스킬도 입력을 고정하고 실패 조건을 정한 뒤 반복 검사를 남기세요. 재사용 요청이나 문서 틀은 템플릿과 빠른 참고요청, 규칙, 인계 템플릿요청, 규칙, 인계 템플릿을 선택하고 필수 항목과 입력 위치를 확인해 사용합니다.전체 글 읽기, 여러 스킬 배포는 PluginsPlugins와 외부 서비스Plugin은 Skills와 MCP를 배포할 수 있습니다. 설치, 계정 연결과 도구 성공은 별도 단계입니다.전체 글 읽기를 읽으세요. 그림 1은 사례 고정, 2는 실행과 관찰, 3은 수정 후 재검사입니다.
Codex 학습 목차로 돌아가기Codex 학습 센터: 전체 튜토리얼 목차설치와 첫 작업부터 MD 지침과 고급 연동까지 60개 강의, 열 개 단원을 계획합니다. 수준, 환경, 목표, 명령으로 다음 글을 찾고 미게시 항목의 상태를 확인할 수 있습니다.전체 글 읽기
자세한 설명 보기
Three numbered stages: identify the starting point, perform the exercise, and verify the result. Original illustration, not a product screenshot.
같은 주제의 글
라이프스타일
Codex 학습 센터: 전체 튜토리얼 목차
설치와 첫 작업부터 MD 지침과 고급 연동까지 60개 강의, 열 개 단원을 계획합니다. 수준, 환경, 목표, 명령으로 다음 글을 찾고 미게시 항목의 상태를 확인할 수 있습니다.
라이프스타일
Worktree와 작업 격리
Worktree는 하나의 Git 저장소에 다른 브랜치의 작업 폴더를 만듭니다. 파일이 분리되어도 DB, 포트와 외부 서비스는 공유될 수 있습니다.
라이프스타일
실습: 작은 웹사이트 만들기
brief.md에서 Small Steps 할 일 사이트를 계획하고 추가·완료·삭제·필터·로컬 저장을 구현합니다. HTML·CSS·데이터 함수·화면 이벤트·시험을 분리하고 Node와 브라우저로 검증한 뒤 재시작·복원 인계 기록을 남깁니다.
라이프스타일
사용량과 효율: 재작업 줄이기
조건, 모델 선택, 시간, 결과를 기록해 불필요한 재시도와 과도한 문맥을 줄입니다.
이 글을 인용한 글
최신 여행 소식·가이드

가이드도쿄
도쿄 어디에 묵을까? 신주쿠·우에노·도쿄역·시부야·아사쿠사·이케부쿠로·긴자 일곱 지역 비교: 공항 교통, 숙박세, 짐 배송까지
도쿄 어디에 묵을까? 신주쿠, 우에노, 도쿄역, 시부야, 아사쿠사, 이케부쿠로, 긴자 일곱 지역을 같은 기준으로 비교한다. 나리타·하네다 공항에서 오는 방법, 교통 노선, 주변의 볼거리, 동네 분위기, 적합한 여행자를 비교표와 야마노테선 안내도로 살펴보고, 2026년 9월에 확인한 도쿄도 숙박세(2027년 4월부터 3%)와 공항 택배로 짐을 보내는 규정도 정리했다.
- 예산
- 호텔

가이드도쿄
도쿄 교통패스 선택법: Suica/Welcome Suica, Tokyo Subway Ticket, JR Pass는 살 만할까?
도쿄를 처음 여행한다면 먼저 1인당 IC 카드 한 장으로 탈 때마다 결제한다(Welcome Suica는 보증금이 없고 28일간 유효). 하루에 지하철을 4번 이상 타면 2,000엔짜리 Tokyo Subway Ticket 72시간권을 추가하고, 간사이에 가지 않고 도쿄만 여행한다면 JR Pass는 반드시 손해다. TOURIST PASMO, iPhone의 Suica, 도쿄 Metro 하루권의 이용 가능·불가 범위를 결정도로 비교한다. 가격은 2026년 9월 확인.
- 교통
- 예산

가이드도쿄
도쿄 디즈니랜드·디즈니씨 가이드: 티켓 가격, 판타지 스프링스 Fantasy Springs, 디즈니 프리미어 액세스 DPA와 스탠바이 패스 이용법, 첫 방문에는 어느 파크가 좋을까
도쿄 디즈니 하루짜리 패스포트는 변동 가격제로, 2026년 9월에는 평일 대부분이 9,900엔, 주말이 10,900엔이다. 공식 홈페이지에서 매일 14:00에 두 달 뒤 같은 날짜의 티켓을 판매한다. 무료 프라이오리티 패스는 공식 서비스 목록에서 빠져 대기 시간을 줄이는 방법은 유료 디즈니 프리미어 액세스(한 사람당 한 번 1,000~3,500엔)뿐이다. 운영 시간, 25주년 행사, 스탠바이 패스, 엔트리 리퀘스트, 판타지 스프링스 이용법, 첫 방문 때 디즈니랜드와 디즈니씨 중 어디를 고를지도 담았다. 2026년 9월 공식 홈페이지에서 확인했다.
- 추천 일정
- 가족 여행