←  IndexCase StudyGet the appOpen Source · 2026中文

Independent product — design, build & release — Jul 2026 →

Moodle
Agent

An agent that runs the whole weekly chore unattended: every slide, worksheet and assignment brief filed into the right week, every lecture recording read into text, and results logged as they post — so what is waiting for you is a folder a language model can actually work from.

PythonPlaywrightBeautifulSoupCustomTkinterPyInstallerLLM APIs
01Problem

Course material arrives late, and never in one place.

Every unit publishes files across a dozen nested sections, and rarely all at once — slides before class, worksheets during the week, solutions days later. Keeping a clean local copy means revisiting every unit, every week, and remembering what was already downloaded.

Existing browser extensions only shortened the clicking: the student still had to open each course page and decide what to grab. The real problem was never download speed — it was that the task depended on a person remembering to do it at all, and that half of each lecture was locked inside a video nothing could read.

01Staggered publishing
Solutions and extra reading appear days after the lecture — one pass over a unit is never enough.
02Deeply nested structure
Weeks are sub-sections of a parent section, each holding further sub-sections; nothing sits on the course home page.
03Authentication friction
Any automation has to survive single sign-on and multi-factor authentication without ever holding a password.
04Unreadable by machine
The richest material is spoken, inside a recording — useless to any tool until it becomes text.
02Discovery

Reading the system before automating it

The first crawler returned nothing. The course home page carries no file links at all: this Moodle runs a custom format where weeks are sub-sections of a Learning section, and each week holds further sub-sections that actually contain the material.

Mapping it meant fetching real pages and reading the markup. The crawler now walks section links breadth-first, builds a parent tree, and lets a child inherit its parent’s week. Course discovery uses the same AJAX endpoint the Moodle dashboard calls — which also exposes which courses the student has starred, so the tool offers a list instead of asking anyone to copy an ID.

Assumed — flat

course/view.php
Week 1
Week 2

0 files found

Actual — nested

course/view.php
section 3 · Learning
section 7 · Week 1
Own-time / Real-time / Wrap-up
section 11 · Week 2

Section numbers are not sequential. Children inherit their parent’s week.

03Recordings

Turning the spoken half into text

Slides are only half of what a lecture contains; the rest is said out loud. Each recording is read into a document — no video is ever downloaded, only its captions — which is the step that makes everything downstream possible.

The hard part was never the download. Staff publish recordings four different ways and all four are in use, so anything handling only the obvious one silently missed the rest. Panopto then authorises each recording separately — a recording whose viewer was never opened reports no captions at all rather than an error. That single behaviour is why videos labelled “with subtitles” were being reported as having none.

Four ways one recording arrives

  1. 01

    A link on the section page

  2. 02

    A bare URL typed into the page text

  3. 03

    An iframe embedded inside a page

  4. 04

    A page or url activity wrapping one of the above

When it can’t — say why

01No captions
Named in the week note, so you know it exists.
02Rate-limited
Will retry on a later sync.
03Needs sign-in
Asks for one extra sign-on, once.
04Queued
Held back deliberately to stay under the limit.
04AI Workflow

The output is something a model can read

A transcript is not the end of the job — it is the input to whatever the student actually wants to do: ask about a concept, build a revision sheet, find where a topic was covered. The agent’s real product is a week of material already in a form you can paste into a model.

Which model is deliberately not the tool’s decision. Summaries are off until you supply a key, any of eight providers is accepted, and with no key the pipeline still runs — you simply get the transcripts instead of the summaries. Nobody’s key is bundled, so nobody pays for anybody else’s usage, and a student who wants no model involved keeps a tool that works.

Whose model, whose bill

01Bring your own key
Eight providers accepted; nothing is bundled and nothing is resold.
02Off by default
With no key configured, not a byte is sent to any model.
03Degrades, never breaks
No key means no summaries — the transcripts still land.
04Formats people paste
Word and plain text, because that is what chat tools accept.

The loop, end to end

  1. 01

    Collect

    Every nested section crawled; only what is new is fetched.

  2. 02

    Read

    Each recording’s captions pulled and written out as a document.

  3. 03

    Summarise — optional

    Your key, your provider, your call. Off by default.

  4. 04

    Hand over

    A week folder of plain text and Word files, ready to paste into any model.

05Product

Two screens, then never again

Distribution was treated as part of the design, not an afterthought. The whole product is a single 75 MB file: no runtime to install, no admin rights, no command line. Setup asks two questions and shows a tick-list of courses it found by itself; afterwards the window exists only to answer “is it working?” Everything else — collecting, reading, logging results — happens while nobody is watching.

As-is · manual

  1. 01Remember to check Moodle
  2. 02Log in, open each unit
  3. 03Expand every week section
  4. 04Compare against local folder
  5. 05Download the new files
  6. 06Scrub a 47-minute video

Weekly, per unit · easy to forget · lectures stay unreadable

To-be · agentic

  1. 01App wakes on its own
  2. 02Session restored silently
  3. 03Every section crawled
  4. 04Manifest diffed
  5. 05Recordings read into text
  6. 06Filed, logged, ready for a model

Every 3 hours · nothing to remember · material arrives machine-readable

06Security

Never hold what you don't need to hold

Asking students for their university password would have made the tool trivial to build and impossible to trust. Instead the login runs where it belongs: a real browser window on the institution’s own sign-on page, complete with multi-factor authentication. The application never sees a credential.

What it does keep is the resulting session, stored locally outside the project directory so it can never be committed or synced to the cloud. Nothing leaves the machine unless you explicitly configure a model key — no server, no telemetry, no account. Console output prints paths relative to the download folder, so a shared screenshot never leaks a username.

  1. 01

    University SSO + MFA

    Runs in a real browser — the user types, the app only watches for completion.

  2. 02

    Session cookies

    Stored locally, outside the repo and outside cloud-synced folders.

  3. 03

    Silent headless sync

    Re-injected on the next run. No window, no password, no server.

  4. 04

    Model calls are opt-in

    The only outbound traffic beyond Moodle is one you switched on with your own key.

07Results
0
Passwords stored or transmitted — login never leaves university SSO

and zero duplicate downloads across runs, on a manifest-tracked incremental sync

4
Ways a recording gets found
link · bare URL · iframe · wrapper activity
3h
Unattended sync interval
plus one run at every logon
13
Week folders per unit
plus Assignments and _Other
8
AI providers you can plug in
your key — and it runs fine with none
1
File to download, nothing to install
no Python, no admin rights
2
Documentation languages
English and Simplified Chinese

Deliverables

//Course-structure reverse engineering
//Breadth-first section crawler
//SSO session persistence
//Incremental manifest sync
//Assignment & assessment capture
//Grade tracking, per unit
//Desktop GUI — setup and dashboard
//Background auto-sync service
//Panopto & YouTube transcript pipeline
//Multi-provider AI layer, bring-your-own-key
//Weekly summary notes, per unit
//Word and plain-text document output
Source code and releases ↗
08Learnings

What the project actually taught me, as opposed to what it shipped.

01

Remove the task, not the clicks

Faster downloading still leaves a chore with the student. Only running unattended solves the problem the chore represents — that was a product decision, not a technical one.

02

The useful output is machine-readable

Filing a video changes nothing; reading it into text changes what the student can do next. The transcript, not the download, is what made an AI workflow possible at all.

03

Read the system first

The initial crawler failed because I automated an assumed structure. Fetching the real markup and mapping how weeks nest is what made everything downstream possible.

04

Let the user own the model

Bundling a key would have meant paying for strangers’ usage and choosing their provider for them. Bring-your-own-key costs a settings screen and removes both problems.

05

Trust is a design constraint

Keeping credentials out of the tool made it harder to build and is the reason it can be handed to a stranger. Security decided the architecture, not the other way round.

06

Silent skipping hides bugs

Recordings that failed were quietly passed over, so a whole class of breakage stayed invisible for weeks. Every skip now reports a reason and says whether it is final or will be retried — which is how several of them were found at all.