48: The Bundled Quillins - transcript

Download the MP3

Liam: The QUILL Cast, episode forty-eight. I'm Liam. Today we open the box the bundled Quillins ship in. These are the extensions that ride along with every QUILL install, the working examples the project trusts enough to put in front of you before you've ever written a line of code.

Jessica: I'm Jessica. Last episode was the author tools mega, episode forty-seven, where we walked the whole export side of the house. DAISY talking books out the door from quill/io/daisy.py, the Audio Studio dialog for stitching recordings together, and the braille production pipeline under main_frame_braille.py. That episode was about the destinations: what QUILL can hand a reader, an ear, or an embosser. Today we change direction. We stop and look at the editor itself, the parts you don't see by default, the things bundled in so the experience is already larger than what's on the surface.

Liam: Frame for the next forty minutes: a Quillin is QUILL's name for an extension. They live in a directory called quill/quillins_bundled, and as of this recording there are seventeen of them. We are going to walk them in groups, by what they give you, not just by name. We will read the manifests against the JSON schema at quill/core/schemas/extension.json. We'll point out the field names that earn their keep. And we'll be honest where a manifest drifts from what an earlier episode said.

Jessica: The standing guarantee, repeated because it never stops being load-bearing: Safe Mode disables all extensions with one flag. Whatever any of these Quillins do, your clean room is one restart away. That is the floor under all the excitement.


Liam: First, a tiny bit of context for listeners who haven't built a Quillin yet. Every bundled Quillin is a directory, a manifest.json, an optional entry module, and whatever supporting files it needs. The manifest is validated against the published JSON schema before anything is allowed to load. That means the editor, the linter, the build, and the docs all agree on what a valid Quillin is. There is no negotiation. The schema is the contract.

Jessica: That schema, at quill/core/schemas/extension.json, is the single source of truth. It defines the four required fields, schema, id, name, version, then the optional identity fields, author, description, license, min_quill_version. Then capabilities, an array of strings from a fixed enum. Then categories, a separate enum that the Quillin Manager filters by. Then the contribution surface inside contributes: commands, menus, context_menu, hotkeys, abbreviations, smart_triggers, document_events, preferences, status_bar, schedule, file_types, snippet_gallery, transcription_providers, plus the sound pack and sound event contributions. That's a lot. We will not enumerate every key, but we'll see the ones the bundled Quillins actually use.

Liam: A short do this now beat before we get into the code. If you have QUILL running, open the Quillin Manager. Preferences, Extensions, Quillin Manager. Don't change anything yet. Just read the list. Note the names, the version numbers, the categories on the right. Pause the audio, look, and come back. That list, the one you just read, is the seventeen directories we are about to walk through in this episode. The seeing is part of the learning.


Jessica: Group one, the safest Quillins: pure Layer 1 snippets. These have no capabilities array entries that touch your files, network, or clipboard, and they exist to insert text. The first is insert-tools, id com.quill.bundled.insert-tools, declared as a Bundled Quillin whose description is pure Layer 1 snippets that insert the current date, time, or both, surfaced through the Insert Date and Time submenu. It contributes three commands, ext.insert.date, ext.insert.time, ext.insert.datetime, each with a run field whose snippet is a placeholder string. The schema calls these out by name: dollar-sign curly date, dollar-sign curly time, dollar-sign curly cursor, the cursor placeholder parks the caret where you want it.

Liam: That is the model for every snippet Quillin in the editor. No code runs, the editor expands the snippet, the cursor lands where the template says it should. Insert Tools is the smallest Quillin in the box by every measure. Reading its manifest is the fastest way to understand what a Layer 1 extension is.

Jessica: Group two, writing helpers. Three Quillins in this group, all with main fields, all real Layer 2 Python extensions. First, smart-insert, id com.quill.smartinsert. This is the one that powers the equals bug, equals meeting, equals todo, equals rand, equals logentry, equals brftest, equals journal, those typed triggers we covered back in episode fifteen. Its manifest declares seven commands, a menus array putting them on the Insert menu, an abbreviations array with five triggers, qbug, qmeet, qlog, qtodo, qbrf, and a smart_triggers array with seven typed entries. The schema lets a Quillin contribute both kinds of insert automation, and Smart Insert does both, which is why it feels like a single feature that works in two different ways depending on whether you type a prefix-and-paren or an abbreviation and a delimiter.

Liam: Second in this group, journal-stamp, id com.quill.journalstamp. This Quillin listens for document events, specifically document.created with a file_path_pattern condition that matches folders whose names include journal, diary, or notes, and inserts a date header in the new document. Its manifest also subscribes to document.after_save to announce the word count, document.loaded_from_session to mark that the document was restored, quillin.enabled for an activation cue, and settings.changed to refresh internal configuration. The capability list reads document.events, editor.write, editor.read, ui.announce, settings.own.read, settings.own.write. That is a Quillin that watches your folder structure and your writing routine.

Jessica: Third in the writing helpers group, doc-guardian, id com.quill.docguardian. The description says guards your work with smart pre-close and pre-save checks, warns before closing very short documents that look unfinished, and optionally stamps an Updated line before every save. Its manifest declares six document events: document.before_close, document.before_save, document.after_save, quillin.enabled, quillin.disabled, and quill.shutdown. The before_close event is the most interesting one: it speaks a warning if the document is suspiciously short, never saved, or contains a TODO marker you can configure. It does not block the close. It makes sure you heard the question before answering it.

Liam: The honesty correction we owe. Episode forty-six implied that all bundled Quillins target the same minimum QUILL version. They don't. Reading the manifests tells the real story. Journal Stamp and Document Guardian declare min_quill_version 0.6.0. Smart Insert declares 0.6.0 as well, with a different id namespace. Most of the newer entries declare 1.0.0. The word-count-node Quillin declares 1.1.0, because it needs the Node runtime which lands at 1.1.0. That difference is real, and a Quillin author who depends on a 1.1 feature has to set the floor correctly. Verify against the manifest.


Jessica: Group three, the document transformation tools. Four Quillins that operate on the text you've already written, not on the editor lifecycle. First, line-tools, id com.quill.bundled.line-tools. The description is plain: duplicate, delete, move up and down, and join lines using cursor-aware operations. The manifest contributes six commands, ext.lines.duplicate, ext.lines.delete, ext.lines.move_up, ext.lines.move_down, ext.lines.join, ext.lines.join_next, each with a run handler. Every one of them lives on the Edit menu, which the schema calls out as one of the allowed parents, alongside File, Insert, Format, Tools, Navigate, Search, View, Help, and the conventional submenu Date and Time.

Liam: Second, text-tools, id com.quill.bundled.text-tools. The description names the four operations: number lines, hard-wrap, count and extract regex matches, and cursor-split set operations. The manifest contributes seven commands, ext.text.number_lines, ext.text.hard_wrap, ext.text.count_regex, ext.text.extract_regex, ext.text.lines_first_only, ext.text.lines_common, ext.text.html_to_markdown. The menus array is honest about where each one belongs: Format for the line operations, Search for the regex ones, Edit for the HTML-to-Markdown paste command. The capability list is the longest of any writing helper: editor.read, editor.write, ui.announce, ui.prompt, ui.command, clipboard.read. clipboard.read is the one to notice. It exists because html_to_markdown reads the clipboard, so the manifest has to ask for it. The discipline of asking for what you use is the entire consent model.

Jessica: Third, markdown-helpers, id com.quill.bundled.markdown-helpers. The description is unusually explicit: a Layer 1 front-matter snippet and a Layer 2 bold-selection handler, surfaced on the Format menu, the editor context menu, and a hotkey. That is the kind of description that does its job. Two commands, ext.mdh.frontmatter with a snippet run, ext.mdh.bold with a handler run, menus place both on Format, the context menu gates bold on editor.hasSelection, the hotkey binds Ctrl plus Shift plus B to bold. The capability list is editor.read, editor.write, ui.announce, ui.command. No filesystem, no network, no clipboard, no prompts. So this Quillin triggers no consent dialog, ever, because it asks for nothing that needs consent.

Liam: Fourth, insert-character, id com.quill.bundled.insert-character. The description is the one-liner the manager shows in the row: insert any Unicode character by code point, hex, decimal, or U+ notation. The command is ext.insert.character, the menu parent is Insert, the context menu fires always. The capability list adds ui.prompt because the Quillin asks you which character to insert. That ui.prompt entry is the host's way of saying this Quillin is allowed to put up a dialog. The dialog is built by the host, the Quillin only asks.

Jessica: Group four, math and structure. One Quillin here, math-equations, id com.quill.bundled.math-equations, and it is the longest manifest in the box. Two commands, ext.math.insert_equation and ext.math.explore_equation_structure. Two menus on Insert, two context menu entries, two hotkeys, Ctrl plus Shift plus E to insert, and the QUILL Key chord Ctrl plus Shift plus Grave, F to explore. The abbreviations array is the work of art. It declares triggers that begin with backslash and expand to mathematical operators, relations, sets, arrows, Greek letters, calculus symbols, and vectors, organized by category. The schema calls out the abbreviations contribution model in its description, and Math Equations is the canonical example of how rich a Quillin can be without ever asking for the network or the filesystem.

Liam: The snippet_gallery contribution is also worth reading in this manifest. Quadratic formula, Pythagorean theorem, slope intercept, point slope, midpoint, difference of squares, circle area, circle circumference, each as a body with curly brace placeholders that match declared params. The Quillin Manager is the path that surfaces this gallery, and the math snippets are filled in by prompts the user answers before insertion. That's the Quillin as a teaching library, not just as a tool.


Jessica: Group five, accessibility surface. Three Quillins that are explicitly about living with the editor. First, status-scribe, id com.quill.statusscribe. The description says it adds a live word-count cell to the status bar, updated after every save, and demonstrates the status_bar contribution, the api.log developer logging, and the quillin enabled and disabled lifecycle events. The status_bar contribution has one cell, id count, label Words dash dash, handler get_count_cell, tooltip explaining what the cell shows, width fourteen. The schedule contribution declares a five-minute interval timer that recounts the active document so the cell never goes stale. This is the Quillin that makes the bottom-right corner of the editor feel alive.

Liam: Second, brf-tools, id com.quill.brftools. The description calls it a bundled Quillin, user-configurable preferences for braille translation, page handling, and status bar display, demonstrating multi-tab Quillin preferences. Its file_types contribution registers handlers for dot brf and dot brl, so opening a braille file in QUILL triggers the Quillin. Its preferences are organized in four tabs: Translation, Page Handling, Status Bar, and Advanced, with settings that match the production workflow episode forty-nine will cover in detail. The capability list is settings.own.read, settings.own.write, document.events, editor.read, ui.announce, ui.status. Notice ui.status. That is the capability that lets a Quillin read the status bar state, distinct from the status_bar contribution that writes a cell.

Jessica: Third in this group, the three transcription providers. openai-whisper-transcription, id com.quill.openaiwhisper, kind openai_whisper. groq-transcription, id com.quill.groq, kind groq. elevenlabs-transcription, id com.quill.elevenlabs, kind elevenlabs. Each manifest is small, each declares a transcription_providers contribution with one entry, and the entry's kind field is the host adapter that performs the actual upload. The schema's description for transcription_providers is sharp: the Quillin declares the provider, QUILL performs the upload via the named kind adapter under the network-egress audit, so the sandbox never handles audio bytes or the API key. Purely declarative. The Quillin runs no code, and the net capability is not required because the host's call is audited. That is a different safety model than the rest of the Quillin system, and it is worth flagging.

Liam: Final group, the contribution-only Quillins. Three entries in the bundled set exist to ship a content file, not to run code. ai-writing-prompts, id com.quill.bundled.ai-writing-prompts, version 1.0.0, contributes a prompts.json that the host loads into the Prompt Library the moment the user opens it. ai-writing-skills, id com.quill.bundled.ai-writing-skills, version 1.0.0, contributes four .sqp files: accessible-rewrite, argument-strengthener, meeting-notes-to-actions, research-and-draft. Both manifests declare an empty capabilities array and an empty commands array. Their purpose is to feed the registries the AI system consumes. The schema allows this. A Quillin is not always a command. Sometimes a Quillin is a contribution that shows up in a library tab and never once runs handler code.

Jessica: And the Node example, word-count-node, id com.quill.bundled.word-count-node, runtime node, main extension.js, version 1.0.0, min_quill_version 1.1.0. The capability list is editor.read, ui.announce, ui.command. One command, ext.wcn.count, one menu entry on Tools. The schema's allOf block switches the main filename pattern to a dot js suffix when runtime is node, and a dot py suffix otherwise. The README in that directory is honest about what the example does, what the protocol looks like, and what the published path is, the at-quill-slash-api npm package, which hides the JSON line protocol that the inline shim exposes for clarity. The bundled example inlines a small runtime shim to stay self-contained. The published path imports the package. Both are valid.


Liam: A pattern observation, walking all seventeen. The Quillin Manager's categories filter, the schema's categories enum, and the manifest's categories array are the same vocabulary, writing, accessibility, braille, productivity, developer, formatting, navigation, ai, integration, education, utilities. The bundled Quillins are honest about which labels they wear. Smart Insert declares writing, productivity, formatting. Status Scribe declares writing, productivity, accessibility. Document Guardian declares writing, productivity. Math Equations declares nothing, because its work spans algebra and geometry, not the bundled enum's terms. That gap is real and worth naming: not every Quillin has a category that fits. The schema does not require a categories array, and the project has not yet extended the enum to cover the gaps. If you write a math teaching Quillin, you ship without a label, and the manager filter cannot find you. Honest correction number two, filed.

Jessica: The linter, before we close. python dash m quill dot tools dot quillin_lint, with a directory, and a dash dash strict flag, validates a Quillin against the schema and the project's own rules. It does three independent things: it runs the executable JSON schema subset, it calls the manifest validator that the loader enforces, and it checks structure and capability hygiene. The linter is the same gate the project uses in its own CI, and the docs say it. Run it on the bundled directory with dash dash strict and you'll see seventeen PASS lines, or you'll see exactly which manifest drifted and why. This is the test loop. The linter is dependency-free and wx-free, so it runs anywhere quill imports.

Liam: Honest correction number three, also filed. The linter module docstring claims a Quillin author or CI runs it before submission, and a path that itself contains a manifest dot json is linted as one Quillin, a path that does not is treated as a collection. That works. The interesting edge case is what happens when you pass the parent directory without dash dash strict. The linter passes warnings and only fails on errors. The bundled Quillins all pass under strict, which is what made it into the repo, but a Quillin author who skips strict will see warnings about missing descriptions and missing authors and never know the warnings are not optional. The fix is one line. Use strict. The docs imply it, the linter enforces it when you tell it to.


Jessica: One more honest correction before the homework, the kind we promised at the top of the series. The bundled Quillins are seventeen in number, not the round number the user-facing manager's filter columns imply. We read the directory directly. The exact list, in alphabetical order: ai-writing-prompts, ai-writing-skills, brf-tools, doc-guardian, elevenlabs-transcription, groq-transcription, insert-character, insert-tools, journal-stamp, line-tools, markdown-helpers, math-equations, openai-whisper-transcription, smart-insert, status-scribe, text-tools, word-count-node. If a Quillin Manager or a marketing page names a different number, the directory is the source of truth, and the directory says seventeen.

Liam: What to take away, in the QUILL way. The bundled Quillins are the project's own exhibit A. They are real, they are short, they are honest in their manifests about what they ask for and what they do. Reading them is the fastest way to learn the schema, the capability model, the contribution surface, and the difference between a Layer 1 snippet and a Layer 2 handler. The author of a new Quillin does not need to read the schema end to end. They need to read two manifests, then one more, and the pattern lands. We just walked the whole collection in this episode. The next time you open the Quillin Manager, the rows are not strangers anymore.


Jessica: Homework, four steps. One: open the Quillin Manager, and for every enabled Quillin, read its manifest dot json, or at least the description, the capabilities, and the commands array. Notice which ones are contribution-only with no commands, and which are full Layer 2 handlers. The exercise is pattern recognition. The same shape keeps appearing, and the second time you see it you stop reading it as configuration and start reading it as vocabulary. Two: pick one Quillin you don't use, disable it, restart QUILL, and confirm in the manager that it is gone from the enabled list. Re-enable it. The exercise is the off switch, in your own hands. If you can turn a Quillin off and back on, you have learned the only skill that matters when extension code misbehaves. Three: run python dash m quill dot tools dot quillin_lint quill slash quillins_bundled dash dash strict, and read the PASS line for each of the seventeen. If any report FAIL, that is a real signal, copy the message and bring it to the issue tracker. The linter is the same gate the project uses in its own CI, so the same finding you see locally is the finding the project would see. Four: pick one bundled Quillin whose commands you have not used, and run two of its commands from the command palette in a scratch document. The goal is the muscle memory of finding a feature by name, opening it, hearing the screen reader announce the result, and confirming the editor state changed in the way you expected.

Liam: Next episode is forty-nine, braille production end to end. BRF and BRL, PEF, page geometry, the repair loop, layout metrics, trailing spaces. The brf-tools Quillin we walked today, its preferences tabs, are the controls that episode will exercise in real production. Two episodes after that, fifty, opens the hood on Quillins themselves, the architecture, the Quillin Manager, the developer console, the safety model. Then fifty-one walks you through building your own. The full course arc runs fifty-four episodes total, and we are forty-eight of fifty-four. Six more after this one.

Jessica: The thread we keep returning to, the screen reader first principle, the consent specific principle, the escape hatch guaranteed principle, all three are visible in the manifests we walked today. Insert Tools asks for nothing because it does nothing risky. Smart Insert asks for editor write because it inserts. Status Scribe asks for schedule and ui status because it ticks and writes a cell. The capability list is the literal fence around the work. The entry module is the literal work. The manifest is the literal contract. That's the shape, and that's what you can audit.

Liam: One more thing, because this matters. Some of the bundled Quillins ship in the box because the project wanted to demonstrate the surface, not because everyone needs them. Math Equations is for the math teacher. Journal Stamp is for the journal writer. BRF Tools is for the braille producer. Status Scribe is for the person who wants the word count always visible. None of them are required. Disable the ones you do not use. The editor is the same editor with or without them, only the menus, the bindings, and the status cell change. That is the smallest possible promise from extension code: the host is the host, the Quillin is a guest, and the guest is allowed to leave. And if a guest ever misbehaves, the door is not a feature flag buried in a config file, it is a checkbox in the manager, followed by a restart, and the editor is back to the version you trust. The design is not subtle on purpose. Subtle escape hatches are escape hatches no one finds.

Jessica: I'm Jessica.

Liam: I'm Liam. Read a manifest, run the linter, and we'll see you in braille production.

Back to all episodes