DEV Community

Cover image for How I Made My Terminal Understand English
Lacy Morrow
Lacy Morrow

Posted on • Originally published at lacy.sh

How I Made My Terminal Understand English

Every time I need AI help while coding, I do the same thing:

  1. Copy terminal output
  2. Switch to Claude or ChatGPT
  3. Paste and ask my question
  4. Wait for the response
  5. Copy the answer
  6. Switch back to terminal
  7. Paste and run

That loop happens 20+ times a day.

AI coding tools like Claude Code and Gemini CLI already live in the terminal. But you still have to switch into them, type claude, ask your thing, then go back to your regular shell. Two workflows, one terminal.

So I built Lacy Shell, a ZSH/Bash plugin that figures out whether you're typing a command or a question and sends it to the right place. Commands run in your shell. Questions go to your AI agent. No prefix, no hotkey. You just type.

Demo of Lacy Shell showing real-time color indicator

The color indicator

The thing that made it click for me was the color indicator. As you type, a dot next to your prompt changes color:

  • Green = shell command
  • Magenta = AI agent

The first word gets syntax-highlighted too. Both update on every keystroke, so you know what's going to happen before you press Enter.

ZSH also gets a mode badge in the right prompt: SHELL, AGENT, or AUTO. Ctrl+Space toggles between them.

How detection works

The part that surprised me: you don't need AI to classify input. Lacy uses lexical analysis. No network call, no API key, no latency. Under a millisecond.

Here are the rules, in order:

1. Agent words catch obvious natural language.

About 150 conversational words ("explain", "why", "thanks", "perfect", "yes", "no") always route to AI. explain this error has no ambiguity. It's a lookup table, not a model.

2. Shell reserved words are trickier than they look.

Words like do, then, in, fi, and select pass command -v (they're valid shell syntax), but they're never the first token of a standalone command. Nobody types do and means a do loop. "Do we have a way to deploy?" is a question. "In the codebase, where is auth?" is a question. Lacy catches these.

3. If the first word is a valid command, it goes to shell.

git status, ls -la, docker ps — if command -v finds it, shell gets it.

4. Single non-command words go to shell.

If you type gti (a typo for git), Lacy lets the shell handle it so you see the normal error. Single words that aren't commands are almost always typos, not questions.

5. Multiple words starting with a non-command go to AI.

"Fix the bug in auth" starts with "fix" — not a command on most systems. Multiple words, first word isn't a command. That's natural language.

6. Post-execution reroute catches the rest.

This is the one I like best. Sometimes a valid command gets natural language arguments: kill the process on localhost:3000. kill is a real command, so Lacy sends it to the shell. It fails. Lacy checks: did the error match a known pattern ("No such process")? Did the input have natural language markers (articles, pronouns, 3+ bare words)? If both match, it silently reroutes to the AI agent. You never see the failed attempt.

Routing table

In practice:

You type Routes to Why
ls -la Shell Valid command
what files are here AI Agent word "what"
git status Shell Valid command
do we have auth? AI Reserved word "do"
cd.. Shell Single word (typo)
fix the bug AI Multi-word, not a command
kill the process on 3000 Shell, then AI Valid command fails with NL patterns
make sure the tests pass Shell, then AI "sure" is an NL marker, make fails

Works with whatever AI tool you have

Lacy isn't another AI tool. It's a routing layer for the ones you already have:

Tool How Lacy calls it
Claude Code claude -p "query"
Gemini CLI gemini --resume -p "query"
OpenCode opencode run -c "query"
Codex codex exec resume --last "query"
Lash lash run -c "query"

It auto-detects what's on your system, or you can set a custom command. Lacy doesn't compete with any of these. If you use Claude Code, Lacy just makes it easier to reach.

The unexpected part

I built this to stop context-switching. But the thing that actually changed my workflow was different: I started asking my terminal stuff I'd never have bothered looking up.

What's the flag for recursive grep again? How do I find processes on port 8080? What's the git command to undo the last commit without losing changes?

I'd normally Google these or just fumble through man pages. Now I type the question where I'm already working.

Install

One line:

curl -fsSL https://lacy.sh/install | bash
Enter fullscreen mode Exit fullscreen mode

Or Homebrew:

brew install lacymorrow/tap/lacy
Enter fullscreen mode Exit fullscreen mode

Or npx:

npx lacy
Enter fullscreen mode Exit fullscreen mode

Works on macOS, Linux, and WSL. ZSH and Bash 4+. MIT licensed.

If you try it, I want to hear about the edge cases. The boundary between command and question is inherently fuzzy, and real usage is the best way to tune it.

Top comments (0)