ORF-R-2026-001·Preview Project

Niotebook: an open-source CS50 companion where the lecture, a real in-browser editor, and a tutor that knows your exact place in the video share one canvas

Premise

Can the lecture, the editor, and the help a self-taught CS student needs live on one surface, with a tutor grounded in the exact moment of the video rather than guessing, and every language running in the browser with nothing on a server?

Finding

Yes, and the proof is on screen: the lecture plays beside a real editor and terminal, and when the learner asks what the professor is explaining right now, the tutor answers from the transcript at that timestamp. Every language runs in the browser behind its own isolation primitive, and the learner's API key is encrypted inside a server boundary that never returns it.

March 2026 · research preview · open

A student teaching themselves computer science from an open course lives in a maze of tabs. The lecture plays in one. The editor is in another. A generic chatbot, which has no idea what the lecture just said, sits in a third. Notes go in a fourth. The thread of the lesson breaks on every switch. Niotebook is the argument that it does not have to be that way: the lecture, a real editor and terminal, and a tutor that knows exactly where the learner is in the video, on one surface. The recording below is one continuous take.

The overhang, one learner at a time

The lab has written about the capability overhang: the widening gap between what the frontier can already do and what most people get from it. The argument there was that the gap does not close with more tools. It closes with embedding, with the work moved inside the actual workflow instead of bolted on beside it.

A self-taught learner has an overhang of their own. The lecture is good, the editor is real, the help is one prompt away, and yet they sit in different tabs, and the distance between them is where attention leaks and momentum dies. What a learner could absorb and what they actually do are two different curves, and the space between them is the understanding left on the table.

niotebook is that same embedding move, applied to one person learning. It does not add a cleverer chatbot to the pile. It puts the lecture, the editor, and a tutor that knows where you are into one place, so the help arrives in the same thought as the confusion. The claim is not that the model is smarter. It is that the workflow stops leaking, and over a course the two learners pull apart.

with niotebook a maze of tabs the learner’s overhang MASTERY progress through the course
Figure 1. The capability overhang, drawn for a single learner: niotebook closes the gap by putting the lecture, the editor, and a grounded tutor in one place instead of a maze of tabs.

That picture is the thesis, not a measurement. We have not run a learning-outcomes study, and the axes carry no units. The evidence for niotebook is the working software above and the public repository below, not a curve we drew. The curve only names the gap the rest of this piece is built to close.

One canvas, not four tabs

The whole product is a single synchronized canvas. The lecture video, the code editor with its terminal, and the tutor sit in one workspace that the learner reshapes on the fly: one pane, two panes, or all three, by a keystroke. The point is not the layout. The point is that the three things a learner is doing, watching, writing, and asking, stop being three places and become one thought.

Underneath, the synchrony is deliberate engineering, not a coincidence of being on the same page. The video’s current time is broadcast through a small external store the panes subscribe to, so a tick of the playhead reaches the tutor without re-rendering the editor the learner is typing in. The lecture moves, the tutor’s sense of where the lesson is moves with it, and the code the learner is mid-keystroke on does not flicker. The canvas is the thesis the rest of the piece defends: keep the lesson, the runtime, and the help in the same place, and the friction that scatters a self-taught learner’s attention goes away.

A tutor that is grounded, not guessing

The tutor is called Nio, and the thing that makes it useful is also the thing most chatbots cannot do: it answers from the lecture the learner is actually watching. In the demo, the question is “what is the professor explaining right now?” and the answer names floating-point division, type casting, and memory layout, because that is what the lecture is on at that timestamp. It is not recalling a general fact about C. It is reading the transcript window around the playhead.

That grounding is a pipeline, and the load-bearing part of it is a cascade the server runs to resolve the lecture window itself, never trusting the client to supply it. The browser sends the request with the learner’s place in the video; the server authenticates it, rate-limits it, and neutralizes prompt-injection attempts in the message; then it resolves the transcript four ways in order, and the first that succeeds wins.

browser requesta question, with the learner’s place in the video api route · validateClerk + Convex auth rate limit & scrubConvex · prompt-injection defence context build4-tier transcript cascade · fixed character budget BYOK streamServer-Sent Events · the learner’s own key persistidempotent Convex write tier 1 tier 2 tier 3 tier 4
Figure 2. From browser request through auth, a rate-limit and prompt-injection scrub, a four-tier transcript cascade built under a fixed character budget, to BYOK streaming and an idempotent persist.

The discipline shows in two details. The transcript is handed to the model labelled as untrusted context, so a lecture that quotes an instruction cannot hijack the tutor. And the assembled context is held to a fixed character budget, shed in a fixed order when it overflows: the oldest chat history goes first, then the transcript is trimmed, then the code, and the current code and the lecture window are the last things to be cut. History is the cheap thing to lose. Where the learner is, and what they wrote, are protected.

The pedagogy is encoded too. Nio is a teaching assistant, not an answer key: it is told to refuse complete solutions to graded work, to never invent a transcript or a timestamp it was not given, and to say plainly when the lecture window is empty rather than fill the silence. A good CS section leader’s restraint, written down.

A real workspace, run in the browser

The editor is not a toy. It runs seven languages, JavaScript, Python, C, HTML and CSS, SQL, and R, and it runs all of them in the browser. There is no server that executes the learner’s code, which means there is no remote-code-execution surface to defend. The interesting part is that there is no single sandbox doing the work. Each language is isolated by the primitive that actually fits it.

CSP allowlist · the outer wall no server · no remote code execution JS · HTML · CSS opaque-origin iframes sealed by origin C a Web Worker off the main thread Python · SQL · R WASM linear memory sealed by the sandbox heap Wasmer path COOP + COEP sandbox cross-origin isolated each language sealed by its own primitive, inside the one wall
Figure 3. A real workspace run entirely in the browser: a CSP allowlist as the outer wall, and each language sealed by its own primitive: opaque-origin iframes, a Web Worker, WASM linear memory, a COOP/COEP sandbox.

The honesty in the engineering is worth naming, because it is the kind of thing a marketing page would smooth over. C does not run on a compiler. It runs on JSCPP, an interpreter, inside a Web Worker, and the Wasmer path that does compile is an experimental terminal-only alternate, not the default. Each language gets the stop button that suits it: a JavaScript run that overstays is killed by removing its iframe, a C run is killed by terminating its worker, a Python run is interrupted by a shared-memory signal where the headers allow it. The shape is deliberately heterogeneous because the browser does not offer one clean way to run everything, and pretending it does would be the lie.

Your key, encrypted, never handed back

The tutor is bring-your-own-key. A learner can use every other feature without an API key at all, and if they want Nio, they paste their own key for Gemini, OpenAI, or Anthropic. The promise the architecture makes about that key is precise: once saved, the plaintext is never returned to the browser, by any code path.

browsersends provider key Convex action · the relay SHA-256 → non-extractable key AES-256-GCM · random per-key IV decrypts only inside the relay decrypted key marked: no return rest in Convex base64 ciphertext + IV at rest HTTPS model provider only last-4 keyHint loops back
Figure 4. The key is encrypted under a non-extractable derived key, rests as ciphertext, and is decrypted only inside the relay to stream to the provider. Only a last-4 hint returns to the browser; the plaintext key is never handed back.

The guarantee is structural, not a matter of remembering to be careful. The key is encrypted inside a Convex action with AES-256-GCM under a key derived by SHA-256, with a fresh random initialization vector per key. What rests in the database is ciphertext. The only thing the client can ask for back is a four-character hint, enough to recognize which key is saved, useless to anyone who steals it. The plaintext exists for a moment, inside the server-side action that relays the call to the provider, and nowhere else. This is the bring-your-own-key promise made literal: the learner keeps control, their usage is their own and transparent, and there is no mystery layer between them and the model.

The file tree that lives in your browser

A workspace needs files, and niotebook’s files live in the browser too. There is a virtual filesystem, an in-memory tree with the ordinary ceilings of a real one, that the editor and terminal read and write, and that persists to the browser’s own IndexedDB so a lesson survives a refresh and a return. There is no file store on a server.

editor + terminal (React + Zustand) VirtualFS in-memory Map tree IndexedDB niotebook-vfs write / rename 1 MB per file 50 MB per project snapshot() save, debounced keyed by lessonId restore on load on a write failure the store stays in memory; nothing is lost mid-session
Figure 5. niotebook's files live in the browser: the editor and terminal write to an in-memory VirtualFS, which holds the ordinary 1 MB per file and 50 MB per project ceilings, snapshots to the browser's own IndexedDB on a debounced save keyed by lesson id, and restores from it on load. On a write failure the store stays in memory, so nothing is lost mid-session.

The discipline underneath

None of this is held together by good intentions. The codebase is split into four layers with the boundaries enforced in continuous integration, not just documented. The domain layer is pure: a check in CI fails the build if it imports React, Convex, or anything with a side effect, and the same pure modules are the single source of business logic shared by both the web app and the backend, so there is no second, drifting copy. The backend forbids the any type by a script that fails the build. The result is a system where the rules about how it is allowed to be built are themselves tested.

We will not pretend the contract is perfect, because the repository does not. A handful of infrastructure files still hold thin React hooks the layer rules say they should not, a real gap between the contract and the code, left visible in the open rather than quietly papered over. A lab that publishes its own delta is more believable than one that claims none.

Where this honestly stands

This is an open beta, and it has rough edges we would rather name than have you find. The editor reads the filesystem when it opens a file and writes when it saves, but it does not yet listen for changes made underneath it, so a file rewritten by the terminal while it is open in a tab updates the tree without updating the open editor until the tab is reopened. Python runs on the browser’s main thread, which can briefly freeze the tab on a heavy program where the headers needed for a worker are not present. An external adversarial review of the codebase, run earlier in its life, graded it in the middle of the range while crediting its layering and its consistent typing, and we keep that review in view rather than out of it.

There is a licensing nuance that is not a footnote but a design principle. The niotebook software is MIT licensed: take it, run it, change it. The CS50 course content it draws on, the transcripts and the lecture metadata, is licensed by Harvard under Creative Commons Attribution-NonCommercial-ShareAlike. Non-commercial. That single word is why the open, free, bring-your-own-key shape is not a phase to be grown out of but the honest fit: the project cannot and does not commercialize the courseware, so it does not try to. The constraint and the design agree.

What transfers

The lessons here are not about CS50, and not even about education. Grounding beats generation: an assistant that reads the transcript at the learner’s timestamp is more useful than a cleverer model guessing, and the engineering that matters is the cascade that resolves the right context, not the prompt. Isolation belongs at the boundary you actually control: there is no single sandbox for seven languages, so each gets the primitive that fits, and the system is more honest for refusing to pretend otherwise. And a secret should be encrypted at the boundary that holds it, inside the server action, never handed back to the client that supplied it. Build a learning tool that way and the proof is the learner asking what the professor just said and getting a true answer.

If your operation has a body of knowledge people need to learn against, and a frontier worth grounding an assistant in, this is what embedding AI into that can look like when the guardrails are real. Start a conversation, and we will scope it.

The honest state of AI in learning

It would be easy to oversell this. The category is loud right now, and most of the noise is a promise that an AI will do the learning for you: paste the assignment, take the answer, move on. That is not a tutor. It is an answer machine, and it tends to hollow out the very struggle that turns watching into understanding.

niotebook is built against that grain on purpose. The tutor refuses complete solutions to graded work, grounds every answer in the lecture the learner is actually on rather than a general recollection, and hands back the next step instead of the finished one. The bet is that the useful place for a model in education is beside the work, not in place of it. We think that bet is right. We do not yet know that it is, and we are not going to pretend a drawn curve settles it.

What is honestly true today is narrow and worth stating plainly. AI can keep a learner from getting stuck on the wrong thing at the wrong moment, and it can do that grounded in where they are. Whether that compounds into people who learn more, and hold it longer, is a question only real use over real courses will answer, and the answer will not come from the people selling the tools. So we are building this one in the open, the repository and its history there to be read, because the education sector does not need another confident story about AI. It needs tools that keep the learner in the work, shown honestly enough that someone can check.

References

  1. Niotebook. The public, MIT-licensed repository. github.com/Akram012388/niotebook_v0.2
  2. CS50. Harvard University. cs50.harvard.edu/x
  3. Creative Commons Attribution-NonCommercial-ShareAlike 4.0. creativecommons.org/licenses/by-nc-sa/4.0
  4. Pyodide. The Python scientific stack in WebAssembly. pyodide.org
  5. WebR. R compiled to WebAssembly. docs.r-wasm.org/webr
  6. Wasmer and WASIX. wasmer.io
  7. JSCPP. A C interpreter in JavaScript. github.com/felixhao28/JSCPP
  8. sql.js. SQLite compiled to WebAssembly. sql.js.org
  9. CodeMirror 6. codemirror.net
  10. Convex. The reactive backend. convex.dev
  11. Clerk. Authentication. clerk.com
  12. Next.js. nextjs.org