Repackaging a Neovim distribution as a plugin

Most Neovim distributions ship as a repo you clone into ~/.config/nvim, which makes your config and their distribution the same git repository. Splitting them into a plugin plus a starter template fixes that — here’s why, and how.

August 19, 2026 · 13 min · Omar Crosby

Lua in Neovim, from the ground up

A comprehensive introduction to Lua as it lives inside Neovim — why the project bet on it, which Lua Neovim actually runs (LuaJIT, Lua 5.1 semantics with select extensions), the whole language walked in from smallest values to metatables and coroutines, the five gotchas, and the vim.* namespace that turns Lua into a text-editor scripting language.

August 16, 2026 · 34 min · Omar Crosby

ETL in plain language

A jargon-free introduction to ETL — what Extract, Transform, and Load actually mean; the vocabulary defined without hand-waving; concrete examples; and how to decide when an organization actually needs one.

August 14, 2026 · 22 min · Omar Crosby

ETL's real failure mode is silent, not slow

ETL’s dominant failure mode isn’t a slow pipeline — it’s a green one that produces wrong data. Four invariants that separate ‘finished’ from ‘correct.’

August 13, 2026 · 9 min · Omar Crosby

Data modeling in plain language

A jargon-free introduction to data models and data modeling — what a data model actually is, how they’re typically represented (ER diagrams, relational schemas, JSON structures, dimensional models), and why deciding the shape of your data before writing the code that manipulates it is usually the cheapest work you’ll do all quarter.

August 11, 2026 · 19 min · Omar Crosby

Vim macros, from record-and-replay to reshaping thousands of lines

A Vim macro is a recorded sequence of keystrokes that you replay against a range, and it is the tool that beats sed, awk, and multi-cursor for irregular structural edits. This is the reference post: recording, replaying, applying over ranges, editing a macro as text in a register, recursive macros, and the specific patterns that make macros a daily tool. Fourth and final in the Vim series.

August 9, 2026 · 12 min · Omar Crosby

Vim registers, all ten kinds and when each one saves you

Vim has ten kinds of registers — unnamed, numbered, named, small-delete, read-only, expression, selection, black-hole, alternate-file, and last-search. Most Vim users know two of them and lose work to the other eight. This is the reference post: what each register is for, when it saves you, and the concrete recipes that turn registers from trivia into a daily tool. Third in a four-part Vim series.

August 9, 2026 · 14 min · Omar Crosby

Vim motions and text objects, the actual language

Motions and text objects are where Vim’s productivity actually lives. This post is a full reference — every motion category, every text object, the counts and repeats that combine with them, and worked examples showing why ‘change inside quotes’ is the command you’ll type ten times a day. Second in a four-post series on Vim, following the modal-editing intro and preceding the deep dives on registers and macros.

August 9, 2026 · 14 min · Omar Crosby

Modal editing in Vim, from scratch

Modal editing is not a keyboard shortcut scheme. It’s a small language for describing text edits, and once you see it as a language the rest of Vim stops being a pile of trivia. First in a four-post series: this one covers the four core modes, the verb-motion-object grammar, and the smallest set of commands that gets a new user productive by the end of the afternoon. Companion posts go deep on motions and text objects, registers, and macros.

August 9, 2026 · 12 min · Omar Crosby

grep, sed, and awk: a practical introduction for Mac users

You export a report from some web app and it hands you a 40,000-line CSV. You need three columns out of it, only the rows from last Tuesday, with one misspelled city name fixed throughout. You could open it in a spreadsheet, wait for the beachball, scroll, sort, find-and-replace, and export again. Or you could describe the whole job in one line of text and get the answer before the spreadsheet finishes loading. ...

August 8, 2026 · 10 min · Omar Crosby

Skills vs MCP: what we're actually arguing about

Three voices argue about how to extend a Claude agent — skills-first, MCP-anchored, complementary. The debate dissolves once you separate procedural knowledge from live reach.

August 7, 2026 · 14 min · Omar Crosby

The anatomy of an SDK, in Go

A walkthrough of the surface an SDK exposes, in seven parts, with idiomatic Go for every piece: the client constructor with functional options, resource groupings that mirror the caller’s mental model, typed requests and responses, typed errors with request IDs and errors.As, first-class pagination via iter.Seq2, streaming and retries and instrumentation, and the docs/samples/changelog trio that finishes the surface. Companion to the SDK fundamentals post.

August 7, 2026 · 8 min · Omar Crosby

What makes a good SDK

An eight-point rubric for judging whether an SDK is any good, each criterion paired with a real currently-shipping SDK that gets it right — Stripe (idiomatic hand-crafted per language, typed errors with request IDs, exceptional docs), AWS SDK for Go v2 (boring auth via the credential-provider chain, paginators as a distinct type), Anthropic and OpenAI (sensible retry defaults, streaming), Stainless-generated SDKs (types from a single spec), GitHub Octokit (honest versioning). Followed by the two-sided value proposition — what building on those axes actually buys for the vendor and the caller.

August 7, 2026 · 15 min · Omar Crosby

Capability-first SDK design, and where new work belongs

The question is almost never ‘how do we add this method to the SDK?’ — it’s ‘where should this capability live?’ A companion to the SDK fundamentals post, covering capability-first SDK design (with the caller-sketch discipline as the practice), the five-way routing framework for new capability requests (pure SDK / additive API change / new endpoint / new API service / push down for generation), signals for extending an existing API vs. creating a new one (with Stripe Terminal and AWS Lambda as named examples), and the version-coordination process when a capability requires changes on both sides.

August 7, 2026 · 17 min · Omar Crosby

What an SDK actually is, and when to build one

An SDK is not just a client library — it’s the smallest thing a platform can ship that turns ‘read our docs and call our API’ into ‘install this and get to work.’ First in a four-post series on SDK design: this one covers the fundamentals — what SDKs are, where they came from, how they differ from libraries and frameworks and protocols, why they’re becoming the product itself, and a concrete decision framework for when to build one. Companion posts cover the anatomy of an SDK’s surface in Go, the rubric for what makes one good with named exemplars, and the design-process question of routing new capabilities between the SDK and the API.

August 7, 2026 · 16 min · Omar Crosby

How a Claude Code project is structured on disk

A file-by-file walkthrough of the project-scoped Claude Code layout — CLAUDE.md, .mcp.json, settings, rules, commands, skills, subagents, and hooks — and the team-shared / personal-local split behind every file.

August 4, 2026 · 15 min · Omar Crosby

What makes a CLI Claude-friendly

A concrete look at what turns a command-line tool into something an AI coding agent can drive reliably, with contrived before/after examples for structured output, subcommands, non-interactive defaults, exit codes, self-documenting help, idempotency, and when a token-oriented format like TOON is worth adding as a second output mode.

July 30, 2026 · 14 min · Omar Crosby

Speed up terminal navigation with zoxide and fzf

A plain-language guide to zoxide (a smarter cd) and fzf (a general-purpose fuzzy finder) — what they are, how to install and configure each on its own, and how they combine into a terminal that feels like it can read your mind.

July 26, 2026 · 9 min · Omar Crosby

Mutation testing: grading the tests, not the code

The anchor post of the mutation-testing series. What mutation testing actually measures, why it exists as a complement to line coverage, when to reach for it, and the specific classes of test-suite weakness it uncovers — written to stand alone regardless of your language.

July 25, 2026 · 21 min · Omar Crosby

Mutation testing in Rust: getting started with cargo-mutants

The Rust chapter of the mutation-testing series: what the technique measures, why the number is stronger than line coverage, and how to run cargo-mutants against a real Rust crate in five minutes.

July 25, 2026 · 14 min · Omar Crosby

Mutation testing in Go: getting started with gremlins

The Go companion to the mutmut post: what mutation testing actually measures, how gremlins produces the score, and how to run it against a real Go module in five minutes.

July 25, 2026 · 16 min · Omar Crosby

Mutation testing in Python: getting started with mutmut

Line coverage tells you where the tests went. Mutation testing tells you whether the tests you have would notice if the code were wrong. A plain-language getting-started guide with mutmut.

July 25, 2026 · 15 min · Omar Crosby

Black-box unit tests: testing behavior, not implementation

Unit tests that break every time you refactor are describing the implementation, not the behavior. A senior engineer’s playbook for writing black-box tests that survive.

July 24, 2026 · 15 min · Omar Crosby

Unit tests: what we're actually arguing about

Four voices argue about unit tests. The debate dissolves once you separate coverage-as-target from coverage-as-detector, with testability as the real prize.

July 24, 2026 · 13 min · Omar Crosby

The anatomy of a Claude Code configuration

Claude Code is Anthropic’s AI-powered coding assistant — the one that reads files, runs commands, edits code, and drives a full development workflow from your terminal, editor, or a desktop app. It is a distinct product from the browser-based Claude chat at claude.ai; the two share the same underlying model but almost nothing about how you interact with them. Everything in this post is about Claude Code specifically. Out of the box, Claude Code behaves the same for everyone. But almost every serious user ends up with a personal configuration: a folder called ~/.claude/ on their machine that quietly shapes how Claude Code behaves for them. ...

July 21, 2026 · 16 min · Omar Crosby

Design patterns as vocabulary

Not a catalog of the Gang of Four patterns — an argument for why they’re foundational. Design patterns are a shared vocabulary that lets you read a codebase’s architectural intent from the names alone, and the value of that shared language transcends any specific programming language.

July 20, 2026 · 14 min · Omar Crosby

Hexagonal architecture, in plain language

A jargon-free introduction to hexagonal architecture — the idea that your business logic should sit in the middle and the outside world (databases, screens, APIs, tests) should plug into it through simple, agreed-upon shapes. Small worked examples in Python, Go, and Rust show what changes when a new requirement arrives.

July 20, 2026 · 16 min · Omar Crosby

Web feeds: RSS, Atom, JSON Feed, and OPML

A working tour of the web-feed ecosystem — the RSS 2.0 lineage, IETF Atom (RFC 4287), JSON Feed 1.1, and OPML for exchanging subscription lists between readers — with practical guidance on which format to publish and current recommendations for desktop, mobile, and self-hosted readers.

July 20, 2026 · 14 min · Omar Crosby

Semantic Versioning, Semantic Release, and a Go-native implementation

How Semantic Versioning and Semantic Release fit together — the standard, the automation contract that turns commit history into version tags, and why I re-implemented the Node.js tool in Go to remove the JavaScript toolchain from CI pipelines that don’t otherwise need one.

July 20, 2026 · 12 min · Omar Crosby

Conventional Commits, and the thinking they encourage

A working tour of Conventional Commits — the format, the reason it makes each changeset better before any tool touches it, how to identify good scopes, what the Angular convention adds on top, and where the whole thing fits into the release-automation ecosystem (semantic-release, release-please, cocogitto, git-cliff, commitlint).

July 20, 2026 · 18 min · Omar Crosby

Regular expressions across Unix, Python, Go, and Rust

A tour of regular expressions shallow enough to onboard a beginner and deep enough to refresh an expert — literals, quantifiers, groups, lookaround, and the engine differences between PCRE-family backtrackers and RE2-family linear-time engines that power grep, Python, Go, and Rust.

July 20, 2026 · 21 min · Omar Crosby

Distributing CLI tools with a personal Homebrew tap

How to publish Python, Go, and Rust command-line tools through your own Homebrew tap — including a personal GitHub account, GoReleaser and cargo-dist for platform builds, and go-semantic-release for automatic version bumps that flow all the way through to brew upgrade.

July 20, 2026 · 14 min · Omar Crosby

The pair-programming session that made me write tests first

Years ago, on my first day at a new company, I sat down for what I thought was going to be a normal pair-programming session. There was a story on the board — I no longer remember what it was, exactly. Some feature, a handful of requirements, the usual shape of a first ticket at a new job. I read the requirements, my mind raced ahead to how I’d build it, and I started talking through my approach. ...

July 18, 2026 · 8 min · Omar Crosby

Learning Rust from the C Family

I have spent most of my career in C-family languages — C and C++ for systems work, Go for services, plus enough Java, C#, and JavaScript to be dangerous. Rust is the first language in a long time that made me feel like a beginner again. Not because the syntax is exotic (it isn’t — it looks like a slightly opinionated cousin of C++), but because the rules are different. The compiler asks questions I had been avoiding for twenty years, and it refuses to build until I answer them. ...

July 18, 2026 · 20 min · Omar Crosby

Go concurrency, explained slowly

If you have read three articles on Go concurrency and closed each one more confused than when you started, this post is for you. Most writing on the subject moves too fast — it uses the word “channel” as if you already know what one is, drops phrases like “fan-out fan-in” as if they refer to well-known landmarks, and expects you to bring your own mental model of how goroutines relate to threads. This post makes the opposite bet. It starts from zero, defines each term the moment it appears, keeps the code samples small enough to hold in your head, and — this part matters — puts the primitives (the building blocks) and the best practices (the rules of thumb) in separate sections so you never have to guess which one you are looking at. ...

July 18, 2026 · 25 min · Omar Crosby

Five structural decisions that shape a Neovim plugin's future

A pattern shows up when a plugin author reopens their own plugin a year after last touching it. Half the design choices in the code they wrote themselves are now inscrutable. Why does setup() bail early when called twice? Why is the autocmd group named the way it is? Why does the picker call path have a pcall wrapped around it and a vim.ui.select fallback beneath? The uncomfortable answer, most of the time, is that those choices weren’t really decisions when they were made. They were the shape the code happened to take when a specific problem forced it. Five of these shapes recur in every plugin worth shipping, and each one has a recommended default that becomes obvious only in retrospect. Make them consciously in the first hour of work and the plugin absorbs future features without contortion. Skip them, and you’ll rediscover them in a year — usually as a rewrite. ...

July 18, 2026 · 10 min · Omar Crosby

The Neovim plugin directory structure that scales

A pattern shows up in almost every first attempt at a real plugin. The author has read the source of a plugin they respect, sees its lua/ directory with eight submodules, a types.lua, a health.lua, an after/ftplugin/ file, and a full vimdoc under doc/. So they scaffold their own new plugin with the same shape on day one — a config.lua that reads no config, a types.lua with no types, an init.lua that just re-exports what the other files export. Two weeks later they can’t add a feature without also picking which of the empty scaffolding files it belongs in, and each choice feels arbitrary because there’s no pressure yet to justify it. ...

July 18, 2026 · 11 min · Omar Crosby

How Neovim actually loads a plugin

A pattern shows up in the way most people first install a Neovim plugin. They add a line to their plugin manager’s config — a URL, maybe a version pin — restart Neovim, and the plugin’s commands, keymaps, and behaviors just appear. The install feels like a black box: you handed the manager a name, the manager did something, the plugin exists. The black box is smaller than it looks. Underneath every plugin manager is Neovim’s own built-in plugin discovery, and it’s mechanical, deterministic, and short enough to explain in a single post. Once you know what fires when, the directory structure of any plugin — including one you write yourself — stops looking like a convention someone made up and starts looking like a straightforward consequence of Neovim’s rules. ...

July 18, 2026 · 9 min · Omar Crosby

Your first Neovim plugin

A pattern shows up in almost every Neovim user I talk to who has been using the editor for a year or two. They have their config version-controlled. They know their leader mappings by feel. They can name ten plugins they rely on daily. And they’ve been meaning to write one of their own for months. The gap between using a plugin and writing one feels larger than it actually is. Not because the work is hard, but because nothing in the getting-started path makes the shape of a plugin obvious. Every tutorial jumps to configuration DSLs, package managers, or a distribution’s opinion about layout. The mechanics underneath all of that — how Neovim actually finds and loads your code — stay invisible right up until you try to write a plugin, at which point they become the whole problem. ...

July 18, 2026 · 8 min · Omar Crosby

lexicon: a shared language for requirements that compiles to Gherkin and Gauge

A previous post argued that Dev, QA, and Product read the same requirement differently not because anyone is careless, but because prose leaves three things implicit — the precondition, the action, and the outcome — and that a structured format forces those three things into the open. It also argued that the specific tool doesn’t matter much: Gherkin’s Given/When/Then is one well-known way to get the structure, not the only one, and a team is free to define its own. ...

July 16, 2026 · 12 min · Omar Crosby

Why dev, QA, and product read the same requirement differently

A pattern shows up on almost every team I’ve worked with, regardless of how disciplined the process otherwise is: Dev, QA, and Product each walk away from the same requirement holding a slightly different picture of what’s being built. It rarely surfaces at the moment the requirement is written. It surfaces later, and by then it’s expensive — a bug report that turns out to be a misunderstanding, a scope argument in the middle of a sprint, a story that stalls because QA and Dev quietly disagreed about what “done” meant and neither noticed until the story was in review. ...

July 16, 2026 · 6 min · Omar Crosby

Getting started with Neovim

A practical starter track: install Neovim, put your config in a GitHub repo you own, and layer on a small set of plugins that turn the empty editor into something you’ll want to keep using.

July 13, 2026 · 13 min · Omar Crosby

Why I love Neovim

The case for Neovim from someone who spent thirty-plus years on vi and years on JetBrains before finally trying it — not because either was broken, but because Neovim’s customizability makes your editor a Personal Development Environment in a way IDEs can’t match. With concrete examples from the yoda.nvim distribution.

July 12, 2026 · 10 min · Omar Crosby

How the NCAA women's soccer RPI actually works — and why teams pick their opponents carefully

A plain-English walkthrough of the Rating Percentage Index — the three components, the strength-of-schedule feedback loops, why the formula shapes non-conference scheduling decisions across the sport, and why recomputing it is genuinely expensive.

July 11, 2026 · 14 min · Omar Crosby

Keeping a YouTube iframe playing across every page with Turbo Frames

I wanted the music player on my /music/ page to keep playing when a visitor clicks around the rest of the site. No stop, no restart, no auto-mute — just seamless continuous playback while the DOM around it swaps. The obvious approach — the one every blog post about Turbo tells you to use — didn’t work. The one that actually worked took me through three false starts. If you’re building a Hugo (or Jekyll, or Rails) site and you want an audio or video iframe that survives site-wide navigation, this post is what I wish I’d found on day one. ...

July 10, 2026 · 9 min · Omar Crosby

Static analysis for Go: what golangci-lint catches, and why it belongs in CI

Code review catches the bugs a human happens to notice. Static analysis catches the bugs a specific, well-defined check is built to notice — every time, on every line, before anyone opens the diff. Those are different guarantees, and the difference matters most for the bug classes reviewers are worst at: an HTTP response body that never gets closed three call sites deep, an error return silently discarded in a one-line change, a security-sensitive value generated with the wrong random source. None of these look wrong at a glance. All of them are mechanically detectable. ...

July 9, 2026 · 21 min · Omar Crosby

Testing Go with Ginkgo and Gomega without giving up go test

If you’ve never looked at Ginkgo and Gomega, there’s a decent chance you’re picturing something that replaces go test — a separate test runner, a separate CI step, another tool your team has to adopt wholesale before anyone sees a benefit. That picture is wrong, and it’s worth correcting up front, because it’s the single biggest reason Go developers who’d genuinely enjoy Ginkgo never try it. Here’s the fact that should change your mind: a Ginkgo spec is a Go test. It compiles into the same test binary, it runs when you type go test ./..., and your existing CI pipeline doesn’t need to know Ginkgo exists. What Ginkgo adds is a richer vocabulary for organizing specs — nested Describe/Context/It blocks instead of a flat list of Test* functions — plus first-class suite lifecycle (BeforeSuite/AfterSuite), table-driven specs, async timeouts, and labels for slicing a suite into subsets. Gomega adds the assertion language (Expect(x).To(Equal(y))) that makes failures read like a sentence instead of a %v != %v diff. ...

July 9, 2026 · 12 min · Omar Crosby

How writing tests first changes the shape of Go code

Most of the debate around test-first development gets stuck on process — red-green-refactor, coverage percentages, whether it slows you down on day one. That debate misses a simpler, more concrete effect, and you don’t need to know Go, or even know how to code, to follow it: Whichever thing you write second has to bend to fit whatever you wrote first. Write the code first and the test second, and the test has no choice but to accommodate whatever the code already does — however it talks to the database, however it calls the network, however it happens to be built. Write the test first, and it’s the code’s turn to bend: it has to be built in whatever shape lets the test — which doesn’t have a real database or a real network sitting around — actually run. That’s the entire mechanism. Nothing about willpower, experience, or caring more. Just: which one existed first gets to set the terms. ...

July 9, 2026 · 13 min · Omar Crosby

Keeping the daily standup from becoming a status meeting

Some teams have quietly turned the daily standup into a status report — going around the room instead of walking the board, and asking for updates from people who aren’t touching a single story that sprint. Here’s what the Agile literature actually says a standup is for, and a few small structural fixes.

July 7, 2026 · 5 min · Omar Crosby

kyber: function-level code quality analysis for Go

Existing Go linters tell you which lines break a rule. kyber tells you which functions carry the most risk, using twelve metrics — McCabe, cognitive, Halstead, maintainability index, and structural signals — in one pipeline.

July 5, 2026 · 8 min · Omar Crosby

neospec: a self-contained test runner and coverage tool for Neovim plugins

One Go binary that manages its own Neovim, runs Lua tests inside the real editor, and emits LCOV/Cobertura/JUnit — no system install, no vendored framework, no shell-script gymnastics.

July 5, 2026 · 6 min · Omar Crosby

Bridging Tradovate, Bookmap, and Thinkorswim to Claude with MCP

market-bridge is an MCP server that gives Claude direct access to real-time /ES futures data from the three platforms I trade on. No CSV exports, no context-switching.

July 4, 2026 · 3 min · Omar Crosby

Building MCP servers for NWSL and ECNL soccer data

jk-mcp-nwsl and jk-mcp-ecnl give Claude direct access to live league data — standings, rosters, RPI, results — from three different upstreams stitched into a coherent tool surface.

July 4, 2026 · 7 min · Omar Crosby

Holocron: a Go-native distributed log with NATS JetStream ergonomics and Kafka semantics

Holocron is a single-binary Go distributed log broker. JetStream’s operational simplicity plus the per-partition ordering and Kafka-shaped log model JetStream lacks.

July 4, 2026 · 4 min · Omar Crosby

nasm-lint: static analysis for NASM x86 in three shapes

One Rust-written analyzer for NASM assembly, delivered as a CLI, an LSP for editor diagnostics, and a GitHub Action that emits SARIF for GitHub code scanning.

July 4, 2026 · 3 min · Omar Crosby

Reading intraday SPX bias: turning market signals into credit-spread trades

strike-pilot is a Python engine that reads intraday SPX signals, scores its own confidence, and produces a concrete credit-spread recommendation — or explicitly refuses to trade.

July 4, 2026 · 4 min · Omar Crosby

Writing semantic-release in Go, with real monorepo support

go-semantic-release is a Go-native re-implementation of the semantic-release contract, with four monorepo discovery modes and a CLI surface compatible with the JS original. It’s what publishes this site.

July 4, 2026 · 4 min · Omar Crosby

Yoda: what I learned making a Neovim distribution modular

yoda.nvim is a Neovim distribution built from a family of independently useful plugins — yoda-core, yoda-window, yoda-logging, yoda-diagnostics, yoda-terminal, and adapters. Modularity was the design goal, not a refactor after the fact.

July 4, 2026 · 3 min · Omar Crosby