Skip to content
Django administration
Welcome, guest. / Documentation /

Site administration

I'm just a boy, sitting in front of some code, looking for the right abstraction.

👋 Hi, I’m Josh. I live in Alabama with my wife and our two kids, and I build software for a living.

I’ve been messing with computers for about as long as I can remember. I was swapping out the Windows shell on the family Gateway when I was ten and bought C++ for Dummies on a band trip in high school. Somehow it still took me until my thirties to figure out that I should probably do this for a living.

I took the scenic route getting there. I came to the University of Alabama to study music education and play trombone in the Million Dollar Band, eventually graduated in civil engineering, and spent a few years doing other things before finding my way into IT and then software. Once I got the chance to build software professionally, I pretty much took the reins and never let go.

Open source is where a lot of that curiosity ends up. Partly because I learned this stuff by drafting off people who put their own work out there, and it feels wrong to only take. Mostly, though, it’s where I go to play. I’ll get interested in something, disappear down a rabbit hole, and sometimes come back with a Django package or a language server or some other thing that probably didn’t need to exist until I decided it did.

This is where I put the things I make, the things I’m learning, and whatever else I feel like writing about.

Work

#The Westervelt Company

#Web developer

The Westervelt Company

2020–present

Westervelt is a land and lumber company, and I’m its lead developer. I look after about ten Django applications across a surprisingly wide business: safety in our lumber mills, mineral payments, bookings at our hunting lodge, our public websites, and plenty in between.

The biggest is our hunting lease application. It’s been around for nineteen years and manages hundreds of clubs across roughly three-quarters of a million acres, bringing in about $8 million a year. It’s deceptively simple and frustratingly complex: nineteen years is a lot of business rules, exceptions, abandoned ideas, and decisions whose reasons aren’t always obvious anymore.

These days I have another developer and outside consultants to share the load with, but I’m still involved from the first conversation through production. I work with the people who use the applications to figure out what we actually need to build, design and build it, test it, ship it, and then stick around to find out whether we were right. I don’t get to throw the code over the wall; if I make a bad decision today, there’s a good chance I’ll be the person discovering why six months from now.

When I took the job, we didn’t even have source control. I created the company’s GitHub organization and, piece by piece, added the things I needed to trust the software I was responsible for: code review, automated tests, CI, dependency updates, staging environments, repeatable deployments, observability. I was learning plenty of it as I went. Mostly, I wanted enough evidence around a change that I could deploy it and still sleep that night. Six years later, those things aren’t projects anymore. They’re just how we work.

#Computer & Systems Operations Support Analyst

The Westervelt Company

2018–2020

I joined Westervelt on the IT support team, helping people across the company with their computers and the systems they used every day. As usual, I started automating the repetitive parts of my own job whenever I could. Those two years gave me a chance to learn the business and get to know the people in it before an opening on the web side gave me my shot at doing software professionally.

#Nathan & Nathan, P.C.

#IT Support Analyst / Junior System Administrator

Nathan & Nathan, P.C.

2017–2018

Nathan & Nathan was where my IT career really started. At this Birmingham law firm, I did the usual mix of help desk and junior sysadmin work: fixing people’s day-to-day problems, managing computers from setup through replacement, and looking after internal IT services.

Projects

Most of these started because I wanted something that didn’t exist, wanted to understand how something worked, or got curious enough to disappear down a rabbit hole. I learned to build software by reading what other people put out in the open, so this is where a lot of mine ends up too.

#Language tooling & editors

Learning Rust led me to build a language server for Django. The editor extensions and pre-commit integration are separate pieces of the same project: making Django templates easier to work with wherever you write them.

  • #django-language-server

    A language server for Django, written in Rust. It started because I wanted a real project to learn Rust with, and I’d wanted better tooling for Django templates for years. It has since turned into a much bigger static-analysis problem than I expected: parsing Python and Django templates, following values through a project, understanding models, forms, URLs, settings, and template context, all without importing or executing the Django project. It’s probably the project I’ve learned the most from. I knew basically nothing about language servers, compilers, parsers, or static analysis when I started it.

  • #tree-sitter-htmldjango

    A fork of the tree-sitter grammar for Django templates that I maintain for Zed, with fixes and additions for comments, translation syntax, and verbatim blocks.

  • #zed-django

    Django support for the Zed editor.

  • #djls-vscode

    A VS Code client for Django Language Server.

  • #djls-pre-commit

    Run Django Language Server checks with pre-commit.

  • #django-template-ast

    Experiment. An earlier attempt at learning Rust by building a Django template compiler, before the language server.

  • #djtagspecs

    Abandoned experiment. An RFC-style specification for describing Django template tags in TOML, from the early language-server work. I eventually abandoned the approach in favor of extracting the information statically, but I’ve kept it around as a record of one of the paths I went down first.

#Django & Python

Most of my day-to-day web development is in Django, so I’ve ended up making a lot of things for it. Some came out of work, some were things I wanted for my own projects, and some were just ideas I wanted to try.

  • #mcp-django

    An MCP server that gives coding agents structured, ORM-aware access to Django projects. Instead of making an agent work everything out from source text alone, it gives it a way to inspect the project through Django itself.

  • #djangodocs.org

    Documentation search built for the way I use Django with coding agents: get the relevant documentation into context without making the model hunt through the web or guess. It’s currently in private alpha.

  • #docs2markdown

    The CLI tool and Python library underneath djangodocs.org, which turns HTML documentation into Markdown suitable for search and LLM context.

  • #django-github-app

    A toolkit for building GitHub Apps with Django: signed webhooks, event routing, installation and repository state, and authenticated sync and async GitHub API clients. It now powers the Python Software Foundation’s CLA bot.

  • #django-simple-nav

    Define navigation in Python and render it in Django templates, with URL resolution, active-page detection, and permission filtering.

  • #django-bird

    High-flying components for perfectionists with deadlines. Reusable components defined entirely in Django templates, with properties, slots, and their own CSS and JavaScript. I wanted the ergonomics of a component system without leaving Django’s template language. I’m not actively maintaining it these days; most of that time now goes into the language server.

  • #django-bird-playground

    An interactive web playground for building and testing django-bird components.

  • #django-bird-autoconf

    Automatically configures the Django settings needed by django-bird.

  • #django-q-signals

    Process Django signals asynchronously with Django Q2.

#LLMs & agent harnesses

I use coding agents enough to keep finding things I want them to do differently. Some of these extend OpenCode or Pi; others help me share skills, manage sessions, or keep track of usage across tools.

  • #ast-grep-rules

    Reusable ast-grep rules for catching recurring mistakes in agent-written code, across Rust, TypeScript, Svelte, Python, Go, and more. They run as deterministic checks rather than relying on the agent to remember the same instructions every time.

  • #gh-actionkit

    A GitHub CLI extension for finding Actions, checking for outdated references, validating workflow syntax, and running security checks.

  • #agent-skills

    Workflows and patterns for coding agents, packaged as reusable skills.

  • #ts-skills

    A registry for sharing agent skills privately within a Tailscale network.

  • #vibeusage

    Track usage across LLM providers from the terminal.

  • #opencode-beads

    The Beads issue tracker inside OpenCode, so an agent can create, update, and reason about work without leaving the coding session.

  • #opencode-agent-memory

    Persistent memory for OpenCode, inspired by Letta. It started from wanting useful context to survive between coding sessions without stuffing everything into one ever-growing prompt.

  • #opencode-agent-skills

    An OpenCode plugin that provides tools for using agent skills.

  • #opencode-handoff

    Create focused handoff prompts for continuing work in new OpenCode sessions.

  • #pi-o-my

    My collection of Pi extensions, installable together or individually.

  • #pi-opensync-plugin

    Sync Pi sessions to OpenSync dashboards.

  • #hrd

    A terminal picker for local and remote Herdr sessions, with support for Sprites sandboxes.

  • #agents-svelte

    Community Svelte 5 bindings for the Cloudflare Agents SDK.

  • #llm-uv-tool

    Makes plugin installation and upgrades work when Simon Willison’s LLM command-line tool is installed through uv tool.

  • #pi-peon-ping

    Peon-ping sound notifications for the Pi coding agent.

#Web interfaces

I use Svelte for most of my frontend work outside Django. A few of these started because I found something built for React that I liked and wanted to use it without React.

#Desktop & command-line tools

Small tools for my own computer, mostly Linux: capturing a thought, working in the terminal, or filling a gap in the software I use. Some are everyday tools, and some are still ideas I’m trying out.

  • #waywire

    Stream a Wayland desktop to the browser.

  • #dashtext

    A quick-capture text editor for Linux, inspired by Drafts.

  • #dictate

    A command-line tool for local voice-to-text transcription on Linux.

  • #kbd

    A keyboard-shortcut engine for Rust.

  • #wakatime-focusd

    A daemon for Linux that tracks focused desktop applications and sends heartbeats to WakaTime.

  • #sp

    Prototype. A personal music player for the Linux terminal.

#Shared work at The Westervelt Company

Libraries shared across our applications at work and published for other people to use, too. They grew out of the practical details of running Django applications together.

Project statistics & contributions

More on GitHub

Community

I’ve learned an enormous amount from the Django and Python communities. I try to give some of that back when I can.

I occasionally contribute to projects in Django Commons. I also contributed to Jazzband before it shut down.

Talks

Writing

Feed

Writing archive

Elsewhere