Clip: Emacs voice control - describing my setup during Linkarzu's livestream

| emacs, speech, speech-recognition

linkarzu wins the clip-off thanks to his fancy AI-powered clipping process! Here's a snippet from our conversation today. He'll be posting more clips, and I'm also going to edit the transcript of the conversation. Fun fun fun!

Additional notes:

  • Substitution: I use (add-hook 'substitute-post-replace-functions #'sacha-substitute-save-common-edits) to save the changes. sacha-substitute-save-common-edits Edit text has functions like sacha-subed-fix-common-errors-in-text that apply those changes to my speech recognition results and sacha-subed-fix-common-errors-from-start that apply them to already-prepared transcripts.
  • sachac/whisper.el has my fork of natrys/whisper.el to support voice commands. speech-input has a bunch of other things, too, and of course my Emacs config.
  • I've been using phony to define more voice commands using a parser.
  • Apparently I cannot spell when thinking out loud. It is Orgzly Revived, not ogrzly.
  • This actually doesn't use generative AI in the sense of Gemini or Claude, except for the conversational French demo. I use a local speech recognition model (currently Orukeet) and local speech synthesis (Kokoro FastAPI), So depending on your feelings about large language models, the models might be small enough to be fine with you. Alternatively, there are classical approaches to both speech recognition and speech synthesis like kaldi and espeak-ng.
Transcript and screenshots

0:00 Voice commands that mishear

Sacha: It turns out I cannot say start streaming reliably. Sometimes I say start screaming.

Linkarzu: Or like if I say Neovim, it doesn't get it. It says "New of him". I want to take a look at what you were sharing a moment ago. The speech to text, and it happens in real time, right?

Sacha: Oh yeah, yeah.

0:20 How the live transcript works

Linkarzu: But I don't do stuff real-time the way that you're doing right now. The transcription happens when we're done with the call and the process starts automatically. And a few hours after, I have the clips in my dashboard that I can upload if I want, right? But it's not real-time and I'm like, oh, and I saw how you did it on your side and it's pretty accurate. Like, what's the magic? What are you doing there? You're sending it somewhere, right?

Sacha: No, this is an entirely local model and I'm running it in a computer with hardly any GPU. So I'm actually just making it use CPU only for the speech recognition because I have a Lenovo P52 from 2018, I think. So it doesn't do this GPU thing very well. I think you're usually On a Mac, so you're spoiled for choices there. But speech recognition has gotten really good over the last few years. I'm using Orukeet at the moment. It's a multilingual model, so it can handle my poor French pronunciations just as fine as my English ones. I can press my keyboard shortcut. For example, I can say, this is a test during a chat with linkarzu. And then, because I've modified my dictionary, your channel name actually shows up properly. Oh, okay. Okay, okay, okay. We are talking about speech-to-text, dictation, all sorts of other things like that. Oh, where's my phone?

Linkarzu: Okay, yeah, so it just puts it in. It's pretty accurate. It's extremely accurate. What's the name you said? Because I use Wispr Flow, a local model as well. I do the transcript locally on my Mac. Wispr Flow is what the AI decided to use and I'm like, oh, it gets it, but not...

Sacha: Yeah, the model I'm currently using is called Orukeet. I think it's based on Parakeet, but it's been tweaked for more performance and less memory. But there are so many new models coming out. It's really quite interesting because every day or every other day, there's like, oh, try this new model. I'm not good enough to keep on top of all those changes. If I can manage to get the AI to generate me a server that has an OpenAI interface, I can plop it right into my Emacs setup and it will just work. So I'm happy with that. And this is fast enough that I can use it to think and then when I have the text, I can rearrange it however I'd like.

2:52 Playing with voice commands

Sacha: So for example, "prepare to fast forward." We're here.

Linkarzu: I have a similar command. Let me see if it works. Hold on. You see my terminal right now, right? Yes. I don't know if you can see my screen. Virgin mode off.

Sacha: Mm hmm. Yeah, yeah, yeah. I saw that.

Linkarzu: It didn't work. But it changes my wallpaper and it changes my...

Sacha: I have one too. Laser. Look, I changed my cursor to a laser so I can say, here's my mouse cursor, right?

Linkarzu: Okay. Pretty cool.

Sacha: Yeah, so the nice thing about it... Oh, it's still listening. Okay. Let me just turn off laser mode here. Oh, ah! Laser. Laser. Laser.

Linkarzu: It happens to me as well.

Sacha: Edit, retry. Laser. Yeah, okay, there you go.

3:51 Speech commands enable more shortcuts

Sacha: The nice thing about speech commands is that it opens up a whole lot of other ways to run commands without necessarily having to memorize keyboard shortcuts. And you can have more fun with it too. So for example, now I have this command. It turns out I cannot say "start streaming" reliably. Sometimes I say start screaming. Or at least that's... Well, I know sometimes I accidentally say that and sometimes that's what the speech recognition hears. So instead, my command for starting this stream, because of course Emacs controls my OBS through WebSockets, is "let's go live". And my command for stopping the stream is "over and out". And just because it's a little more fun to say, it becomes easier for me me to remember what I need to say in order to make this happen.

4:37 Does it handle hard words?

Linkarzu: Yeah, yeah, yeah. Now, why is it accurate? And you have a dictionary of like the difficult words. Like if I say Neovim, it doesn't get it. It says "New of him", or it just puts whatever it wants, whenever it wants. Sometimes it puts something random out there. What do you do for yours?

Sacha: "Neovim is okay, I guess." Let's see if it does a thing. Yeah, it got that without my needing to correct things. Let's pick a harder word. Anti-disestablishmentarianism. Close enough. Okay, you know, that requires very little editing. What's a difficult word? Oh, actually, let's pick a different name. Sometimes it gets Prot's name wrong. "Prot does a lot of videos on Emacs." Oh, no, it got him too. If there was a thing that is difficult to say... What was that? Okay. "Heisenbug is making org.nvim." That one. Okay, here we go. "Heisenbug is making org.nvim." I mean, it's getting him.

5:51 Thanking sponsors and members

Linkarzu: Let me thank my YouTube members, the CEOs are shown on screen, web2three, web2trhee.com, TED, cpnllc.com, and also Gallo, these are the three CEOs, and I just want to thank the rest of the YouTube members, which are the ones that are shown here, so just appreciate each one of the members for supporting the channel, okay?

6:14 Fixing misrecognized words with a shortcut

Linkarzu: So, it's a local model, interesting. It is a local model. Do you feed it a dictionary at some point?

Sacha: If I do need to change things... Okay, so if I need to change things, let's say for example, Orgzly Revived, you probably can't get that one. "I use Orgzly Revived on my phone to check my tasks." Oh yeah, so here, right?

image from video 00:06:33.143Sacha: It says Orgsley Revived. What is that even? But I can press Ctrl+; and it uses substitute.el.

image from video 00:06:40.066Sacha: Orgzly Revived here. And what that does, in addition to the substitutions that happen throughout the buffer, so for example, if I'm adding a transcript, it will change that all throughout the transcript. I've also added some code because this is Emacs, I can just do that. that saves this in common errors or commonly misrecognized words. And then when I recognize text, whether it's before a voice command or if I'm just doing this or whatever, it will apply all of those common fixes. Common edits.

image from video 00:07:16.061Sacha: Here we go. So it automatically adds it to this thing here, which gets saved automatically for me. And that's the change that I've just added.

Linkarzu: Interesting. Pretty cool.

Sacha: So it's really nice to have that kind of [dictionary] shortcut built into the way that I edit things. All I know is I just hit Ctrl+; and put in what it's supposed to be. And then it gets not only fixed in my current file, but in the future as well.

Linkarzu: Yeah, I need to work on my transcript game.

7:51 How the live transcript began

Sacha: Like many things in Emacs, this came out of a bunch of small, seemingly unrelated hacks. One was, I was having this conversation with a French tutor and I was like, man, I am having a hard time making sure... Like, he would switch into lecture mode and I was trying to have more conversation mode so I could practice some more, right? So I think I've got this right. Anyway, so I had a large language model generate a Python server, because sometimes I'm like, I just want a proof of concept for this. I don't necessarily know all the details of how to work with the Silero voice activity detection thing. Anyway, so make me a server that can listen to my audio devices in real time without messing up my actual microphone use if I'm on stream. Okay, so I have this Python server and then I wanted to visualize it within Emacs. I got that visualizing inside Emacs. Then I wanted to say, all right, you know, why don't I have speech recognition listening on this thing so that if I say something, it can check it off, like playing bingo, you know, if I say it, then it gives me a note that I've actually said that word or phrase. And so it could show me a list of the words or phrases that I still want to say in conversation. And then, as we're preparing for this conversation, I was like, you know what would be really cool is if I could have that speech recognition, which is running anyway, give me a transcript of the current conversation in a way that I can use it. I could then clip if I wanted to because sometimes I'll be doing a live stream and I'd be like, you know, that was a really cool demo and I should grab that. So that I can just grab the screenshot or put it into a blog post or just get a text or extract a clip out of it, turn it into a video, right? And so now I have this thing where, hang on a second, if I'm somewhere else, for example, it's easy for me to get to.

9:53 Prepare to fast forward

Sacha: I have a voice command for it. "Prepare to fast forward", which is of course a Spaceballs reference. It'll show me then this thing. And if we are... Let me load this real quick. It will show me the video that we have or at least the recording that I've got of it. That's on the right side. Here, this MPV is controlled by Emacs. If I go here... Let's say this one. So here's your waveform for it. If I play it back: "which is of course a Spaceballs reference", it'll show me then this thing. And I can copy the text if I wanted to, or I can extract this into its own video.

10:41 Talking with Emacs

image from video 00:00:00.000Linkarzu: What other tricks do you want to show us there? What other things do you want to share about, brag about your Emacs workflow?

Sacha: It's really hard to say. I told you how M-x doctor was the beginning of my experience, right?

Linkarzu: Your journey, yep.

Sacha: Yes, yes. So this is the doctor. You can say things like, "I'm feeling happy today," as I said, right? And then it uses that to generate its response. But I have this conversation mode. "Yes, especially when I get to tinker with Emacs." And then, uh... "What happened when you get to tinker with Emacs?" Did that...? Does the TTS come through? Yeah, it does. And the reason I did this was because after I showed off my vocal commands to Emacs Paris, they were like, oh, you know, what if you can have a conversation? So I was like, OK, let's come back full circle to the thing that got me curious about Emacs in the first place, and voice enable that. And then, of course, this is a very old AI. It's much more interesting if you apply it to the new models. So if I want to, for example, practice French. This is one of my voice commands here. Then I can...

Doctor: "What would happen? I would appreciate it if you would continue."

Sacha: Okay, here we are. Then I might say, "Je parle avec linkarzu." And then I think... There you go. It will eventually... Maybe? Thank you.

image from video 00:12:18.696Gemini: "Ah, c'est super de discuter avec lui ! C'est toujours enrichissant de partager (to share) ses passions en direct. Quel sujet abordez-vous ensemble aujourd'hui?"

Sacha: Alright, so this now uses a large language model. This one uses Gemini because gptel makes it super easy to plug in different models. So if I wanted to practice French, but I don't necessarily want to bug people because I take a while to think about my words and sometimes I'm looking stuff up, then at least I can simulate that kind of conversation. And there are a gazillion apps that will sell you a subscription to do this. But because it's here and it's plain text and I can control it, then I can more easily go through it afterwards and analyze the vocabulary or correct the things that it didn't get right, which I know is because of the speech recognition and not because of me or whatever, right? So it's so much fun to be able to tinker with Emacs to do what I wanted to do.

13:19 Life in tiny time chunks

Linkarzu: How long do you spend sitting? Like do you spend sitting most of the day?

Sacha: Most of the time, actually, I have to go help out the kiddo, right? So that keeps me away from the computer, which is one of the reasons why I've had to learn how to deal with very fragmented time. Not much time sitting in front of the computer to focus on something. Everything that I want to do has to be something that I can do in 5, 10, 15 minutes, maybe 30 minutes. There might be... At the moment, she is fairly independent, but I can still be interrupted by somebody who needs breakfast or somebody who needs a hug and whatever. So I need to be able to capture a thought, get it out of the way and work on things in tiny chunks.

Linkarzu: I've seen my wife, how she handles things. And I'm like, man, it's a lot of mental overhead, you know? That's a whole other conversation to say, see, men are the ones that make progress, build their professional careers and wives, you know, usually take care of the kids. It's a huge sacrifice. What do you think? How do you feel about all that?

Sacha: I signed up for it totally knowing what I was getting into. I was like, okay, there's a lot involved in being the default parent, right? The primary person who patches up. But I think partly because of Org Mode and Emacs, it's been very, very helpful to me to be able to say, "Yeah, that's a great idea. I'm going to write that down in my phone or on my computer" - usually on my phone back in the early parenting days. I'm away from my computer. I'm at the playground. So the fact that I can capture a note into Org Mode and then know that I can get back to it in several years when I have more free time, or that Org Mode can keep track of the deadlines that might be a year from now, like when I need to renew my passport, and just have that surface the reminder, at the right time with the notes on exactly what I need to do, and the links to wherever I need to go, I think that has been very, very helpful for me.

15:23 Capturing tasks on phone and computer

Linkarzu: Good point that you brought up because I don't know, quite a few days ago I just came up, well, the clanker came up with a method, we could say, of me just tapping it, saying something to it, and when I come to my computer, the task is there in Neovim, right? Yes. Because I forget, I'm outside, I'm like, okay, I have to remember this, I have to, I'm not gonna remember it, it's just gonna go away. So I do it on the phone, shows up in Neovim. It's a huge benefit. How do you do it

Sacha: For my phone, I often just put it into Orgzly Revived, sometimes with dictation, sometimes just typing in a few keywords to help me remember. A lot of times, if I'm coming across...

Linkarzu: Orgzly Revived, what is it?

Sacha: (Hah, I clearly can't spell) ogrzly?

Linkarzu: If you want to show it, I don't know.

Sacha: It's on my phone. I'm gonna say, okay, because this is what, Orgzly.

Linkarzu: Is it like an app?

Sacha: Yeah, so I use an Android phone. And now there are actually a gazillion apps that talk Org Mode and can synchronize with your files and whatever. I'm currently still just using Orgzly Revived as an app on my phone with Syncthing, With Syncthing being the free synchronization that I can use to just get my files back and forth. But there are lots of other alternatives, so you can find something that fits you well. I am very tempted to figure out finally how to use Emacs native, because there's an Emacs port for Android. Especially if I can get my speech synthesis and speech recognition working on it. I think that would be amazing to have this kind of conversation with Emacs along the way.

17:05 Capturing tasks by voice

Sacha: And then on the computer, if I need to capture something quickly, oh, I can show you this one. Let's see. Okay. "Remind me to put together a quick description of my to-do workflow." And it will take that note and it will stick it into an inbox.

image from video 00:17:36.180Sacha: Here I'm in live mode so my public tasks don't get mixed in with my private tasks. If I do an agenda, it should just be limited to the public stuff. Anyway, so the remind me created the note for me. It includes the audio in case the speech recognition didn't get anything right. And it includes a screenshot so that in case I'm doing this from a different application because my keyboard shortcut is global, I can still see the context and find that sort of stuff. So yeah.

18:01 Building workflows out of little bits of time

Linkarzu: Quite interesting. Quite advanced. Quite complex. It must have taken you months, years to set all of this up.

Sacha: As I said, I can only work in thirty minutes or so. So this one, I think was a 10, 15 minute hack. Okay. Little bits of time. This link here to whatever I was looking at, you got that free from Org Mode. This thing here with a recording, I got that because I already wanted to save my recordings anyway, so it was just a matter of adding a link to the file name that I already had saved. This screenshot, you know, another five minutes, because I already had Spectacle capturing the screenshot of both screens. So it's fairly simple. It will even work for things like, "remind me next month to follow up with linkarzu to see whether he's switched to Emacs."

image from video 00:18:50.296Sacha: So this one here, for example, it says, remind me next month, et cetera, et cetera. And it has scheduled it for next month.

Linkarzu: That's pretty cool.

Sacha: I'm not actually going to pressure you to switch the Emacs. You can keep using Neovim and just borrow all the interesting ideas. org.nvim is there, I can adapt it to do this, you know?

Download the VTT

He hasn't released a clip of this one yet, but this exchange was one of my favourite parts of the main conversation:

[Linkarzu]: I don't know if like that's a particularity of Neovim users, we're all toxic and we just hate each other.

[Sacha]: Yeah, maybe you should just come over to the Emacs community. We have hot chocolate.

[Linkarzu]: If you go to the Emacs subreddit, it's like rainbows and butterflies. There's not a lot of hate. I always wonder why does that happen? It's not moderators, you know, it's just people. Is it just because it's old people? Like the professor, he doesn't want to fight any more. He's old enough. He retired already. He's just ready to pass to the next life. So what, what?

[Sacha]: Hypothesis number two, maybe your editor makes you grumpy.

That's at about 01:30:06 in this unlisted embed of the full conversation:

View Org source for this post

EmacsConf: Using message-sent-hook to run buffer-specific code to keep track of e-mailed schedules

| emacs, org, emacsconf

I make lots of little EmacsConf schedule updates based on the speakers' feedback. I needed a way to keep track of the schedule that I've just sent the speaker so that I could calculate the differences and notify them again the next time I change the schedule for their talk. I like the way that keeping track of this lets me include a summary of the change in the subject and in the body of the message. For example, one of the emails I sent today had the subject: This blog post is about updating the EMAILED_SCHEDULE entry property in my Org Mode file that keeps track of this year's conference talks so that I can save the schedule that I've emailed. I want to set it only after I've successfully sent the email, because I might change my mind or forget to send the e-mail, and I want to make sure the entry property is based on what I've e-mailed.

EmacsConf 2026: Schedule update as of 2026-10-28: svg: Sun ~2:20 PM EST (40 min earlier)

I send the messages within Emacs, of course. This lets me use emacsconf-mail.el to mail-merge using Emacs Lisp. I can then use message-sent-hook to run buffer-specific code once I've sent the message. This lets me set it up so that each message updates its own talk once I've used C-c C-c to send it.

First, I need a function that adds to a talk's logbook. This is not specifically needed for the message-sent-hook, but it's useful for keeping track of the fact that I've sent this kind of email to that speaker on this date. It's very helpful to be able to see who I've already sent the backstage information to or when was the last time I sent them a schedule update. I can also filter the list of talks by the text in the logs so that if I partially send a mail merge and then cancel the rest because I want to tweak the code, I can send the new mail merge only to the remaining speakers. This is in emacsconf.el.

emacsconf-add-to-talk-logbook: Add NOTE as a logbook entry for TALK.
(defun emacsconf-add-to-talk-logbook (talk note)
  "Add NOTE as a logbook entry for TALK."
  (interactive (list (emacsconf-complete-talk) (read-string "Note: ")))
  (save-window-excursion
    (save-excursion
      (emacsconf-with-talk-heading talk
        (emacsconf-add-to-logbook
         (if (functionp note)
             (funcall note)
           note))
        (bury-buffer (current-buffer))))))

This function is the one that gets added to the message sent hook. It's in emacsconf-mail.el:

emacsconf-mail-add-to-logbook: Add to logbook for all matching talks from this speaker.
(defun emacsconf-mail-add-to-logbook (email note)
  "Add to logbook for all matching talks from this speaker."
  (interactive
   (let* ((email (mail-strip-quoted-names
                  (plist-get (plist-get (notmuch-show-get-message-properties) :headers)
                             :From)))
          (talks (emacsconf-mail-talks email)))
     (list
      email
      (read-string (format "Note for %s: "
                           (mapconcat (lambda (o) (plist-get o :slug))
                                      talks", "))))))
  (condition-case e
      (save-window-excursion
        (mapc
         (lambda (talk)
           (emacsconf-add-to-talk-logbook talk note))
         (emacsconf-mail-talks email)))
    (error (message "Error %s" e))))

And this function actually sets up the message-sent-hook:

emacsconf-mail-log-message-when-sent
(defun emacsconf-mail-log-message-when-sent (o message)
  (add-hook 'message-sent-hook
            `(lambda ()
               (save-window-excursion
                 (emacsconf-add-to-talk-logbook
                  ,(plist-get o :slug)
                  ,message))
               (when (match-buffers "*unsent")
                 (switch-to-buffer (car (match-buffers "*unsent")))))
            nil t))

Which gets called by this part of emacsconf-mail-prepare:

(when (plist-get template :log-note)
  (mapc (lambda (talk)
          (emacsconf-mail-log-message-when-sent talk (plist-get template :log-note)))
        (emacsconf-mail-talks email)))

Then my emacsconf-mail-interim-schedule-update can specify the :log-note like this:

      :log-note
      (lambda ()
        (dolist (talk (cdr group))
          (emacsconf-with-talk-heading talk
            (emacsconf-schedule-save-emailed-time)))
        (concat "emacsconf-mail-interim-schedule-update"
                (if log-note (concat ": " log-note) "") " - " summary))

This lets me run that code only when the mail gets sent.

Next automation idea: Someday I may even figure out how to attach an iCalendar file (including updates to events) so that people can add it to their calendars.

If you find yourself wanting to run code when a message gets sent, then definitely take a look at message-sent-hook. You can add a buffer-local hook with the fourth argument to add-hook (ex: (add-hook 'message-sent-hook (lambda () ...) nil t)) so that you can take actions specific to that message.

Have fun!

View Org source for this post

2026-10-26 Emacs news

| emacs, emacs-news

The coolest thing I saw this week is Clerkenwell, a handwritten Clojure notebook (Github).

Links from reddit.com/r/emacs, r/orgmode, r/spacemacs, Mastodon #emacs, Bluesky #emacs, Hacker News, lobste.rs, programming.dev, lemmy.world, lemmy.ml, planet.emacslife.com, YouTube, the Emacs NEWS file, Emacs Calendar, and emacs-devel. Thanks to Andrés Ramírez for emacs-devel links. Do you have an Emacs-related link or announcement? Please e-mail me at sacha@sachachua.com. Thank you!

View Org source for this post

subed.el and quoting snippets of YouTube videos from the auto captions

| emacs, audio, subed

I'm preparing for a conversation with linkarzu. It would be fun to quote snippets from some of the other videos he has. I like the way he does a lot of reaction videos that build on what people have shared. He tends to listen to things at 1.25 or 1.5x speed. I'm not sure if I have the patience even for that, so it'd be nice to be able to just quickly skim the text. He also clips a lot of his own videos. It might be interesting to play around with my workflows for listening to snippets and clipping them.

I've grabbed YouTube captions and reformatted them before:

This time around, I want to get the VTT format so that I can possibly use them with subed-record to clip audio or video.

From a YouTube link, I want to run a single command that gets me a VTT file with that as the media source and with the captions. If there are any chapters in the description, it would be lovely to get them too. I can get them from the JSON, yay!

Now I can use M-x sacha-subed-youtube to open the VTT file, which is cached locally, and I can use M-x sacha-subed-youtube-region-as-quote after selecting a section. Well, actually, I have an Embark command s (for "subed") that I can run on a YouTube video link and a selected-mode shortcut for y that I can run when the region is selected. Results:

I Asked Prot If I Should Switch to Emacs

00:09:46: I think the value of Org is that it is in the context of Emacs, which can now do other things. It can be your email client. It can be your agenda. Of course, it can be your programming environment. All these sorts of things, like your RSS feed reader and so on. And in the context of all that, you also have Org. So for me, that's kind of the value. But otherwise, having Org elsewhere, it's great still, because the paradigm of Org, I think, is a portable paradigm.

Org Mode in Neovim Is Finally Here - Full org.nvim Demo

00:00:00: I think that I achieved like 100% of parity with the original Org Mode version on Emacs.

Code for subed + YouTube
(defvar sacha-subed-youtube-dir "~/proj/youtube-captions"
  "Directory with YouTube captions.")
(defvar sacha-subed-youtube-temp-dir "~/Downloads" "Snap installations need a workaround for permission.")
;;;###autoload
(defun sacha-subed-youtube (url)
  "Download the automatic subtitles or check my cache."
  (interactive "MURL: ")
  (let* ((id (sacha-org-yt-id url))
         (existing (car (directory-files sacha-subed-youtube-dir t
                                         (concat "^" (regexp-quote id) ".*\\.vtt\\'")))))
    (if existing
        (progn
          (find-file existing)
          (subed-mpv-play-from-url url))
      ;; Download
      (let ((directory (make-temp-file (expand-file-name "yt-dlp" sacha-subed-youtube-temp-dir) t))
            filename
            json
            match
            chapters
            subtitles)
        (with-current-buffer (get-buffer-create "*yt-dlp*")
          (let ((default-directory directory))
            (call-process
             "yt-dlp" nil t nil
             "--skip-download"
             "--write-info-json"
             "--sub-format"
             "vtt"
             "--write-subs"
             "--write-auto-subs"
             url)))
        (when (null (directory-files directory t "\\.json$"))
          (error "Could not get data."))
        (setq json (json-read-file (car (directory-files directory t "\\.json$"))))
        (setq chapters (alist-get 'chapters json))
        (setq filename (expand-file-name
                        (concat id " - " (alist-get 'title json) ".vtt")
                        sacha-subed-youtube-dir))
        (setq subtitles (subed-parse-file (car (directory-files
                                                directory t
                                                "\\.vtt$"))))
        (delete-directory directory t)
        ;; add the chapters as comments
        (mapc
         (lambda (sub)
           (when (and chapters
                      (>= (elt sub 1)
                          (* (alist-get 'start_time (car chapters)) 1000)))
             (setf (elt sub 4) (alist-get 'title (pop chapters)))))
         subtitles)
        (subed-create-file
         filename
         subtitles
         t)
        (find-file filename)
        (subed-mpv-play-from-url url)))))

(defun sacha-subed-youtube-id ()
  "Return the YouTube ID."
  (or (save-restriction
        (save-excursion
          (goto-char (point-min))
          (subed-forward-subtitle-text)
          (when (subed-record-get-directive "YOUTUBE_URL")
            (sacha-org-yt-id
             (subed-record-get-directive "YOUTUBE_URL")))))
      (car (split-string (file-name-base (buffer-file-name)) " "))))

;; Now we just need a quick way to copy a YouTube URL.
;;;###autoload
(defun sacha-subed-youtube-url (&optional start-msecs end-msecs)
  "Copy YouTube URL for the current timestamp."
  (interactive)
  (when-let*
      ((id (sacha-subed-youtube-id))
       (s
        (if end-msecs
            (format "https://youtu.be/%s?t=%d&end=%d"
                    id
                    (/ (or start-msecs (subed-subtitle-msecs-start))
                       1000)
                    (1+ (/ end-msecs
                           1000)))
          (format "https://youtu.be/%s?t=%d"
                    id
                    (/ (or start-msecs (subed-subtitle-msecs-start))
                       1000)))))
    (when (called-interactively-p 'any)
      (kill-new s)
      (message "%s" s))
    s))

;;;###autoload
(defun sacha-subed-youtube-play ()
  "Play this video from YouTube."
  (interactive)
  (when-let*
      ((id (sacha-subed-youtube-id))
       (s (concat "https://youtu.be/" id)))
    (when (string= subed-mpv-media-file s)
      (subed-mpv-play-from-url s))
    (subed-mpv-jump-to-current-subtitle)
    (subed-mpv-unpause)))

;;;###autoload
(defun sacha-subed-youtube-region-as-quote (beg end &optional label)
  "Format this as a quote."
  (interactive (list (region-beginning) (region-end) (when current-prefix-arg (read-string "Label: "))))
  (let* ((id (sacha-subed-youtube-id))
         (url (sacha-subed-youtube-url
               (save-excursion
                 (goto-char beg)
                 (subed-subtitle-msecs-start))
               (save-excursion
                 (goto-char end)
                 (subed-subtitle-msecs-stop))))
         (base (file-name-base (buffer-file-name)))
         (text (subed-subtitle-list-text (subed-subtitle-list beg end)))
         (s (format
             "%s\n#+begin_quote\n%s: %s\n#+end_quote\n"
             (org-link-make-string
              (concat "yt:" url)
              (or label
                  (and (string-match (format "^%s - \\(.+\\)" (regexp-quote id)) base)
                       (match-string 1 base))
                  (sacha-page-title url)))
             (org-link-make-string
              (concat "vtime:"
                      (subed-msecs-to-timestamp
                       (save-excursion
                         (goto-char beg)
                         (subed-subtitle-msecs-start))
                       t)))
             (with-temp-buffer
               (insert text)
               (let ((fill-column most-positive-fixnum))
                 (fill-region (point-min) (point-max))
                 (string-trim (buffer-string)))))))
      (when (called-interactively-p 'any)
        (kill-new s)
        (message "%s" s))
      s))

Some of this code hasn't been committed to subed yet, but I will commit it sometime this week.

My next steps might be to:

  • cache the video as a whole to make it easier to check the waveforms
  • extract the segment to a standalone video file so that it's easy for me to play back or include in another video
  • see if I can use my voice activity detection and semi-streaming speech recognition to get a VTT of my current OBS recording
This is part of my EmacsConfiguration.
View Org source for this post

Analyzing Emacs News: 564 posts over 11 years, > 34k items, ~60/post

| emacs, community

While summarizing my history with Emacs, I was curious about just how many Emacs News posts I've written and how many links I've highlighted. 564 posts, > 34000 items, an average of 60 items per posts.

Analysis: It turned out that my emacs-news/index.org only went back to about 2016, missing a few months of 2015. To fill in the data, I needed to convert the old HTML files into Org format.

find -name \*news\*.html -exec zsh -c 'pandoc -f html -t org {} --wrap=none -o $(basename {} .html).org' \;

Then I inserted the old entries into my file. insert-file-contents doesn't seem to move the point, but if I narrow to my Posts subtree (org-narrow-to-subtree), then I can go to the end of the narrowed part.

(defun sacha-emacs-news-insert-old-ones ()
  (interactive)
  (let ((dir "~/proj/static-blog/blog/2015/"))
    (dolist (f
             (sort
              (directory-files-recursively dir "news.*org$")
              :key #'file-name-base
              :reverse t))
      (insert "** " (substring (file-name-base f) 0 10) " Emacs News\n\n")
      (insert-file-contents f)
      (goto-char (point-max)))))

With all the entries in place, let's look at the list items that start with a link.

code for analysis
;;;###autoload
(defun sacha-emacs-news-count-links ()
  "Return the number of main links in this subtree."
  (interactive)
  (let ((count 0))
    (save-excursion
      (org-back-to-heading)
      (while (re-search-forward "^ *- \\[\\[" (save-excursion (org-end-of-subtree)) t)
        (incf count)))
    (when (called-interactively-p 'any)
      (message "%d" count))
    count))

;;;###autoload
(defun sacha-emacs-news-analyze ()
  "Count how many entries and items. Make a table of entries."
  (interactive)
  (with-current-buffer (find-file-noselect "~/sync/emacs-news/index.org")
    (goto-char (point-min))
    (let (results)
      (org-map-entries
       (lambda ()
         (let ((title (org-entry-get (point) "ITEM")))
           (when (string-match "\\([0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]\\) Emacs" title)
             (push (list (match-string 1 title)
                         (sacha-emacs-news-count-links))
                   results)))))
      (seq-uniq (sort results :key 'car :reverse t)))))
(append '(("Date" "Count") hline) (sacha-emacs-news-analyze))
set title "Number of links in Emacs News per week"
set xdata time
set timefmt "%Y-%m-%d"
set format x "%Y"
set xlabel "Year"
set ylabel "Count"
set grid
plot data using 1:2 with lines title "Items"
emacs-news.png

This probably tracks my availability more than anything else. The dip in 2017 and 2018 corresponds pretty well to the time that the kiddo needed more of my attention. Babies sleep a lot; toddlers, not so much.

I generally feel that there are so many interesting rabbit holes to go down each week, and the Emacs community is active enough that there's always one or two things I want to add to my to-do list to explore further. Putting together Emacs News is one of the highlights of my week. It takes me about 1 - 2 hours, and some of that is just because I get distracted trying out the cool stuff I come across.

Learning from similar newsletters: OCaml Weekly News has a single author as well and does a lot more summarization, but includes fewer links. This Week in Rust is a similar link-dump weekly newsletter. It's written by a larger team and it has more commentary. I think that for the Emacs community, I'm still leaning towards this large list of categorized links for easy skimming. As I get the hang of writing more, I'd like to write more blog posts myself that Emacs News can also link to. If your community doesn't already have a weekly or monthly newsletter, I highly recommend it as a way to bring the community together.

Here's the table, in case you're curious:

Data
Date Count
2026-10-19 74
2026-10-12 74
2026-10-05 72
2026-09-28 55
2026-09-21 50
2026-09-14 53
2026-09-07 73
2026-08-31 86
2026-08-24 75
2026-08-17 71
2026-08-10 66
2026-08-03 74
2026-07-27 74
2026-07-20 99
2026-07-13 50
2026-07-06 78
2026-06-29 60
2026-06-22 72
2026-06-15 66
2026-06-08 93
2026-06-01 56
2026-05-25 56
2026-05-18 57
2026-05-11 94
2026-05-04 88
2026-04-27 71
2026-04-20 91
2026-04-13 86
2026-04-06 84
2026-03-30 69
2026-03-23 61
2026-03-16 75
2026-03-09 83
2026-03-02 86
2026-02-23 96
2026-02-16 89
2026-02-09 87
2026-02-02 109
2026-01-26 59
2026-01-19 84
2026-01-12 86
2026-01-05 88
2026-01-04 59
2025-12-29 63
2025-12-22 99
2025-12-15 65
2025-12-08 74
2025-12-01 62
2025-11-24 71
2025-11-17 57
2025-11-10 76
2025-11-03 69
2025-10-27 64
2025-10-20 51
2025-10-13 57
2025-10-06 62
2025-09-29 64
2025-09-22 66
2025-09-15 71
2025-09-08 61
2025-09-01 74
2025-08-25 82
2025-08-18 69
2025-08-11 84
2025-08-04 53
2025-07-28 82
2025-07-21 70
2025-07-14 65
2025-07-07 56
2025-06-30 67
2025-06-23 63
2025-06-16 62
2025-06-09 50
2025-06-02 68
2025-05-26 61
2025-05-19 74
2025-05-12 58
2025-05-05 57
2025-04-28 96
2025-04-21 70
2025-04-14 99
2025-04-07 64
2025-03-31 83
2025-03-24 74
2025-03-17 94
2025-03-10 102
2025-03-03 102
2025-02-24 74
2025-02-17 85
2025-02-10 64
2025-02-03 84
2025-01-27 78
2025-01-20 80
2025-01-13 59
2025-01-06 66
2024-12-30 92
2024-12-23 85
2024-12-16 72
2024-12-09 82
2024-12-02 63
2024-11-25 75
2024-11-18 67
2024-11-11 59
2024-11-04 73
2024-10-28 65
2024-10-21 52
2024-10-14 72
2024-10-07 80
2024-09-30 56
2024-09-23 93
2024-09-16 85
2024-09-09 52
2024-09-02 67
2024-08-26 56
2024-08-19 62
2024-08-12 48
2024-08-05 45
2024-07-29 51
2024-07-22 56
2024-07-15 60
2024-07-08 68
2024-07-01 67
2024-06-24 77
2024-06-17 86
2024-06-10 82
2024-06-03 79
2024-05-27 71
2024-05-20 66
2024-05-13 91
2024-05-06 73
2024-04-29 84
2024-04-22 63
2024-04-15 94
2024-04-08 67
2024-04-01 95
2024-03-25 91
2024-03-18 78
2024-03-11 79
2024-03-04 84
2024-02-26 72
2024-02-19 69
2024-02-12 78
2024-02-05 70
2024-01-29 96
2024-01-22 83
2024-01-15 70
2024-01-08 99
2024-01-01 76
2023-12-25 77
2023-12-18 74
2023-12-11 66
2023-12-04 56
2023-11-27 85
2023-11-20 76
2023-11-13 62
2023-11-06 52
2023-10-30 59
2023-10-23 69
2023-10-16 91
2023-10-09 93
2023-10-02 82
2023-09-25 73
2023-09-18 72
2023-09-11 90
2023-09-04 79
2023-08-28 83
2023-08-21 78
2023-08-14 84
2023-08-07 49
2023-07-31 69
2023-07-24 46
2023-07-17 53
2023-07-10 52
2023-07-03 67
2023-06-26 59
2023-06-19 53
2023-06-12 41
2023-06-05 52
2023-05-29 49
2023-05-22 64
2023-05-15 66
2023-05-08 57
2023-05-01 73
2023-04-24 67
2023-04-17 66
2023-04-10 49
2023-04-03 76
2023-03-27 92
2023-03-20 65
2023-03-13 85
2023-03-06 64
2023-02-27 62
2023-02-20 64
2023-02-13 65
2023-02-06 67
2023-01-30 70
2023-01-23 85
2023-01-16 83
2023-01-09 83
2023-01-02 89
2022-12-26 89
2022-12-19 83
2022-12-12 92
2022-12-05 69
2022-11-28 90
2022-11-21 82
2022-11-14 64
2022-11-07 75
2022-10-31 74
2022-10-24 37
2022-10-17 54
2022-10-10 77
2022-10-03 81
2022-09-26 75
2022-09-19 75
2022-09-12 77
2022-09-05 67
2022-08-29 73
2022-08-22 50
2022-08-15 45
2022-08-08 65
2022-08-01 69
2022-07-25 60
2022-07-18 55
2022-07-11 75
2022-07-04 56
2022-06-27 51
2022-06-20 60
2022-06-13 67
2022-06-06 65
2022-05-30 38
2022-05-23 68
2022-05-16 65
2022-05-09 67
2022-05-02 82
2022-04-25 59
2022-04-18 71
2022-04-11 69
2022-04-04 63
2022-03-28 67
2022-03-21 71
2022-03-14 64
2022-03-07 68
2022-02-28 65
2022-02-21 77
2022-02-14 88
2022-02-07 49
2022-01-31 75
2022-01-24 74
2022-01-17 83
2022-01-10 57
2022-01-03 67
2021-12-27 47
2021-12-20 56
2021-12-13 57
2021-12-06 69
2021-11-29 75
2021-11-22 55
2021-11-15 56
2021-11-08 94
2021-11-01 79
2021-10-25 66
2021-10-18 77
2021-10-11 70
2021-10-04 91
2021-09-27 86
2021-09-20 63
2021-09-13 79
2021-09-06 63
2021-08-30 68
2021-08-23 64
2021-08-16 77
2021-08-09 69
2021-08-02 59
2021-07-26 77
2021-07-19 65
2021-07-12 48
2021-07-05 64
2021-06-28 46
2021-06-21 65
2021-06-14 37
2021-06-07 65
2021-05-31 65
2021-05-24 46
2021-05-17 65
2021-05-10 58
2021-05-03 47
2021-04-26 57
2021-04-19 73
2021-04-12 52
2021-04-05 70
2021-03-29 65
2021-03-22 82
2021-03-15 64
2021-03-08 70
2021-03-01 55
2021-02-22 84
2021-02-15 96
2021-02-08 74
2021-02-01 73
2021-01-25 71
2021-01-18 58
2021-01-11 66
2021-01-04 76
2020-12-28 72
2020-12-21 73
2020-12-14 92
2020-12-07 76
2020-11-30 65
2020-11-23 51
2020-11-16 47
2020-11-09 57
2020-11-02 72
2020-10-26 51
2020-10-19 76
2020-10-12 70
2020-10-05 57
2020-09-28 71
2020-09-21 81
2020-09-14 79
2020-09-07 61
2020-08-31 64
2020-08-24 73
2020-08-17 80
2020-08-10 89
2020-08-03 70
2020-07-27 56
2020-07-20 60
2020-07-13 55
2020-07-06 48
2020-06-29 43
2020-06-22 56
2020-06-15 63
2020-06-08 66
2020-06-01 116
2020-05-25 64
2020-05-18 83
2020-05-11 62
2020-05-04 77
2020-04-27 63
2020-04-20 63
2020-04-13 62
2020-04-06 49
2020-03-30 62
2020-03-23 58
2020-03-16 52
2020-03-09 50
2020-03-02 43
2020-02-24 53
2020-02-17 65
2020-02-10 60
2020-02-03 67
2020-01-27 68
2020-01-20 65
2020-01-13 61
2020-01-06 70
2019-12-30 51
2019-12-23 76
2019-12-16 71
2019-12-09 53
2019-12-02 51
2019-11-25 57
2019-11-18 55
2019-11-11 62
2019-11-04 70
2019-10-28 32
2019-10-21 59
2019-10-14 76
2019-10-07 63
2019-09-30 68
2019-09-23 88
2019-09-16 51
2019-09-09 55
2019-09-02 47
2019-08-26 61
2019-08-19 84
2019-08-12 79
2019-08-05 58
2019-07-29 79
2019-07-22 96
2019-07-15 78
2019-07-08 49
2019-07-01 86
2019-06-24 76
2019-06-17 63
2019-06-10 51
2019-06-03 92
2019-05-27 69
2019-05-20 86
2019-05-13 100
2019-05-06 72
2019-04-29 92
2019-04-22 88
2019-04-15 97
2019-04-08 88
2019-04-01 94
2019-03-25 85
2019-03-18 53
2019-03-11 29
2019-03-04 70
2019-02-25 80
2019-02-18 72
2019-02-11 52
2019-02-04 65
2019-01-28 29
2019-01-21 27
2019-01-14 41
2019-01-07 63
2018-12-31 49
2018-12-24 41
2018-12-17 40
2018-12-10 43
2018-12-03 42
2018-11-26 40
2018-11-19 42
2018-11-12 58
2018-11-05 38
2018-10-29 31
2018-10-22 37
2018-10-15 31
2018-10-08 28
2018-10-01 49
2018-09-24 33
2018-09-17 28
2018-09-03 84
2018-08-27 23
2018-08-20 24
2018-08-13 26
2018-08-06 25
2018-07-30 24
2018-07-23 27
2018-07-16 25
2018-07-09 35
2018-07-02 26
2018-06-25 36
2018-06-18 35
2018-06-11 33
2018-06-04 56
2018-05-28 28
2018-05-21 33
2018-05-14 29
2018-05-07 33
2018-04-30 41
2018-04-23 40
2018-04-16 31
2018-04-09 44
2018-04-02 20
2018-03-26 22
2018-03-20 29
2018-03-12 37
2018-03-04 55
2018-02-26 23
2018-02-19 39
2018-02-12 20
2018-02-05 48
2018-01-29 26
2018-01-23 48
2018-01-15 18
2018-01-09 30
2018-01-01 26
2017-12-26 30
2017-12-19 28
2017-12-11 20
2017-12-04 41
2017-11-27 20
2017-11-20 34
2017-11-13 35
2017-11-06 35
2017-10-30 28
2017-10-23 28
2017-08-21 40
2017-08-14 55
2017-08-07 29
2017-07-31 53
2017-07-24 52
2017-07-17 54
2017-07-10 47
2017-07-03 35
2017-06-26 50
2017-06-19 21
2017-06-12 24
2017-06-05 33
2017-05-29 32
2017-05-22 35
2017-05-15 35
2017-05-08 40
2017-05-01 33
2017-04-24 32
2017-04-17 35
2017-04-10 41
2017-04-03 35
2017-03-27 31
2017-03-20 40
2017-03-13 41
2017-03-06 38
2017-02-27 44
2017-02-20 35
2017-02-06 23
2017-01-30 30
2017-01-23 43
2017-01-16 32
2017-01-13 55
2017-01-09 34
2017-01-02 25
2016-12-26 37
2016-12-19 44
2016-12-12 36
2016-12-05 37
2016-11-28 27
2016-11-21 34
2016-11-14 50
2016-11-07 40
2016-10-31 35
2016-10-24 35
2016-10-17 36
2016-10-10 34
2016-10-03 41
2016-09-26 32
2016-09-19 39
2016-09-12 27
2016-09-05 32
2016-08-29 78
2016-08-22 19
2016-08-15 17
2016-08-08 19
2016-08-01 32
2016-07-25 33
2016-07-18 26
2016-07-10 32
2016-07-04 48
2016-06-27 32
2016-06-20 33
2016-06-13 34
2016-06-06 29
2016-05-30 39
2016-05-23 47
2016-05-16 43
2016-05-09 60
2016-05-02 45
2016-04-25 40
2016-04-18 35
2016-04-11 40
2016-04-04 42
2016-03-28 47
2016-03-21 42
2016-03-14 93
2016-02-22 72
2016-02-15 55
2016-02-15 55
2016-02-08 57
2016-02-01 55
2016-01-25 55
2016-01-18 37
2016-01-11 51
2015-12-28 55
2015-12-21 33
2015-12-14 45
2015-12-07 50
2015-11-30 56
2015-11-23 47
2015-11-16 54
2015-11-09 40
2015-11-02 25
2015-10-26 32
View Org source for this post

Upcoming chat with linkarzu about using Emacs for 25 years

Posted: - Modified: | community, emacs
  • : Added more notes based on topics in the description
  • : Ha, I accidentally left in some raw transcription output. Serves me right for not scrolling down.

Also, I've added a summary image.

I'm going to be chatting with linkarzu about Emacs and life. He's more of a Vim person than an Emacs person, so I'll try to share things that are generally useful. He's called it: "Why Sacha Chua Still Lives in Emacs After 20+ Years."

I am not sure my eyebrows have ever done that, but linkarzu does like his AI-generated thumbnails, so we'll let that pass. =)

(America/Toronto, -0400) = Thu Oct 29 0800H EDT / 0700H CDT / 0600H MDT / 0500H PDT / 1200H UTC / 1300H CET / 1400H EET / 1730H IST / 2000H +08 / 2100H JST

His description:

Sacha Chua joins me to talk about Emacs. She has been living in it for decades, and she shares the Emacs world with all of us through Emacs News, Emacs Chat and EmacsConf.

I want to see how she runs her life in Org Mode and how she uses her speech and audio braindump workflows, and to ask her what she thinks of what Prot and I have been doing with Emacs.

We'll also be discussing Neovim and other usual tech related topics

As a backup and so that it shows up on my YouTube feed, it's also going to be streamed at:

(but watch it on his channel instead for the stats boost!)

Note: Both videos will become unlisted afterwards. I think that means you'll still be able to reach it from my blog post or from a direct link, but you won't see it on his channel or mine, at least until he posts the edited video publicly. Also, to encourage people to sign up for his memberships (and to keep things more focused during the conversation), Linkarzu limits chat during the livestream to members of his channel. That's totally fine, he's allowed to experiment with ways to make a living, so please don't give him any grief about it. =) If you have any questions about what we talk about, or would like to continue the conversation, feel free to leave a comment or email me at sacha@sachachua.com and I will check it afterwards.

I like making things available and searchable long-term. I plan to post the transcript of either the full conversation or excerpts of it on my blog, and I'll probably also post screenshots or clips of the video or audio where it makes sense. It might be something like the transcript I posted in Chatted with John Wiegley and Karthik Chikmagalur about personal information management.

I am looking forward to learning more about the NeoVim community. I think the NeoVim community does the YouTube thing really well, and I'm hoping that the new org.nvim stuff might encourage people to do more literate programming and blogging. I put together some notes on my Emacs history, building on from the title that Linkarzu put on his event ("Why Sacha Chua Still Lives in Emacs After 20+ Years"). I'll probably add a little bit more over the next two days. I am more curious about where the conversation can take us rather than switching into presentation mode, since I can write blog posts and make videos whenever I want. =)

I put together some sketches to help me organize my thoughts. His channel uses dark mode, so let's experiment with dark mode in my sketches too. I want to think about things so that the relevant resources are readily available and so that I can express myself more concisely. I can put together a presentation or write a blog post by myself, so I'm more curious about the kinds of things he wants to explore in the conversation.

About me

I'll probably need to do a brief introduction to set the context so that people know where I'm coming from. Let's disclaim my professional irrelevance up front.

Image text and links

About me 2026-10-24-03

  • sachachua.com (since 2001 :) )
  • Emacs News
  • planet.emacslife.com
  • EmacsConf
  • Where: Manila, Philippines to Toronto, Canada in 2005
  • Now:
    • Continuing with hanging out with A+ (kiddo) and W- (husband)
    • Experimenting with retirement
  • Previously: web prototypes, data analysis, sketchnoting, computer science
  • Currently tinkering with: learning French, hybrid speech interfaces, community sharing

It turns out that I've been using Emacs for at least 25 years, which is pretty cool. I am 43, so that's more than half my life.

Quick notes on the stuff he mentioned in the description

  • How I run my life in Org Mode
    • Capture into an inbox on my computer or on my phone (Orgzly Revived + Syncthing),
    • Agenda on either Orgzly or my computer.
    • Several large files that I add a lot of ideas to and slowly chip away at when I have time. I'm still the primary parent for our ten-year-old. Although I have a little bit more focus time now that she (usually) attends virtual school, I still find myself capturing ideas and knowing that I will get to them maybe sometime over the next few years.
  • It's a lot of fun to be able to make tiny improvements that add up.
  • Speech and audio brain dump workflow
  • What I think of Linkarzu and Prot's conversations
    • It's totally okay if you want to stick with NeoVim. I'm looking forward to seeing what people come up with!
    • I think the discussions we can have about workflows can cross editor boundaries. =)

Summary of other important things

Let's start with a summary so that we don't worry about running out of time and so that people don't have to listen to two hours before getting to the good stuff. I want people to be able to get something out of this, whether they're a Vim diehard or experimenting with Helix, or even if they're passionate about things other than text editors. Here are some of the things I'm learning about that I think are important.

  • Community:
    • It's really hard to learn Emacs all by yourself. It's obscure, arcane, and overwhelming.
    • Fortunately, we have a strong culture of sharing, starting with the GNU General Public License and continuing through things like literate programming. We have mailing lists, blog posts, videos, meetups, and conferences. One of the best ways to learn Emacs is to learn out loud. Another way is to look over someone's shoulder. It doesn't take a lot of time or money to do the kinds of things that I enjoy doing to connect the Emacs community, and I'd love to see other tech communities experiment with things like that too.
  • Adaptability: You can customize Emacs to really fit the way you want to work. The more people do this, the easier it gets to adapt Emacs to even more workflows.
  • Incremental improvements: Even small changes add up, and code turns out to be surprisingly reusable. It often pays off beyond the recommendations of xkcd: Is It Worth the Time?.
  • Imagination and play: Tweaking Emacs can be lots of fun. Fun is important.

Quick notes on the stuff he mentioned in the description:

  • How I run my life in Org Mode
    • Capture into an inbox on my computer or on my phone (Orgzly Revived + Syncthing),
    • Agenda on either Orgzly or my computer.
    • Several large files that I add a lot of ideas to and slowly chip away at when I have time. I'm still the primary parent for our ten-year-old. Although I have a little bit more focus time now that she (usually) attends virtual school, I still find myself capturing ideas and knowing that I will get to them maybe sometime over the next few years.
  • It's a lot of fun to be able to make tiny improvements that add up.
  • Speech and audio brain dump workflow
  • What I think of Linkarzu and Prot's conversations
    • It's totally okay if you want to stick with NeoVim. I'm looking forward to seeing what people come up with!
    • I think the discussions we can have about workflows can cross editor boundaries. =)

History

Here's a brief overview of my history with Emacs, in case anything sparks curiosity.

The details are a little bit fuzzy, but fortunately I've written about some things in previous blog posts. I'd like to flesh this out with an outline and maybe even some sentences or paragraphs later on. I love the way that different themes recur. I find myself building on things that I started exploring years ago. For example, my current interest in hybrid speech interfaces echoes all the way back to M-x doctor and Emacspeak from the beginning.

Large language models and artificial intelligence

linkarzu mentioned wanting to talk about artificial intelligence. I don't know nearly as much as lots of other people do. Maybe I can just share the things that I've been experimenting with, and also what I care about from a community perspective. I would like to help figure out how to deal with this turbulence and come out the other side happier.

Text from sketch

Large language models and other things 2026-10-24-02

  • Y'all know much more than I do. You have more at stake.
  • Me: tiny steps, using it for tightly scoped tools
    • grammar/fixing literal translations, explanations
    • troubleshooting
    • prototypes (ex: Python servers)
  • Next:
    • help people who want to connect and experiment
      • human-focused
      • LLM-assisted (only if you want)
  • Keep exploring what I'm curious about: experiments > hype
  • Yay:
    • more people learning about and customizing things
    • more capable local models
    • adding up fragments of time
  • Boo:
    • flood of slop, "content", spam
    • overwhelmed developers
    • centralization
    • polarization
    • externalized costs
    • non-deterministic
View Org source for this post

Dictating blog posts into Emacs

| emacs, speech-recognition

Matt is experimenting with dictating his blog posts. He says:

I write really well. I have very good grammatical skills, for the most part, when I’m typing. But when I speak, I don’t speak like that. My grammar is not very good. I say words out of order a lot. I have filler words. And I say things that don’t make any sense.

This is totally me too! It's one of the reasons why I want to get used to dictation, because it'll give me a lot more practice in saying things, which can only help when I'm making videos or talking to people.

While I’m talking, the text that’s outputted has no punctuation or paragraphs or anything like that.

Oh yeah, no, that's mostly a matter of picking the right speech recognition engine. For example, I'm using a local instance of Orukeet, and it seems to do a reasonable job of dividing my thoughts into properly-capitalized and punctuated sentences in both English and French. In fact, I have some code in Emacs that wraps it to one sentence per line (as part of sacha-whisper-insert which uses sachac/whisper.el). This allows me to use Org shortcuts to move lines around in order to reorganize them into something that makes more sense.

Some people use large language models to clean up raw transcripts and remove false starts or filler words. I don't quite trust large language models to leave my wording alone. I have some code that uses replace-regexp-in-string to take out some of my filler words and fix commonly misrecognized words that I've saved with substitute.el.

I'm not sure if I was ever any good at multitasking, but nowadays at 43 years old, I find that talking and typing at the same time has gotten a little bit harder for me. I type much more slowly if I want to narrate things at the same time, like when I'm recording a video or live streaming. When I'm just thinking on my own, I type quickly enough that my computer sometimes jumbles the keystrokes up because it doesn't handle keyboard interrupts well when it's busy. It's not just my fingers; it sometimes happens even when I was trying to use wdotool to simulate typing. Speech recognition is surprisingly reliable, even though I have to correct it from time to time. The broad strokes are there, and I save the recordings so that I can fix misrecognized words.

I also love the way that speech recognition opens up so many more possibilities for commands I would never be able to memorize keyboard shortcuts for. "Remind me today to…" is now one of my favourite ways to capture an Org Mode task.

Besides, I think it's a good idea to plan ahead just in case I can't type very well in the future. All sorts of things can happen: accidents, disease, old age. I wrote about that a bit more in Emacs Carnival Oct 2026: Exploring keys and voice input in Emacs.

All that to say: exciting times ahead. I think it would be pretty amazing if this sort of thing allows more people to write and share. Looking forward to reading (and possibly listening to) what people have been learning about!

View Org source for this post