What you’ll leave with
A chapter-sized study plan, a checked concept map, and a before-and-after exercise you can score yourself.
Before you begin. Node.js 22+, npm, a supported provider API key, and an EPUB or tagged PDF you may send to that provider. This walkthrough was researched, not executed. The independent SQL check needs Python 3 with its standard sqlite3 module; it makes no model request.
What the documentation establishes
Tutor turns supplied books into a concept-based course. Its model writes lessons and grades answers. Source ↗
Chapter previews write review files without changing the database; they still make billable model requests. Source ↗
The walkthrough below is an original worked exercise. We have not independently tested this product’s performance.
A tutor is useful when it exposes a misunderstanding while you still have time to fix it. A long explanation can feel productive even when you cannot solve the next problem. This exercise starts with a prediction, uses the chapter to investigate mistakes, and ends with a different problem that cannot be answered by repeating the first example.
Tutor creates a course from material you supply and uses your chosen model to teach and grade. The application setup comes from its documentation; the SQL fixture and answer checker below are original and run separately. We have not installed Tutor or evaluated its model-generated lessons.
1. Choose one thing you want to do without help
For the first session, choose a short chapter about SQL grouping. Write this objective before opening a lesson: given a small table, I can explain how filtering rows before aggregation differs from filtering grouped results. If your chapter covers another subject, keep the structure of the exercise and replace the example.
Limit the session to three concepts: row filtering, grouping, and aggregate filtering. Exclude joins, window functions, indexing, and performance tuning for now. Those topics are valuable, but they make it difficult to tell which misconception caused a wrong answer. Keep a page or section reference next to each concept in your own notes.
Topic: row filters versus group filters
Time box: 30 minutes, plus a five-minute check tomorrow
Starting evidence: one prediction written before any hints
Source boundary: one chapter; write the edition and section references
Success: explain the intermediate rows and solve a changed example
Stop: source text is missing, costs exceed my limit, or feedback contradicts the chapter
Record: my answer, the feedback, the source, and the correction2. Prepare the project and inspect one chapter
In a new folder, clone the linked repository, enter tutor, run npm install, and copy .env.example to .env. These are documented setup instructions, not commands executed in this review. Keep the key in that local file. Provider requests are billable and send the selected book text to that provider.
LLM_PROVIDER=openrouter
LLM_MODEL=REPLACE_WITH_EXACT_VENDOR_MODEL_ID
OPENROUTER_API_KEY=REPLACE_IN_LOCAL_ENV_ONLY
LLM_REASONING=Replace the model placeholder with an available OpenRouter model identifier of the form vendor/model; this is configuration, not a runnable default. Leave optional reasoning and routing preferences unset for the first check. Run npm run llm:check, which sends three small model requests. Proceed only if those requests succeed. A 401 suggests a key/account problem; an unknown-model error means the configured identifier or access needs correction. Check the provider usage before expanding the trial.
npm run parse -- /path/to/book.epubReplace the path and inspect one definition, one code sample and one table in the extracted chapter. Start the app with npm start and open http://localhost:3000. Create subject SQL, choose Add a book, select the book and one chapter, then Preview. Check the displayed request count before starting. Preview uses the model but does not commit the course. If its concepts match the chapter, choose Save these chapters. If extraction drops an operator or table column, fix that source problem first.
Use the three concepts from section 1; exclude unrelated material. A valid model connection does not prove that its teaching or grading is correct. The next exercise gives you an independent answer check.
3. Write an answer before accepting a hint
Predict the results first, then copy this complete SQL fixture. It creates its own table and four rows in an empty scratch database. Use the separate Python checker below for a no-install in-memory run. Do not run CREATE TABLE against an existing project database.
CREATE TABLE sales(region TEXT NOT NULL, amount INTEGER NOT NULL);
INSERT INTO sales VALUES ('North',40),('North',70),('South',120),('South',10);
-- A: filter rows, then group
SELECT region, SUM(amount) AS total FROM sales
WHERE amount >= 50 GROUP BY region ORDER BY region;
-- B: group all rows, then filter groups
SELECT region, SUM(amount) AS total FROM sales
GROUP BY region HAVING SUM(amount) >= 100 ORDER BY region;Answer A contains North = 70 and South = 120. The 40 and 10 rows were removed first. Answer B contains North = 110 and South = 130 because all rows contributed before the group totals were compared with 100. If your answer differs, name the stage where your mental calculation changed. Do not settle for saying that WHERE and HAVING are different.
4. Use the lesson to repair a specific mistake
In Tutor, choose concepts to test or learn and arrange the study queue. Lessons include book references; answers are model-graded. Its grade-dispute action counts an answer as correct, so keep your own evidence of understanding.
Before studying, write one precise uncertainty, such as “I thought every South row was removed because one value was below 50.” During review, locate the relevant passage in the chapter. Restate it in your own words, then explain how it applies to one specific row. This prevents a correct general definition from hiding an incorrect application.
If feedback seems wrong, preserve your original answer rather than silently replacing it. Compare the disputed claim with the chapter and the hand calculation. Mark it unresolved if neither settles it. For a real course, bring that short record to a teacher or a knowledgeable colleague; a green progress indicator is not a substitute for resolving the disagreement.
| Check | Evidence to record |
|---|---|
| Order of operations | Name which rows survive before grouping in query A. |
| Arithmetic | Show 70 and 120 for A; 110 and 130 for B. |
| Explanation | Describe why a group can pass even when one member is small. |
| Transfer | Solve the changed example below before revealing its answer. |
5. Change the problem and check again tomorrow
Add East = 60 and East = 60. Change query A to WHERE amount >= 100 and query B to HAVING SUM(amount) >= 120. Predict the results on paper without the lesson. A now returns only South = 120. B returns South = 130 and East = 120. North no longer passes B because its group total is 110.
The new East group makes the distinction visible: neither individual row passes the first filter, while their combined value passes the second. Explain that sentence to somebody who has not read the chapter. If you need to look up the answer, return to the relevant concept and try another pair of values.
Tomorrow, invent a fourth region whose sum passes the group threshold although every row fails the row threshold. Save your example and answer. Add another chapter only when you can explain this case, rather than treating ingestion of more material as progress.
import sqlite3
connection = sqlite3.connect(":memory:")
connection.executescript("""CREATE TABLE sales(region TEXT NOT NULL, amount INTEGER NOT NULL);
INSERT INTO sales VALUES ('North',40),('North',70),('South',120),('South',10);""")
def result(where, having):
return connection.execute("SELECT region,SUM(amount) FROM sales " + where +
" GROUP BY region " + having + " ORDER BY region").fetchall()
assert result("WHERE amount >= 50", "") == [("North",70),("South",120)]
assert result("", "HAVING SUM(amount) >= 100") == [("North",110),("South",130)]
connection.executemany("INSERT INTO sales VALUES (?,?)", [("East",60),("East",60)])
assert result("WHERE amount >= 100", "") == [("South",120)]
assert result("", "HAVING SUM(amount) >= 120") == [("East",120),("South",130)]
print("Four SQL answer checks passed; no Tutor or model call was made.")
connection.close()python3 check-study.pyExpected output: Four SQL answer checks passed; no Tutor or model call was made. To test the checker, temporarily change North,70 in the first expected result to North,71: it must raise AssertionError. Restore the expected value afterwards. If Python reports No module named sqlite3, use a Python distribution with that standard module; do not alter the answer to hide an environment issue.
6. Diagnose the first failure before adding complexity
| Symptom | Next action |
|---|---|
| Chapter contents look wrong | Compare extraction with the original and select the report index, not the printed heading number. |
| The course is too broad | Reduce your learning objective to one observable action and select fewer concepts. |
| A polished explanation does not help | Ask yourself for an intermediate state: which rows exist at this exact step? |
| Your grade and the answer key disagree | Keep both answers, the chapter reference, and a manual calculation; leave the issue unresolved until checked. |
| You keep paying for experiments | Record provider usage after the first chapter and choose a personal ceiling before expanding. |
A useful session ends with a small artifact: your initial prediction, the correction, and a successful transfer problem. Keep those three items together. They tell you what changed in your understanding and give the next study session a concrete starting point.
Sources & next steps
- Tutor repository ↗
Configuration variables, first-run check and UI path re-read October 16; no third-party installation or model call.
- Tutor usage guide ↗
Current app usage, preview and study flow; read October 16.
Guide history
Revisions preserve the original instructions. A source recheck alone does not create a new revision.
Revision 2 · Explicit provider configuration/check, documented chapter preview flow, complete SQL fixture and independently executed four-case answer checker.
Revision 1 · First guide: chapter preview, original SQL task, independent answer key, retention check and troubleshooting.