Skip to main content

Turn natural language into shell commands via the DeepSeek API, with a confirm-before-run step.

Project description

nlsh

Describe what you want to do in plain language; nlsh asks the DeepSeek API for the matching shell command, shows it with a short explanation, and waits for your confirmation before running it.

$ nlsh find the 5 largest files under this directory
╭─ proposed command ───────────────────────────────────────╮
│ $ du -ah . | sort -rh | head -n 5                         │
│                                                           │
│ Lists files by size and shows the five largest.          │
╰───────────────────────────────────────────────────────────╯
Run it? [y/n/e] (n):

y runs it, n cancels, e opens the command in your $EDITOR first.

Install

Once published to PyPI, install it as a standalone tool (the package is nlsh-cli; the command it installs is nlsh):

uv tool install nlsh-cli     # or: pipx install nlsh-cli

From source

One command sets up the virtual environment and all dependencies from the lockfile:

uv sync

This creates .venv/ and installs nlsh. Run it with uv run nlsh ..., or activate the env first (source .venv/bin/activate) and just call nlsh.

Plain pip (no uv) works too:

python -m venv .venv && . .venv/bin/activate
pip install -r requirements.txt
pip install -e .

Configure

Easiest — store the key interactively (written to ~/.config/nlsh/config.toml, mode 0600):

nlsh config set-key
nlsh config set-model deepseek-v4-pro   # optional, change default model
nlsh config show                        # show resolved config (key masked)

Or via environment variable:

export DEEPSEEK_API_KEY=sk-...

or edit ~/.config/nlsh/config.toml directly:

api_key  = "sk-..."
model    = "deepseek-v4-flash"        # optional (also: deepseek-v4-pro)
base_url = "https://api.deepseek.com" # optional

Resolution order for each setting is: environment variable → config file → default.

Usage

nlsh <natural language request>

  -y, --yes        run without confirmation (dangerous commands still prompt)
  -n, --dry-run    only print the command, never run it
      --pro        use the stronger model (deepseek-v4-pro) for this request
  -m, --model ID   override the model id for this request
      --no-stream  wait for the full response instead of streaming it
      --version    show version

The command streams in live as the model generates it (on a terminal); use --no-stream to disable.

At the confirmation prompt: y runs, n cancels, e edits first, c copies the command to the clipboard without running it. Commands that match risky patterns (rm -rf, dd of=/dev/…, mkfs, fork bombs, curl … | sh, sudo, …) are flagged in red and require typing the full word yes before they run — even under --yes. Multi-stage commands (pipes, &&) are shown with a per-step breakdown.

Explain a command (reverse mode)

Paste a command you don't understand and get a stage-by-stage breakdown:

nlsh explain git log --oneline --graph --decorate

Clipboard copy uses an OSC 52 terminal escape by default, so it reaches your local clipboard even over SSH. When there is no terminal it falls back to pbcopy/wl-copy/xclip/xsel/clip.exe.

Development

uv sync                 # installs deps + dev tools (pytest, ruff)
uv run pytest -q        # run the test suite
uv run ruff check .     # lint

CI (GitHub Actions) runs ruff + pytest across Python 3.9–3.13 and checks the lockfile on every push and PR.

Releasing

The version is derived from the git tag by hatch-vcs, so a release is just a tag:

git tag v0.1.0
git push origin v0.1.0

The Publish workflow builds the sdist/wheel and uploads them to PyPI via Trusted Publishing (configure a pypi environment on the repo and register the workflow as a trusted publisher — no API token stored).

How it works

nlsh sends your request plus context (OS, shell, current directory) to the DeepSeek chat API constrained to JSON output, parses {command, explanation}, and runs the chosen command through your $SHELL so aliases and the working directory behave as expected.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

nlsh_cli-0.2.0.tar.gz (32.9 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

nlsh_cli-0.2.0-py3-none-any.whl (14.9 kB view details)

Uploaded Python 3

File details

Details for the file nlsh_cli-0.2.0.tar.gz.

File metadata

  • Download URL: nlsh_cli-0.2.0.tar.gz
  • Upload date:
  • Size: 32.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.11.23 {"installer":{"name":"uv","version":"0.11.23","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for nlsh_cli-0.2.0.tar.gz
Algorithm Hash digest
SHA256 063065e76b95511e55c421599a8a5f5a1396b563988390da5ae07623a098c0e2
MD5 7567c7e16a625fdb074ad45ba712ca7f
BLAKE2b-256 e96957674f014c236eaa621ed418db0f7e432f8ffe11fc60bd98dbb7ede19f20

See more details on using hashes here.

File details

Details for the file nlsh_cli-0.2.0-py3-none-any.whl.

File metadata

  • Download URL: nlsh_cli-0.2.0-py3-none-any.whl
  • Upload date:
  • Size: 14.9 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.11.23 {"installer":{"name":"uv","version":"0.11.23","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for nlsh_cli-0.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 95ed2e8c1b8d51848ee7f26e60a0ac967e797043645c03a6233a0ba13f56f4e2
MD5 68aa829a73693ee0a06e0d98001c7a01
BLAKE2b-256 3a16a50cbc12efe5501c87b9f7b7f8c25c2f0696b80153baba3dcf22e462926b

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page