prisma-client-api (prisma/skills)
Prisma Client의 쿼리, 필터, 연산자, 메서드를 CRUD, 관계, 트랜잭션 기준으로 참고합니다.
prisma-client-api: 측정 가능한 효과 없음. 18회 실행 모두 모든 검사를 통과했습니다(대조군 5.0, 한 문장 프롬프트 5.0, 스킬 5.0). 모델이 이미 Prisma다운 코드를 작성합니다
Codex CLI · gpt-6-astra
24.0 / 30
스킬 없이 대비 향상폭: +0.00 · 상황에 따라 · 18회 실행
상황에 따라: 향상폭 +0.00가 +1.0 미만. 추천이 되려면 총점 22/30, 출력 품질 3.5, 향상폭 +1.0이 필요합니다.
SOTA
통과Codex로 테스트
커버 대상 Codex, Claude Code
Codex CLI 0.166 (SOTA 티어): 채점된 실행 18회. 여기서 통과하면 티어 규칙에 따라 Claude Code도 커버되지만, 두 번째 티어에 대해서는 아무것도 말해주지 않습니다.
점수
각 차원은 0~5점이며 여섯 차원을 더하면 30점 만점의 총점이 됩니다. 모든 차원에서 5가 가장 좋습니다. 비용 5는 저렴하고 빠름, 설치 5는 쉬움을 뜻합니다.
- 트리거 신뢰도
- 5.0
- 스킬 없이 대비 향상폭
- 2.0
- 출력 품질
- 5.0
- 토큰 및 시간 비용
- 5.0
- 설치 및 이식성
- 3.0
- 안전성
- 4.0
보안 리뷰
안전정적 스캔: CRITICAL 9 / HIGH 9 / MEDIUM 0. 수동 검토: 네트워크가 차단된 샌드박스에서 실행 안전(스캐너 지적 사항은 설명됨). 스캔이 깨끗하다고 해서 스킬이 안전하다는 증거는 아닙니다.
설치
npx skills@latest add prisma/skills --skill prisma-client-api
고정 커밋: 8ea289b730c2e89f7ff1f518af128b113d842a92
테스트일: 2026-11-02
테스트한 과제
- 설명에서 타입 지정 쿼리 작성 — Prisma Client를 사용해 src/queries.ts에 다음 함수를 작성하세요. getUserWithPosts(id)는 사용자와 그 사용자의 게시글 중 게시된 것만 최신순으로 최대 10개를 반환합니다. searchPosts(term, cursor?)는 커서 페이지네이션(페이지 크기 20) 방식의 대소문자 무시 제목 검색입니다. upsertUser(…
- N+1 쿼리 제거 — src/report.ts가 큰 테이블에서 느립니다. src/report.ts의 성능 문제를 고치되 반환 형태는 그대로 유지하세요.
- Prisma 코드에서 실수 검토 — src/search.ts와 src/report.ts에서 Prisma 실수와 위험한 부분을 검토하세요. 문제를 심각한 것부터 나열하세요. 파일은 수정하지 마세요.
장점
- 스킬 이름을 언급하지 않았는데도 적용되었습니다. 스킬 사용군 실행 6/6회에서 스킬 파일을 읽었습니다.
- 토큰 오버헤드 없음: 스킬 없이의 1.05배 토큰을 사용합니다.
- 스킬 사용 시 높은 절대 품질: 5.0/5.
단점
- 스킬 없이보다 측정 가능한 향상 없음(+0.00, 노이즈 범위 안).
- 한 문장 프롬프트는 5.0점, 스킬 사용은 5.0점(+0.00).
- 대조군이 이미 5.0점입니다. 천장 효과 때문에 이 테스트로는 향상을 보여줄 수 없습니다.
- 과제·그룹당 n=2이며, 약 1점 미만의 차이는 노이즈입니다.
리뷰
Codex CLI 0.166 (gpt-6-astra, low reasoning)을 전용 Windows 테스트 PC에서 실행했고, 실행마다 새 임시 프로젝트와 임시 HOME/TMPDIR/캐시를 사용했습니다. 스킬 설치(스킬 사용군), 미설치(대조군), 미설치 상태에서 스킬의 핵심 요구사항만 한 문장으로 압축해 프롬프트에 덧붙인 경우(한 문장 프롬프트군)로 나눴으며, 과제·그룹당 2회씩 실행했습니다. 네트워크는 끄고 /tmp 쓰기는 차단했습니다. 프롬프트에는 스킬 이름을 언급하지 않았습니다(아래에 적은 경우 제외). 작은 Prisma 프로젝트(schema, seed, src 파일)를 준비했습니다. 과제는 src/queries.ts에 타입 지정 쿼리 함수 다섯 개 작성(게시된 최근 게시글 10개와 함께 사용자 조회, 커서 페이지네이션 대소문자 무시 검색, upsert, 게시글의 원자적 이전, groupBy 카운트), 출력 형태를 유지한 채 src/report.ts의 N+1 수정, 두 파일에서 Prisma 실수 검토(문자열 보간으로 만든 원시 쿼리 등)입니다. 프롬프트에는 Prisma 기능 이름을 쓰지 않았습니다. 한 문장 프롬프트는 Prisma에서 권장하는 패턴들을 한 문장으로 나열합니다.
3개 그룹 비교
| 그룹 | 평균 점수 (0-5) | 실행당 토큰 |
|---|---|---|
| 스킬 없음 | 5.0 | 92k |
| 한 문장 프롬프트 | 5.0 | 88k |
| 스킬 사용 | 5.0 | 97k |
Codex CLI에서 18회 실행해 측정했고, LLM 심사 없이 규칙 기반 검사로 채점했습니다. 총점 24.0 / 30, 판정 상황에 따라.
판정: 상황에 따라 다름 (24.0 / 30). 출처: prisma/skills, prisma-client-api, 커밋 8ea289b에 고정. 설치: npx skills@latest add prisma/skills --skill prisma-client-api. 라이선스: Apache-2.0(저장소 LICENSE).
무엇인가
prisma-client-api 스킬(prisma/skills)은 Prisma Client 쿼리 API(findUnique/findMany, select/include, 필터, 커서 페이지네이션, upsert, 트랜잭션, groupBy, 원시 쿼리)를 다루는 레퍼런스와 문서 스타일 지침을 SKILL.md와 규칙 파일로 제공합니다.
테스트 방법
전용 Windows 테스트 PC에서 Codex CLI 0.166(gpt-6-astra, 낮은 추론)을 실행했고, 실행마다 새 임시 프로젝트와 임시 HOME/TMPDIR/캐시를 사용했습니다. 스킬을 설치한 경우(스킬 사용군), 설치하지 않은 경우(대조군), 스킬 없이 스킬의 핵심 요구사항을 한 문장으로 압축해 프롬프트 끝에 붙인 경우(한 문장 프롬프트군)로 나눴고, 작업마다 각 군 2회씩 실행했습니다. 네트워크는 끄고 /tmp 쓰기는 차단했습니다. 프롬프트에는 스킬 이름을 전혀 언급하지 않았습니다(아래에 적은 표현은 예외).
작은 Prisma 프로젝트(schema, seed, src 파일)를 준비했습니다. 작업: 타입이 지정된 쿼리 함수 5개가 담긴 src/queries.ts 작성(사용자와 마지막 게시글 10개, 커서 페이지네이션을 쓰는 대소문자 무시 검색, upsert, 게시글의 원자적 이전, groupBy 카운트), src/report.ts의 N+1을 출력 형태를 유지한 채 수정, 두 파일에서 Prisma 실수(문자열 보간으로 만든 원시 쿼리 등) 리뷰. 프롬프트는 Prisma 기능을 이름으로 언급하지 않습니다. 한 문장 프롬프트는 관용적 기능을 한 문장으로 나열합니다.
- 설명으로 타입 지정 쿼리 작성 — Prisma Client를 사용해 다음 함수를 담은 src/queries.ts를 작성하세요: getUserWithPosts(id)는 사용자와 그 사용자의 게시글만, 최신순, 최대 10개 반환; searchPosts(term, cursor?)는 커서 페이지네이션(페이지 크기 20)을 쓰는 대소문자 무시 제목 검색; upsertUser(…
- N+1 쿼리 제거 — src/report.ts는 큰 테이블에서 느립니다. src/report.ts의 성능 문제를 고치고 반환 형태는 그대로 유지하세요.
- Prisma 코드의 실수 리뷰 — src/search.ts와 src/report.ts에서 Prisma 실수와 위험한 부분을 리뷰하고, 문제를 가장 심각한 것부터 나열하세요. 어떤 파일도 변경하지 마세요.
채점은 프로그램 방식(숨은 테스트, 심어 둔 문제 탐지, 제약 조건 검사, 해당되는 경우 렌더링+OCR)으로 실행당 0~5점입니다. 점수를 결정한 LLM 심사자는 없습니다.
결과
세 번째 군에 전달한 한 문장 프롬프트: "Prisma Client를 관용적으로 사용하세요: 고유 필드에는 findUnique, N+1과 과다 조회를 피하려면 include/select, 필터에는 mode: 'insensitive', 페이지네이션은 take를 쓰는 커서 방식, 삽입 또는 갱신에는 upsert, 원자적 변경에는 $transaction 또는 updateMany, 집계에는 groupBy, 그리고 보간된 입력으로 $queryRawUnsafe를 절대 쓰지 마세요."
| 작업 | 대조군 점수 | 한 문장 프롬프트 | 스킬 사용 | 대조군 토큰 | 한 문장 프롬프트 토큰 | 스킬 사용 토큰 | 스킬 읽음 |
|---|---|---|---|---|---|---|---|
| t1-queries | 5.0 | 5.0 | 5.0 | 83k | 83k | 105k | 2/2 |
| t2-n-plus-1 | 5.0 | 5.0 | 5.0 | 103k | 103k | 100k | 2/2 |
| t3-review | 5.0 | 5.0 | 5.0 | 89k | 75k | 84k | 2/2 |
평균 점수: 스킬 없음 5.0, 스킬 사용 5.0(차이 +0.0). 실행당 토큰: 92k 대 97k(1.05배), 시간: 44초 대 40초. 한 문장 프롬프트 군: 5.0(한 문장 프롬프트 대비 스킬의 이득 +0.0, 스킬 없음 대비 한 문장 프롬프트의 이득 +0.0). 한 문장 프롬프트의 실행당 토큰은 88k이므로 스킬은 한 문장 프롬프트의 1.10배 비용을 씁니다.
무슨 일이 있었나
- 모든 군의 모든 실행이 모든 검사를 통과했습니다. 대조군 5.00, 한 문장 5.00, 스킬 5.00(각 n=6). 생성된 쿼리는 findUnique,
mode: 'insensitive', cursor + take, upsert, $transaction/updateMany, groupBy를 사용했습니다. N+1은 include/select 또는 배치 처리로 고쳤고, 리뷰는 모든 실행에서 안전하지 않은 원시 쿼리 보간을 찾아냈습니다. - 스킬은 6/6회 스킬 사용 실행에서 읽혔고, 실행당 97k 토큰으로 대조군 92k, 한 문장 88k(1.05배) 대비 약간의 오버헤드만 있었고 이득은 없었습니다.
- 스킬 사용 실행은 스킬의 규칙 파일을 프로젝트로 복사합니다(실행당 평균 9.7개).
- 검사 집합에는 천장 효과가 있습니다. 모든 실행이 최고점이면 스킬이 해를 끼치지 않았다는 것만 말할 수 있고, 도움이 되지 않는다고는 말할 수 없습니다. 이득을 찾으려면 더 어려운 작업(Prisma 7 드라이버 어댑터, 모델이 모를 수 있는 최신 기능)이 필요합니다.
항목별 점수
| 항목 | 점수 | 근거 |
|---|---|---|
| 1. 출력 품질 | 5.0 | 스킬 사용 시 평균 5.00/5(프로그램 검사, 작업별 표 참조). |
| 2. 스킬 없음 대비 향상 | 2.0 | 스킬 없음 5.00 대비 +0.00점(작업당 n=2, 약 1점 미만은 노이즈). |
| 3. 트리거 | 5.0 | 스킬 사용군 6/6회 실행에서 스킬 파일을 읽었습니다. |
| 4. 지침 이식성 | 3 | SKILL.md와 규칙 파일 약 10개. 문서만 포함합니다. |
| 5. 효율성 | 5 | 토큰 1.05배(실행당 97k 대 92k), 시간 0.92배(40초 대 44초). |
| 6. 안전성·위생 | 4 | 스캐너가 CRITICAL 9를 보고했으며, 모두 문서에서
|
이 테스트의 한계
- 코드 텍스트에 대한 규칙 기반 검사. Prisma 클라이언트를 생성하지 않았고 쿼리도 실행하지 않았습니다(오프라인, 데이터베이스 없음).
- 모든 군이 천장에 닿았습니다. 이 작업들은 기본 모델이 이미 아는 기초적인 관용 Prisma를 측정합니다.
- 셀당 n=2. 최신 API 지식(문서형 스킬이 가장 더할 가능성이 큰 부분)은 다루지 않았습니다.
- 작업·군당 n = 2: 약 1점 미만의 차이는 노이즈입니다.
- 규칙 기반 채점은 검사가 볼 수 있는 것만 측정합니다. 취향이나 결과가 최선인지는 판단할 수 없습니다.
보안
security.md를 참조하세요. 스캔: CRITICAL 9 / HIGH 9 / MEDIUM 0. 판정: 실행해도 안전(네트워크 차단 샌드박스). 깨끗한 스캔 결과가 스킬의 안전성을 증명하지는 않습니다.
결론
일상적인 Prisma Client 작업에서는 순수 Codex도 이미 정확하므로, 이 스킬은 여기서 눈에 보이는 변화 없이 약간의 토큰 비용만 더합니다. 이 테스트가 다루지 않은 아주 새로운 Prisma 기능에서는 의미가 있을 수 있습니다.
트랜스크립트
실행 로그: prisma-client-api (Codex CLI, network off, per-run temp HOME/TMPDIR, one row per graded run.) 열: 작업, 그룹-회차, 점수(0-5), 토큰, 초, 통과한 검사, 에이전트가 연 스킬 파일. t1-queries control-1: 점수 5.0, 토큰 84040, 초 35.0, 검사 7/7, 연 파일 없음 t1-queries control-2: 점수 5.0, 토큰 83803, 초 36.4, 검사 7/7, 연 파일 없음 t1-queries oneliner-1: 점수 5.0, 토큰 83731, 초 38.4, 검사 7/7, 연 파일 없음 t1-queries oneliner-2: 점수 5.0, 토큰 83779, 초 38.1, 검사 7/7, 연 파일 없음 t1-queries treatment-1: 점수 5.0, 토큰 110031, 초 39.9, 검사 7/7, 연 파일 prisma-client-api t1-queries treatment-2: 점수 5.0, 토큰 100691, 초 36.8, 검사 7/7, 연 파일 prisma-client-api t2-n-plus-1 control-1: 점수 5.0, 토큰 103258, 초 57.7, 검사 3/3, 연 파일 없음 t2-n-plus-1 control-2: 점수 5.0, 토큰 103374, 초 54.2, 검사 3/3, 연 파일 없음 t2-n-plus-1 oneliner-1: 점수 5.0, 토큰 103307, 초 51.8, 검사 3/3, 연 파일 없음
18회 실행, 아티팩트 3개
샘플 출력
SOTA · With the skill: src/queries.ts (t1-queries, run 1, Codex)
import { prisma } from "./db"; export function getUserWithPosts(id: number) { return prisma.user.findUnique({ where: { id }, include: { posts: { where: { published: true }, orderBy: [{ createdAt: "desc" }, { id: "desc" }], take: 10, }, }, }); } // Pass the last post's id as the cursor for the next page. export function searchPosts(term: string, cursor?: number) { return prisma.post.findMany({ where: { title: { contains: term, mode: "insensitive" } }, orderBy: { id: "asc" }, take: 20, ...(cursor !== undefined ? { cursor: { id: cursor }, skip: 1 } : {}), }); } export function upsertUser(email: string, name: string | null) { return prisma.user.upsert({ where: { email }, update: { name }, create: { email, name }, }); } // Returns { count } with the number of posts transferred. export function transferPosts(fromId: number, toId: number) { return prisma.$transaction(async (tx) => { await tx.user.findUniqueOrThrow({ where: { id: fromId } }); await tx.user.findUniqueOrThrow({ where: { id: toId } }); return tx.post.updateMany({ where: { authorId: fromId }, data: { authorId: toId }, }); }); } // Includes authors with posts; each row has { authorId, _count: { _all } }. export function postCountsByAuthor() { return prisma.post.groupBy({ by: ["authorId"], _count: { _all: true }, orderBy: { authorId: "asc" }, }); }