Repo learner
Orchestrator for the repo-learner skill suite. Routes /learn commands to specialized sub-skills for analyzing codebases, generating exercises, tutoring, and quizzing. Trigger on any /learn command, "help me learn this repo", "teach me this codebase", "I want to understand this project", or any request to systematically learn a codebase. Also trigger when the user references an existing learn/ directory.From its SKILL.md
npx -y skills add PranitMohnot/repo-learner-suite --skill repo-learnerAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
2 things to look at
- 2 stars2 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
- runs commandsInstructs the agent to run 4 commands, including `uname -ms` and 3 more.
SKILL.md
16.0 KB, ~3.9k tokens by cl100k_base, as published. Nobody here has run it
Repo Learner — Orchestrator
Routes /learn commands to the right sub-skill.
Command Routing
| Command | Sub-skill |
|---|---|
/learn analyze <path> | repo-analyzer |
/learn exercises [section] | exercise-gen |
/learn tutor [section] | code-tutor |
/learn quiz [section] | code-quiz |
/learn status | (self — parse README.md checkboxes) |
/learn test | full pipeline in test mode → learn_test/ (see below) |
No subcommand — always lead with one action
Check state and recommend ONE thing:
- No
learn/directory: "Let's start. I'll analyze the codebase and build your learning path." → run analyze pipeline. No menus. learn/curriculum.mdexists, no checkboxes ticked: "Your curriculum is ready — openlearn/curriculum.md(orlearn/curriculum.htmlfor interactive). Start with Section 0 (overview), or saytutor,quiz,exercises."- Some checkboxes ticked: "You're on Section X.Y. Pick up where you left off?"
→ recommend the next unchecked step. One escape line at the end:
"Or:
tutor,quiz,exercises,status."
Never dump a decision tree. One recommended action, one escape line.
Front-Loaded Questions (start of any fresh pipeline)
Before reading any code, ask the user 3–4 questions in a single AskUserQuestion call. The user's answers directly shape tutoring depth, exercise scaffolding, and environment setup — they cannot be auto-detected.
Step 0: auto-detect language + platform (silent)
Sniff the repo before asking anything:
| Signal | Language |
|---|---|
*.py, pyproject.toml, setup.py, requirements.txt, uv.lock, poetry.lock | python |
Currently only Python is supported by the notebook scaffolder. Other
languages will be added as language profiles (see
exercise-gen/scripts/scaffold_notebook.py:LANGUAGE_PROFILES). If a
repo's primary language is not python, surface that to the user and ask
how to proceed.
Persist as repo.language in .config.json. Downstream skills
(exercise-gen, code-quiz) read it.
Also detect the user's platform via uname -ms (or ver on Windows).
Map to a canonical string:
uname -ms output | user.platform |
|---|---|
Darwin arm64 | macos-arm64 |
Darwin x86_64 | macos-x86_64 |
Linux x86_64 | linux-x86_64 |
Linux aarch64 | linux-arm64 |
| Windows (any) | windows-x86_64 |
Persist as user.platform in .config.json. exercise-gen reads it during
dependency selection (see exercise-gen/SKILL.md → "Dependency selection")
to avoid shipping notebooks with platform-broken deps.
What to ask (adapt to the detected repo + language):
-
Domain familiarity. "How familiar are you with [domain]?" Options:
[none / textbook / built one]. Show detected default inline. -
Language/framework familiarity. Detect the primary framework and ask the equivalent question — e.g. "Pandas familiarity?", "Async/await familiarity?". Skip if the repo uses no specialized framework.
-
Environment manager. Auto-detect from lockfiles (uv.lock → uv, poetry.lock → poetry, requirements.txt → pip). Show detected default: "I detected
uv.lock— use uv?" Options:[uv / pip / poetry / conda]. -
Depth. "Comprehensive (default — deep read, 8–12 exercises, full QA) or Light (~1/4 cost — leaner curriculum, 3–5 exercises, skips mock-student validation)?" Persist as
tuning.depth: comprehensive | lightin.config.json. Default tocomprehensiveif the user accepts defaults. -
Open-ended catch-all. "Anything else I should know? (learning goals, time constraints, areas of interest)" — free text, optional.
Rules:
- Ask only what the user uniquely knows; auto-detect everything else.
- Show detected defaults inline. "Use all defaults" is always an option but is never silently chosen for them.
- Persist answers to
learn/internals/.config.json. All downstream skills read it. Never reference a package manager other than the one stored there in user-facing artifacts.
.config.json schema (the canonical paths downstream skills read):
{
"user": {
"domain_familiarity": "none | textbook | built_one",
"framework_familiarity": "...",
"env_manager": "uv | pip | poetry | conda",
"platform": "macos-arm64 | linux-x86_64 | ...",
"goal_notes": "free text from the open-ended question"
},
"repo": {
"name": "...",
"language": "python | ...",
"root": "absolute path to the repo being learned"
},
"tuning": {
"depth": "comprehensive | light",
"mode": "normal | test"
}
}
Downstream skills depend on these paths exactly:
reconcile.pyreadsuser.env_managerandrepo.language.scaffold_notebook.py:generate_env_filesderives the host-repo editable-install path fromrepo.root(or the orchestrator passes it explicitly).exercise-genreadsuser.platformfor dependency selection.tuning.depthandtuning.modegate Light mode and Test mode behavior across all skills.
Shared State
All sub-skills read/write to <repo-root>/learn/:
learn/
├── curriculum.md # THE document. Section 0 = overview. Per-step
│ # checkboxes. Exercises linked inline. From
│ # repo-analyzer; exercise-gen edits at markers.
├── curriculum.html # Interactive HTML mirror of curriculum.md
│ # (clickable checkboxes + localStorage, hint/
│ # solution dropdowns, syntax highlight).
├── cheatsheet.md # Quick-reference card (separate from narrative).
├── notebooks/ # From exercise-gen
│ ├── README.md # Setup + exercise sequence
│ ├── requirements.txt
│ ├── pyproject.toml
│ └── exercise-*.ipynb
└── internals/ # Build artifacts (accessible but not highlighted)
├── .config.json # User answers from front-loaded questions
├── exercise-candidates.md
├── exercise-plan.md # The manifest — see Shared Contracts below.
├── quiz-bank.md # Source bank for /learn quiz (mutable)
└── validation/ # Per-notebook mock-student + nbconvert reports
└── exercise-NN.validation.json
No separate README.md, no separate overview.md, no path.html. Section 0 of curriculum.md is the overview. curriculum.html is the interactive mirror.
Progress Tracking
Progress lives in learn/curriculum.md as per-step markdown checkboxes inside
each section. The orchestrator parses these checkboxes. learn/curriculum.html
mirrors them via localStorage with a round-trip export-to-markdown button.
A section looks like:
<a id="s1.3"></a>
### Section 1.3: First custom dataframe pipeline — sales aggregation
<!-- step:1.3:read-pipeline -->
- [ ] Read [pipelines/sales.py:14-60](src/pipelines/sales.py)
— focus on the `groupby().agg()` chain.
<!-- step:1.3:run-the-demo -->
- [ ] Run `python -m examples.sales_demo` and inspect the resulting
summary table.
<!-- step:1.3:exercise-03 -->
- [ ] [Exercise 03 — sales aggregation](notebooks/exercise-03-sales-agg.ipynb)
<!-- step:1.3:checkpoint-multi-index -->
> **Checkpoint:** Why does `.reset_index()` come after `.agg()` and not before?
> <details><summary>Answer</summary>
> `.agg()` operates on the grouper's MultiIndex; resetting earlier collapses
> the grouping key into a column and changes what `.agg` is grouping over …
> </details>
Shared Contracts (manifest + markers + reconciliation)
These contracts let repo-analyzer and exercise-gen work without colliding.
The manifest — learn/internals/exercise-plan.md
Single source of truth for "where does each exercise live and how is it
rendered." repo-analyzer writes the initial manifest (Stage 2 of the analysis
pipeline). exercise-gen reads it, updates status and notebook_path as it
works, and writes the final state.
Each exercise entry is a markdown section with a yaml code fence at the top
holding the machine-readable fields, followed by free-form prose:
## Exercise 3: Joint-limit avoidance from scratch
```yaml
exercise: 3
section: "1.3"
type: create # use | modify | debug | create | compare
emission: notebook # notebook | inline
slot: exercise-03 # slug; resolves to <!-- step:1.3:exercise-03 -->
notebook_path: notebooks/exercise-03-joint-limits.ipynb
status: planned # planned | scaffolded | validated | inserted
```
**Goal:** …
**Builds on:** Exercise 2.
**Notebook structure:** …
Field rules:
emission: inlineis reserved forcompareexercises and short copy-paste- run blocks (no scaffold/validation). Default isnotebook. The long-term direction is everything becomes a notebook — inline is an exception.slotis a kebab-case slug, unique within its section. Resolves to the marker<!-- step:SECTION:SLOT -->in curriculum.md.statuslifecycle:planned— manifest entry exists, no artifact yet.scaffolded— notebook (or inline block) emitted; not yet validated.validated— mock-student + nbconvert checks passed.inserted— curriculum.md placeholder replaced with real link/block.
notebook_pathis required whenemission: notebook. Omit for inline.
Marker convention — curriculum.md
Every checkbox step in a section is preceded by an HTML-comment marker on its own line:
<!-- step:SECTION:slug -->
- [ ] …step content…
SECTIONis the section ID, e.g.1.3.slugis kebab-case, unique within the section. Slug derives from step intent:read-validator,run-the-demo,exercise-03,checkpoint-async,compare-eager-vs-lazy. The analyzer picks them.- Markers are invisible in rendered markdown and stable across edits to surrounding prose.
Markers serve three purposes: (1) exercise-gen looks up insertion points via
the manifest's slot field, (2) curriculum.html's parser keys on them, (3)
reconciliation cross-checks them.
For exercise slots specifically, the analyzer initially emits a placeholder
checkbox after the marker (e.g. - [ ] Exercise 03 — pending). exercise-gen
replaces that one line with the real link (notebook) or the real inline block.
It MUST NOT edit anything outside that one line.
Pipeline order (orchestrator)
- Step 0: silently detect language + platform; persist to
.config.json. - Front-loaded questions → write the rest of
internals/.config.json. - repo-analyzer → curriculum.md (with markers + exercise-pending stubs),
cheatsheet.md, draft
internals/exercise-plan.md,internals/quiz-bank.md. - exercise-gen, internally:
- Stage 4a: generate notebook
.ipynbfiles. - Stage 4b: emit env files (
requirements.txt+pyproject.tomlfor Python; per-language variants when other languages are added). - Stage 4c: run the env install command (e.g.
uv sync). MANDATORY — Stage 4d's nbconvert validation needs the env to exist. - Stage 4d: validate (mock-student + nbconvert).
- Stage 4e: replace pending stubs in curriculum.md, update manifest.
- Stage 4a: generate notebook
- Regenerate
learn/curriculum.htmlfrom the final curriculum.md by runningrepo-analyzer/scripts/curriculum_html.py. - Reconciliation pass — see below. Runs the script
repo-learner/scripts/reconcile.py. Fail loud if any check fails.
Reconciliation pass (orchestrator, end of pipeline)
Concrete runner: repo-learner/scripts/reconcile.py --learn-dir learn.
The orchestrator refuses to declare "done" until all of:
- Every manifest entry has
status: inserted. - Every
<!-- step:X.Y:exercise-NN -->marker in curriculum.md is followed by a real link or fenced code block — nopendingstubs remain. - Every
notebook_pathin the manifest exists on disk and parses as validnbformatJSON. - Every notebook has a
internals/validation/exercise-NN.validation.jsonreport with bothvalidator_passed: trueandnbconvert_passed: true. - Artifact grep: no
<parameter>,<antml,<function, or other tool-call fragments in any user-facing file (curriculum.md, curriculum.html, cheatsheet.md, notebooks/*.ipynb, notebooks/README.md). - Package-manager consistency: no manager other than the one in
.config.json:env_manageris mentioned in user-facing files.
If any check fails, fix it (regenerate, re-validate, re-insert). Do not silently skip.
Silent Defaults (never ask the user about these)
- Mock-student validation + nbconvert execute: both always run.
- Subagent fan-out: 1 agent per notebook when exercise count > 4. Each agent
gets the shared brief template (see
exercise-gen/references/) + its one spec. Main agent runs a stitcher pass after. - Filename slugging: always strip non-alphanumerics.
- Output directory: always
learn/. - Build artifact location: always
learn/internals/. - Reconciliation: always run as the final stage. Refuses to declare "done" unless all six checks pass (see Shared Contracts above).
Pipeline cadence — "no stopping" rule
Run the pipeline end-to-end for the user; run QA exhaustively for yourself. After the initial questions, do not pause for user input unless you are genuinely blocked (unresolvable dependency, missing file, ambiguous instruction). Internal checks — mock-student validation, nbconvert execute, artifact grep, self-questioning — are part of the pipeline, not pauses. When you must ask, use AskUserQuestion. Prefer one question over silent guessing; prefer silent guessing over a low-quality default.
Test mode
/learn test runs the full pipeline as a smoke test against the real
repo and writes to learn_test/ (never to learn/). It's intended for:
- Verifying the suite works on a new codebase before committing to a full run.
- Debugging changes to the suite itself.
- Quickly inspecting what shape the agent's adaptation produces for an unfamiliar repo.
What's different in test mode:
- Output directory:
learn_test/instead oflearn/. All paths in the shared-state tree shift accordingly (learn_test/curriculum.md,learn_test/internals/.config.json, etc.). .config.json:tuning.mode == "test"is persisted, alongside the rest.tuning.depthis forced tolightinternally (test mode is about pipeline structure, not analysis thoroughness).- repo-analyzer: produces Section 0 (overview) + Section 1.1 only. Trimmed cheatsheet (~30 lines). 3 quiz seeds covering different palette types. Manifest has 1 entry — the simplest "use" exercise from the candidates.
- exercise-gen: 1 exercise. No subagent fan-out. All Stage 4 sub-stages still run (generate → emit env files → install env → validate → insert). This is the whole point — the smoke test catches Stage 4c (env install) failures, validation crashes, insertion bugs.
- Reconciliation runs against
learn_test/and must pass — the 1 entry must be fully inserted, the 1 notebook must validate, etc.
What's the same:
- Front-loaded questions still run. They're adapter inputs (env_manager, language, platform), and skipping them would defeat the "adaptivity works" check.
- All artifacts must be repo-dependent. The single section must describe the actual codebase. The single exercise must reference real source files. Test mode is a minimal real run, not a stock template.
- curriculum.html still regenerates.
Cleanup:
learn_test/ is meant to be inspected and discarded. To turn a test run
into a real run, rm -rf learn && mv learn_test learn and re-run the
analyzer in normal mode to fill in the rest. (Or just re-run from
scratch — test mode is fast.)
What ships with it: 3 files
12.9 KB alongside SKILL.md, 1 of them executable
commands/
- learn.md1.1 KB
scripts/
- reconcile.pyruns11.7 KB