-- Leo's gemini proxy

-- Connecting to gemini.circumlunar.space:1965...

-- Connected

-- Sending request

-- Meta line: 20 text/gemini; lang=en-US


This is scrawlspace. I scrawl in this space. Do not expect coherence or permanence here.

2021-07-16: It’s broken for the normal people, too

For as long as I’ve tried to get work done on an iPad, I’ve been frustrated that C-e doesn’t go to the end of the logical line — it only goes to the end of the visual line. I’ve reported bugs about this, but Radar is a black hole.

Today, I decided to try and work around the problem by pressing the Mac-native equivalent, command-right.

It still only went to the end of the visual line.

It’s moderately comforting that the OS is broken even for the moderately normal people and not just the turbo-nerds.

2021-07-09: All wind-up, no performance

Background reading:


I tried Boop. It’s neat. I made a script for it. Because my short-term memory isn’t great, I decided to start by writing out the types…

    "name":"Prettier HTML",
    "description":"Makes your HTML prettier",

 * @callback InsertFunction
 * @param {string} what - String to insert at the caret. If there is text already selected, the selected text is replaced.

 * @callback PostFunction
 * @param {string} message - What message to show to the user.

 * @typedef ScriptExecution
 * @type {object}
 * @property {string} text
 * @property {string} fullText
 * @property {string} selection
 * @property {InsertFunction} insert
 * @property {PostFunction} postInfo
 * @property {PostFunction} postError

 const prettier = require("prettier");

  * @param {ScriptExecution} state
 function main(state) {
   const result = prettier.format(state.text, { parser: "babel" });

   state.text = result;

…only to find out that, evidently, requiring external code isn’t something that’s currently possible with Boop. Drat.

2021-06-27: One addendum to Sarah K. Peck’s monthly-review questions: backing away slowly

Background reading:

How To Do a Monthly Review — Sarah K. Peck

I do this monthly. It’s been somewhat helpful for me, although I don’t have quite the same problems that she has. Being a type-A personality seems nice, if only for the novelty factor.

One thing I found useful to add to my question template, though, is this. It goes right at the end of “People and Community”:

> Whom should I see less of?

Oftentimes this prompt isn’t responded to, which, quite honestly, is normal. However, it’s occasionally worth considering whom one surrounds himself with, and whether doing so is all that good of an idea. More than a few times, I’ve stuck around a group out of sheer inertia and/or lack of options even though the group is a decidedly mixed bag or even a net negative.

While realizing that one should back away slowly from a particular group won’t tell you what to do with the freed-up time, sometimes it’s worth asking whether your association with a group is a net positive, net negative, or just not nearly as positive as it used to be. In this latter case, it’s worth considering whether other affiliations might be more worth your time.

2021-06-26: Scientists fail to watch their language

on arxiv.org: “How Developers Choose Names”

One aspect of variable naming that the researchers didn’t seem to address was how different languages encourage slightly different names. Standard Go style generally prefers short method names like `.At()`, while Objective-C is — or was — perfectly fine with having method calls like `[things objectAtIndex:5]` for an operation that would look like `things[5]` or `arr[5]` in most other languages.

Still, neat paper.

2021-06-07: WWDC 2021 first-day wrap-up

No announced hardware.

App Library in the Dock: I could use this, at least in theory, to choose some random app that I haven’t run recently to take up half the screen. At any rate, this is bundled with a bunch of changes that will let me pick an arbitrary app to run with multitasking without requiring me to have a keyboard installed to trigger the command-space switcher.

Voice processing back on the device: This hasn’t been a thing since Siri took over. I’m glad it’s back.

Universal Control: Control an iPad from your Mac, or a Mac from another Mac? I could use this.


two cool-to-me features (on-device voice processing isn’t actually cool)

nothing worth risking running a beta for

Not bad. I wonder how buggy it will all be on release. This isn’t a No New Features™ release, but one can hope everyone spent 20% more time cooped up in their houses fixing bugs instead of just adding new things.

2021-06-02: WWDC 2021 predictions

Here’s what I expect to see next week:

≈16″ MacBooks Pro with ARM chips in them (99%)

…that are also available without a discrete GPU, a configuration that hasn’t been available since the 2015 models were retired (90%)

…that are available with more than 16 GB of RAM (90%)

…that have a default display resolution that’s an even multiple of the actual pixels involved (@2x most likely, @3x very unlikely) (60%)

Here’s what I expect to NOT see next week:

any indication that iPadOS is making large strides towards becoming an operating system for a real computer, like a shell into a chrooted jail (5%)

more than two cool-to-me new features in iPadOS (20%?)

more than three cool-to-me new features in i(Pad)OS (20%)

anything that makes me want to rush out and buy the latest iPad Pro with the LIDAR and M1 the humongous (by iOS standards) amounts of RAM (10%)

anything that makes me actually install a beta on one of my gizmos because it’s that cool (1%)

There are a few formulae in Homebrew that still lack ARM ports that I use. I wonder if the release of proper large-size MacBooks Pro will noticeably speed up the conversion of the remaining programs.

2021-05-27: Recreating YouTube attention-grabbing dynamics

Some fraction of visitors to this capsule do so through CAPCOM, a Geminispace aggregator (something that reads a bunch of feeds and combines them into one list). I have no idea what fraction this is, but it’s got to be some fraction of the total.

One of CAPCOM’s recent-ish changes is that it won’t show updates from literally everything submitted to it and approved: it only picks 100 feeds out of its list per month and displays them. It also says this:

> If you’re enjoying content from one feed, you should subscribe to it yourself in some way, because that feed is not guaranteed to be one of the 100 feeds chosen next month!

This is not visually distinct text, and at any rate it gets lost in the noise after you’ve visited a couple of times because really, you want to get to the links. Gemini doesn’t have blink tags, after all.

However, given that our capsules aren’t guaranteed to be part of next month’s rotation, we authors do have an incentive to close out the month with a request to, well, there’s no built-in Like function in Geminispace, but there are subscriptions in most clients.

> we didn’t start the fire

> it was always burning

> since the world’s been turning

2021-05-09: I like space

In response to:

benk on formatting Gemini documents

Yeah, basically that. I used to double-space above headers in Markdown but some autoformatter I was using nagged me if I had any more newlines in between elements for any reason, so I got broken of that habit. It was also kind of difficult to apply consistently (I’d forget a newline or two), so I stopped.

For posts like this, the in-response-to link line seems like it shouldn’t be equidistant from its mini-header above it and the body text below it, but I’m not quite sure I want to bunch it all up right next to the “In response to:” line.

2021-05-07, another short while later: Deno really is still in flux

I finally got a chance to get back to my Deno-based Gemini server. It uses Deno.Conn.

When I last worked on this, Deno.Conn was a generic type. I used Deno.Conn<Deno.NetAddr> (as opposed to Deno.UnixAddr, I guess).

Now, the remoteAddr of a Deno.Conn is either a NetAddr or a UnixAddr, and the best way to tell them apart seems to be to ensure that its transport is TCP (or UDP, or whatever).

So now, before getting back to any new real work, I made this change:

diff --git a/mod.ts b/mod.ts
index 3e7499f..c3febf4 100644
--- a/mod.ts
+++ b/mod.ts
@@ -65,7 +65,7 @@ enum ResponseCode {

 class Bag {
-  constructor(conn: Deno.Conn<Deno.NetAddr>) {
+  constructor(conn: Deno.Conn) {
     this.conn = conn;
     this.startTime = Date.now();
@@ -78,11 +78,19 @@ class Bag {
         ret[k] = v;
+    if (this.conn.remoteAddr.transport !== "tcp") {
+      throw new Error(
+        `Assertion failed: connection transport not TCP: ${this.conn}`,
+      );
+    }
     ret.from = this.conn.remoteAddr.hostname;
     return ret;

-  conn: Deno.Conn<Deno.NetAddr>;
+  conn: Deno.Conn;
   startTime: number; // milliseconds since midnight 1/1/1970, UTC
   request?: string; // e.g. “gemini://localhost/foo/\r\n”
   host?: string; // e.g. “localhost”

This seems like a pretty deep-reaching change to be made at a point when Deno seems almost mature. I’m not complaining, but I am surprised.

Personally, I’ll like not having to type angle brackets, but I’m not sure I (or anyone else) will enjoy having a five-line type assertion just to use constructs like conn.remoteAddr.hostname.

2021-05-07, a short while later: Service lives of old computers vs. how much electricity it takes to run them

Since I’m back in the CAPCOM rotation this month, I figured the soapbox I’m standing on is a little taller than normal.

I have a question for the floor.

In some corners of Geminispace, there are people who are interested in Gemini because it doesn’t take much computing oomph to either serve or consume. As long as your server can manage to serve up everything over TLS 1.2 or (ideally) 1.3, you should be fine. Unlike on the Web, console Gemini clients are generally no less full-featured than desktop ones.

Because of all this, I’ve seen some people be quite glad to serve up things over Gemini on quite old computers, often with a stated goal of trying to reduce computer waste as a political statement.

Still, I have to wonder. Old computers, generally speaking, use more power to get the same amount of computation done. I can see why someone might prefer running an old Pentium 4 or a BeBox or Sun workstation or whatever instead of buying a new Raspberry Pi to serve up Gemtext, but if this sort of thing describes you, how much extra would you have to spend in energy costs to keep the old computer running before you give up, recycle the old computer, and buy a new computer that runs at least as fast for a fraction of the electricity use?

2021-05-07: OK fine then, I won’t

A while back I sketched out a two-column layout for my main site. The main benefit of having space on the side is that you can stuff “extra” info in it — publish/update dates, tags, statuses, notes, and even a tl;dr if it’s long enough to warrant one.

Most of what I write isn’t long enough or branched enough for that sort of thing, so I decided against moving to a two-column layout.

Since multicolumn layouts aren’t even an option in Gemtext, I’ve been even less interested in surfacing metadata in metadata places. Sure, these Scrawlspace entries have dates in their headers, but that’s about it for metadata.

I kind of miss having metadata blocks in my source files. At this point, I’ve gotten used to having YAML documents where I can stuff all sorts of never-to-be-shown notes at the top of Markdown files. That said, the radical simplification of Gemtext is nice, even though there are all sorts of things I miss from my Markdown-to-HTML-via-Hugo workflow. By keeping a handful of features out of my capsule’s feature set, I’ve managed to keep it so I’m not even tempted to complicate my workflow with a separate build step with a static-site generator.

Sure, I still have to manually add an Atom-feed entry, but somehow that seems like smaller potatoes than picking/generating a filename, typing a post, and then adding that post to a page full of links to posts. Maybe it’s because the bookkeeping work is optional and at the end of the writing, as opposed to some of it being mandatory and at the beginning.

2021-05-06: OK fine then, I contain multitudes

As nice as it is to not have to worry about fonts and layout as a document author in Geminispace, I’ve been enjoying tinkering with Inter, a sans-serif font that seems somewhere in the Helvetica/San Francisco space. That is, it’s the right kind of boring typeface for things I might want to do over port 443.


2021-04-29: Darndest file I’ve ever seen

root:~ # exa -l
.rw-r--r-- 6.1k root 19 Feb 16:44 shutdown -r now

Yes, that’s the only non-dotfile in root’s home directory. No, I don’t create much as root on a FreeBSD machine.

2021-04-28: Seeing posts disappear and reappear here is not evidence that you are going crazy

I made a post and pushed it to my capsule.

Later, on another computer, I made another post and pushed it to my capsule.

However, on the second computer, I forgot to pull in my changes from the Git repo this site is stored in, so I ended up overwriting the initial post.

Now that I’m back on the first computer, I’ve managed to pull the new posts, exhume the old post, and put them all up on the capsule.

This is not the first time all this has happened.

2021-04-27: All I want from you is…your VOICE (choice)

iOS 14.5 dropped today. Apple now has four voices in an American accent, not just two. The other English accents (Australian, British, Indian, Irish, and South African) still have only two apiece, one male and one female.

I picked through the new ones and was generally unimpressed, although it’s kind of hard to get a really good feel for a new voice just on the strength of how it says “Hi. I’m Siri. Choose the voice you’d like me to use.”

I then flipped through the different other English voices and settled on South African (Voice 1) (male).

I’m not too pleased by how my iOS devices all share this voice preference. I thought it’d be neat for each gizmo to have its own voice settings, but I guess that’s not in the cards. I half-expect the foreign voices to butcher Spanish names, which is something of a liability when you’re driving in Southern California and following driving instructions from a phone that’s speaking to you.

2021-04-26: I discover chalk(1)

Old: Reinventing emacs

Bold: Reinventing vim

Behold: Reinventing ed

2021-04-25: Dipping your toe into the delta


dandavision/delta on GitHub

I wanted to try delta instead of diff for Git (and others), but I wasn’t sure I wanted to commit to it. All of the examples in the README show you how to completely replace Git’s diff with delta, but I wasn’t sure I wanted to completely throw out the old thing in favor of the new.

Git aliases to the rescue.

Here’s what I put in my ~/.config/git/config:

# …
    keep-plus-minus-markers = true
    line-numbers = true
    side-by-side = true
    delta = "-c core.pager=delta diff"

Now, I can type `git diff` when I want the old thing, and `git delta` when I want the new thing.

2021-04-24: Not all emoji have a text presentation

Evidently the only emoji with text presentations are the ones that were carried over from Wingdings, the old Windows font. I wanted to have a text-presentation yawning emoji in the title of yesterday’s post, but evidently it doesn’t exist unless all your emoji have text presentation, like in Lagrange.

2021-04-23: Apple released things

Thunderbolt out the back, 3.5mm out the side, and Ethernet on the power brick

“now in purple”

something for people who lose things

gizmos with 8 or 16 GB of RAM

4K@60 with a decent remote

I wanted to be tempted by something, but everything I have, however old, is still just fine. Never once have I thought “I wish my iPad were faster”. When I think about my iPad’s deficiencies, I think of how option-shift-down does nothing in Discord and how I need to force-quit OmniOutliner sometimes because the built-in file picker gets wedged.

And as for things that run macOS, I’m still waiting for a decent 15″ (or larger) laptop that doesn’t have a discrete GPU. Also, I’m in no rush to switch to the new thing if I still have to run Terminal in Rosetta. Ideally, I’ll be able to entirely bypass that phase of the transition.

Then again, some of the projects I run rely on positively ancient dependencies. For these, I wonder if I’ll be able to get off Rosetta before I’m actively forced off. Worst case, I’ll have to keep an Intel-based Mac around for development because current versions of macOS won’t support ancient databases anymore. I’m not looking forward to that future, as I can’t really spare the desk space.

2021-04-14: A Gemini server in 21 lines of Deno

After writing yesterday’s entry, I thought I might try my hand at writing a Gemini server. After all, it can’t be as hard as HTTP/1, can it?

Turns out, it was much, much easier than I figured.

I figured my first problem would be generating a self-signed certificate. I searched for “gemini generate self-signed certificate” and found gemcert, a small Go program that generates certificates for Gemini. Unfortunately, I needed to generate a go.mod file, but that wasn’t too difficult since I trusted myself to make up a decent module name:

module tildegit.org/solderpunk/gemcert

go 1.16

I then generated a cert for localhost:

go build
./gemcert --server --domain localhost

This gave me localhost.crt and localhost.key.

I copied these files to a suitable project directory and added a mod.ts file.

After searching the Deno docs for “listen” (I found Deno.listenTls) and DuckDuckGo for “deno string to uint8array” (I found an article by a Dan Vega), I wrote the following mod.ts with one eye on the Gemini spec:

const port = 1965;
const certFile = "./localhost.crt";
const keyFile = "./localhost.key";

const listener = Deno.listenTls({ port, certFile, keyFile });
for await (const conn of listener) {
  const msg = new TextEncoder().encode(
    "20 text/gemini; charset=UTF-8; lang=en-US\r\n# Hello, world!\r\nThis is a Gemini server."

  try {
    await conn.write(msg);
  } catch (e) {
      `Attempted to write a message of length ${msg.byteLength} but couldn’t:`,


I then ran it in the usual one-off way:

deno run --allow-net --allow-read mod.ts

Finally, I opened up Lagrange (it’s handy and permissive) and pointed it at localhost and saw my hello-world page.

Boom. 21 lines of code.

OK, my first version lacked a call to conn.close() so Lagrange never finished working the first time. And I forgot --allow-read in deno run. And I thought conn.write() migh resolve to a number other than the length of the message. Still. 21 lines of code, and it didn’t even take a full hour to finish writing.



the Gemini spec

Deno docs

Dan Vega: Working with Standard Input and Output in Deno

2021-04-13: A reminder of why Gemini’s telos is different from HTTP’s

I read the Deno 1.9 release notes today. They’ve got a new HTTP/2-capable web server built in now.

This passage, however, stood out to me:

> The current HTTP server in Deno, std/http, is implemented in pure TypeScript on top of TCP sockets. It has [surprisingly] good tail latency despite using a scripted HTTP server. But std/http's major down side is that it is HTTP/1.1 only - with no easy path forward towards HTTP/2.


> Ultimately we don't want to be in the business of writing HTTP servers. HTTP is increasingly non-trivial and there are already well-implemented HTTP servers in native code.

“HTTP is increasingly non-trivial”.

I want people to be able to write good, useful servers easily. From scratch, whatever that might mean in their languages of choice. Even if that means that Gemini users don’t get the performance and features they’d be able to get from a reasonably well-configured HTTP/2 server.


Deno 1.9 release notes: Native HTTP/2 web server

2021-04-09: Keeping your $PATH short with conditional prepending (and using this technique for other shell variables)


Fish, the shell I prefer

If you’re like me, you have a shell configuration that you like.

If you’re more like me than even most nerds, you have a shell configuration that you want to keep roughly similar, even between different underlying operating systems.

If you’re like me about as much as normal nerds are, then you don’t want your $PATH to get cluttered full of paths that aren’t on that particular computer.

So, in order to keep my paths short, I do this:

function conditional_path_prepend -a where
    if test -d      $where
        set -x PATH $where $PATH

I also have a function called conditional_path_append, but so far I haven’t needed to use it.

I then go hog wild with all the paths that I might need to add:

conditional_path_prepend $HOME/bin
conditional_path_prepend $HOME/.local/bin

conditional_path_prepend /Applications/Postgres.app/Contents/Versions/latest/bin

conditional_path_prepend "/Applications/Visual Studio Code.app/Contents/Resources/app/bin"

conditional_path_prepend $HOME/Library/Python/3.7/bin
conditional_path_prepend $HOME/Library/Python/3.8/bin
conditional_path_prepend $HOME/Library/Python/3.9/bin

set -x GOPATH $HOME/Projects/Go
conditional_path_prepend $HOME/.local/opt/go/bin
conditional_path_prepend $GOPATH/bin

And when all that’s done, my $PATH only has 13 items in it. Nothing on Big Sur seems to put Python things in $HOME/Library, so all of that would-be clutter just doesn’t show up.

I also have a bunch of other “if you have the program, add the relevant variables” bits:

set -x DENO_INSTALL $HOME/.deno
if test -f                   $DENO_INSTALL/bin/deno
    conditional_path_prepend $DENO_INSTALL/bin

if command -sq deno # https://deno.land/
    # deno installs its stuff here
    set -x    DENO_INSTALL_ROOT $HOME/.local/opt/deno
    mkdir -p $DENO_INSTALL_ROOT
    conditional_path_prepend  $DENO_INSTALL_ROOT/bin

if command -sq ansible
    set -x ANSIBLE_NOCOWS 1

if command -sq bat # https://github.com/sharkdp/bat
    set -x BAT_STYLE plain

# in case of Ubuntu
if test -f        /usr/bin/vim
    set -x EDITOR /usr/bin/vim

# Use fd for fzf…but only if it’s installed
if command -sq fd # https://github.com/sharkdp/fd
    set -x FZF_DEFAULT_COMMAND 'fd --type f'

This keeps things nice and light on my machines that don’t have ansible, deno, bat, fd, and/or fzf.

2021-04-02: On personal wikis

Prior reading:

Alex Schroeder, “The Bliki Spirit”

> A question for people that have been running their own personal wikis for a few years: do you publish it?

No, because publishing a wiki full of home-improvement information and events and interactions with (potential) contractors never seemed like a good idea.

That said, a personal wiki with this sort of information in it is stupendously handy for answering questions like “When did I last…?” and I recommend that everyone have a personal wiki.

2021-04-01: Don’t believe anything you read on the Internet today

Instead, why not treat yourself to a full viewing of “Never Gonna Give You Up” by Rick Astley? It’s a good song, worth enjoying in its entirety.


2021-03-19: deno.exe growth

Unlike on macOS, where my deno binaries get updated with Homebrew, the deno.exe binary on my Windows machine gets updated whenever I get around to it. Thankfully, it’s as simple as running `deno upgrade` and waiting a few seconds.

This is what the old version looks like:

> deno.old --version
deno 1.7.0 (release, x86_64-pc-windows-msvc)
typescript 4.1.3

And the new version:

> deno --version
deno 1.8.1 (release, x86_64-pc-windows-msvc)
typescript 4.2.2

More amusing, though is the size difference. The old version is 33.5 MB, while the current version is 50.6 MB — about a 50% increase.

I’m not against large software (my editor of choice is VS Code) and the increase is likely due to at least one useful feature (maybe the ability to (cross-)compile standalone applications?), but a jump like that deserves at least some snickering.

2021-03-18: TextExpander doesn’t know how much time it saves me

Every month, I get an e-mail from TextExpander saying how much time it’s/they’ve saved me. It usually says it’s saved me some dinky amount of time, like 22 minutes. I delete these e-mails, but I also got a 2020 end-of-year review e-mail that I kept, and it said I saved three hours that year.

What it’s not taking into account is how long it’d take me to write out a lot of what I have it expand. My second-most-used snippet is “;date”, which currently expands to “2021-03-18”. This saves me the trouble of:

remembering what year it is (OK, not too hard)

looking at my menu bar to see what day of the month it is

trying to figure out the number of the month given what month it is (gets harder the closer that number is to 6)

I use ISO-style dates for a lot of things (this page has a bunch), but I tend to name an awful lot of files with ISO-style dates as prefixes so that no matter what happens to the file metadata, they sort chronologically.

I also use TextExpander to give me picker-free access to a handful of emoji, but fast access to the thinking-face emoji is less impressive (and less frequent) than having a computer handle dates way faster than you can.



2021-03-17: I missed a cool date

> date -r 1000000000
Sat Sep  8 18:46:40 PDT 2001

I don’t remember anyone talking about this day passing, although

I could’ve read something about it on Slashdot

I didn’t read anything about it, and my mind is making up fake memories as I write this

At any rate, 1,000,000,000 seconds after midnight on 1/1/1970 ended up being on September 8, 2001 here. 100,000,000 was in March of 1973; 10,000,000,000 will be in…2286.

> date '+%s'

Maybe there are cool numbers between 1,616,055,107 and 10,000,000,000 that I can use to make up excuses to throw a party. Ideally, they're closer to the smaller number than the larger.

2021-03-16: Man, my Gemini bookmarks are a mess and fixing the mess would create even more mess

I have bookmarks and subscriptions set up in a bunch of places.

amfora on my desktop

amfora on my laptop

lagrange on my desktop

lagrange on my laptop

elaho on my iPad

amfora’s bookmarks format is a TOML file where the keys are base64 (or thereabouts) bundles of URL and heaven knows what else. The values are the bookmark’s description, like “Introduction to sysadminning”.

Lagrange’s bookmarks.txt allocates three lines per bookmark entry:

numbers (seconds since 1/1/1970?) and the URL

user-supplied description


I can only guess what Elaho’s bookmark structure is like, or how to get it out to a real computer.

I can’t say I’d want all these programs to connect to some centralized sync service, and I can’t also say that I’d want a general expectation of Gemini browsers to use some common bookmarks file format, but my life would be way nicer if they all stored bookmarks in sorted YAML or something.

Here’s what the file might look like for maybe a maximal entry:

url: gemini://gemini.circumlunar.space/capcom/
description: CAPCOM
last visited: 1616058364 # ≈1.6·10⁹ seconds since epoch; max safe JS int is ≈9.0·10¹⁵
tags and positions:
- {tag: discovery, position: 0}
- {tag: Bookmarks Bar/Aggregators, position: 1}
subscription: true
subscription style: look at new headers # or: "look for new date links" — Lagrange has an option like this
# …

A good Gemini bookmarks.yaml editor would keep all entries sorted by URL to make diffing easier.

Why tags and positions? Because tags seem popular (as opposed to requiring every bookmark to occur in only one folder). What’s more, tags seem at least as popular in the clients I’ve tried compared to old-school folders.

Of course, if one particular client has a special kind of tag, like one for a bookmarks bar, then that would be kind of weird in other clients.

Tag positions can be important for people whose clients allow them to sort items in a label. That said, neither amfora nor Lagrange seem to allow this.

Having a bunch of different Gemini browsers try to write to a YAML file or whatever in a stable format sounds like a huge mess. I’m beginning to wonder if a shared SQLite database might be better, or maybe some kind of language-server protocol where one program manages the database in whatever format and Gemini browsers send updates and query requests to it.

Of course, if I were writing a client, I would _not_ want to bother with all this. I’m a huge fan of keeping Gemini browsers easy to implement just about anywhere, so I’m more than wishy-washy on whether this is a good idea or not.

2021-03-11: Weighted blankets: More fun than you’d think, even when you’re awake

I got a weighted blanket today.

Like most blankets, it came with a duvet cover.

Unlike most blankets, it's tied into the inside of the duvet cover. The duvet cover has pairs of short strings (think of very wide shoelaces) and the blanket proper has little loops that the string pairs get knotted around.

Taking the blanket out of the box and hauling it onto a work surface (a large chair) was a minor upper-body workout.

Putting the duvet cover back on the thing after washing the cover was an exercise in both (1) forearm strength and topology. When I took the cover off the blanket I noticed how it was slowly coming inside out. I tried to recreate that sort of process, but it seems like I only recreated it by accident. Putting the thing back together again took about 20 minutes, which is way longer than most recoverings.

I can only hope it’s at least as fun when I’m underneath it.

Update, a day later: I got a good night’s sleep, but nothing special.

2021-02-26 (and not just technically): Modern challenges in desktop-wallpaper design

I upgraded to Big Sur recently. On my main monitor, I’m using the “Big Sur” dynamic photograph that changes with the time of day. The picture is of the California coast, looking down from a northward-pointing camera. As I’m writing this in the afternoon, the sun is beyond the left end of the wallpaper. Since I face northward when I’m sitting down at my computer, everything seems right and proper.

On my secondary monitor, I’m using the “Catalina” dynamic photograph. that particular photo must’ve been taken on the north side of the island because the sun goes from left to right.

Just now I briefly considered moving my secondary monitor to a place behind my chair to keep the sun in the right place all the time.

2021-02-26: People don’t like the Node ecosystem

In reply to:


Money quote:

> The entire software ecosystem surrounding NodeJS is bad and I wish I didn’t have to use it.

I wonder what the author thinks of the Deno ecosystem.

Then again, the Deno ecosystem seems about as natural as a bunch of freshly-planted, tastefully-chosen juvenile bushes that nonetheless look like they’re all too far apart from each other. It’s certainly there, but I don’t think Dahl’s ideas on how to import things from where and what to call them have been demonstrated to be a good idea or not.


2021-02-25: Goodbye, favicon.txt

I nuked my favicon.txt. It was the hunk-of-meat emoji.

Of course, you probably didn’t see it anyway since my site isn’t at the root of anything.

2021-01-21: Toward a baroque Gemini log format

I’d go with newline-delimited JSON or a sequence of mappings in YAML (basically NDJSON with “- ” prefixed to every line). I like easy-to-have-someone-else-parse-it-for-me formats.

Not that I’m planning on writing a geminid anytime soon, but here’s what I’d put in it (written out as YAML for ease of reading)

ip:          ""
redacted ip: "127.0.x.x"  # what would this look like for an IPv6 address?
when:        "1611306826" # seconds since the epoch
time:        "21/Jan/2021:00:57:24 -0500"
url:         "gemini://localhost/blah.gmi"
status code: "20"
mime type:   "text/gemini"
length:      "475"
old-school:  ' [21/Jan/2021:00:56:39 -0500] "gemini://localhost/blah.gmi" 20 text/gemini 475'

Zeroth, spaces in dictionary keys are fun.

First, everything’s a string because I don’t want to have to think about whether any number will come close to 2⁵³−1, the maximum safe integer in JavaScript.

It’d be silly to log both an IP address and a partially-redacted IP address, but a server might default to logging only a heavily-redacted IP address and only let its administrator enable logging the full IP address after turning some option on. What would a similarly-redacted IPv6 address look like, though?

I think it’d be nice to have a monotonic clock so logging systems don’t get confused by what happens during daylight savings time changeovers. I also think it’s nice to be able to look at your logs and immediately know when something happened without having to translate from some weird format like “seconds since midnight 1/1/1970, in UTC”. The names need work.

I probably should be pickier about the distinction between URLs and URIs, but that can be tackled after the spec decides on how much non-ASCII gets handled by whom.

There’s probably at least one good reason why Jetforce logs MIME type and length, even though I can’t figure out what any might be. That said, there’s lots of room for logging since no client is wasting bytes claiming to be “like Gecko”.

Caddy has the functionality of “old-school” in its JSON-based log format, but that sort of thing might be of zero use in the Gemini world if there’s no preexisting Common Log Format.





Caddy’s log format

2021-01-19: Writing as a before-bed wind-down

I’m writing a thing. There’s barely any creation to it, just recollection. It seems to be pretty effective as a slow, semi- (quasi-?)productive before-bed wind-down.

This might stop being useful as a before-bed wind-down once all my preexisting ideas get written down already, but one crisis at a time.

2021-01-13: I discover onefetch(1)

I ran onefetch on my capsule:

             :::::::::::::                 Project: gemini-capsule (1 branch)
           ::::::::::::::::::              HEAD: c2ede08 (master, origin/master)
          :::   ::::::::::::::             Created: 4 months ago
          ::::::::::::::::::::             Language: Python (100.0 %)
                    ::::::::::             Last change: 4 days ago
    :::::::::::::::::::::::::: ______      Commits: 115
  :::::::::::::::::::::::::::: ________    Lines of code: 145
 ::::::::::::::::::::::::::::: _________   Size: 48.98 KiB (24 files)
::::::::::::::::::::::::::::: __________
:::::::::::::::::::::::::::: ___________
::::::::::: ____________________________
:::::::::: _____________________________
::::::::: _____________________________
 :::::::: ____________________________
   :::::: __________________________
          ______________   ___

Do we have anyone in Geminispace who has some decent ASCII-art skills who could supply a better logo? Not for Python, I mean. For a Git repo full of .gmi files.

onefetch on GitHub

2021-01-09: Quite possibly doing it wrong: When at an art gallery, make your own scavenger hunt

In high school, our entire graduating class went to a museum. Some of us were given a scavenger-hunt list of things to look for. Some of us weren’t. I can definitely think of arguments both for and against giving high-school students a list of things to search for.

At any rate, if you don’t know what to look for at an art gallery, there’s a good chance you won’t get much out of it. Me, I struggle to appreciate art sometimes, and a list of things to look for in all the exhibits might stimulate…something.

Of course, there’s nothing keeping you from looking at pieces and trying to come up with your own questions. If you’re looking for some sort of stimulus, looking at pieces and trying to come up with a question about it might be the sort of thing you need to get your brain active when you’re walking around an art gallery.

2021-01-02: A man’s gotta know his limitations

A man’s gotta know his limitations. This can be made more difficult if his limitations fluctuate.

My ability to like/appreciate/tolerate 72% chocolate ebbs and flows. Right now my low-sugar tolerance must be at an ebb end, because apparently I currently actively dislike 72% chocolate, even in baked goods.

Trader Joe’s sells Pound Plus (500g) bars of chocolate in three nutless strengths:




I try to stick with the darkest chocolate I can tolerate because it has the least sugar in it. The snag, though, is that too-dark chocolate has a medicinal taste. While this can be overcome somewhat by not eating pure chocolate all by itself and instead putting the chocolate into something sweeter (like cookie batter), this technique doesn’t work for everyone all of the time.

After two or three sub-mediocre batches of cookies made with 72% chocolate, I decided to buy a half-kilo of merely dark chocolate. Apparently this was the winning move, because my most recent batch actually tastes good.

I’ll probably re-acclimate to 72% again (I’ve done it two or three times now), but right now, that’s not what my taste buds are up for.

My (well, Kenji’s) go-to chocolate-chip cookie recipe


I told you people to not expect permanence. Here’s where I moved 2020’s scrawls to:



If you want to stay abreast of updates, have a look at this capsule’s colophon. It has JSON Feed and Atom feeds on it.



Hi! I’m a one-pixel invisible tracking image! View me to let my webmaster know you’ve scrolled through the entire page!

-- Response ended

-- Page fetched on Tue Aug 3 09:38:19 2021