DocumentationPractising
Guides
Practising
The daily loop in detail: how to start and test a problem, when to use hints, how a grade is computed, and how cstudy decides what you practise next.
On this page
The loop
Every problem goes through the same commands, whatever the language:
cstudy next -> cstudy start <slug> --lang kotlin -> edit in your editor -> cstudy test --watch
-> cstudy bench (optional) -> cstudy done --rating ok -> cstudy solution (optional)Commands that take a problem accept its slug (two-sum), its id, or the path of one of your solution files. Without one, they act on the active attempt: your most recent attempt still in progress.
cstudy serve runs the same loop on a local page; see Practising in the browser.
Choosing a language
Pass --lang python, typescript, java, kotlin, go or rust to cstudy start, or set default_lang in your configuration. Reviews are scheduled per problem, so you can solve a problem in one language and review it in another.
A file path names both the problem and the language, which is how editors run cstudy on the open file: cstudy test python/practice/two_sum.py is cstudy test two-sum --lang python.
| Language | Your solution file |
|---|---|
| Python | python/practice/two_sum.py |
| TypeScript | typescript/practice/two-sum.ts |
| Java | jvm/java/src/main/java/practice/two_sum/Solution.java |
| Kotlin | jvm/kotlin/src/main/kotlin/practice/two_sum/Solution.kt |
| Go | go/practice/two_sum/two_sum.go |
| Rust | rust/practice/two_sum.rs |
Starting and resuming
cstudy start <slug> writes the stub, renders the statement to .statements/<slug>.md, begins an attempt and opens both files in $VISUAL or $EDITOR. The stub opens with the problem’s title, a short summary, the path of the statement and the command that runs it. Starting a problem you already have in progress in the same language resumes that attempt and keeps your file.
| Flag | Effect |
|---|---|
--lang L | The language; default: default_lang |
--fresh | Move your existing file to .archive/ and write a new stub; a review attempt does the same, and nothing is deleted |
--timer 25m | A time box, such as 25m or 1h; finishing over it caps the grade at hard |
--no-open | Do not launch the editor |
Set open_on_start = false in your configuration if you never want cstudy to launch the editor.
Testing
cstudy test runs your code against the problem’s cases. With --watch it runs again each time you save. Visible cases are always listed; passing hidden cases collapse into a count unless you pass --all; a failing hidden case shows its input, the expected answer and yours.
$ cstudy test --time-limit
two-sum · kotlin · 16 cases (2 visible, 13 hidden, 1 generated) · time limit 5x · timer 12:31 / 25:00
build 1.8s (gradle, warm)
PASS ex1 0.04ms
PASS ex2 0.03ms
FAIL h1 hidden
input nums=[-3, 8, 0, 3] target=0
expected [0, 3] (unordered)
actual [2, 2]
note negatives and zero
TLE g1 hidden · 412ms > limit 95ms (5x hash-map, calibrated)
PASS 12 hidden cases
14/16 passed · 1 failed · 1 tle · total 2.6s| Status | Meaning |
|---|---|
PASS | The comparator accepted your output |
FAIL | Wrong answer |
ERROR | Your code raised an exception or crashed |
TIMEOUT | The hang guard (10 seconds by default) stopped a run that did not finish |
TLE | Right answer, but over the time limit (only with time limits on) |
INVALID | Your output cannot be read as the declared type |
STALLED | A concurrent stress run was still unfinished at its deadline, or a project case on a virtual clock deadlocked |
NOT RUN | The case did not run |
Useful flags
| Flag | Effect |
|---|---|
--case ID | Run only these cases; repeatable |
--all | List every case, passing hidden ones included |
--time-limit[=VALUE] | Turn time limits on. The default gives each case 5 times the reference’s time (5x), with a floor of 100 ms; --time-limit=1500ms sets one limit for every case |
--no-time-limit | Turn them off, even when your configuration turns them on |
--perf | After every case passes, run a short benchmark and print its verdict |
--typecheck | TypeScript: also run tsc, since Node’s type stripping does not type-check |
--stress N | Function and design problems: also check your code on N generated inputs against a brute-force oracle; concurrent problems: run each stress case N times |
--debug | Wait for your debugger; see Debugging |
On a full pass the summary ends with all passed. Next: cstudy done --rating easy|ok|hard. Every run except a debug run is recorded, so cstudy knows whether your latest run passed when you finish.
Hints and solutions
cstudy hint reveals the next hint of the problem. Hints are counted per attempt, and using any caps the grade at ok.
$ cstudy hint
two-sum · hint 1 of 3
Fix one element. Which single value would complete the sum with it?cstudy solution shows, through your pager, the explanation of the optimal approach and its code in your language. Before your attempt has passed, it asks first, because revealing the solution grades the attempt as again:
Reveal the solution? The attempt will be graded as again. [y/N]| Flag | Effect |
|---|---|
--lang L | Show the code in another language |
--approach ID | Show one approach, such as brute-force |
--all | Show every approach, in ladder order |
--explanation-only | Leave out the code |
--broken[=ID] | Concurrent problems and projects with stress cases: show a deliberately broken reference, as a spot-the-bug exercise |
--yes | Skip the confirmation |
Finishing an attempt
cstudy done closes the attempt and schedules the review. When your latest test run passed every case, rate how it went with --rating easy, ok or hard; when it did not, finish with --gave-up. Add --notes "…" to keep a note on the attempt.
A problem with levels needs only level 1 for a rating: the attempt passes through the highest level you passed, as in passed · through level 2 of 4, and comes back on its normal review schedule. The next attempt starts at level 1, and its statement and cstudy status name the level to try. A mock interview still needs every level.
$ cstudy done --rating ok
two-sum · kotlin · passed · 18m 40s · rating ok · hints 0
next review 2026-10-27 (in 3 days) · ease 2.50The rating becomes a grade, and some things cap it. The lowest cap wins:
| Situation | Grade |
|---|---|
| Gave up, or revealed the solution before passing | again (0) |
| Rated easy, ok or hard | easy (3), ok (2), hard (1) |
| Used a hint | at most ok |
| Finished over the --timer time box | at most hard |
| Latest benchmark of the attempt is suboptimal, at medium or high confidence | at most hard (turn this off with penalize_suboptimal = false under [schedule]) |
Solve time is the wall-clock time from cstudy start to cstudy done; there is no pause.
Stopping without finishing
cstudy abort stops working on a problem: after a question, the attempt ends as abandoned, with no grade and no rating, and your review schedule does not change. Your files stay where they are, and the attempt’s hints and runs stay in cstudy history. It refuses while a run or a job is active.
$ cstudy abort --yes
two-sum · python · abandoned · 2s
kept python/practice/two_sum.py
next cstudy start two-sumThe next cstudy start of the problem begins a new attempt in the file that stayed. For a problem with a review scheduled, the file first moves to .archive/; nothing is deleted.
Reviews and spaced repetition
cstudy schedules each problem with a simplified SM-2 algorithm. A good grade pushes the next review further out; a lapse brings the problem back tomorrow. This is how one problem moves through 6 reviews:
| Review | Grade | Next review in | Ease after |
|---|---|---|---|
| 1 | ok | 3 days | 2.50 |
| 2 | ok | 7 days | 2.50 |
| 3 | ok | 18 days | 2.50 |
| 4 | hard | 22 days | 2.35 |
| 5 | again | 1 day | 2.15 |
| 6 | ok | 3 days | 2.15 |
Intervals never exceed 180 days (max_interval_days). A problem counts as mastered once its interval reaches 21 days with a last grade of ok or better, and as due on and after its review date. While an attempt is open it shows as in progress instead.
A problem with levels is mastered level by level, each on its own reviews: it reads mastered through level 2 of 4 until every level is, and a plain mastered means every level.
These are the defaults. The fixed intervals, the cap and the mastered threshold are yours to change, under [schedule] in your configuration. A new interval applies to reviews scheduled from then on, and dates already set do not move.
What cstudy next picks
cstudy next answers “what should I practise now?” the same way every time for the same progress and date:
- An attempt you have open, the one you used most recently, with any others listed after it.
--newand--reviewskip this step. - Otherwise a due review, ranked by how overdue it is relative to its interval, plus how weak its pattern is.
- Otherwise a new problem from the weakest pattern (or, outside the algorithms track, the weakest track). Within it, easy problems come first; medium opens once you pass an easy one, and hard once you pass a medium one.
- Otherwise it prints
nothing due and no new problems in scope.
$ cstudy next
resume merge-intervals (medium · intervals) attempt 3 in python, last used 2026-11-07
start cstudy start merge-intervals --lang python
also lru-cache (python)$ cstudy next
review merge-intervals (medium · intervals) overdue 3d, interval 7d
start cstudy start merge-intervals --lang kotlin$ cstudy next
new koko-eating-bananas (medium · binary-search) weakest pattern: binary-search (0.75)
start cstudy start koko-eating-bananas --lang kotlinWeakness combines your recent fail rate, how much of the group you have mastered, and how long ago you last practised it. An untouched group scores 0.75, so cstudy rotates through new patterns before going deep on one.
| Flag | Effect |
|---|---|
--set NAME | From this set of yours, in its order |
--track T | Tracks to pick from, repeatable; default dsa, or next.tracks in your configuration, and every track with --set, --domain, --role or --scope |
--pattern P | Only problems with this pattern |
--difficulty D | easy, medium or hard |
--lang L | Only problems available in this language, and start in it |
--domain D, --role R, --scope S | Only what lists this label |
--new / --review | Only new problems, or only reviews |
--start | Start the pick right away |
Finding problems
cstudy list browses the catalog. Its filters combine, and cstudy next takes the same labels, so you can ask for what you are preparing for:
cstudy list --domain security # also --role and --scope
cstudy list --search retry # a slug or a title
cstudy next --role ai-engineer --lang typescript$ cstudy list --domain security
ID SLUG DIFF PATTERN STATUS DUE REFS
0255 token-claim-... medium arrays-hashing new - py ts
0256 refresh-toke... medium arrays-hashing new - py ts
0257 authorizatio... medium graphs new - py ts
- review-auth-... medium code-review new - -$ cstudy next --domain security
new token-claim-validator (medium · arrays-hashing) weakest track: practical (0.75)
start cstudy start token-claim-validator --lang python--search finds the problems and items whose slug or title holds the text, in any case:
$ cstudy list --search retry
ID SLUG DIFF PATTERN STATUS DUE REFS
0274 vendor-retry... hard - new - ts
- review-payme... hard code-review new - -Guides and paths
A guide is a short reading that teaches one idea before you practise it: the idea in plain words, a worked example, when to use it, the common traps, the cost, notes for experts and the problems that practise it. A path puts guides and problems in order, from a topic’s first idea to an expert’s. There are 74 guides and 11 paths: algorithm topics such as binary search and graphs, AI engineering, data engineering, and getting started, from the terminal and package managers to easy first problems.
cstudy learn # the guides and the paths, with what you have read
cstudy learn --path hashing # a path's steps and the next one
cstudy learn hash-functions # read a guide; add --done once you have
cstudy learn hash-functions --open # read it in the page, with the diagrams drawncstudy learn <guide> prints the guide in the terminal, with each diagram as a text drawing. Reading needs no workspace; --done, which marks the guide read, needs one. cstudy learn --path shows a path’s steps, what is done and the next command:
$ cstudy learn --path hashing
hashing Hashing: from your first hash map to content-addressed storage
From what a hash function is to Merkle proofs, through the problems that practise each idea.
3 of 22 done
# KIND STEP TARGET STATUS TITLE
1 guide hash-functions read What a hash function is
2 guide hash-maps-and-sets read Hash maps and sets
3 problem contains-duplicate passed Contains Duplicate
4 problem two-sum attempted Two Sum
...
20 problem tamper-evident-ledger level 2 level 1 passed Tamper-Evident Ledger
next cstudy start two-sumA problem step is done once the problem passes, or, with a target such as level 2, once that level passes. The page shows the same guides with their diagrams drawn; see Guides in the page.
Problem sets
A set is a list you choose, in the order you want to study it: make one for an upcoming interview, add problems and items to it, and study from it without searching. A problem can be in several sets.
cstudy set create backend-loop --description "The backend loop on the 12th"
cstudy set add backend-loop two-sum lru-cache url-shortener
cstudy next --set backend-loop
cstudy list --set backend-loop$ cstudy set show backend-loop
backend-loop The backend loop on the 12th
0 of 3 passed
# ID SLUG DIFF PATTERN STATUS DUE REFS
1 0001 two-sum easy arrays-hashing new - py ts java kt go rs
2 0002 lru-cache medium linked-list new - py ts java kt go rs
3 - url-shortener medium system-design new - -
next cstudy next --set backend-loopcstudy next --set picks an attempt you have open in the set, then the first entry you have not passed, then a due review from the set. It searches every track unless --track narrows it, and it says so when the set is finished or empty.
$ cstudy next --set backend-loop
new two-sum (easy · arrays-hashing) next in backend-loop, 1 of 3
start cstudy start two-sum --lang python
set backend-loop 0 of 3 passedFor a problem with levels, an entry can aim at a level below the last: cstudy set add backend-loop tamper-evident-ledger --level 2, or - {slug: tamper-evident-ledger, level: 2} in sets.yaml. The set then counts it as passed once level 2 passes, and so does cstudy next --set.
Sets live in sets.yaml at the root of your workspace, so you can read it, edit it by hand and commit it; a change from cstudy touches only the lines it must, so your comments stay. cstudy reset keeps your sets. A problem the catalog no longer has shows as missing and stops nothing. The page that cstudy serve runs has your sets too. Every subcommand is in the command reference.
Checking performance
cstudy bench runs your solution and every reference approach on the same generated inputs at growing sizes, fits how the time grows, and compares you with the optimal reference. It checks your answers at every size too.
$ cstudy bench
two-sum · python · sizes 1e2..1e5 · reps 7 · power AC · load 1.2
TARGET DECLARED n=1e2 n=1e3 n=1e4 n=1e5 SLOPE BAND MEMORY
brute-force O(n^2) 0.21ms 19.8ms 2.04s budget 2.00 ~n^2 constant
hash-map O(n) 0.01ms 0.09ms 0.94ms 10.1ms 1.00 ~n|nlogn linear
you 0.01ms 0.11ms 1.10ms 11.8ms 1.01 ~n|nlogn linear
verdict optimal: matches hash-map, 1.17x at n=1e5 · confidence high (spread 3%, R^2 0.999)
space linear, same as hash-map · confidence high
history best previous 13.0ms at n=1e5 (2026-09-12) · now 9% faster · 1st of 3 runs| Verdict | Meaning |
|---|---|
optimal | Same growth band as the optimal reference, at most 1.5 times its time at the largest size, and not growing apart |
near-optimal | Same band, but the ratio grows with n, likely an extra log factor, or stays above 1.5: a slower constant factor |
suboptimal | A worse growth band, or over the budget where the optimal reference finished |
unknown | Too few usable sizes, or no optimal reference in this language |
Each verdict comes with a confidence, high, medium or low, and a warning when your machine was busy or on battery. Benchmarks compare you with the references and with your own earlier runs, never with other people.
| Flag | Effect |
|---|---|
--sizes LIST | Comma-separated input sizes, such as 100,1000,10000 |
--reps N | Repetitions per size (default 7) |
--refs-only | Benchmark only the references; needs no attempt |
--no-memory | Skip the memory measurement |
--lang L | The language of the attempt to benchmark |
Note
Concurrent and project problems have no benchmark. See the performance analysis spec for what a slope can and cannot tell.
Timers and mock interviews
Any attempt can have a time box: cstudy start two-sum --timer 25m. cstudy test then shows the time left, and finishing over it caps the grade at hard.
cstudy mock simulates an interview. It picks new medium and hard problems, each from a different group where it can, starts them together with one shared timer, and locks cstudy hint and cstudy solution until the timer ends or every problem is done.
$ cstudy mock
mock interview · 2 problems · 45 min shared timer · python
1 group-anagrams (medium · arrays-hashing) weakest pattern: arrays-hashing (0.75)
stub python/practice/group_anagrams.py
statement .statements/group-anagrams.md
2 three-sum (medium · two-pointers) weakest pattern: two-pointers (0.75)
stub python/practice/three_sum.py
statement .statements/three-sum.md
locked cstudy hint and cstudy solution, until the timer ends or every problem is done
next cstudy test group-anagrams --watch| Flag | Effect |
|---|---|
--minutes N | The shared timer (default 45) |
--count N | How many problems (default 2) |
--track T | Tracks to pick from, repeatable |
--lang L | The language to start them in |
In a mock attempt of a project problem, cstudy submit reports only how many hidden cases failed per level, as an interview would.
Tracking progress
cstudy stats summarises your progress per group: problems, attempts, passes, mastered problems, the pass rate of the last 10 attempts, median solve time and weakness. Below come your streak, the reviews due and your latest benchmark verdicts.
$ cstudy stats
GROUP PROBLEMS ATTEMPTED PASSED MASTERED PASS RATE SOLVE TIME WEAKNESS
arrays-hashing 12 5 4 1 80% 14m 10s 0.42
two-pointers 8 0 0 0 - - 0.75
...
system-design 10 1 1 0 100% 45m 00s 0.30
attempts 6 finished · 5 in the last 7 days · streak 3 days
reviews 1 due today · 1 overdue
bench 4 benched · 2 optimal · 1 near-optimal · 1 suboptimal · 0 unknownGroup by --by pattern (the default), track, lang or difficulty; narrow the attempt columns with --since 2026-10-01; or print --json. To browse problems with their status and next review date, use cstudy list, filtered with --status new|in_progress|attempted|passed|due|mastered:
$ cstudy list
ID SLUG DIFF PATTERN STATUS DUE REFS
0001 two-sum easy arrays-hashing passed 2026-10-27 py ts java kt go rs
0002 lru-cache medium linked-list in progress - py ts java kt go rs
0046 koko-eating-... medium binary-search due 2026-10-21 py ts java kt go rsStarting over
cstudy reset deletes your progress in this workspace, an open attempt included: attempts, scheduled reviews, benchmark runs, run folders and rendered statements. You see what goes and what stays, with counts, before anything does, and you type reset to confirm. It can’t be undone, so run cstudy export first if you may want your progress back.
Your practice files, project folders and notes stay unless you pass --files, and .archive/ stays unless you pass --archive. Your configuration, toolchains, own problems and sets always stay. See the command reference.
Written for cstudy 0.46.0. The specs in the cstudy repository are the source of truth for every detail.