In 2012 I tried to talk my workplace into dropping Subversion and moving to Git. The tech argument was easy. The people argument was not. For a few of my colleagues, the command line was a real hurdle. Git was the right tool, but the way you talked to it was a wall.
So I started building a way over the wall. A graphical front end for Git, where the commands lived behind buttons but you could still see exactly what each button was about to run. I wanted it to lower the bar without hiding the machine, so someone nervous about the CLI could get real work done and pick up what the commands actually did along the way. I called it CommandGit. That little internal helper is the same project that, years later, became TerminalNexus.
The long slog through frameworks
The first version was C++ with MFC. After about a year of slow going I admitted it was fighting me more than helping, and I moved to C# and Windows Forms, which is what I used at my day job and knew I could move quickly in. Functional, but it looked like exactly what it was, and I wanted something I would not be embarrassed to charge for one day.
So I rebuilt the whole interface in WPF. That meant doing the UI layer again from scratch, which was not a small ask of my free time, but it paid off. The screens looked right on high-resolution displays instead of going fuzzy, and laying out controls got a lot less painful. When .NET 5 landed I moved again, mostly for the self-contained publishing. That one feature meant the app would just run on a customer's machine without me chasing whatever was or was not installed on their Windows.
Through all of it I kept a rule for myself: avoid pulling in outside libraries wherever I reasonably could. More work up front, but it meant I understood every part of the thing and nothing broke because some dependency three levels down decided to change its mind.
The cloud detour
Once the app was real, I wanted to charge for it, and that meant a backend for licensing and updates. I went with Azure, partly because I used AWS at work and wanted to learn something new. I reached for serverless functions, since you only pay for what runs. Then I learned the hard way that a serverless function left alone goes to sleep, and waking it up could add up to 30 seconds to my app's startup while it checked the license. For a desktop app, that is forever. I tried keeping the functions warm on a timer, which worked but quietly defeated the whole pay-for-what-you-use point, and eventually I moved the backend onto a plain Linux box on Azure with NGINX in front. That stumble turned into its own post, so I will not retell the whole thing here.
The breakthrough: any CLI, not just Git
Here is where it stopped being a Git tool. My own work had drifted toward backend and cloud, which meant a pile of new CLIs I was not fluent in, and I was tired of hand-typing the same commands and misremembering flags. CommandGit handled my Git. Everything else was still a slog.
Then it clicked. There was no reason CommandGit had to be about Git at all. The same idea, a command behind a button you can read before you run it, works for any command line. At first I thought that was a crazy amount of scope for one person. The more I sat with it, the more I realized I was closer to it than I felt.
So I taught it the other shells. Git Bash, PowerShell, the Command Prompt, and later WSL, with toolbar buttons to switch between them. A button could open a Linux tab and send commands to it, the next could jump to PowerShell, and I added a small internal sleep so I could pause between steps, say wait a moment for one tab to open before firing commands into the next. I also sat down and wrote over 400 commands, sorted into categories, and shipped them built in. I had not planned to, but I was living in the app every day anyway, so I figured I would hand people a running start.
The features that came from actually using it
Almost everything good in there came from me hitting an annoyance in my own day and fixing it.
I kept needing to drop a Jira ticket number into a Git command, so I built input prompts: click a button, it asks for the value, then runs. There is a date picker for the same reason. You can chain several commands onto one button, so a fetch and a status happen with a single click. You can attach whole scripts, Bash or Python or Go. And because I have absolutely run the wrong command at the wrong time, I added a warning prompt you can set on any command that is dangerous enough to deserve a second look. That one has saved me more than once.
The other big piece was scheduling. I wanted commands to run quietly in the background on a timer, things like checking the health of my Linux instances or pulling NGINX error logs, without me standing up a whole telemetry stack to do it. So scheduled commands got a logging system with filters and categories, and the option to watch output in real time. Then I added distribution, so a scheduled command could send its result to email, Slack, or Teams.
That last part taught me something. Once it was wired to Slack, a check running every five minutes meant a new message every five minutes, including all the times nothing was wrong. Nobody needs to be told all is well, over and over. So I added conditional distribution: only send the output when it matches something I care about, like a search term or a pattern in the result. Catch the problem fast, stay quiet when there is no news. No news is good news, finally built into the tool.
The trial, and where it landed
Charging for a desktop app is its own puzzle, because there is no website login deciding who is in and who is out. I also knew exactly what I did not want as a user: handing over my email and card just to try something I might not even keep, then fighting to cancel later. So CommandGit got a real free trial with no signup and no payment details, backed by that Azure cloud API. Nothing is unbreakable, mine included, but it does the job and I am not making anyone jump through hoops to kick the tires.
That is the tool that grew up into TerminalNexus. Same core idea I started with in 2012, a friendlier way to live at the command line without pretending the command line is not there, just a lot more of it, and a lot more polished. It is still entirely designed and built by me, which means if a feature annoys you, there is exactly one person to blame, and that would be me. It also kept evolving after the rename, including cutting the Windows Terminal dependency it used to lean on, but that is a story for another post.
Thanks for reading. If you have ever built a tool mostly to scratch your own itch and watched it turn into something bigger than you planned, send me a line. I read everything.
TerminalNexus
Comments