Minggu, 18 Mei 2025

From Flow to Frustration — and Back Again: How I Made My Terminal Smarter

| Minggu, 18 Mei 2025

Problem Description

Do you know this feeling?

You’re in the middle of coding. Your brain has created the logic and the full picture of how everything should work. Your fingers are flying across the keyboard, while you hold the entire system-its schema and the relationships between components-in your head.

You’re not just writing variables and function calls.

You’re creating interfaces, classes, structures.

You’re building the system in real time-one large piece after another.

You’ve caught the wave. 🌊

You’re deep, deep in the flow of creation.

And then suddenly… you need to do something trivial-start a container, assign an IP address, add a service to systemctl.

So you pause. Open a terminal. Try to recall the exact command.

And Boom! - your flow is gone.

Now you’re googling CLI flags, guessing command formats, brute-forcing options. Flow state gone. Now you’re just debugging a terminal.

One Command, Five Attempts

Here’s what this actually looks like in practice:

# What I tried first
$ python -m pip update requests
# ERROR: unknown command "update"

# Okay... maybe:
$ python -m pip upgrade requests
# ERROR: unknown command "upgrade"

# Maybe pip just updates on install?
$ python -m pip install requests
# Already satisfied. No upgrade happened.

# Let’s try this:
$ python -m pip install requests --upgrade
# Still no upgrade.

# Eventually, after searching:
$ python -m pip install --upgrade requests
# Success.

That tiny task derailed 20 minutes of deep mental context.

I hated it.

Now your brain is no longer building systems.

It’s brute-forcing CLI flags.

The magic is dead.

You’re not cool anymore.

Welcome to the Valley of Despair.

Valley of Despair

Why Am I Still Copy-Pasting From ChatGPT?

I use the terminal a lot-bash with Ubuntu at work, zsh on macOS at home.

Different shells, different environments.

Of course I remember the basics.

But for everything else, I still find myself going to Google, StackOverflow, or ChatGPT.

At some point, I stopped and asked myself:

Why the heck am I still copy-pasting commands from ChatGPT like an ancient human?

Old way

Yes, Copilot exists in VS Code. Yes, Warp exists too.

But I don’t have those setups everywhere. And Warp feels like overkill.

I don’t want a new IDE or terminal replacement.

I just want to keep using my terminal-and add just a little bit of magic that saves me from repetitive interruptions.

Turning Frustrations Into Requirements

So I took all those small pain points and turned them into requirements:

  • I want to transform plain English into CLI commands.
  • I want to keep using my terminal exactly the same way as before.
  • It should be easy to trigger, ideally with a hotkey.
  • It should be invisible, lightweight, and persistent.

And then I thought:

Wait, I can just build this.

Introducing nls: Natural Language Shell

It started simple.

I wrote a zsh function that replaces an English sentence in the terminal with the actual command. I bound it to CTRL+T.

You type:

upgrade the requests package using pip

You press CTRL+T.

It becomes:

python -m pip install --upgrade requests

Flow: preserved.

Early Problems and Fixes

1. Input Vanished Too Soon

After the English sentence was replaced with the response, the original input was gone.

So if the result wasn’t correct, I had to retype everything again.

Fix: I made the tool also add the English sentence to shell history.

Now I can easily recall and tweak it with the up arrow.

2. Prompt Needed Context

Since I work in different environments, I always had to mention which OS or shell I was using. That got annoying.

Fix: I added the shell and OS to the prompt automatically, so I didn’t have to repeat it every time.

When Project Context Changed Everything

Here’s where things got really interesting.

I tried writing:

run integration test for the traffic block for specific component

But nls gave me nothing useful.

Which makes sense-there’s no universal command for that.

It’s a project-specific action.

And then I thought:

Why can’t I just feed the README to ChatGPT? Or the .gitlab-ci.yml?

These files already contain all the commands we use-with real descriptions.

So I tried adding that content as part of the prompt’s context.

And it worked. Surprisingly well.

Of course, it wasn’t perfect the first time. I had to polish the prompt a bit.

Sometimes the output would hallucinate or grab the wrong line.

So I added this rule:

“Only use the project context if it’s directly relevant. Otherwise, ignore it.”

That made a big difference.

Suddenly, I could write vague internal commands like:

restart payment service test runner

…and get something accurate, based on how my team actually names things.

Eventually, the prompt looked like this:

You're a Linux CLI expert. Convert a natural language instruction into a safe,
one-line bash command for {os} ({shell}).
Only use the project context if directly relevant.
Output plain text only. No markdown, no extra text.
Instruction: {query}
Project context: {optional_readme_or_ci_file}

This prompt gave much more reliable results-and let me build in project context support.

From Local Script to Shared Tool

After using it locally for a while, I wanted to share it with my colleagues.

But the script used my personal ChatGPT API key-not ideal.

So I took a different approach:

  • I created an AWS Lambda function that includes my token, prompt, and API access.
  • Locally, I kept only the bash function-it just sends the data to the Lambda endpoint.

It worked well, but there was still a risk:

What if someone abuses the endpoint with too many requests?

Securing It

To protect it:

  • I added token-based access to the local script.
  • Every request now includes a personal token.
  • On the backend, I added a DynamoDB table that tracks token usage and limits.
  • I also added a second Lambda + API Gateway layer for authentication, usage tracking, and request limiting-to protect against DoS attacks.

Now it works on most machines, safely, and for free, as I even added some public tokens with generous limits, so anyone can try it out.

Summary

This little script only took a few hours to build. But it changed the way I work every day.

It reminded me that so many things in our lives are under our control. With a little effort and creativity, we can fix annoyances and make our tools work better for us-and maybe for others too.

Try It Out

You can find the code and install instructions here:

👉 README.md - DmytroHuzz/nls

It’s free. It’s fast. It might still be a little raw.

But if you hit a bug-open an issue or message me. I’d love to hear what you think.

Thanks for reading.

Stay creative. Stay in flow.

-Dmytro


Related Posts

Tidak ada komentar:

Posting Komentar