Tristan Dunn

Glamorous Christmas: Bringing Charm to Ruby (cache, source)

Ruby developers deserve glamorous terminals too. I want Ruby developers to build terminal applications so beautiful that even people who “don’t like CLIs” find themselves captivated.

I’ve recently been using AI to write CLI utilities in Go with Charm, but I know Ruby much better than Go so this is very exciting news. I’m even more excited about the coming work for the libraries to “feel more Ruby-like and idiomatic”.

at 12:56 AMcli, open-source, ruby

Why I Write (And You Should Too!) (cache)

Be okay with bad writing. Most writing isn’t great! If my hit rate is 1 out of 5, I’m thrilled. Get comfortable publishing things that aren’t perfect. I know many people who wait too long to publish and, well, never do.

at 2:40 PMai, writing

Ruby 3.4.8 Released (cache)

Ruby 3.4.8 has been released as a routine update that includes bug fixes. The full details are available in the release notes on GitHub.

It’d be nice if the Ruby team maintained the Docker image now that Ruby has a release schedule. Always feels odd to see a new release and then have to wait for an image update to be able to test a deployment.

at 10:28 PMopen-source, ruby

Litestream VFS (cache, source)

This is Litestream VFS. It runs SQLite hot off an object storage URL. As long as you can load the shared library our tree builds for you, it’ll work in your application the same way it does in the SQLite shell.

I’m imagining running this in the browser with the WASM version of SQLite3 using read-only credentials. Combined with JSON virtual columns, this could create a serverless interface to data being streamed into the database from another source. This could power a graphing interface for analytics or metrics, where the data is truncated at specific intervals to keep the database compact while using litestream_time to query historical data.

at 2:40 PMdatabases, sqlite

Upgrading to RubyGems/Bundler 4 (cache)

We introduced breaking changes in RubyGems/Bundler 4 in order to improve usability, security, and maintainability of the tool.

I’ve upgraded a few projects and not noticed any issues so far. Restoring the default command to be install is nice for my muscle memory locally, but elsewhere, like in a Dockerfile, I already use bundle install explicitly.

And while new lockfiles include checksums by default, you have to manually add them to existing lockfiles via bundle lock --add-checksums.

at 10:19 PMrails, ruby

Claude CLI deleted my entire home directory! Wiped my whole Mac. (cache, source)

I found the problem and it’s really bad. Looking at your log, here’s the catastrophic command that was run: rm -rf tests/ patches/ plan/ ~/

Not that it’s a foolproof solution, but I’ve aliased rm to a trash command for almost ten years now to move files to the trash instead of deleting them. A trash command is built into macOS Sequoia and newer.

The one downside is the command doesn’t support the -f or -r arguments, so it often causes issues with Claude Code. Sometimes it’ll switch to using rmdir, so I’m also aliasing that now.

I’m not sure how much moving the home directory to the trash would have helped, since the trash command does completely remove files and directories prefixed with a period.

at 5:34 PMai, cli

Simple and Free Speech-to-Text on macOS

After seeing Wispr Flow mentioned a few times, I was curious about using speech-to-text to interact with Claude Code. The idea of paying $12/month and potentially sharing all my prompts wasn’t ideal, so I decided to see what Claude Code could help me build.

With a bit of experimentation, I settled on using sox for audio recording, since it seemed the best at silence detection, and parakeet-mlx for transcribing. I tried various improvements to silence detection, but found turning up my input volume helped the most.

With three commands in a script, I have a decent local speech-to-text solution:

#!/bin/bash
RECORDING_FILE="/tmp/record-recording.wav"
TRANSCRIPT_FILE="/tmp/record-recording.txt"
# Record until silence or 60 seconds.
rec -q "${RECORDING_FILE}" rate 16k pad 0.2 0 silence 1 0.05 1% 1 1.0 1% trim 0 60
# Transcribe and output.
if [ -f "${RECORDING_FILE}" ]; then
parakeet-mlx "${RECORDING_FILE}" --output-format txt --output-dir /tmp --chunk-duration 30 >/dev/null 2>&1
if [ -f "${TRANSCRIPT_FILE}" ]; then
cat "${TRANSCRIPT_FILE}"
fi
fi

The real script is a little more verbose, but this demonstrates the core of it. I use Hammerspoon to trigger the script and type the response for me. I also have it display a recording and transcribing status indicator in the menu bar.

My next step is to decide what to use for transcription on Linux so I can use it on my other machine. I might also create a second script that pipes the results through an LLM for use outside of prompts.

at 10:00 PMai, speech-to-text

Introducing Mistral 3 (cache, source)

The release also features the Ministral 3 series—three edge-focused models (3B, 8B, and 14B parameters) designed for superior cost-to-performance efficiency. These smaller models include multimodal and multilingual capabilities, making them suitable for edge deployments.

I’m excited to see small models continuing to advance. While I’m all in on Claude Code for code-related tasks, I enjoy using local models for simple copywriting tasks or for tasks requiring complete privacy.

at 7:29 PMai, open-source