<?xml version="1.0" encoding="UTF-8" ?> <?xml-stylesheet type="text/xsl" href="rss.xsl"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/"> <channel> <title>Hypertext Dispatches</title><description>Hypertext Dispatches by Ryan Johnson</description><link>https://tenthirtyam.org/</link><atom:link href="https://tenthirtyam.org/rss.xml" rel="self" type="application/rss+xml" /> <managingEditor>Ryan Johnson</managingEditor><language>en</language> <pubDate>Sun, 19 Apr 2026 04:06:17 -0000</pubDate> <lastBuildDate>Sun, 19 Apr 2026 04:06:17 -0000</lastBuildDate> <ttl>1440</ttl> <generator>MkDocs RSS plugin - v1.19.0</generator> <image> <url>None</url> <title>Hypertext Dispatches</title> <link>https://tenthirtyam.org/</link> </image> <item> <title>I&#39;m Just a River</title> <author>Ryan Johnson</author> <category>Americana</category> <category>Country</category> <category>Music</category> <category>Songwriting</category> <category>Songwriting</category> <category>Southern Gothic</category> <description>&lt;h1&gt;I&#39;m Just a River&lt;/h1&gt; &lt;iframe width=&#34;100%&#34; height=&#34;166&#34; scrolling=&#34;no&#34; frameborder=&#34;no&#34; allow=&#34;autoplay&#34; src=&#34;https://w.soundcloud.com/player/?url=https%3A//api.soundcloud.com/tracks/soundcloud%3Atracks%3A2304485240%3Fsecret_token%3Ds-2G7qKx6TSGC&amp;color=%23ff5500&amp;auto_play=false&amp;hide_related=true&amp;show_comments=false&amp;show_user=true&amp;show_reposts=false&amp;show_teaser=true&#34;&gt;&lt;/iframe&gt; &lt;div style=&#34;font-size: 10px; color: #cccccc;line-break: anywhere;word-break: normal;overflow: hidden;white-space: nowrap;text-overflow: ellipsis; font-family: Interstate,Lucida Grande,Lucida Sans Unicode,Lucida Sans,Garuda,Verdana,Tahoma,sans-serif;font-weight: 100;&#34;&gt;&lt;a href=&#34;https://soundcloud.com/39north&#34; title=&#34;39 North&#34; target=&#34;_blank&#34; style=&#34;color: #cccccc; text-decoration: none;&#34;&gt;39 North&lt;/a&gt; · &lt;a href=&#34;https://soundcloud.com/39north/im-just-a-river/s-2G7qKx6TSGC&#34; title=&#34;I&amp;#x27;m Just a River&#34; target=&#34;_blank&#34; style=&#34;color: #cccccc; text-decoration: none;&#34;&gt;I&amp;#x27;m Just a River&lt;/a&gt;&lt;/div&gt; &lt;p&gt;!!! heart &#34;In Loving Memory&#34; Written to process the death of my nephew.&lt;br&gt; Rest in Peace, Phin. &lt;/p&gt; &lt;pre&gt;&lt;code&gt;Phineas Harvey Alexander Tillman June 4, 2001–January 11, 2026 &lt;/code&gt;&lt;/pre&gt; &lt;p&gt;!!! copyright &#34;Copyright&#34; &lt;strong&gt;Lyrics&lt;/strong&gt;: &amp;copy; 2026 J. Ryan Johnson. All rights reserved.&lt;/p&gt; &lt;p&gt;--8&amp;lt;-- &#34;./snippets/ai-recording-disclaimer.md&#34;&lt;/p&gt;</description> <link>https://tenthirtyam.org/dispatches/2026/04/19/im-just-a-river/</link> <pubDate>Sun, 19 Apr 2026 00:00:00 +0000</pubDate> <source url="https://tenthirtyam.org/rss.xml">Hypertext Dispatches</source><guid isPermaLink="true">https://tenthirtyam.org/dispatches/2026/04/19/im-just-a-river/</guid> </item> <item> <title>A Deep Dive into golangci-lint</title> <author>Ryan Johnson</author> <category>Developer Experience</category> <category>Developer Tools</category> <category>Developer Workflow</category> <category>Go</category> <category>Open Source</category> <category>Static Analysis</category> <category>Technology</category> <category>golangci-lint</category> <description>&lt;p&gt;&lt;a href=&#34;https://golangci-lint.run&#34;&gt;&lt;code&gt;golangci-lint&lt;/code&gt;&lt;/a&gt; is one of the highest-leverage tools in the Go ecosystem because it turns a loose collection of static analysis tools into a single, fast, repeatable code-quality gate. Used well, it catches real bugs, reduces review noise, and helps maintainers keep a project consistent without turning style preferences into endless pull request commentary.&lt;/p&gt; &lt;p&gt;For many Go teams, the mistake is not adopting &lt;code&gt;golangci-lint&lt;/code&gt;. The mistake is adopting it without a strategy. Enabling too many linters at once, tolerating unexplained &lt;code&gt;//nolint&lt;/code&gt; comments, or treating the default output as a substitute for judgment quickly turns a useful signal into background noise.&lt;/p&gt; &lt;p&gt;This post walks through how &lt;code&gt;golangci-lint&lt;/code&gt; works, how I think about configuring it for a real project, and how to run it in ways that are practical for both day-to-day development and long-term open source maintenance.&lt;/p&gt; &lt;p&gt;Much of what I know about &lt;code&gt;golangci-lint&lt;/code&gt; was learned the unglamorous way: maintaining Go-based open source projects where lint output has to hold up in front of contributors, CI systems, release processes, and real users. That includes work across HashiCorp Terraform providers, HashiCorp Packer plugins, and Go SDKs.&lt;/p&gt; &lt;p&gt;If you want the broader project list behind that perspective, see the &lt;a href=&#34;../resume/index.md#open-source-projects&#34;&gt;Open Source Projects section of my resume&lt;/a&gt;.&lt;/p&gt; &lt;p&gt;That context matters because this is not an abstract &lt;em&gt;&#34;here are the docs&#34;&lt;/em&gt; walkthrough. It is an opinionated maintainer&#39;s view of what actually keeps linting useful in a long-lived Go codebase.&lt;/p&gt;</description> <link>https://tenthirtyam.org/dispatches/2026/04/18/a-deep-dive-into-golangci-lint/</link> <pubDate>Sat, 18 Apr 2026 00:00:00 +0000</pubDate> <source url="https://tenthirtyam.org/rss.xml">Hypertext Dispatches</source><guid isPermaLink="true">https://tenthirtyam.org/dispatches/2026/04/18/a-deep-dive-into-golangci-lint/</guid> </item> <item> <title>What the Record Shows</title> <author>Ryan Johnson</author> <category>Imposter Syndrome</category> <category>Personal</category> <category>Personal</category> <category>Work</category> <category>Writing</category> <description>&lt;p&gt;&lt;img alt=&#34;Imposter Syndrome&#34; src=&#34;../images/post-imposter-syndrome.png&#34;&gt;{ style=&#34;display: block; margin: 0 auto;&#34; .skip-lightbox }&lt;/p&gt; &lt;p&gt;!!! note &#34;&#34; &lt;em&gt;Image Source: InnerSloth&lt;/em&gt;&lt;/p&gt; &lt;p&gt;There is a kind of performance that no longer feels like performance because you have been doing it so long that it has settled into your bones.&lt;/p&gt; &lt;p&gt;Each morning arrives with its own familiar ritual: the steady voice, the practiced calm, the expression that says, &lt;em&gt;&#34;I belong here.&#34;&lt;/em&gt; After enough years, it becomes automatic. People hear you speak, ask for your judgment, trust what you have to say. Your name appears on work that matters.&lt;/p&gt; &lt;p&gt;From the outside, it can look like certainty.&lt;/p&gt; &lt;p&gt;But beneath all of that, there can still be a quieter voice saying something else entirely:&lt;/p&gt; &lt;p&gt;!!! quote &#34;&#34; &lt;em&gt;&#34;Today will be the day they figure out I don&#39;t belong here after all.&#34;&lt;/em&gt;&lt;/p&gt; &lt;p&gt;It has a name, of course: &lt;em&gt;&lt;strong&gt;Imposter Syndrome&lt;/strong&gt;&lt;/em&gt;. That old habit of treating your own record like disputed evidence.&lt;/p&gt; &lt;p&gt;That voice is stubborn. It doesn&#39;t yield easily to experience, praise, or proof. It survives accomplishment with an almost insulting ease. It can sit in the same room with a long career, meaningful work, and the respect of other people, and remain completely unimpressed.&lt;/p&gt; &lt;p&gt;I&#39;ve spent most of my professional life inside the orbit of very large institutions, places whose names carry their own kind of weather.&lt;/p&gt; &lt;p&gt;On paper, my record isn&#39;t especially mysterious. I&#39;ve held serious roles. I&#39;ve contributed to products and open source projects people actually use. I&#39;ve written extensive designs and documentation that helped people do their jobs. I&#39;ve even written a book. I&#39;ve earned certifications and accreditations, sometimes less out of ambition than out of a private need to quiet the voice that keeps insisting I&#39;ve not done enough. I&#39;ve stood in rooms where others came to listen, and I&#39;ve spoken at more technology conferences than I could name without stopping to count, somehow managing not to waste their time.&lt;/p&gt;</description> <link>https://tenthirtyam.org/dispatches/2026/04/17/what-the-record-shows/</link> <pubDate>Fri, 17 Apr 2026 00:00:01 +0000</pubDate> <source url="https://tenthirtyam.org/rss.xml">Hypertext Dispatches</source><guid isPermaLink="true">https://tenthirtyam.org/dispatches/2026/04/17/what-the-record-shows/</guid> </item> <item> <title>Automating Releases with GoReleaser</title> <author>Ryan Johnson</author> <category>Docker</category> <category>GitHub Actions</category> <category>Go</category> <category>GoReleaser</category> <category>Homebrew</category> <category>Open Source</category> <category>Release Engineering</category> <category>Supply Chain Security</category> <category>Technology</category> <description>&lt;p&gt;&lt;img alt=&#34;GoReleaser&#34; src=&#34;../images/post-goreleaser.png&#34;&gt;{ align=right width=225 .skip-lightbox }&lt;/p&gt; &lt;p&gt;Shipping a polished release for a software project by hand gets old fast: building for multiple platforms, packaging archives, generating checksums, publishing GitHub releases, cutting container images, and updating a Homebrew tap is exactly the kind of repetitive work that should not depend on memory or heroics.&lt;/p&gt; &lt;p&gt;&lt;a href=&#34;https://goreleaser.com&#34;&gt;GoReleaser&lt;/a&gt; turns that whole workflow into a repeatable release pipeline that scales from your first CLI to a heavily used open source project.&lt;/p&gt; &lt;p&gt;!!! tip &#34;Not Just for Go-based Project Releases&#34; Despite the name, GoReleaser supports releasing for Go, Python, Rust, Zig, and TypeScript based projects.&lt;/p&gt; &lt;p&gt;Manual releases often seem manageable at first, then turn into a mess the moment users ask for macOS support, ARM builds, checksums, containers, or a one-line &lt;code&gt;brew install&lt;/code&gt; experience. Maintainers end up writing ad hoc shell scripts, copying files into GitHub Releases by hand, and hoping the version embedded in the binary matches the git tag they just pushed.&lt;/p&gt; &lt;p&gt;GoReleaser solves that by treating release engineering as configuration. You describe what to build, package, sign, and publish, then let one command, or one CI job, do the same thing every time. It handles the boring parts well enough that you get to focus on your project instead of your release checklist.&lt;/p&gt;</description> <link>https://tenthirtyam.org/dispatches/2026/04/17/automating-releases-with-goreleaser/</link> <pubDate>Fri, 17 Apr 2026 00:00:00 +0000</pubDate> <source url="https://tenthirtyam.org/rss.xml">Hypertext Dispatches</source><guid isPermaLink="true">https://tenthirtyam.org/dispatches/2026/04/17/automating-releases-with-goreleaser/</guid> </item> <item> <title>How to Create Terminal Demos as Code with VHS by Charm</title> <author>Ryan Johnson</author> <category>Automation</category> <category>Developer Workflow</category> <category>Documentation</category> <category>Go</category> <category>Open Source</category> <category>Technology</category> <category>Terminal</category> <description>&lt;p&gt;&lt;img alt=&#34;VHS&#34; src=&#34;../images/post-vhs-logo-dark.png&#34;&gt;{ align=right width=225 .skip-lightbox }&lt;/p&gt; &lt;p&gt;Manual terminal recordings tend to age badly. The timing is inconsistent, the cursor jumps, the window size changes between takes, and the one command you needed to correct means starting over. If you have ever tried to capture a polished CLI walkthrough for a README, release note, or docs site, you have probably spent more time re-recording than documenting.&lt;/p&gt; &lt;p&gt;&lt;a href=&#34;https://github.com/charmbracelet/vhs&#34;&gt;VHS&lt;/a&gt; from &lt;a href=&#34;https://charm.land&#34;&gt;Charm&lt;/a&gt; (&lt;em&gt;a.k.a.&lt;/em&gt;, Charmbracelet) fixes that by turning terminal demos into source code. Instead of screen recording your desktop, you write a small &lt;code&gt;.tape&lt;/code&gt; file that describes the terminal session: window size, theme, typing speed, commands, pauses, screenshots, and output format. Then VHS renders the result into a GIF, MP4, WebM, or even a directory of raw frames.&lt;/p&gt; &lt;p&gt;There are two hard parts in terminal documentation:&lt;/p&gt; &lt;ol&gt; &lt;li&gt;Capturing a terminal session that looks clean and readable.&lt;/li&gt; &lt;li&gt;Keeping that session reproducible as the tool, docs, and CLI output evolve.&lt;/li&gt; &lt;/ol&gt; &lt;p&gt;Traditional recording tools help with the first part, but not the second. A hand-recorded GIF is an artifact, not a build input. Once it drifts from reality, you either live with stale docs or record it all over again.&lt;/p&gt; &lt;p&gt;VHS treats terminal demos the same way we treat infrastructure, tests, and CI workflows: as code.&lt;/p&gt;</description> <link>https://tenthirtyam.org/dispatches/2026/04/16/how-to-create-terminal-demos-as-code-with-vhs-by-charm/</link> <pubDate>Thu, 16 Apr 2026 00:00:01 +0000</pubDate> <source url="https://tenthirtyam.org/rss.xml">Hypertext Dispatches</source><guid isPermaLink="true">https://tenthirtyam.org/dispatches/2026/04/16/how-to-create-terminal-demos-as-code-with-vhs-by-charm/</guid> </item> <item> <title>Git Submodules Deep Dive for Platform Engineering</title> <author>Ryan Johnson</author> <category>CI/CD</category> <category>DevOps</category> <category>Developer Experience</category> <category>Developer Workflow</category> <category>Git</category> <category>GitHub</category> <category>GitLab</category> <category>Infrastructure-as-Code</category> <category>Platform Engineering</category> <category>Technology</category> <description>&lt;p&gt;Platform engineering teams face a recurring challenge: shared code. You have a library of Terraform modules that ten product teams consume, a set of Ansible roles that every configuration management pipeline needs, or a collection of CI/CD workflow templates that must stay consistent across dozens of repositories. The naive solution is to copy files between repositories, but then every fix requires propagating changes to every consumer by hand. Git submodules offer a structured alternative: embed one Git repository inside another as a tracked dependency with an explicit, auditable version reference.&lt;/p&gt; &lt;p&gt;This post covers how submodules work at the Git level, how to add and consume them, the day-to-day operations that platform engineers and DevOps practitioners need to know, CI/CD automation with GitHub Actions, and the common pitfalls that cause teams to abandon submodules prematurely.&lt;/p&gt; &lt;p&gt;&lt;img alt=&#34;Git submodules mental model: the parent repository stores a gitlink commit pointer, not the submodule&#39;s files.&#34; src=&#34;../images/post-git-submodules-dark.svg#only-dark&#34;&gt;{ align=center .skip-lightbox } &lt;img alt=&#34;Git submodules mental model: the parent repository stores a gitlink commit pointer, not the submodule&#39;s files.&#34; src=&#34;../images/post-git-submodules.svg#only-light&#34;&gt;{ align=center .skip-lightbox }&lt;/p&gt;</description> <link>https://tenthirtyam.org/dispatches/2026/04/16/git-submodules-deep-dive-for-platform-engineering/</link> <pubDate>Thu, 16 Apr 2026 00:00:00 +0000</pubDate> <source url="https://tenthirtyam.org/rss.xml">Hypertext Dispatches</source><guid isPermaLink="true">https://tenthirtyam.org/dispatches/2026/04/16/git-submodules-deep-dive-for-platform-engineering/</guid> </item> <item> <title>Lost in Shades of I&#39;m Okay</title> <author>Ryan Johnson</author> <category>Personal</category> <category>Personal</category> <category>Writing</category> <description>&lt;h1&gt;Lost in Shades of &lt;em&gt;&#34;I&#39;m Okay&#34;&lt;/em&gt;&lt;/h1&gt; &lt;p&gt;&lt;img alt=&#34;&#34; src=&#34;../images/post-the-hard-days.png&#34;&gt;{ align=center .skip-lightbox }&lt;/p&gt; &lt;p&gt;!!! note &#34;&#34;&lt;/p&gt; &lt;pre&gt;&lt;code&gt;This piece contains discussion of depression and hopelessness. Please read with care. &lt;/code&gt;&lt;/pre&gt; &lt;p&gt;There is a particular meanness to depression.&lt;/p&gt; &lt;p&gt;It doesn&#39;t always arrive like a storm. More often it comes like summer heat: slow, saturating, difficult to argue with. It settles into the walls, into the body, into the space between one thought and the next, until everything feels heavy with it. The house seems to take it in. Even the light looks tired by the time it reaches the room.&lt;/p&gt; &lt;p&gt;I have known days when the floor felt like the safest place to keep my eyes. Old wood, scarred and splitting, honest in its damage. Floorboards don&#39;t ask anything of you. They don&#39;t expect performance. They don&#39;t require you to explain why lifting your head feels like lifting stone. Looking down became a kind of prayer then, if prayer can be made out of exhaustion. I studied every crooked crack as if it might tell me how to stay in one piece. Lost in shades of &lt;em&gt;&#34;I&#39;m okay.&#34;&lt;/em&gt;&lt;/p&gt;</description> <link>https://tenthirtyam.org/dispatches/2026/04/15/lost-in-shades-of-im-okay/</link> <pubDate>Wed, 15 Apr 2026 00:00:00 +0000</pubDate> <source url="https://tenthirtyam.org/rss.xml">Hypertext Dispatches</source><guid isPermaLink="true">https://tenthirtyam.org/dispatches/2026/04/15/lost-in-shades-of-im-okay/</guid> </item> <item> <title>Shadow of the Cloud</title> <author>Ryan Johnson</author> <category>Americana</category> <category>Country</category> <category>Music</category> <category>Songwriting</category> <category>Songwriting</category> <category>Southern Gothic</category> <description>&lt;h1&gt;Shadow of the Cloud&lt;/h1&gt; &lt;iframe width=&#34;100%&#34; height=&#34;166&#34; scrolling=&#34;no&#34; frameborder=&#34;no&#34; allow=&#34;autoplay&#34; src=&#34;https://w.soundcloud.com/player/?url=https%3A//api.soundcloud.com/tracks/soundcloud%3Atracks%3A2299686026%3Fsecret_token%3Ds-jSXMGkQkVFo&amp;color=%23ff5500&amp;auto_play=false&amp;hide_related=true&amp;show_comments=false&amp;show_user=true&amp;show_reposts=false&amp;show_teaser=false&#34;&gt;&lt;/iframe&gt; &lt;div style=&#34;font-size: 10px; color: #cccccc;line-break: anywhere;word-break: normal;overflow: hidden;white-space: nowrap;text-overflow: ellipsis; font-family: Interstate,Lucida Grande,Lucida Sans Unicode,Lucida Sans,Garuda,Verdana,Tahoma,sans-serif;font-weight: 100;&#34;&gt;&lt;a href=&#34;https://soundcloud.com/39north&#34; title=&#34;39 North&#34; target=&#34;_blank&#34; style=&#34;color: #cccccc; text-decoration: none;&#34;&gt;39 North&lt;/a&gt; · &lt;a href=&#34;https://soundcloud.com/39north/shadow-of-the-cloud/s-jSXMGkQkVFo&#34; title=&#34;Shadow of the Cloud&#34; target=&#34;_blank&#34; style=&#34;color: #cccccc; text-decoration: none;&#34;&gt;Shadow of the Cloud&lt;/a&gt;&lt;/div&gt; &lt;p&gt;!!! copyright &#34;Copyright&#34; &lt;strong&gt;Lyrics&lt;/strong&gt;: &amp;copy; 2025 J. Ryan Johnson. All rights reserved.&lt;/p&gt; &lt;p&gt;--8&amp;lt;-- &#34;./snippets/ai-recording-disclaimer.md&#34;&lt;/p&gt;</description> <link>https://tenthirtyam.org/dispatches/2026/04/14/shadow-of-the-cloud/</link> <pubDate>Tue, 14 Apr 2026 00:00:02 +0000</pubDate> <source url="https://tenthirtyam.org/rss.xml">Hypertext Dispatches</source><guid isPermaLink="true">https://tenthirtyam.org/dispatches/2026/04/14/shadow-of-the-cloud/</guid> </item> <item> <title>Oh My Zsh on macOS: A Reference for a Clean, Maintainable Shell</title> <author>Ryan Johnson</author> <category>Developer Experience</category> <category>Developer Workflow</category> <category>Oh My Zsh</category> <category>Open Source</category> <category>Technology</category> <category>Terminal</category> <category>Zsh</category> <category>macOS</category> <description>&lt;p&gt;!!! example &#34;&#34;&lt;/p&gt; &lt;pre&gt;&lt;code&gt;```shell % omz version __ __ ____ / /_ ____ ___ __ __ ____ _____/ /_ / __ \/ __ \ / __ `__ \/ / / / /_ / / ___/ __ \ / /_/ / / / / / / / / / / /_/ / / /_(__ ) / / / \____/_/ /_/ /_/ /_/ /_/\__, / /___/____/_/ /_/ /____/ master (061f773) ``` &lt;/code&gt;&lt;/pre&gt; &lt;p&gt;If you spend a large part of your day in a terminal, your shell stops being just a shell and starts becoming part of your development environment. On my Mac, that environment is built around Zsh, &lt;a href=&#34;https://ohmyz.sh&#34;&gt;Oh My Zsh&lt;/a&gt;, the &lt;a href=&#34;https://spaceship-prompt.sh&#34;&gt;Spaceship prompt&lt;/a&gt;, and a small set of plugins that improve the things I do constantly: Git, GitHub, containers, Kubernetes, Terraform, Python, Go, and Ansible. The result is not flashy for the sake of being flashy. It is a shell that surfaces useful context quickly, stays out of the way when I am focused, and is still simple enough to maintain without turning &lt;code&gt;~/.zshrc&lt;/code&gt; into a junk drawer.&lt;/p&gt;</description> <link>https://tenthirtyam.org/dispatches/2026/04/14/oh-my-zsh-on-macos-a-reference-for-a-clean-maintainable-shell/</link> <pubDate>Tue, 14 Apr 2026 00:00:01 +0000</pubDate> <source url="https://tenthirtyam.org/rss.xml">Hypertext Dispatches</source><guid isPermaLink="true">https://tenthirtyam.org/dispatches/2026/04/14/oh-my-zsh-on-macos-a-reference-for-a-clean-maintainable-shell/</guid> </item> <item> <title>Automate Locking Closed Issues and Pull Requests on GitHub</title> <author>Ryan Johnson</author> <category>Developer Experience</category> <category>Developer Workflow</category> <category>GitHub</category> <category>GitHub Actions</category> <category>Open Source</category> <category>Technology</category> <description>&lt;h1&gt;Automate Locking Closed Issues and Pull Requests on GitHub&lt;/h1&gt; &lt;p&gt;Locking a closed thread prevents new comments from being added. It keeps old threads quiet and lets maintainers direct their attention toward work that is still active. This post covers two approaches: a shell script using the GitHub CLI for one-time or ad hoc locking across one or more repositories, and a GitHub Actions workflow using &lt;a href=&#34;https://github.com/dessant/lock-threads&#34;&gt;&lt;code&gt;dessant/lock-threads&lt;/code&gt;&lt;/a&gt; for ongoing automation.&lt;/p&gt;</description> <link>https://tenthirtyam.org/dispatches/2026/04/14/automate-locking-closed-issues-and-pull-requests-on-github/</link> <pubDate>Tue, 14 Apr 2026 00:00:00 +0000</pubDate> <source url="https://tenthirtyam.org/rss.xml">Hypertext Dispatches</source><guid isPermaLink="true">https://tenthirtyam.org/dispatches/2026/04/14/automate-locking-closed-issues-and-pull-requests-on-github/</guid> </item> <item> <title>Managing Stale Issues and Pull Requests with GitHub Actions</title> <author>Ryan Johnson</author> <category>Developer Experience</category> <category>Developer Workflow</category> <category>GitHub</category> <category>GitHub Actions</category> <category>Open Source</category> <category>Technology</category> <description>&lt;h1&gt;Managing Stale Issues and Pull Requests with GitHub Actions&lt;/h1&gt; &lt;p&gt;Every open-source project eventually faces the same problem: issues and pull requests that were once active go quiet. A bug report with no updates in a year. A pull request that was never finished. A feature request that the contributor lost interest in. These threads accumulate over time, and before long a repository&#39;s issue tracker becomes a graveyard of items that no one knows are still relevant.&lt;/p&gt; &lt;p&gt;The &lt;a href=&#34;https://github.com/actions/stale&#34;&gt;&lt;code&gt;actions/stale&lt;/code&gt;&lt;/a&gt; GitHub Action gives maintainers a way to address this automatically. It scans issues and pull requests on a schedule, labels anything that has gone too long without activity, warns contributors that it will be closed soon, and closes it if no activity follows. The whole process is configurable and runs without manual intervention.&lt;/p&gt; &lt;p&gt;This post covers what the action does, how to configure it, a real-world example from one of my own projects, and an honest look at the tradeoffs so you can decide whether it makes sense for yours.&lt;/p&gt;</description> <link>https://tenthirtyam.org/dispatches/2026/04/13/managing-stale-issues-and-pull-requests-with-github-actions/</link> <pubDate>Mon, 13 Apr 2026 00:00:00 +0000</pubDate> <source url="https://tenthirtyam.org/rss.xml">Hypertext Dispatches</source><guid isPermaLink="true">https://tenthirtyam.org/dispatches/2026/04/13/managing-stale-issues-and-pull-requests-with-github-actions/</guid> </item> <item> <title>Ignoring Files in Git with `.gitignore`</title> <author>Ryan Johnson</author> <category>Developer Experience</category> <category>Developer Workflow</category> <category>Git</category> <category>GitHub</category> <category>GitLab</category> <category>Open Source</category> <category>Technology</category> <description>&lt;h1&gt;Ignoring Files in Git with &lt;code&gt;.gitignore&lt;/code&gt;&lt;/h1&gt; &lt;p&gt;Every Git repository accumulates files that should never be committed: compiled binaries, dependency directories, editor configuration, operating system metadata, and local environment files that contain secrets. Without a mechanism to exclude them, every &lt;code&gt;git status&lt;/code&gt; output and &lt;code&gt;git add .&lt;/code&gt; command becomes a manual filtering exercise. The &lt;code&gt;.gitignore&lt;/code&gt; file is Git&#39;s built-in solution to that problem, and understanding how it works end to end, including its pattern syntax, scope model, and debugging tools, eliminates a class of frustration that affects developers at every experience level.&lt;/p&gt;</description> <link>https://tenthirtyam.org/dispatches/2026/04/12/ignoring-files-in-git-with-gitignore/</link> <pubDate>Sun, 12 Apr 2026 00:00:00 +0000</pubDate> <source url="https://tenthirtyam.org/rss.xml">Hypertext Dispatches</source><guid isPermaLink="true">https://tenthirtyam.org/dispatches/2026/04/12/ignoring-files-in-git-with-gitignore/</guid> </item> <item> <title>Tracking Empty Directories in Git with `.gitkeep`</title> <author>Ryan Johnson</author> <category>Developer Experience</category> <category>Developer Workflow</category> <category>Git</category> <category>GitHub</category> <category>Open Source</category> <category>Technology</category> <description>&lt;h1&gt;Tracking Empty Directories in Git with &lt;code&gt;.gitkeep&lt;/code&gt;&lt;/h1&gt; &lt;p&gt;Git tracks files, not directories. That distinction is easy to overlook until you run into the consequence: an empty directory you create locally simply does not exist after a fresh clone. No staging, no commit, no push will capture it, because Git has nothing to work with. The &lt;code&gt;.gitkeep&lt;/code&gt; convention is the widely adopted workaround for this behavior, and it requires nothing more than a single empty file placed inside the directory you need to preserve.&lt;/p&gt;</description> <link>https://tenthirtyam.org/dispatches/2026/04/12/tracking-empty-directories-in-git-with-gitkeep/</link> <pubDate>Sun, 12 Apr 2026 00:00:00 +0000</pubDate> <source url="https://tenthirtyam.org/rss.xml">Hypertext Dispatches</source><guid isPermaLink="true">https://tenthirtyam.org/dispatches/2026/04/12/tracking-empty-directories-in-git-with-gitkeep/</guid> </item> <item> <title>Controlling Git Repository Behavior with `.gitattributes`</title> <author>Ryan Johnson</author> <category>Developer Experience</category> <category>Developer Workflow</category> <category>Git</category> <category>GitHub</category> <category>GitLab</category> <category>Open Source</category> <category>Technology</category> <description>&lt;h1&gt;Controlling Git Repository Behavior with &lt;code&gt;.gitattributes&lt;/code&gt;&lt;/h1&gt; &lt;p&gt;A &lt;code&gt;.gitattributes&lt;/code&gt; file lets you assign attributes to file paths in a Git repository, giving you explicit control over how Git handles those files during checkouts, merges, diffs, and archives. Line ending inconsistencies, corrupted binary diffs, merge conflicts in generated files, and bloated archive packages are all problems that a well-constructed &lt;code&gt;.gitattributes&lt;/code&gt; file prevents before they reach your team.&lt;/p&gt;</description> <link>https://tenthirtyam.org/dispatches/2026/04/11/controlling-git-repository-behavior-with-gitattributes/</link> <pubDate>Sat, 11 Apr 2026 00:00:00 +0000</pubDate> <source url="https://tenthirtyam.org/rss.xml">Hypertext Dispatches</source><guid isPermaLink="true">https://tenthirtyam.org/dispatches/2026/04/11/controlling-git-repository-behavior-with-gitattributes/</guid> </item> <item> <title>Managing GitHub Repository Settings with Probot Settings</title> <author>Ryan Johnson</author> <category>Automation</category> <category>Developer Experience</category> <category>Developer Workflow</category> <category>GitHub</category> <category>Open Source</category> <category>Technology</category> <description>&lt;h1&gt;Managing GitHub Repository Settings with Probot Settings&lt;/h1&gt; &lt;p&gt;GitHub repository settings can be managed through the web UI, the REST API, or the &lt;code&gt;gh&lt;/code&gt; CLI. Default branch, merge strategies, issue tracking, vulnerability alerts, labels, branch protection rules: regardless of how you change them, the result is the same: no audit trail tied to your repository, no peer review process, and no straightforward way to reproduce the configuration in another repository without repeating the same steps manually.&lt;/p&gt; &lt;p&gt;The &lt;a href=&#34;https://probot.github.io/apps/settings/&#34;&gt;Probot Settings app&lt;/a&gt; solves that problem by treating repository configuration as code. You commit a &lt;code&gt;.github/settings.yml&lt;/code&gt; file to your repository, and the app syncs its contents to GitHub&#39;s API every time the file changes. The settings are versioned, reviewable, and repeatable.&lt;/p&gt; &lt;p&gt;This post covers how the app works, how to install it, what it can configure, and how to structure a &lt;code&gt;settings.yml&lt;/code&gt; file that covers the settings I apply to every project.&lt;/p&gt;</description> <link>https://tenthirtyam.org/dispatches/2026/04/10/managing-github-repository-settings-with-probot-settings/</link> <pubDate>Fri, 10 Apr 2026 00:00:00 +0000</pubDate> <source url="https://tenthirtyam.org/rss.xml">Hypertext Dispatches</source><guid isPermaLink="true">https://tenthirtyam.org/dispatches/2026/04/10/managing-github-repository-settings-with-probot-settings/</guid> </item> <item> <title>Fare Thee Well</title> <author>Ryan Johnson</author> <category>Americana</category> <category>Country</category> <category>Folk</category> <category>Music</category> <category>Songwriting</category> <category>Songwriting</category> <category>Southern Gothic</category> <description>&lt;h1&gt;Fare Thee Well&lt;/h1&gt; &lt;iframe width=&#34;100%&#34; height=&#34;166&#34; scrolling=&#34;no&#34; frameborder=&#34;no&#34; allow=&#34;autoplay&#34; src=&#34;https://w.soundcloud.com/player/?url=https%3A//api.soundcloud.com/tracks/soundcloud%3Atracks%3A2298378773%3Fsecret_token%3Ds-40U8jpt2Tfv&amp;color=%23ff5500&amp;auto_play=false&amp;hide_related=true&amp;show_comments=false&amp;show_user=true&amp;show_reposts=false&amp;show_teaser=false&#34;&gt;&lt;/iframe&gt; &lt;div style=&#34;font-size: 10px; color: #cccccc;line-break: anywhere;word-break: normal;overflow: hidden;white-space: nowrap;text-overflow: ellipsis; font-family: Interstate,Lucida Grande,Lucida Sans Unicode,Lucida Sans,Garuda,Verdana,Tahoma,sans-serif;font-weight: 100;&#34;&gt;&lt;a href=&#34;https://soundcloud.com/39north&#34; title=&#34;39 North&#34; target=&#34;_blank&#34; style=&#34;color: #cccccc; text-decoration: none;&#34;&gt;39 North&lt;/a&gt; · &lt;a href=&#34;https://soundcloud.com/39north/fare-thee-well/s-40U8jpt2Tfv&#34; title=&#34;Fare Thee Well&#34; target=&#34;_blank&#34; style=&#34;color: #cccccc; text-decoration: none;&#34;&gt;Fare Thee Well&lt;/a&gt;&lt;/div&gt; &lt;p&gt;!!! note &#34;Rendition Notes&#34; This rendition features original lyrics inspired by the traditional folk song &lt;a href=&#34;https://en.wikipedia.org/wiki/Dink%27s_Song&#34;&gt;&#34;Dink&#39;s Song&#34;&lt;/a&gt;, also known as &#34;Fare Thee Well&#34;.&lt;/p&gt; &lt;p&gt;!!! copyright &#34;Copyright&#34; &lt;strong&gt;Lyrics&lt;/strong&gt;: &amp;copy; 2026 J. Ryan Johnson. All rights reserved.&lt;/p&gt; &lt;p&gt;--8&amp;lt;-- &#34;./snippets/ai-recording-disclaimer.md&#34;&lt;/p&gt;</description> <link>https://tenthirtyam.org/dispatches/2026/04/09/fare-thee-well/</link> <pubDate>Thu, 09 Apr 2026 00:00:00 +0000</pubDate> <source url="https://tenthirtyam.org/rss.xml">Hypertext Dispatches</source><guid isPermaLink="true">https://tenthirtyam.org/dispatches/2026/04/09/fare-thee-well/</guid> </item> <item> <title>Please Format Your Code Blocks: GitHub Issue Etiquette</title> <author>Ryan Johnson</author> <category>Developer Experience</category> <category>Developer Workflow</category> <category>GitHub</category> <category>Open Source</category> <category>Technology</category> <description>&lt;h1&gt;Please Format Your Code Blocks: GitHub Issue Etiquette&lt;/h1&gt; &lt;p&gt;You are a maintainer. You have carved out thirty minutes between meetings to work through the open issues on your project. You open the first one. The title is promising. The reporter clearly hit a real bug. And then you see it: a wall of unformatted YAML, raw Terraform, and shell output, all smooshed together into a single paragraph, every newline stripped, every indentation gone, triple-quoted strings collapsed into nothing, angle brackets eaten by the Markdown renderer. You cannot tell where the config ends and the error begins.&lt;/p&gt; &lt;p&gt;You close the tab.&lt;/p&gt; &lt;p&gt;If you are a maintainer, you have lived that moment.&lt;/p&gt; &lt;p&gt;If you are a contributor, please keep reading, because this post is for you, and it will help your issues get more attention.&lt;/p&gt;</description> <link>https://tenthirtyam.org/dispatches/2026/04/09/please-format-your-code-blocks-github-issue-etiquette/</link> <pubDate>Thu, 09 Apr 2026 00:00:00 +0000</pubDate> <source url="https://tenthirtyam.org/rss.xml">Hypertext Dispatches</source><guid isPermaLink="true">https://tenthirtyam.org/dispatches/2026/04/09/please-format-your-code-blocks-github-issue-etiquette/</guid> </item> <item> <title>DCO vs CLA: Managing Contribution Agreements in Open Source</title> <author>Ryan Johnson</author> <category>Compliance</category> <category>Developer Workflow</category> <category>GitHub</category> <category>Open Source</category> <category>Security</category> <category>Technology</category> <description>&lt;h1&gt;DCO vs CLA: Managing Contribution Agreements in Open Source&lt;/h1&gt; &lt;p&gt;When you accept code contributions to an open-source project, you are entering a legal relationship with every contributor. Who owns the code? Do you have the right to relicense it? What happens if a contributor later claims you do not have permission to use their work? Two mechanisms exist to answer those questions before they become problems: the Contributor License Agreement (CLA) and the Developer Certificate of Origin (DCO).&lt;/p&gt; &lt;p&gt;This post takes a thorough look at both: what they are, how they work, the tradeoffs involved, and the tooling available to automate enforcement on GitHub.&lt;/p&gt;</description> <link>https://tenthirtyam.org/dispatches/2026/04/08/dco-vs-cla-managing-contribution-agreements-in-open-source/</link> <pubDate>Wed, 08 Apr 2026 00:00:00 +0000</pubDate> <source url="https://tenthirtyam.org/rss.xml">Hypertext Dispatches</source><guid isPermaLink="true">https://tenthirtyam.org/dispatches/2026/04/08/dco-vs-cla-managing-contribution-agreements-in-open-source/</guid> </item> <item> <title>A Better Inbox for Pull Requests on GitHub</title> <author>Ryan Johnson</author> <category>Developer Experience</category> <category>Developer Workflow</category> <category>GitHub</category> <category>GitHub Copilot</category> <category>Open Source</category> <category>Pull Requests</category> <category>Technology</category> <description>&lt;h1&gt;A Better Inbox for Pull Requests on GitHub&lt;/h1&gt; &lt;p&gt;GitHub released a new Pull Requests dashboard in public preview at the end of March 2026. It replaces the existing pull request list at &lt;a href=&#34;https://github.com/pulls&#34;&gt;github.com/pulls&lt;/a&gt; with something that functions more like an inbox: a view that surfaces the PRs that actually need your attention rather than presenting every open PR you are associated with.&lt;/p&gt;</description> <link>https://tenthirtyam.org/dispatches/2026/04/07/a-better-inbox-for-pull-requests-on-github/</link> <pubDate>Tue, 07 Apr 2026 00:00:00 +0000</pubDate> <source url="https://tenthirtyam.org/rss.xml">Hypertext Dispatches</source><guid isPermaLink="true">https://tenthirtyam.org/dispatches/2026/04/07/a-better-inbox-for-pull-requests-on-github/</guid> </item> <item> <title>Why I Use JetBrains GoLand and PyCharm Over VS Code</title> <author>Ryan Johnson</author> <category>Ansible</category> <category>Developer Experience</category> <category>Developer Tools</category> <category>Developer Workflow</category> <category>Go</category> <category>IDE</category> <category>JetBrains</category> <category>Open Source</category> <category>Python</category> <category>Technology</category> <category>Terraform</category> <description>&lt;h1&gt;Why I Use JetBrains GoLand and PyCharm Over VS Code&lt;/h1&gt; &lt;p&gt;VS Code is a remarkable editor. It is fast, extensible, and free, and it has become the default tool for an enormous portion of the developer community. I use it myself for PowerShell, general Markdown, and lightweight editing. But when I sit down to write Go or Python, GoLand and PyCharm are where I do my best work.&lt;/p&gt; &lt;p&gt;This is not a condemnation of VS Code. It is an explanation of why, for language-specific work, purpose-built IDEs make me a more productive and deliberate developer.&lt;/p&gt;</description> <link>https://tenthirtyam.org/dispatches/2026/04/06/why-i-use-jetbrains-goland-and-pycharm-over-vs-code/</link> <pubDate>Mon, 06 Apr 2026 00:00:00 +0000</pubDate> <source url="https://tenthirtyam.org/rss.xml">Hypertext Dispatches</source><guid isPermaLink="true">https://tenthirtyam.org/dispatches/2026/04/06/why-i-use-jetbrains-goland-and-pycharm-over-vs-code/</guid> </item> </channel> </rss>