Knowing Less, Producing More
On AI, Craftsmanship, and the Slow Erosion of Productive Friction.
61 posts across 9 years
On AI, Craftsmanship, and the Slow Erosion of Productive Friction.
A 15-minute introduction to vui.el - React-style declarative UI components for Emacs. Learn props, state, composition, and the basics of building interactive interfaces without wrestling with buffers.
Vulpea v2 drops its org-roam dependency. Here's how I got there - from monster SQL queries to materialised views to finally writing my own foundation.
How React-style hooks work without explicit keys—using call order during execution to establish identity. A pattern that's non-obvious but elegant, implemented in Emacs Lisp.
Practical patterns and common mistakes when building vui.el applications
How vui.el works internally — virtual nodes, instances, reconciliation, and the render cycle
Master use-ref, use-callback, and use-memo — the hooks that help you avoid unnecessary work. Learn when mutable references beat state, how stable callbacks prevent wasteful re-renders, and when memoisation pays off.
Master vui.el's four hooks - on-mount, on-unmount, use-effect, and use-async. Learn cleanup patterns, avoid stale closures with functional updates, and see runnable examples throughout.
Solve prop drilling with context and learn four composition patterns - container/presentational, compound components, render props, and slots - that keep complex UIs maintainable.
Build a working file browser from scratch in 8 incremental steps. Learn component decomposition, state lifting, callbacks, and the patterns that make UI code maintainable.
Complex Emacs UIs are hard - multiple data sources, cascading updates, cursor management. I tried three approaches to the same interface: imperative rendering, widget.el with zones, and declarative components. Here's what I learned, and why I ended up writing a 2.5k line library.
A bash script to track GitHub contributions across all branches — because the official graph lies, and I needed data to correlate commit frequency with questionable life choices.
A deep dive into Emacs's widget library: what it does well, where it falls apart, and a step-by-step case study of building a table widget with editable cells. Includes working code and hard-won lessons about state management, layout hacks, and cursor position preservation.
After using Nix, nix-darwin, and home-manager for 4-5 years, I've finally switched back to Homebrew and bash scripts. Here's why the promise of reproducibility didn't hold up on macOS, and how freeing 80GB of disk space was the final push I needed.
After fixing PATH injection on macOS 15, I'm dusting off a year-old feature: proper Finder integration for emacsclient. Using AppleScript instead of shell scripts, Emacs Client.app now handles file opening from Finder, drag-and-drop, and auto-starts the daemon. With one cosmetic icon issue that needs your help to solve.
A complete visual overhaul of this site—migrating from Hakyll to Next.js, adopting a brutalist + jRPG aesthetic, and upgrading to Tailwind CSS v4.1. Sharp corners, bold colors, and way less fighting with build systems.
Announcing Vulpea v0.3, with major performance improvements for note querying operations. The release introduces a materialised view table that provides a 4.5x speed boost for general queries, plus specialised query functions that can be up to 150x faster in certain scenarios. Whilst write operations take a small hit, the trade-off is worth it for large note collections. I've also added several quality-of-life improvements like better metadata handling and new tag utility functions.
Sharing how I improved PATH handling in Emacs+ to solve a common pain point. By injecting the user's PATH into Emacs.app during build, users now get the expected environment variables when launching Emacs from anywhere on macOS. This change also simplifies native-comp configuration and helps avoid common compilation issues. Whilst it's not as dynamic as exec-path-from-shell, it provides a solid out-of-the-box experience for Emacs+ users.
Sharing some analytics insights from Emacs Plus and how they'll influence future maintenance. Looking at installation data, Emacs 28 is currently the most popular version, and features like native-comp and xwidgets are heavily used. I'm considering deprecating some rarely-used options whilst making it easier to enable simple build flags. For icons, modern-doom3, nobu417-big-sur, and spacemacs lead in popularity. Any major changes will be well-communicated to avoid disrupting users' workflows.
Sharing my yabai configuration for automatically setting up workspaces in macOS. I walk through how to create a consistent set of labelled spaces, clean up extras, and automatically move applications to specific workspaces on startup. Whilst tiling window managers aren't for everyone, this setup helps maintain an organised workflow by ensuring applications always land in their designated spaces.
A personal note explaining that whilst I'll be less available due to the war in Ukraine, projects will continue—though help from the community would be welcome.
Migrating from org-roam v1 to v2—covering mandatory IDs, improved note structure, enhanced database queries, and the transition from file-based to ID-based linking, with migration scripts and lessons learned.
Fixing PATH order issues when using Fish shell with nix-darwin—Fish's path_helper reimplementation was moving .nix-profile/bin to the end, preventing nix packages from overriding system binaries. Solution: preserve original PATH and restore order after Fish initialisation.
Streamlining task capture in org-roam with dedicated inbox files per machine, processing via org-agenda, and dynamic capture templates that automatically place one-on-one meeting notes in the correct person's file.
Comparing build tools for Emacs packages—makem.sh for simplicity, cask for robustness, and eldev for extensibility—with observations on when each tool suits different project needs.
Making Emacs configurations maintainable with eldev, straight.el, and structured init/lib/config files—achieving fast startup whilst enabling proper byte compilation, linting with elisp-lint, and testing with buttercup.
Handling network instability when updating Emacs packages with straight.el by creating a retry wrapper using advice-add to automatically retry failed network operations.
Building a utility function to select a person and view all related tasks in org-agenda, supporting aliases whilst leveraging vulpea's selection capabilities and org-mode's tag matching.
Optimizing org-roam agenda performance by dynamically tracking notes containing TODOs with a 'project' tag, reducing agenda loading from over 50 seconds to under 1 second.
Automating task tagging in org-roam with vulpea—when you mention someone in a task by linking to their note, the task automatically gets tagged with that person's name.
Managing person-related tasks in org-roam using filetags to automatically tag all tasks (like @FrodoBaggins), maintaining tag inheritance whilst moving to individual notes.
Fixing category display in org-roam agenda views by showing meaningful categories based on note titles instead of file IDs, with automatic extraction and formatting for clean, readable results.
How to organize tasks and projects in org-roam whilst maintaining compatibility with org-mode's agenda features. Implementing a familiar structure of tasks, projects, and meta-projects across multiple files.
Functions for managing tags in org-roam notes with completion support. Whilst this functionality is now part of org-roam v2, the code demonstrates how to extend org-roam and work with its database.
Custom Emacs functions for smarter line navigation that jump to meaningful content before the actual line start. Includes an enhanced org-mode version that handles headlines, TODO items, and list bullets intelligently—no external packages required.
Exploring different approaches to encoding preconditions in Haskell libraries, from simple Maybe types to sophisticated type-level guarantees. Drawing on insights from Alexis King's "Parse, don't validate" and Matt Noonan's "Ghosts of Departed Proofs", learn how to make illegal states unrepresentable.
Exploring predicate composition in Haskell through multiple implementation approaches—from simple operators to Semigroup instances and coercion. Learn how to create elegant abstractions without runtime penalties by leveraging GHC's optimisation capabilities, complete with Core dumps and benchmarks.
Status update on emacs-plus: improvements to CI/CD with GitHub Workflows, better patch management, and thoughts on simplifying build options whilst maintaining experimental features.
Introducing env-extra, a small Haskell library that improves environment variable handling with Text support, flexible return types, and better error handling—reducing boilerplate from System.Environment.
Announcing flyspell-correct 0.6 with a new avy-menu interface, fixed point movements, lexical binding, and various improvements. Special thanks to @clemera and @Ergus for their contributions!
How to make the helpful package reuse windows more sensibly in Emacs by customizing helpful-switch-buffer-function to keep your code visible whilst browsing documentation.
Learn how to create a reusable 'ask' function in Bash that handles both required and optional user inputs with default values. Discover why bash's indirection and declare features are safer alternatives to eval for variable manipulation.
Introducing Eru.sh, my system bootstrapping script that sets up my development environment across different machines. Learn how I use Bash patterns like mapping over files and handling optional themes to make the code more maintainable, plus how to avoid eval whilst still achieving dynamic variable handling.
Exploring the quirky world of booleans in Emacs Lisp—or rather, the lack of them! Since everything is either nil (the empty list) or some form of "true", comparing boolean values gets interesting. Learn different approaches using if/when, not, and xor to handle boolean comparisons properly.
Learn how to create high-quality GIFs from video using FFmpeg's custom palette generation. I share my 'gifify' script that automates the process, with options for FPS, scaling, and compression, plus visual examples comparing default vs custom palettes.
Announcing flyspell-correct 0.5 with rapid mode for fixing multiple words in one run, function renames, improved skipping behaviour, and test coverage.
A quick tip for generating high-entropy random bytes using OpenSSL's rand command. Learn how to use hex or base64 encoding to create valid random strings for passwords, and how to handle the output length when encoding changes the byte count.
Discover Org mode's built-in structure templates that make inserting source blocks and other structural elements effortless. Learn how to use C-c C-, for modern template insertion or enable the legacy Easy Template system with <s<TAB> for quick shortcuts.
Building a GitHub API client in AppleScript for OmniFocus integration. The script handles authentication and data extraction, though it has some efficiency limitations when fetching multiple values.
A simple Fish shell hack to help you stay focused: get notified when long-running commands complete instead of getting distracted whilst waiting. Learn how to use Fish's CMD_DURATION variable to detect lengthy commands and send notifications when they finish.
Exploring Git's conditional includes feature and comparing it to my git-config-manager tool—whilst the native solution elegantly handles many use cases, there's still room for unique features.
A humorous reflection on yak shaving: how wanting to write a blog post led me down a rabbit hole of infrastructure improvements—from EC2 to S3, Hakyll to Docker, and everything in between. Sometimes the journey is more interesting than the destination.
A personal reflection on my love-hate relationship with org-mode. Exploring how this deceptively simple outliner keeps drawing me back in, gradually imposing more complex features upon myself, whilst remaining an essential tool for organising my life.
Learn how to write robust shell scripts that handle errors gracefully. This practical guide covers exit-on-error mode (set -e), signal traps for cleanup operations, and best practices for preventing corrupted states when commands fail.
How to use version-specific package directories in Spacemacs to avoid reinstalling packages when switching between different Emacs versions.
Announcing flyspell-correct v0.1, featuring a complete package restructuring into separate core and interface modules, improved dependency management, and a new function for backwards spell-checking correction.
A defence of Emacs' extensibility philosophy in response to discussions about Vim's composability. Exploring how Emacs' flexible architecture allows the community to implement any feature they value—including composability itself—whilst offering multiple paths to customisation.
Introducing flyspell-correct, a unified Emacs package that brings distraction-free spell-checking correction to your favourite completion framework. Learn how to correct misspelt words without leaving your current position, implement custom interfaces, and use rapid mode to fix multiple mistakes efficiently.
A historical look at solving Cabal Hell when installing Haskell executables. Learn how to use Cabal sandboxes to isolate dependencies and automate the process with custom Fish shell functions. Note: Stack and Nix-style builds have since made this approach obsolete.
A comprehensive review of the Fish shell after switching from Zsh. Discover how Fish's blazingly fast autocompletion, man page parsing, and sensible defaults provide an excellent out-of-the-box experience, plus the trade-offs you should consider regarding POSIX compatibility.
A summary of the third major release of CanonicalPath library, highlighting API changes, performance improvements, and enhanced testing infrastructure while maintaining compatibility with major Haskell package repositories.