DEV Community

everwinner64
everwinner64

Posted on

I kept leaving the terminal for little things, so I spent 6 months building a CLI for them

Six months ago, I started noticing a pattern in the way I work.

I'd be in the middle of something in the terminal or in my IDE, then I'd need to do one tiny thing.

  • Decode a JWT.
  • Generate a UUID.
  • Check when a certificate expires.
  • Convert a timestamp.
  • Figure out why an HTTP request is taking forever.

Nothing very difficult. Yet I'd open a browser tab. Then another one.

Sometimes I'd Google the exact openssl command I used three months ago, or some command that looks like a Konami code.
Sometimes I'd write a five-line Python script that I'd never use again. And every now and then I'd end up with 37 browser tabs open, most of them containing things I was supposed to do in 30 seconds.
It started annoying me enough that I decided to build something for it.

That's how Denev happened.

So what is Denev?

Denev is a command-line toolkit for developer tasks that should be easy, but aren't. It aims to centralize solutions to these tasks under a consistent, human friendly syntax. I didn't want to remember the exact incantation for every little thing, and I didn't want to switch between 10 different tools every time I needed something.

For example:

dnv crypto hash "hello world"
Enter fullscreen mode Exit fullscreen mode
dnv jwt inspect <token>
Enter fullscreen mode Exit fullscreen mode
dnv cert inspect github.com --domain --warn-days 100
Enter fullscreen mode Exit fullscreen mode
dnv http timing example.com
Enter fullscreen mode Exit fullscreen mode
dnv uuid generate --type V7
Enter fullscreen mode Exit fullscreen mode

Some command outputs:

dnv cert inspect github.com --domain --warn-days 100:

dnv cert inspect

dnv jwt inspect eyJhbGciOiJub25lIiwidHlwIjoiSldUIn0.eyJzdWIiOiJldmVyd2lubmVyNjQiLCJyb2xlIjoiYWRtaW4iLCJleHAiOjE3ODg1MzU2MzV9.:

Denev JWT inspect

dnv regex test "(a+)+$" "aaaaaaaaaaaaaaaaaaaaaaaaaaaa!":

Denev regex test

The boring stuff is actually the useful stuff

One of the first things I cared about was consistency.

I didn't want every command to feel like it came from a completely different CLI. So the commands follow the same general shape:

dnv <domain> <action>
Enter fullscreen mode Exit fullscreen mode

And I tried to keep the same ideas across the different parts of the tool. Flags should have the same logic and meaning everywhere. Flags shouldn't be ambiguous with others, for example -d and -D having completely different meanings. Normal output should be readable. When I'm scripting something, I don't want a box made of Unicode characters and three lines of explanatory text. So there's --quiet. Input can come from arguments or stdin. Exit codes are predictable. And there is clipboard support for the cases where I'm going to paste the result somewhere anyway.

A few examples

JWTs

A JWT is a good example of the kind of thing that pushed me toward making this.

Usually I don't need a full JWT debugger.

I just want to know what's inside the token.

dnv jwt inspect <token>
Enter fullscreen mode Exit fullscreen mode

I can see the header, payload, timestamps and relevant metadata without first opening a website and pasting a token into it. That saves maybe 20 seconds, which doesn't sound like much. But doing it ten times a week for months gets surprisingly irritating or impossible if your connection is down.

Certificates

Certificates are another one.

I can never remember the exact openssl s_client incantation when I just want a quick answer to:
"Is this certificate going to expire soon?"

So:

dnv cert inspect github.com --domain --warn-days 100
Enter fullscreen mode Exit fullscreen mode

I don't want to reconstruct the operation from memory every time.

HTTP timing

I also wanted something slightly more useful than "the request took 412 ms". Sometimes you want to know where that time went.

So:

dnv http timing example.com
Enter fullscreen mode Exit fullscreen mode

gives you a breakdown of the request rather than just one number, which is much more helpful to me.

I also wanted it to be hard to misuse by accident

This is probably one of the less visible parts of Denev, but it ended up being one of the things I cared about most. Some operations are technically valid but worth a warning. For example, hashing something with MD5 or SHA-1 isn't an error. But silently presenting it as if it were a good default isn't great either. Likewise, an unsigned JWT can be perfectly legitimate in some contexts, but it's something I'd rather make visible than quietly ignore. There are similar checks around things like potentially problematic regular expressions. The idea isn't to stop someone from doing something unusual. It's to avoid the CLI quietly encouraging a bad assumption. Warnings can be bypassed when you know what you're doing. I just don't want the default experience to pretend that context doesn't matter.

There was also a less obvious goal

I didn't want to build a giant "developer toolbox" where every imaginable utility gets thrown into one binary. What interested me was the feeling of using one tool where I already knew how things worked.

Once you learn:

dnv <domain> <action>
Enter fullscreen mode Exit fullscreen mode

you can guess your way around a lot of the CLI. That matters more to me than the number of commands it has. I'd rather have 50 commands that feel coherent than 500 commands that each require their own little lesson.

What six months of using it taught me

The interesting part of building Denev wasn't implementing hashes or UUIDs. The harder part was deciding what the tool should do by default. When should a command warn? What counts as a useful default? How much information is too much? What should happen when input comes from stdin? How should different commands behave when something goes wrong?

A CLI is basically a collection of small opinions. And once you use it every day, you start noticing all of them.

One important caveat

The Denev CLI itself is closed-source and distributed under a custom license. The website and documentation are open. I know that's a dealbreaker for some developers, and that's completely fair. I'm mentioning it here rather than trying to hide it behind the last paragraph of a landing page.

Where it is now

Denev currently runs on Linux, macOS and Windows.
You can find the docs and examples here: Denev CLI

I'd genuinely like to know what you think.
What would you remove? What would you change? What developer task keeps sending you out of the terminal?

Note: English isn't my first language, so I used a little help to polish the grammar and phrasing of this post!

Top comments (0)