2025-11-03 Emacs news

| emacs, emacs-news

The Emacs Carnival blog theme for November is An Ode to Org Babel. Check out last month's posts about maintenance!

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

consult + org-db-v3: Approximate search of my sketches using text, and a multi-source consult command for approximately searching sketches and blog posts

| emacs

I like to draw sketchnotes when I want to untangle a thought or build up a thought over several posts.1 Following up on Playing around with org-db-v3 and consult: vector search of my blog post Org files, with previews, I want to be able to search my sketches using approximate text matches. I also want to have an approximate search interface that includes both sketches and blog posts.

Here's what I've gotten working so far:

Screencast of my-sketch-similar and my-consult-similar

  • 0:00: Text preview: All right, so here's a preview of how I can flip through the images that are similar to my current text. Let's say, for example, I've got my-sketch-similar. I'm passing in my whole blog post. This one is a text preview. It just very quickly goes through the OCR text.
  • 0:27: Image preview: I can use the actual images since Emacs has image support. It's a bit slower and sometimes it doesn't work. So far it's working, which is nice, but you can tell there's a bit of a delay.
  • 0:51: External viewer like Geeqie: The third option is to use an external program like Geeqie. Geeqie? Anyway, that one seems a lot faster.
  • 1:12: my-consult-similar: Then I can use that with this new multiple source consult command that I've just defined. So, for example, if I say my-consult-similar, I can then flip through the related blog posts as well as the related sketches in one go. I was calling it with a C-u universal prefix argument, but I can also call it and type in, for example, parenting and anxiety. Then I can see my recent blog posts and sketches that are related to that topic. I think I should be able to just… Yes, if I press enter, it will insert the link. So that's what I hacked up today.

The data

As part of my sketchnote process,2 I convert my sketches to text files.3 I usually use Google Cloud Vision to automatically convert the images to text. By keeping .txt files beside image files, I can easily search for images and include them in blog posts.4 I usually edit the file afterwards to clean up the layound and fix misrecognized words, but even the raw text output can make files more searchable.

I indexed the sketches' text files with:

(defun my-org-db-v3-index-recent-sketches (after)
  (interactive (list
                (when current-prefix-arg
                  (org-read-date nil nil nil "After: " nil "-2w"))))
  (setq after (or after (org-read-date nil nil "-2w")))
  (mapcar #'org-db-v3-index-file-async
          (seq-remove
           (lambda (o) (string> after (file-name-base o)))
           (directory-files "~/sync/sketches" t "\\.txt$"))))

Completion code

Writing the Consult completion code for the sketches was pretty straightforward because I could base it on my blog posts.

(defun my-org-db-v3-sketch--collection (input)
  "Perform the RAG search and format the results for Consult.
Returns a list of cons cells (DISPLAY-STRING . PLIST)."
  (mapcar
   (lambda (o)
     (cons (file-name-base (alist-get 'source_path o)) o))
   (seq-uniq
    (my-org-db-v3-to-emacs-rag-search input 100 "%sync/sketches%")
    (lambda (a b) (string= (alist-get 'source_path a)
                           (alist-get 'source_path b))))))

(defun my-sketch-similar (&optional query hide-initial)
  "Vector-search blog posts using `emacs-rag-search' and present results via Consult.
If called with \\[universal-argument\], use the current post's text.
If a region is selected, use that as the default QUERY.
HIDE-INITIAL means hide the initial query, which is handy if the query is very long."
  (interactive (my-11ty-interactive-context current-prefix-arg))
  (consult--read
   (if hide-initial
       (my-org-db-v3-sketch--collection query)
     (consult--dynamic-collection
         #'my-org-db-v3-sketch--collection
       :min-input 3 :debounce 1))
   :lookup #'consult--lookup-cdr
   :prompt "Search sketches (approx): "
   :category 'sketch
   :sort nil
   :require-match t
   :state (my-image--state)
   :initial (unless hide-initial query)))

(defun my-sketch-similar-insert (link)
  "Vector-search sketches and insert a link.
If called with \\[universal-argument\], use the current post's text.
If a region is selected, use that as the default QUERY.
HIDE-INITIAL means hide the initial query, which is handy if the query is very long."
  (interactive (list
                (if embark--command
                    (read-string "Sketch: ")
                  (apply #'my-sketch-similar
                         (my-11ty-interactive-context current-prefix-arg)))))
  (my-insert-sketch-and-text link))

(defun my-sketch-similar-link (link)
  "Vector-search sketches and insert a link.
If called with \\[universal-argument\], use the current post's text.
If a region is selected, use that as the default QUERY.
HIDE-INITIAL means hide the initial query, which is handy if the query is very long."
  (interactive (list
                (if embark--command
                    (read-string "Sketch: ")
                  (apply #'my-sketch-similar
                         (my-11ty-interactive-context current-prefix-arg)))))
  (when (and (listp link) (alist-get 'source_path link))
    (setq link (my-image-filename (file-name-base link))))
  (insert (org-link-make-string (concat "sketchLink:" link) (file-name-base link))))

(From Handle sketches too in my config)

Previewing images

Displaying images in Emacs can be a little bit slow, so I wanted to have different options for preview. The fastest way might be to preview just the text to see whether this is a relevant image.

(setq my-sketch-preview 'text)
2025-10-29_14-46-06.png

Another way to preview to load the actual image, if I have a bit more patience.

(setq my-sketch-preview t)
2025-10-29_14-47-45.png
Figure 2: Screenshot of image preview

Sometimes Consult says "No partial preview of a binary file", though, so I can probably look into how to get around that.

Using an external program is another option. Here I have some code to use Geeqie to display the images.

(setq my-sketch-preview 'geeqie)
2025-10-29_14-48-57.png
Figure 3: Using Geeqie to flip through images

Using Geeqie feels faster and more reliable than using Emacs to preview images.

The preview is implemented by the following function in the Completing sketches part of my config.

(declare-function 'my-geeqie-view "Sacha.el")

(defvar my-sketch-preview 'text
  "*Preview sketches.
'text means show the associated text.
'geeqie means open image in Geeqie.
t means open image in Emacs.")

(defun my-image--state ()
  "Manage preview window and cleanup."
  ;; These functions are closures captured when the state is initialized by consult--read
  (let ((preview (consult--buffer-preview))
        (open (consult--temporary-files)))
    ;; The returned lambda is the actual preview function called by Consult
    (lambda (action cand)
      (unless cand
        (funcall open))
      (when my-sketch-preview
        (let ((filename (cond
                         ((and (eq my-sketch-preview 'text)
                               (listp cand)
                               (alist-get 'source_path cand))
                          (alist-get 'source_path cand))
                         ((and (listp cand)
                               (alist-get 'source_path cand))
                          (my-image-filename (file-name-base (alist-get 'source_path cand))))
                         (t cand))))
          (when filename
            (pcase my-sketch-preview
              ('geeqie (my-geeqie-view (list filename)))
              (_ (funcall preview action
                          (and cand
                               (eq action 'preview)
                               (funcall open filename)))))))))))

The following function calls geeqie. It's in the Manage photos with geeqie part of my config.

(defun my-geeqie-view (filenames)
  (interactive "f")
  (start-process-shell-command
   "geeqie" nil
   (concat
    "geeqie --remote "
    (mapconcat
     (lambda (f)
       (concat "file:" (shell-quote-argument f)))
     (cond
      ((listp filenames) filenames)
      ((file-directory-p filenames)
       (list (car (seq-filter #'file-regular-p (directory-files filenames t)))))
      (t (list filenames)))
     " "))))

Multiple sources

Now I can make a Consult source that combines both blog posts and sketches using semantic search. I wanted to have the same behaviour as my other functions. If I call it interactively, I want to type in text. If I call it with a region, I want to search for that region. If I call it with the universal prefix argument C-u, I want to use the current post text as a starting point. Since this behaviour shows up in several functions, I finally got around to writing a function that encapsulates it.

Then I can use that for the interactive arguments of my new my-consult-similar function.

(defvar my-consult-source-similar-blog-posts
  (list :name "Blog posts"
        :narrow ?b
        :category 'my-blog
        :state #'my-blog-post--state
        :async (consult--dynamic-collection
                   (lambda (input)
                     (seq-take
                      (my-org-db-v3-blog-post--collection input)
                      5)))
        :action #'my-embark-blog-insert-link))

(defvar my-consult-source-similar-sketches
  (list :name "Sketches"
        :narrow ?s
        :category 'sketch
        :async (consult--dynamic-collection
                   (lambda (input)
                     (seq-take (my-org-db-v3-sketch--collection input) 5)))
        :state #'my-image--state
        :action #'my-insert-sketch-and-text))

(defun my-consult-similar (query hide-initial)
  (interactive (my-11ty-interactive-context current-prefix-arg))
  (if hide-initial
      (let ((new-sources
             (list
              (append
               (copy-sequence my-consult-source-similar-blog-posts)
               (list :items (seq-take (my-org-db-v3-blog-post--collection query) 5)))
              (append
               (copy-sequence my-consult-source-similar-sketches)
               (list :items (seq-take (my-org-db-v3-sketch--collection query) 5))))))
        (dolist (source new-sources)
          (cl-remf source :async))
        (consult--multi new-sources))
    (consult--multi '(my-consult-source-similar-blog-posts
                      my-consult-source-similar-sketches)
                    :initial query)))

(defun my-org-db-v3-index-recent-public (after)
  (interactive (list
                (when current-prefix-arg
                  (org-read-date nil nil nil "After: " nil "-2w"))))
  (setq after (or after (org-read-date nil nil "-2w")))
  (mapc #'org-db-v3-index-file-async
        (my-blog-org-files-except-reviews after))
  (my-org-db-v3-index-recent-sketches after))

This is what it looks like given this whole post:

2025-10-29_14-36-24.png
Figure 4: Screenshot of semantic search for both blog posts and sketches

Thoughts and next steps

The vector search results from my sketches don't feel as relevant as the blog posts, possibly because there's a lot less text in my sketches. Handwriting is tiring, and I can only fit so much on a page. Still, now that I'm sorting results by similarity score, maybe we'll see what we get and how we can tweak things..

It might be nifty to use embark-become to switch between exact title match, full-text search, and vector search.

plz supports asynchronous requests and org-db-v3.el has examples of doing this, so maybe I can replicate some of Remembrance Agent's functionality by having an idle timer asynchronously update a dedicated buffer with resources that are similar to the current paragraph, or maybe the last X words near point.

I wonder if it makes sense to mix results from different sources in the same list instead of splitting it up into different categories.

View org source for this post

Playing around with org-db-v3 and consult: vector search of my blog post Org files, with previews

Posted: - Modified: | emacs, org

: Sort my-org-db-v3-to-emacs-rag-search by similarity score.

I tend to use different words even when I'm writing about the same ideas. When I use traditional search tools like grep, it can be hard to look up old blog posts or sketches if I can't think of the exact words I used. When I write a blog post, I want to automatically remind myself of possibly relevant notes without requiring words to exactly match what I'm looking for.

Demo

Here's a super quick demo of what I've been hacking together so far, doing vector search on some of my blog posts using the .org files I indexed with org-db-v3:

Screencast of my-blog-similar-link

Play by play:

  • 0:00:00 Use M-x my-blog-similar-link to look for "forgetting things", flip through results, and use RET to select one.
  • 0:00:25 Select "convert the text into a link" and use M-x my-blog-similar-link to change it into a link.
  • 0:00:44 I can call it with C-u M-x my-blog-similar-link and it will do the vector search using all of the post's text. This is pretty long, so I don't show it in the prompt.
  • 0:00:56 I can use Embark to select and insert multiple links. C-SPC selects them from the completion buffer, and C-. A acts on all of them.
  • 0:01:17 I can also use Embark's C-. S (embark-collect) to keep a snapshot that I can act on, and I can use RET in that buffer to insert the links.

Background

A few weeks ago, John Kitchin demonstrated a vector search server in his video Emacs RAG with LibSQL - Enabling semantic search of org-mode headings with Claude Code - YouTube. I checked out jkitchin/emacs-rag-libsql and got the server running. My system's a little slow (no GPU), so (setq emacs-rag-http-timeout nil) was helpful. It feels like a lighter-weight version of Khoj (which also supports Org Mode files) and maybe more focused on Org than jwiegley/rag-client. At the moment, I'm more interested in embeddings and vector/hybrid search than generating summaries or using a conversational interface, so something simple is fine. I just want a list of possibly-related items that I can re-read myself.

Of course, while these notes were languishing in my draft file, John Kitchin had already moved on to something else. He posted Fulltext, semantic text and image search in Emacs - YouTube, linking to a new vibe-coded project called org-db-v3 that promises to offer semantic, full-text, image, and headline search. The interface is ever so slightly different: POST instead of GET, a different data structure for results. Fortunately, it was easy enough to adapt my code. I just needed a small adapter function to make the output of org-db-v3 look like the output from emacs-rag-search.

(use-package org-db-v3
  :load-path "~/vendor/org-db-v3/elisp"
  :init
  (setq org-db-v3-auto-enable nil))

(defun my-org-db-v3-to-emacs-rag-search (query &optional limit filename-pattern)
  "Search org-db-v3 and transform the data to look like emacs-rag-search's output."
  (org-db-v3-ensure-server)
  (setq limit (or limit 100))
  (mapcar (lambda (o)
            `((source_path . ,(assoc-default 'filename o))
              (line_number . ,(assoc-default 'begin_line o))
              ,@o))
          (sort
           (assoc-default 'results
                          (plz 'post (concat (org-db-v3-server-url) "/api/search/semantic")
                            :headers '(("Content-Type" . "application/json"))
                            :body (json-encode `((query . ,query)
                                                 (limit . ,limit)
                                                 (filename_pattern . ,filename-pattern)))
                            :as #'json-read))
           :key (lambda (o) (alist-get 'similarity_score o))
           :reverse t)))

I'm assuming that org-db-v3 is what John's going to focus on instead of emacs-rag-search (for now, at least). I'll focus on that for the rest of this post, although I'll include some of the emacs-rag-search stuff just in case.

Indexing my Org files

Both emacs-rag and org-db-v3 index Org files by submitting them to a local web server. Here are the key files I want to index:

  • organizer.org: my personal projects and reference notes
  • reading.org: snippets from books and webpages
  • resources.org: bookmarks and frequently-linked sites
  • posts.org: draft posts
(dolist (file '("~/sync/orgzly/organizer.org"
                "~/sync/orgzly/posts.org"
                "~/sync/orgzly/reading.org"
                "~/sync/orgzly/resources.org"))
  (org-db-v3-index-file-async file))

(emacs-rag uses emacs-rag-index-file instead.)

Indexing blog posts via exported Org files

Then I figured I'd index my recent blog posts, except for the ones that are mostly lists of links, like Emacs News or my weekly/monthly/yearly reviews. I write my posts in Org Mode before exporting them with ox-11ty and converting them with the 11ty static site generator. I'd previously written some code to automatically export a copy of my Org draft in case people wanted to look at the source of a blog post, or in case I wanted to tweak the post in the future. (Handy for things like Org Babel.) This was generally exported as an index.org file in the post's directory. I can think of a few uses for a list of these files, so I'll make a function for it.

(defun my-blog-org-files-except-reviews (after-date)
  "Return a list of recent .org files except for Emacs News and weekly/monthly/yearly reviews.
AFTER-DATE is in the form yyyy, yyyy-mm, or yyyy-mm-dd."
  (setq after-date (or after-date "2020"))
  (let ((after-month (substring after-date 0 7))
        (posts (my-blog-posts)))
    (seq-keep
     (lambda (filename)
       (when (not (string-match "[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]-emacs-news" filename))
         (when (string-match "/blog/\\([0-9]+\\)/\\([0-9]+\\)/" filename)
           (let ((month (match-string 2 filename))
                 (year (match-string 1 filename)))
             (unless (string> after-month
                              (concat year "-" month))
               (let ((info (my-blog-post-info-for-url (replace-regexp-in-string "~/proj/static-blog\\|index\\.org$\\|\\.org$" "" filename) posts)))
                 (let-alist info

                   (when (and
                          info
                          (string> .date after-date)
                          (not (seq-intersection .categories
                                                 '("emacs-news" "weekly" "monthly" "yearly")
                                                 'string=)))
                     filename))))))))
     (sort
      (directory-files-recursively "~/proj/static-blog/blog" "\\.org$")
      :lessp #'string<
      :reverse t))))

This is in the Listing exported Org posts section of my config. I have a my-blog-post-info-for-url function that helps me look up the categories. I get the data out of the JSON that has all of my blog posts in it.

Then it's easy to index those files:

(mapc #'org-db-v3-index-file-async (my-blog-org-files-except-reviews))

Searching my blog posts

Now that my files are indexed, I want to be able to turn up things that might be related to whatever I'm currently writing about. This might help me build up thoughts better, especially if a long time has passed in between posts.

org-db-v3-semantic-search-ivy didn't quite work for me out of the box, but I'd written an Consult-based interface for emacs-rag-search-vector that was easy to adapt. This is how I put it together.

First I started by looking at emacs-rag-search-vector. That shows the full chunks, which feels a little unwieldy.

2025-10-09_10-05-58.png
Figure 1: Screenshot showing the chunks returned by a search for "semantic search"

Instead, I wanted to see the years and titles of the blog posts as a quick summary, with the ability to page through them for a quick preview. consult.el lets me define a custom completion command with that behavior. Here's the code:

(defun my-blog-similar-link (link)
  "Vector-search blog posts using `emacs-rag-search' and insert a link.
If called with \\[universal-argument\], use the current post's text.
If a region is selected, use that as the default QUERY.
HIDE-INITIAL means hide the initial query, which is handy if the query is very long."
  (interactive (list
                (if embark--command
                    (read-string "Link: ")
                  (my-blog-similar
                   (cond
                    (current-prefix-arg (my-11ty-post-text))
                    ((region-active-p)
                     (buffer-substring (region-beginning)
                                       (region-end))))
                   current-prefix-arg))))
  (my-embark-blog-insert-link link))

(defun my-embark-blog--inject-target-url (&rest args)
  "Replace the completion text with the URL."
  (delete-minibuffer-contents)
  (insert (my-blog-url (get-text-property 0 'consult--candidate (plist-get args :target)))))

(with-eval-after-load 'embark
  (add-to-list 'embark-target-injection-hooks '(my-blog-similar-link my-embark-blog--inject-target-url)))

(defun my-11ty-interactive-context (use-post)
  "Returns (query hide-initial) for use in interactive arguments.
If USE-POST is non-nil, query is the current post text and hide-initial is t.
If the region is active, returns that as the query."
  (list (cond
         (embark--command (read-string "Input: "))
         (use-post (my-11ty-post-text))
         ((region-active-p)
          (buffer-substring (region-beginning)
                            (region-end))))
        use-post))

(defun my-blog-similar (&optional query hide-initial)
  "Vector-search blog posts using org-db-v3 and present results via Consult.
If called with \\[universal-argument\], use the current post's text.
If a region is selected, use that as the default QUERY.
HIDE-INITIAL means hide the initial query, which is handy if the query is very long."
  (interactive (my-11ty-interactive-context current-prefix-arg))
  (consult--read
   (if hide-initial
       (my-org-db-v3-blog-post--collection query)
     (consult--dynamic-collection
         #'my-org-db-v3-blog-post--collection
       :min-input 3 :debounce 1))
   :lookup #'consult--lookup-cdr
   :prompt "Search blog posts (approx): "
   :category 'my-blog
   :sort nil
   :require-match t
   :state (my-blog-post--state)
   :initial (unless hide-initial query)))

(defvar my-blog-semantic-search-source 'org-db-v3)
(defun my-org-db-v3-blog-post--collection (input)
  "Perform the RAG search and format the results for Consult.
Returns a list of cons cells (DISPLAY-STRING . PLIST)."
  (let ((posts (my-blog-posts)))
    (mapcar (lambda (o)
              (my-blog-format-for-completion
               (append o
                       (my-blog-post-info-for-url (alist-get 'source_path o)
                                                  posts))))
            (seq-uniq
               (my-org-db-v3-to-emacs-rag-search input 100 "%static-blog%")
               (lambda (a b) (string= (alist-get 'source_path a)
                                      (alist-get 'source_path b)))))))

It uses some functions I defined in other parts of my config:

When I explored emacs-rag-search, I also tried hybrid search (vector + full text). At first, I got "database disk image is malformed". I fixed this by dumping the SQLite3 database. Using hybrid search, I tended to get less-relevant results based on the repetition of common words, though, so that might be something for future exploration. Anyway, my-emacs-rag-search and my-emacs-rag-search-hybrid are in the emacs-rag-search part of my config just in case.

Along the way, I contributed some notes to consult.el's README.org so that it'll be easier to figure this stuff out in the future. In particular, it took me a while to figure out how to use :lookup #'consult--lookup-cdr to get richer information after selecting a completion candidate, and also how to use consult--dynamic-collection to work with slower dynamic sources.

Quick thoughts and next steps

It is kinda nice being able to look up posts without using the exact words.

Now I can display a list of blog posts that are somewhat similar to what I'm currently working on. It should be pretty straightforward to filter the list to show only posts I haven't linked to yet.

I can probably get this to index the text versions of my sketches, too.

It might also be interesting to have a multi-source Consult command that starts off with fast sources (exact title or headline match) and then adds the slower sources (Google web search, semantic blog post search via org-db-v3) as the results become available.

I'll save that for another post, though!

View org source for this post

Slowing down and figuring out my anxiety

| parenting, life, reflection

I am going through a lot. It is not much compared to what other people are going through. But it is more than what I usually go through, so it's a good idea to slow down and give myself space to learn how to handle it.

Part of handling times like these is touching base with what I know. I know that to be human is to have challenging times, so I don't find this surprising. I know that it is objectively difficult and that other people have a hard time with situations like this, so it's not a personal failure and there are no easy solutions. I know that it is temporary and that things will eventually settle into a new normal. I know there will be many such transitions ahead, and I'm getting used to the process of leaving old normals behind and focusing on the next step.

I know the way my brain tends to behave when it's overloaded. My attention hiccups. I hang up my keys on a coat hook instead of the one near the door. My fingers stutter on the piano. I can't multitask. When that starts to get in my way, it's a good reminder to get more sleep and do fewer things. There are very few firm commitments in my life, and I appreciate the flexibility that my past self planned. There's room to wobble1 without bringing everything crashing down.

Text from sketch

A few of my brain's failure modes 2025-09-13-05

  • Tired
    • Sometimes not obvious! Can turn up as fogginess, sluggishness, or grumpiness.
    • Prioritize sleep.
    • Try a 30-min nap, and extend if needed.
    • Can't run on 7h sleep, probably like 8.5+ regularly
  • Over-stimulated
    • Too noisy, too visually overwhelming, too crowded.
    • Go to a quieter place, or take the edge off with earplugs.
    • Draw
    • Nap
  • Decision fatigue
    • Too much research/shopping.
    • Take a break.
    • Take a chance.
  • Fragmented, stuck
    • Argh! I just want to finish this thought!
    • Better to breathe and postpone it to one of my focused time chunks. (Maybe I can move BB to Fri)
  • Anxious, catastrophizing
    • Oh no, what if…
    • Breathe, calibrate
  • Fretful
    • "Remember to…" "I'm not 5, Mom."
    • Breathe, hold my tongue.
    • Let her experiment.
  • Distracted
    • Can overlook things
    • Slow down, make a Conscious effort
  • Overloaded
    • Can't do two things at once.
    • Slow down, prioritize.
  • Craving stimulation
    • Doomscrolling, revenge bedtime procrastination
    • Rest or channel into writing/drawing.
    • Enjoy proper break.
  • Grumpy with the world
    • Try to find something positive to focus on.
  • No clear answers
    • Weighing difficult choices, dealing with complex issues
    • It's just life.
    • Experiment?

I still notice my anxiety spike from time to time. My anxiety spills out as trying to either control too much, or (knowing that control is counterproductive) stepping back, possibly too much. It tends to latch onto A+'s schoolwork as the main thing it could possibly try to do something about. I feel partially responsible for helping her develop study skills and navigate the school system, but these things are mostly outside my control. It's good that it's not in my control. Then there's space for her to learn and grow, and for me to learn along with her.

Instead of trying to push futilely, it's better to step back, simplify, focus on getting myself sorted out, and build up from a solid base. Better to focus on connecting with rather than correcting A+, especially as she takes her own steps towards autonomy. It's okay for now to focus on making simple food, washing dishes,2 combing out the tangles in hair and in thoughts. Maintenance.

Here's the core I'm falling back to for now:

  • Sleep
  • A good walk outside, maybe 30-60 minutes
  • Making an effort to eat a variety of healthy food, picking up ideas from DASH/Mediterranean3
  • Piano, maybe 20 minutes: low stakes, not intense, just enough to notice when my mind wanders or my breathing stops, and the ever so gradual improvement from familiarity;
  • A little bit of exercise: doesn't have to be much, just enough to begin the habit (15-25 minutes)
  • Writing and drawing to untangle my thoughts
  • A little bit of fun for myself. Might be tinkering with Emacs, might be drawing. Simple lines and colours are nice.
  • Giving myself permission to tell other people "That's not one of my priorities for now." There's only so much I can focus on at a time.
  • The reminder that other people have their experiments too. It's not about me; how freeing! It's good to not let my anxiety (just my ego's occasional fears of not doing enough, not being enough) engulf what properly belongs to other people. Learning is mostly A+'s experiment, and I can see this time as collecting data for a baseline. I'm happy to help her when she wants my help. Let's find out what can she do when I'm not pushing.

It's important to me to start from where I am and work with what I've got. Where else could I be, and what else could I use? Only here, only this, and it's enough.

I'm working on embracing my limits. It would be unproductively egotistic to think I have to do this all on my own. It helps to unload my brain into my Org Mode / Denote text files, my sketches, and my index cards so I can see beyond the single dimension of thought. Some days, even that is difficult. It's okay for my brain to not feel cooperative all the time. Some days are more blah than others, and it's hard to shape enough of the thought-fog4 into a post or a diary entry. There's no point in grumping at myself over it. It's okay for those days to be rest days, "take it easy" days, "there's room for this too" days. Goodness knows I've had slow months, slow years.5 (And if that's good for me, why not extend the same grace to A+? She'll figure things out when she's ready.)

I'm practising asking other people for help and letting them actually do so. I know A+ benefits from a wider world, and I'm glad she can chat with her aunts and cousins. I can slowly experiment with finding tutors and enrichment activities for A+, maybe even starting out with classes for me sometimes. She's been going to 1-on-1 gymnastics class for three weeks now. I love seeing how she's slowly learning to check in with her body and catch her breath so that she has more energy and can work on her flips safely. I love the way she gets up and tries again.

I wonder what other teachers and peers I can help A+ find. Next week, A+ will join a small-group art class so that she can have fun with art outside the requirements of school. A friend of hers is in the same extracurricular class, and maybe the fun will get her over the initial hump of practising fine motor skills and tolerating the frustrating gap between taste and skill.6 I want playfulness to be the core of her experience with art, not the pressure my anxiety feels about getting her art homework done. Knowing what my anxiety whispers, I can keep that from leaking out to her. The goal is not to get things done; the goal is simply to have the opportunity to find joy. Someday, when she reaches for a pencil or a brush, I want that feeling to come with warmth, a smile, curiosity: what will we encounter on the page today?

As she learns to read and write and think more deeply, I want the same for her: not the compliance of "have I checked the boxes,7" but "where can these thoughts take me?" Can I find her role models who can share that ineffable joy or opportunities where she can discover it for herself? Can it take root deep within her, something to touch as she goes through her own challenges, something that grows as she grows?

A wider world could help me, too. How wonderful it is to deal with something that so many people have gone through, are going through, even if there are no universal answers. I'm checking out workbooks from the library, and it might be interesting to experiment with seeing a therapist. I have mild anxiety according to the screening tools, but it might still be handy to pay for the accountability and structured exploration of my thoughts. Consulting an intern therapist might be a more affordable starting point that can help me figure out if I need more qualified care. We don't have medical benefits, so I want to be thoughtful about how I use resources, and I want to push myself to try out more help so that I know what that could be like instead of trying to handle everything on my own. Like the way A+'s gymnastics teacher thinks about the next skill that might be in her zone of proximal development8 (not too easy, not too hard), maybe someone else can help me map out what nearby betters could be and how I might get there.

Text from sketch

My brain at its best 2025-09-14-01

  • curious: I notice something interesting and I experiment with it.
  • always improving: I try little ways to make things better.
  • taking notes along the way: This helps me and other people.
  • satisfied: I did something good for me.
  • appreciative: I see and reflect the good around me.
  • supportive: I encourage people.
  • scaffolding: I break things down to make them easier to learn.
  • playful: I make silly puns and use funny voices.
  • adaptable: I work with what I've got.
  • connecting: I combine ideas.
  • resourceful: I solve problems, sometimes creatively.
  • prepared: I anticipated what could happen and my preparations paid off!

I know what it feels like when I can handle tough situations well: when I'm ready with a Band-aid or a hug, when I keep our basic needs sorted out so that we have a solid foundation to experiment on, when I get the hang of spelling new terms and organizing my hasty research into coherent understanding and ideas for things to try, when I can be warm and affectionate and appreciative and supportive.

I know what I hope A+ will feel: believed in, excited about her growing capabilities, supported when she wants help, open to things she might not know to ask about, able to straddle both wanting to be cuddled and wanting to be on her own. I want her to feel like she's the one figuring things out, so I want to get better at being a supporting character instead of letting my ego get in the way. (It's not a power struggle, it's not a moral judgment of me or of her, it's just life.)

When my anxiety wrings her hands, frets, whispers, worries that I'm not enough, I can think: ah, she is just trying to keep all of us safe, figure out how to make things better. I can use this imperative, this desire to try to help A+ live her best life. I know I don't want A+ to be driven by anxiety or controlled by conditional esteem.9 There'll be hard times for A+, like for everyone. I want her to be able to check in with herself, figure out what she needs, and feel her strength grow as she stretches. So I can work on getting better at that myself.

It's good to practise these things now, in this time that seems hard compared to the recent past but will seem easy compared to the future. Embrace the stress test while the stakes are low, so that I can reflexively use the skills when the stakes get higher, and so that A+ can take what she likes (kids are always watching) and use them as she figures out her own way.

Step by step. It's manageable. I can manage it. Could be interesting to see how we can make it slightly better. I'm not looking for answers. No one has them, and things change all the time. But the figuring out, that's the work of being human, isn't it?

This blog post was nudged by the October IndieWeb Carnival theme of ego.

Footnotes

2

The repetitive tasks of daily life remind me of my reflection on renewal.

6

Looking at landscapes; art and iteration and the quote from Ira Glass about the gap between taste and skill

7

More about motivation in Richard M. Ryan, Edward L. Deci, Intrinsic and Extrinsic Motivations: Classic Definitions and New Directions, Contemporary Educational Psychology, Volume 25, Issue 1, 2000, Pages 54-67, ISSN 0361-476X, https://doi.org/10.1006/ceps.1999.1020. (https://www.sciencedirect.com/science/article/pii/S0361476X99910202)

9

Brueckmann, M., Teuber, Z., Hollmann, J. et al. What if parental love is conditional …? Children’s self-esteem profiles and their relationship with parental conditional regard and self-kindness. BMC Psychol 11, 322 (2023). https://doi.org/10.1186/s40359-023-01380-3

Also: Assor A, Roth G, Deci EL. The emotional costs of parents' conditional regard: a self-determination theory analysis. J Pers. 2004 Feb;72(1):47-88. doi: 10.1111/j.0022-3506.2004.00256.x. PMID: 14686884.

View org source for this post

2025-10-27 Emacs news

| emacs, emacs-news

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

Drawing trees

| drawing

Following the tips in How to draw when you don't have time by Javi can draw!, I have been drawing trees. The video is 6.5 minutes long so it's easy to fit in. From the video:

Your main goal is to create a habit of drawing for drawing's sake.

Here are some of my trees:

Text from sketch

Trees sachachua.com/2025-10-20-07

  1. cypress tree
  2. pine tree
  3. oak tree
  4. spruce tree
  5. baobab tree
  6. tree
  7. tree
  8. tree
  9. tree
  10. tree
  11. tree
  12. tree
  13. tree
  14. willow tree
  15. tree
  16. tree
  17. tree
  18. tree
  19. tree
  20. tree
  21. tree
  22. tree
  23. tree
  24. tree
  25. tree
  26. tree
  27. tree
  28. tree
  29. tree by A+
  30. tree
  31. tree
  32. tree
  33. birch tree
  34. mango tree
  35. banana tree

Or in the little icon collection I've been building: trees.

tree--2025-10-20-07-3-1.jpeg

I think my favourite simple tree is this one. I like the way it gives me a little bit of a feeling of leaves being in front or behind, and it looks like something I can get the hang of drawing quickly.

tree--2025-10-20-07-2-5.jpeg

My favourite tree drawn from life is this one. I can think about where I was sitting when I drew it.

oak-tree--2025-10-20-07-0-2.jpeg

It's hard to pick my favourite from a tutorial or a reference photo. Maybe this one. I like the way it has light and dark.

tree-by-a--2025-10-20-07-4-0.jpeg

A+ drew a tree too.

A number of related tutorials and references:

I found the video via Mike Rohde's Sketchnote Lab post for October. Looking forward to drawing more trees!

View org source for this post

2025-10-20 Emacs news

| emacs, emacs-news

: Fixed org-linkin link, thanks gnomon-!

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