Community코딩 & 개발github.com

erikvallow-qt/dont-let-me-slide

문제 해결 후 AI가 세션을 복습하고, 인간과 AI를 위한 교훈을 기록하고, 사용자에게 핵심 포인트 퀴즈를 제공합니다.

dont-let-me-slide란 무엇인가요?

이 스킬은 AI가 사용자와 함께 문제를 해결한 후, 해당 세션을 체계적으로 복습하고 학습 내용을 구조화된 문서로 정리하여 장기 기억을 강화하도록 설계되었습니다. 최근 대화 내역에서 문제 해결 세션을 식별하고, 전체 대화를 분석하여 인간과 AI가 각각 놓친 부분이나 사용자가 어려워했던 개념을 파악합니다. 그런 다음 공식 문서나 권위 있는 자료를 웹 검색하여 각 교훈에 대한 검증된 참고 링크를 찾고, LEARNED.md 파일에 상세한 교훈과 함께 제안된 원샷 프롬프트를 작성합니다. 또한 Python 표준 라이브러리만 사용하는 퀴즈 프로그램(learned_quiz.py)을 생성하여 터미널에서 플래시카드 리뷰, 주제별 필터링 등 다양한 방식으로 학습 내용을 복습할 수 있도록 합니다. 이 스킬은 Claude Code, Cursor, Codex 등 다양한 AI 에이전트 플랫폼에서 실행 가능하며, 템플릿 기반의 일관된 출력과 코드 품질 검사를 보장합니다.

지원 대상~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/erikvallow-qt/dont-let-me-slide/tree/HEAD/dont-let-me-slide

Installed? Explore more 코딩 & 개발 skills: steipete/bluebubbles, steipete/eightctl, steipete/blucli · View all 6 →

즐겨 사용하는 AI에게 물어보기

이 에이전트 스킬이 미리 로드된 새 채팅을 엽니다.

문서

세션 복습: don't let me slide

문제를 해결한 세션을 복습하세요. 다음 두 파일을 제공합니다: LEARNED.md와 learned_quiz.py (터미널 퀴즈).

  1. 세션 식별 최근 대화를 사용하여 문제와 일치하는 대화를 찾으세요. 두 개 이상의 대화가 가능성이 있으면 사용자에게 선택을 요청하세요. 세션이 프로젝트에 속한 경우 해당 프로젝트의 다른 대화도 함께 검토하세요.

  2. 전체 세션 읽기 요약만 읽지 말고 전체를 읽으세요. 문제가 해결되기 전에 인간과 AI가 각각 놓친 부분을 기록하세요. 또한 사용자가 신뢰해야 했거나, 두 번 이상 질문했거나, 잘못 이해한 개념을 기록하세요: 이런 개념은 더 깊이 있는 탐구가 필요합니다.

  3. 쓰기 전에 링크 조사 모든 교훈에 대해 최소한 하나의 링크를 찾으세요. 각 인간 교훈과 2단계의 모든 개념에 대해 1~3개의 심층 탐구 링크를 찾아 기본 원리부터 배경을 설명하는 자료를 연결하세요. 우선 순위는: 공식 문서 또는 사양, 벤더 애플리케이션 노트 또는 매뉴얼, 잘 알려진 튜토리얼 또는 교과서, 그 다음 평판 좋은 블로그 또는 Q&A입니다. WebSearch를 사용한 후 각 링크를 WebFetch로 열어 링크가 로드되고 해당 내용을 다루는지 확인하세요. 실패하거나 주제에서 벗어난 링크는 버리세요. URL을 절대 임의로 만들지 마세요.

  4. LEARNED.md 작성 다음 섹션을 이 순서대로 작성하세요:

    • What happened: 3~5문장과 상태(해결됨 또는 해결되지 않음). 해결되지 않은 경우 열린 항목을 나열하세요.
    • Lessons learned: Human, AI, Shared로 구분하세요. 각 교훈에 대해 요점, 놓친 부분, 한 문장으로 된 교훈, 링크(출처 명시)를 제공하세요. 배경 설명이 필요한 각 인간 교훈 아래에 "Deeper dive" 하위 목록을 추가하세요: 각 항목은 제목, 출처, 그리고 그것이 무엇을 가르치고 여기서 어떻게 도움이 되는지에 대한 한 줄 설명입니다.
    • Test questions: 3~5개의 핵심 질문을 "Test questions" 제목 아래에 작성하고, 답안 키를 추가하세요. 전체 질문 세트는 learned_quiz.py에 있음을 명시하세요.
    • Links: 사용된 모든 링크를 교훈별로 그룹화하고 출처를 명시하세요. 링크가 실행일에 확인되었으며 사용 전에 다시 확인해야 한다고 명시하세요.
    • Suggested one-shot prompt: 이 세션의 문제를 방지할 수 있었던 간결한 한 번의 프롬프트를 제시하세요.
  5. 주장 표시 검증되지 않은 주장은 검증되지 않음으로 표시하세요. 검색 결과에서 가져온 주장은 보고됨으로 표시하고 출처를 링크하세요.

  6. 추측을 결과로 제시하지 마세요 문제의 원인이 확인되지 않은 경우 그렇게 말하세요.

  7. learned_quiz.py 작성 아래 템플릿을 사용하세요. 규칙:

    • Python 3 표준 라이브러리만 사용하세요. macOS, Linux, Windows 터미널에서 실행 가능해야 합니다. GUI는 없습니다.
    • 모든 개념을 다루세요. 35개의 테스트 질문뿐만 아니라: 각 Human 교훈당 최소 2개 질문, 각 AI 및 Shared 교훈당 최소 1개 질문, 각 심층 탐구 개념당 1개 질문. 일반적으로 1025개 질문입니다. 회상, "무엇을 먼저 확인하겠습니까?", "실수 찾기" 유형의 질문을 혼합하세요.
    • 각 질문: 주제(Human, AI, Shared 또는 짧은 개념 이름), 그럴듯한 방해 요소가 있는 4개의 선택지, 정답 인덱스, 1~2문장의 이유, 가장 관련성 높은 검증된 링크.
    • TITLE, SOURCE, QUESTIONS만 채우세요. 엔진은 변경하지 마세요.
    • 보내기 전에 python3 -c "import ast,sys;ast.parse(open(sys.argv[1]).read())" learned_quiz.py를 실행한 다음 python3 learned_quiz.py --list를 실행하고 오류를 수정하세요. 모든 답변 인덱스가 올바른 선택지를 가리키는지 확인하세요.
  8. LEARNED.md를 간결하게 유지하세요 두 파일 모두에서 em 대시를 사용하지 마세요.

  9. SendUserFile로 두 파일 모두 보내기 답변에 실행 명령을 제공하세요: python3 learned_quiz.py (옵션: -r 플래시카드 리뷰, -t TOPIC 필터, -n N 제한, --list 모두 출력, --seed N 고정 순서).

퀴즈 템플릿 (정확히 복사하고, 플레이스홀더와 예제 질문만 교체하세요):

#!/usr/bin/env python3
"""LEARNED quiz: <TOPIC>. Run: python3 learned_quiz.py [-r] [-t TOPIC] [-n N] [--list]"""
import argparse, random, sys, textwrap

TITLE = "<TOPIC>"
SOURCE = "LEARNED.md, <DATE>"
QUESTIONS = [
    {"topic": "Human", "q": "예제 질문?",
     "choices": ["정답", "오답 1", "오답 2", "오답 3"], "answer": 0,
     "why": "이유를 한두 문장으로.", "link": "https://example.com"},
]

def wrap(s, ind="   "):
    return textwrap.fill(s, 78, initial_indent=ind, subsequent_indent=ind)

def ask(prompt, valid):
    while True:
        try:
            a = input(prompt).strip().lower()
        except (EOFError, KeyboardInterrupt):
            print(); sys.exit(0)
        if a in valid:
            return a

def run(qs, review):
    missed = []
    for i, q in enumerate(qs, 1):
        order = list(range(len(q["choices"])))
        random.shuffle(order)
        letters = "abcdefgh"[:len(order)]
        print(f"\n[{i}/{len(qs)}] ({q['topic']})")
        print(wrap(q["q"], ""))
        for L, idx in zip(letters, order):
            print(wrap(f"{L}) {q['choices'][idx]}"))
        right = letters[order.index(q["answer"])]
        if review:
            if ask("   Enter to reveal, q to quit: ", {"", "q"}) == "q":
                sys.exit(0)
            ok = True
        else:
            a = ask(f"   Answer [{letters}], q to quit: ", set(letters) | {"q"})
            if a == "q":
                break
            ok = a == right
            print("   Correct." if ok else f"   Not quite. Answer: {right}")
        if review or not ok:
            print(wrap(f"{right}) {q['choices'][q['answer']]}"))
        print(wrap(q["why"]))
        if q.get("link"):
            print(wrap("More: " + q["link"]))
        if not ok:
            missed.append(q)
    return missed

def main():
    p = argparse.ArgumentParser(description=f"Quiz: {TITLE}")
    p.add_argument("-r", "--review", action="store_true", help="flashcard mode, no scoring")
    p.add_argument("-t", "--topic", help="only this topic (Human, AI, Shared, ...)")
    p.add_argument("-n", type=int, help="ask at most N questions")
    p.add_argument("--list", action="store_true", help="print all Q&A and exit")
    p.add_argument("--seed", type=int, help="fixed shuffle")
    a = p.parse_args()
    random.seed(a.seed)
    qs = [q for q in QUESTIONS if not a.topic or q["topic"].lower() == a.topic.lower()]
    if not qs:
        sys.exit(f"No questions for topic {a.topic!r}.")
    if a.list:
        for i, q in enumerate(qs, 1):
            print(f"{i}. ({q['topic']}) {q['q']}\n{wrap('A: ' + q['choices'][q['answer']])}\n{wrap(q['why'])}")
            if q.get("link"):
                print(wrap("More: " + q["link"]))
        return
    random.shuffle(qs)
    qs = qs[:a.n] if a.n else qs
    print(f"{TITLE}\nSource: {SOURCE}\n{len(qs)} questions.")
    while qs:
        missed = run(qs, a.review)
        if a.review:
            break
        print(f"\nScore: {len(qs) - len(missed)}/{len(qs)}")
        if not missed or ask("Retry missed? [y/n]: ", {"y", "n"}) == "n":
            for q in missed:
                print(wrap(f"Review: {q['q']}", "- ") + ("\n" + wrap(q["link"]) if q.get("link") else ""))
            break
        qs = missed

if __name__ == "__main__":
    main()

관련 스킬