CommunityCoding & Developmentgithub.com

erikvallow-qt/dont-let-me-slide

Run after fixing a problem with AI to review the session, log lessons learned for the human and the AI, and quiz the user on the key points.

What is dont-let-me-slide?

dont-let-me-slide is a Claude Code agent skill that run after fixing a problem with AI to review the session, log lessons learned for the human and the AI, and quiz the user on the key points.

Works with~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 Coding & Development skills: steipete/bluebubbles, steipete/eightctl, steipete/blucli · View all 6 →

Ask in your favorite AI

Open a new chat with this agent skill pre-loaded.

Documentation

Review the session that solved the problem. Deliver two files: LEARNED.md and learned_quiz.py (a terminal quiz).

  1. Identify the session. Use recent chats to find the chat that matches the problem. If more than one is plausible, ask the user which one. If the session belongs to a project, also review the other chats in that project.
  2. Read the whole session, not only a summary. Note where the human and the AI each missed something before the problem was resolved. Also note concepts the human had to take on faith, asked about more than once, or got wrong: these need a deeper dive.
  3. Research links before writing. For every lesson find at least one link. For each Human lesson, and any concept from step 2, find 1 to 3 deeper-dive links that explain the background from first principles. Prefer, in order: official docs or specs, vendor app notes or manuals, well-known tutorials or textbooks, then reputable blogs or Q&A. Use WebSearch, then open each link with WebFetch to confirm it loads and covers the point. Drop any link that fails or is off topic. Never invent a URL.
  4. Write LEARNED.md with these sections, in this order:
    • What happened: 3 to 5 sentences, plus the status (resolved or not). If not resolved, list the open items.
    • Lessons learned: split into Human, AI, and Shared. For each lesson give the point, what was missed, the lesson in one sentence, and a Link (source named). Under each Human lesson that needs background, add a "Deeper dive" sub-list: each entry is Title, the source, and one line on what it teaches and why it helps here.
    • Test questions: 3 to 5 key questions titled "Test questions", followed by an answer key. Note that the full question set is in learned_quiz.py.
    • Links: every link used, grouped by lesson, with the source named. State that links were checked on the run date and should be verified before use.
    • Suggested one-shot prompt: one concise prompt that would have avoided the issues in this session.
  5. Label claims. Mark unverified claims as unverified. Mark claims taken from search results as reported, and link the source.
  6. Do not present guesses as findings. If the cause of a problem was not confirmed, say so.
  7. Write learned_quiz.py from the template below. Rules:
    • Python 3 standard library only. Must run on macOS, Linux, and Windows terminals. No GUI.
    • Cover every concept, not just the 3 to 5 test questions: at least 2 questions per Human lesson, at least 1 per AI and Shared lesson, plus 1 per deeper-dive concept. Typically 10 to 25 questions. Mix recall, "what would you check first", and "spot the mistake" questions.
    • Each question: topic (Human, AI, Shared, or a short concept name), 4 choices with plausible distractors, the correct index, a 1 to 2 sentence why, and the most relevant verified link.
    • Fill TITLE, SOURCE, and QUESTIONS only. Do not change the engine.
    • Before sending, run python3 -c "import ast,sys;ast.parse(open(sys.argv[1]).read())" learned_quiz.py, then python3 learned_quiz.py --list, and fix any error. Check every answer index points at the right choice.
  8. Keep LEARNED.md concise. Do not use em dashes in either file.
  9. Send both files with SendUserFile. In the reply give the run command: python3 learned_quiz.py (options: -r flashcard review, -t TOPIC filter, -n N limit, --list print all, --seed N fixed order).

Quiz template (copy exactly, replace the placeholders and the example question):

#!/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": "Example question?",
     "choices": ["Right answer", "Wrong 1", "Wrong 2", "Wrong 3"], "answer": 0,
     "why": "One or two sentences on 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()

Related Skills