Coding-interview practice with a real editor, a verifying runner, and an agent coach that generates and explains problems — all from the browser.
Install · The Coach · Problems · MIT
reps is a local, CodeSignal-style harness for progressive coding problems (one problem, several levels, each bolting a new requirement onto the same growing system — the format CodeSignal ICAs use). You solve in a real Monaco editor; a sandboxed runner tests each level. When you want a new problem, you ask the built-in Coach, which drives your coding agent (or an API model) to write a fresh drill — spec, starter, reference, and tests — and only ships it once it passes its own verification.
curl -fsSL https://raw.githubusercontent.com/rrrozhd/reps/main/install.sh | bash
repsThat installs a global reps command (app lives in ~/.reps, linked onto
your PATH — no directories to manage). First run walks you through the coach
engine — sign in to a CLI agent (claude auth login, native), point at a local
model (vLLM / Ollama), or paste an API key — then opens http://127.0.0.1:8777.
reps— start (runs first-time setup automatically)reps setup— pick / switch engines, sign inreps status— show the active engine
Reconfigure later from the terminal (reps setup) or the in-app ⚙ Settings.
From source instead:
git clone https://github.com/rrrozhd/reps && cd reps && ./repsThe editor loads Monaco from a CDN (jsDelivr), so the browser needs internet. Everything else — task specs, the runner, linting, your saved solutions — is fully local.
- Real editor — Monaco (the VS Code engine): Python highlighting, bracket
colors, multi-cursor,
⌘/Ctrl+Enterto run,⌘/Ctrl+Sto save. - Live linting —
pyflakespaints warnings/errors in the gutter as you type. - Progressive runner — each drill has multiple levels; Run shows per-level
pass/fail with
expected · gotdiffs. Runs in an isolated subprocess with a timeout, and captures yourprint()output into a panel. - Durable progress — your solution for each drill is saved server-side (plus the browser), so a closed server or cleared browser never loses work.
- Rendered filesystem — the File System drill draws the tree your code builds.
- 90-minute ICA clock, one-click reference solutions.
Open the ✦ Coach tab:
- Generate a problem — type a topic (e.g. sliding-window rate limiter, LRU cache, interval merge), pick easy/medium/hard, hit Generate. The Coach authors a full drill and verifies it before it appears; a broken problem never ships.
- Ask the coach — Explain this level, Give me a hint, Why is my code failing?, or free-text. It sees the current problem, your code, and your last results.
reps is provider-agnostic. The Coach's Engine dropdown lists whatever it
detects, in this precedence (override with REPS_PROVIDER):
| Kind | Engines | Auth |
|---|---|---|
| Local CLI agent (preferred) | claude (Claude Code), gemini, codex, cursor-agent, opencode |
your existing CLI login — no API key |
| API | anthropic (native) · OpenAI-compatible: OpenAI, OpenRouter, Groq, Together, local Ollama/LM Studio |
env key |
| mock | offline sample generator | none — for trying the loop |
API keys / models (any one enables the API path):
export ANTHROPIC_API_KEY=... # native Anthropic
export OPENAI_API_KEY=... # + optional OPENAI_BASE_URL for OpenAI-compatible
export OPENROUTER_API_KEY=... # one key, hundreds of models
export GROQ_API_KEY=...
export REPS_MODEL=... # override the model idWhatever engine writes a drill, reps re-runs the verify gate itself — so correctness never depends on the model, only on passing the tests.
Health check:
GET /api/agent/health(or the Engine dropdown) shows what's detected and active. If a local CLI errors on auth, run it once in a terminal to log in.
17 problems ship with it, all verified (verify_drill.py runs each reference
against its own tests).
9 progressive drills — one growing system, 4 levels, the last level punishes a naive data model:
| Drill | The twist that forces good state design |
|---|---|
| Banking System | historical get_balance + merge → balance is a checkpoint log |
| In-Memory File System | get_file_size(path, at_version) → per-file write log |
| Key-Value Store w/ TTL | get(key, at_ts) + lazy expiry → per-key record log |
| LRU Cache with TTL | eviction + TTL + an as-of read |
| Sliding-Window Rate Limiter | timestamp log + bisect, not a deque you pop |
| In-Memory DB with Transactions | nested begin / commit / rollback |
| Lazy Job Scheduler | jobs fire lazily on the next op, not on a timer |
| Versioned Object Store | versions + restore + as-of read |
| Inventory w/ Expiring Reservations | holds expire lazily; historical availability |
8 algorithms — single function, tested in example / edge / scale groups:
two-sum (hashmap, easy) · valid-parentheses (stack, easy) · merge-intervals
(medium) · search-rotated (binary search, medium) · longest-substring
(sliding window, medium) · num-islands (graphs, medium) · coin-change (DP,
medium) · trapping-rain-water (two-pointers, hard).
Ask the Coach for more, on any topic or difficulty.
The repo ships a drill-authoring skill and a plugin manifest.
- In-repo: open the folder with Claude Code —
.claude/skills/authoring-drillsauto-activates, so/authoring-drills sliding-window hardworks in the terminal. - Install elsewhere:
/plugin marketplace add rrrozhd/reps /plugin install reps@reps
A drill is one module in backend/drills/<slug>.py exposing SLUG, TITLE, DIFFICULTY, ENTRYPOINT, MARKDOWN, STARTER, REFERENCE, LEVELS (see
.claude/skills/authoring-drills/SKILL.md
for the full contract). Prove it before shipping:
python3 backend/verify_drill.py <slug> # runs your REFERENCE against your LEVELSDrills are discovered from the directory — no registration needed.
backend/ app.py (API) · agent.py (engine bridge) · worker.py (sandboxed runner)
verify_drill.py · reps_cli.py (setup wizard) · drills/*.py
frontend/ React + Vite UI — src/*.jsx, styles.css
dist/ ← the built bundle, committed on purpose (see below)
assets/ brand logo set, served at /assets
.claude/ skills/authoring-drills/SKILL.md (the drill contract)
The web UI is React + Vite. frontend/dist/ is committed deliberately — that's
what keeps curl | bash working with zero node toolchain: running reps needs only
Python. Node is a contributor dependency, never a user one.
cd frontend
npm install
npm run dev # hot reload on :5173, proxies /api + /assets to the backend on :8777
npm run build # rebuild dist/ — commit it with your changeIf you change anything under frontend/src/, rebuild and commit dist/, or the
running app won't reflect it. (Monaco loads from a CDN rather than being bundled —
it would add ~5MB to every committed rebuild.)
⌘/Ctrl+Enter run · ⌘/Ctrl+S save · plus all the usual Monaco keys.
MIT — see LICENSE.