Loading lesson…
A CLI quiz app: Claude generates questions on any topic, you answer, it grades. Teaches prompts, loops, and keeping state.
A terminal script that asks for a topic, calls Claude to get 5 multiple-choice questions, asks them one at a time, tracks your score, and shows the final result. Real code, ~80 lines.
# pyproject.toml: anthropic, pydantic import json from pydantic import BaseModel, Field from anthropic import Anthropic class Question(BaseModel): prompt: str options: list[str] = Field(min_length=4, max_length=4) correct_index: int = Field(ge=0, le=3) explanation: str class QuizSet(BaseModel): topic: str questions: list[Question]Pydantic models define the exact shape we expect from the LLM.client = Anthropic() def generate_quiz(topic: str, n: int = 5) -> QuizSet: prompt = f"""Generate exactly {n} multiple-choice questions about: {topic} Return ONLY valid JSON, no markdown fence, matching this shape: {{ "topic": "", "questions": [ {{"prompt": "", "options": ["a","b","c","d"], "correct_index": 0, "explanation": ""}} ] }} Target middle-school difficulty. No trick questions.""" response = client.messages.create( model="claude-opus-4-7", max_tokens=2000, messages=[{"role": "user", "content": prompt}], ) raw = response.content[0].text.strip() if raw.startswith("```"): raw = raw.strip("`").split("\n", 1)[1].rsplit("\n", 1)[0] return QuizSet.model_validate_json(raw)One LLM call returns the whole quiz. Pydantic will reject malformed output.def run_quiz(quiz: QuizSet) -> int: score = 0 for i, q in enumerate(quiz.questions, start=1): print(f"\n--- Question {i}/{len(quiz.questions)} ---") print(q.prompt) for idx, opt in enumerate(q.options): print(f" {idx+1}. {opt}") while True: raw = input("Your answer (1-4): ").strip() if raw in {"1","2","3","4"}: break print("Please enter 1, 2, 3, or 4.") chosen = int(raw) - 1 if chosen == q.correct_index: print("Correct!") score += 1 else: correct = q.options[q.correct_index] print(f"Nope — answer was: {correct}") print(f"Why: {q.explanation}") return score def main(): topic = input("Topic? ").strip() or "the solar system" print(f"Generating quiz about {topic}") try: quiz = generate_quiz(topic) except Exception as e: print(f"Quiz generation failed: {e}") return final = run_quiz(quiz) print(f"\nFinal score: {final}/{len(quiz.questions)}") if __name__ == "__main__": main()The main loop: ask, validate input, score, report.| Ad-hoc JSON parse | Pydantic schema |
|---|---|
| Crashes on bad output | Raises ValidationError with field path |
| Easy to write | Slightly more setup |
| Good for: throwaway scripts | Good for: anything you run twice |
Big idea: an LLM + a typed schema + a simple loop is a stunningly powerful base for any interactive tool. You've now built the skeleton every AI tutor app shares.
8 questions · take it digitally for instant feedback at tendril.neural-forge.io/learn/quiz/end-prog-python-quiz-bot-builders
What is the main idea of "Build It: Terminal Quiz Bot Powered by Claude"?
Which concept is most central to "Build It: Terminal Quiz Bot Powered by Claude"?
Which use of AI fits this topic best?
What should a careful learner remember about "Why a Pydantic schema matters"?
You want to use AI after this lesson. What is the safest next step?
How should AI output about CLI be treated?
Name one way to verify an AI answer about CLI.
Which action would help you apply "Build It: Terminal Quiz Bot Powered by Claude" responsibly?