Skip to content

Latest commit

 

History

18 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Oh Shell! (osh)

Version License

Learn and use Linux through natural language — powered by local LLMs via Ollama.

Describe what you want in plain English and get 3 executable command options, each with detailed explanations that break down every pipe, flag, and chained command so you understand what you're running.

osh translating a natural language query into three ranked shell command options, selecting one, and running it

Features

  • Interactive shell mode — Run osh with no arguments to enter a REPL; type queries continuously, use !help for commands, or exit / !exit to leave
  • Natural language to shell — Describe what you want; get valid commands back
  • 3 alternatives per query — Each generated by its own focused LLM call: a couple of shell variants, then one-liners in awk, perl, python3, etc. depending on what's installed
  • Detailed explanations — Each chained command (pipes, &&, ;) explained on its own line
  • QA safety review — Second-pass LLM review flags dangerous, incorrect, or imprecise commands
  • Command availability check — Detects whether each suggested tool is installed before you run it
  • Language detection — Auto-detects available scripting languages (bash, awk, perl, python3, ruby, node, etc.) and only suggests commands using what's installed
  • Cloud model support — Use any Ollama cloud model by appending :cloud or -cloud to the model name (e.g. llama3.2:cloud); authenticates via OLLAMA_API_KEY
  • Per-invocation model override — Use -m <model> to pick a different model without editing config; use -m - to select interactively from available Ollama models
  • Thinking model support — Handles models that use a separate thinking field (e.g., gpt-oss, deepseek-r1) with automatic response extraction and reformatting
  • Clipboard support — Copy any command to clipboard instead of executing
  • Retry on failure — If a command fails or misses the question, refine and retry interactively
  • Daily log files — All queries, responses, verdicts, and user actions logged to ~/.local/state/osh/YYYYMMDD.log
  • XDG-compliant paths — Config in ~/.config/osh/, state in ~/.local/state/osh/, app in ~/.local/osh/
  • ask companion — Pipe any text through ask for general-purpose LLM Q&A

Requirements

  • Python 3.11+
  • Ollama installed and running locally

Quick Start

# Install
./install.sh

# Use
osh what is my public IP address
osh find all python files modified in the last 24 hours
osh show failed ssh login attempts grouped by IP

Installation

./install.sh

The installer will:

  1. Copy app files to ~/.local/osh/
  2. Create symlinks in ~/.local/bin/ (osh, ask, computer)
  3. Prompt for Python environment (pyenv, venv, or system)
  4. Install pip dependencies
  5. Let you select an Ollama model
  6. Save configuration to ~/.config/osh/config.json

After installation, ensure ~/.local/bin is in your PATH:

echo 'export PATH="$HOME/.local/bin:$PATH"' >> ~/.zshrc  # or ~/.bashrc
source ~/.zshrc

Manual Install

pip3 install -r requirements.txt
chmod +x osh.py ask.py
mkdir -p ~/.local/bin
ln -s $(pwd)/osh.py ~/.local/bin/osh
ln -s $(pwd)/ask.py ~/.local/bin/ask
osh --init

Usage

osh                         # Enter interactive shell mode (REPL)
osh <natural language query>
osh -a <query>              # Always prompt before executing
osh -m <model> <query>      # Use a specific model (overrides config)
osh -m - <query>            # Pick model interactively from Ollama
osh --config PATH <query>   # Use alternate config file
osh --init                  # Interactive configuration
osh --version               # Show version

Shell Mode (REPL)

Running osh without arguments enters an interactive session where you can submit queries one after another without re-invoking the command. The prompt mimics a zsh-style two-line prompt, showing your user, current directory, and git branch (when inside a repo).

osh in interactive shell mode, showing a natural language query and a direct ? question

$ osh
Host: http://localhost:11434  Model: gpt-oss:latest
Oh Shell! - Interactive Shell Mode
Type your request in plain English, or '!help' for commands, '!' to exit.

┌(raul)-[~/src/osh][main]
└─: show disk usage of home directory
...
┌(raul)-[~/src/osh][main]
└─: !help
Available commands:
  !exit                Exit shell mode
  !quit                Exit shell mode
  !help                Show this help message
  !version             Show osh version
  !history             Show recent queries from today's session log
  !                    Exit shell mode (shorthand)

Or type any request in plain English.
┌(raul)-[~/src/osh][main]
└─: exit
Exiting shell mode.
Input Action
Any natural language Translated to shell commands as normal
?<question> Ask the LLM directly (like the ask companion), bypassing shell-command generation
exit, quit, bye, done, … Exit shell mode
!exit / !quit / ! Exit shell mode
!help List available ! commands
!version Show osh version
!history Show recent queries from today's session log
Ctrl-C / Ctrl-D Exit shell mode

Example Session

$ osh find all log files modified in the last 7 days and show their sizes
Host: http://localhost:11434  Model: gpt-oss:latest
Generating command options...
Checking command availability...
Running safety review...

Available commands:

  1. find /var/log -name '*.log' -mtime -7 -exec du -sh {} + [PASS]
     Find all .log files modified within 7 days and display their sizes
     find /var/log -name '*.log' -mtime -7: search for .log files modified in the last 7 days
     -exec du -sh {} +: calculate and display human-readable size for each match

  2. find /var/log -name '*.log' -mtime -7 | xargs du -sh [PASS]
     Same goal using pipe to xargs instead of -exec
     find /var/log -name '*.log' -mtime -7: locate recently modified .log files
     | xargs du -sh: pass found files to du for size display

  3. perl -e 'use File::Find; find(sub { print `du -sh $_` if /\.log$/ && -M $_ < 7 }, "/var/log")' [PASS]
     Perl one-liner using File::Find to traverse /var/log
     find(sub { ... }, "/var/log"): recursively walk the directory
     /\.log$/ && -M $_ < 7: match .log files modified within 7 days
     print `du -sh $_`: shell out to du for each match

Select command [1/2/3] [c]opy or [n]o ==>

Selection Options

Key Action
1–3 Execute that command
c Copy a command to clipboard
n / Enter Cancel

QA Verdicts

Each command is tagged by the safety review:

Verdict Meaning
PASS (green) Correct, safe, matches intent
WARN (yellow) Works but has a concern — confirmation required
MISS (magenta) Safe but doesn't precisely answer the question
FAIL (red) Dangerous, incorrect, or insecure — execution blocked

Ask

Pipe text to ask for general-purpose Q&A:

ask answering a direct question and piped log content

ask "What is the capital of France?"
ask what is the capital of France?
echo "What is the capital of France?" | ask
cat error.log | ask "What went wrong?"

Configuration

Interactive Setup

osh --init

Config File

~/.config/osh/config.json:

{
  "api": "ollama",
  "model": "gpt-oss:latest",
  "temperature": 0.3,
  "max_tokens": 2400,
  "safety": true,
  "qa_review": true,
  "suggested_command_color": "blue",
  "python_venv": null,
  "ollama_endpoint": "http://localhost:11434",
  "ollama_cloud_endpoint": "https://ollama.com",
  "logging_enabled": true,
  "log_retention_days": 30
}
Option Description Default
model Ollama model name gpt-oss:latest
temperature Randomness (0.0–2.0) 0.3
max_tokens Max response tokens (increase for thinking models) 2400
safety Stored/shown by --init and the usage screen; not currently wired to any prompt-before-execute logic (that's controlled by -a/--ask and WARN verdicts) true
qa_review Enable second-pass safety review true
suggested_command_color Terminal color for displayed commands blue
python_venv null, "pyenv:name", or "venv:/path" null
ollama_endpoint Local Ollama API URL http://localhost:11434
ollama_cloud_endpoint Ollama cloud API URL https://ollama.com
logging_enabled Enable daily log files true
log_retention_days Auto-delete logs older than N days 30

Custom Config Path

osh --config /path/to/config.json what is my username

Python Virtual Environment

{"python_venv": "pyenv:312"}
{"python_venv": "venv:/home/user/.venvs/myenv"}
{"python_venv": null}

Cloud Models

Ollama cloud models can be used by appending :cloud or -cloud to any model name:

osh -m llama3.2:cloud list files modified today
osh -m llama3.2-cloud what is my public IP

Or set a cloud model as your default in ~/.config/osh/config.json:

{"model": "llama3.2:cloud"}

Setup (one-time):

  1. Create a free account at https://ollama.com
  2. Generate an API key in your account settings
  3. Export the key in your shell profile (~/.bashrc or ~/.zshrc):
export OLLAMA_API_KEY=<your-key>

If OLLAMA_API_KEY is not set when a cloud model is invoked, osh will exit with a clear error and setup instructions.

Examples

# System
osh what is my current working directory
osh show me system uptime
osh check if port 8080 is open

# Files
osh find all files larger than 100MB
osh compress the logs directory
osh count lines in all python files recursively

# Network
osh what is my public IP address
osh list all IP addresses of NICs that start with wlp
osh show all open network connections

# Processes
osh is nginx running
osh show all python processes
osh kill process on port 3000

# Data processing
osh extract columns 1 and 3 from data.csv
osh count unique values in column 2 of users.csv sorted by frequency

# Log analysis
osh show failed ssh login attempts from auth.log grouped by IP
osh extract unique IPs from nginx access.log that returned 404
osh find all sudo commands in auth.log grouped by user

Architecture

Processing Pipeline

User query
  → For each approach (2 shell variants, then one per detected scripting
    language) issue a focused LLM call requesting exactly one command
    (XML-tagged: <c1>...<e1>...)
  → Collect unique commands, skipping duplicates/parse failures, until
    3 have been gathered
  → Check command availability (shutil.which + shell builtins)
  → QA safety review (single LLM call evaluating all collected commands)
  → Display options with verdicts
  → User selects → Execute

Key Components

File Purpose
osh.py Main application — prompts, LLM interaction, parsing, execution
ask.py Pipe-based general Q&A companion
install.sh Interactive installer with venv and model selection
tests/ pytest suite covering config, parsing, safety guards, and interactive flows
evals/ Opt-in script comparing QA safety-verdict accuracy across local Ollama models

Thinking Model Handling

Models like gpt-oss place output in a thinking field instead of content. When content comes back empty, osh:

  1. Searches the thinking text for <cN>/<eN> tagged commands and explanations
  2. If tags are found, rebuilds them into a normal tagged response
  3. If no tags are found, falls back to returning the raw thinking text as-is
  4. Filters placeholder/garbage commands (literal "command", "echo 'Could not extract commands'")

This is a single best-effort extraction pass — there's no reformat retry or token-budget scaling. If a thinking model's output doesn't contain recognizable tags, that approach is simply skipped, and collect_unique_options moves on (it targets 3 options but doesn't strictly require them).

Language Detection

On startup, osh probes for available scripting languages:

bash, awk, sed, perl, python3, ruby, node, php, lua, Rscript

The detected list is injected into the system prompt so the model only suggests commands using tools actually installed on the system.

Logging

Daily log files in ~/.local/state/osh/YYYYMMDD.log:

2026-02-21 10:30:45 | INFO | AVAILABLE_LANGUAGES: bash, awk, sed, perl, python3, node
2026-02-21 10:30:46 | INFO | SINGLE_OPTION_REQUEST: approach=shell_1
2026-02-21 10:30:47 | INFO | SINGLE_OPTION_RESPONSE: approach=shell_1 | <c1>find / -size +100M -exec ls -lh {} \; </c1><e1>...</e1>
2026-02-21 10:30:47 | INFO | OPTION_ACCEPTED: approach=shell_1 | cmd=find / -size +100M -exec ls -lh {} \;
2026-02-21 10:30:47 | INFO |   ... (repeated per approach until 3 unique options are collected)
2026-02-21 10:30:48 | INFO | COMMAND_CHECK: find | EXISTS: True
2026-02-21 10:30:49 | INFO | QA_REVIEW: Sending 3 commands for safety review
2026-02-21 10:30:50 | INFO | QA_RESPONSE: 1|PASS| | 2|PASS| | 3|WARN|Requires sudo
2026-02-21 10:30:52 | INFO | USER_SELECTED: Option 1 | COMMAND: find / -size +100M -exec ls -lh {} \;
2026-02-21 10:30:52 | INFO | ACTION: EXECUTE

Old logs auto-deleted after log_retention_days (default: 30).

Uninstall

rm -rf ~/.local/osh ~/.config/osh ~/.local/state/osh
rm -f ~/.local/bin/osh ~/.local/bin/ask ~/.local/bin/computer
pip3 uninstall ollama termcolor pyperclip

Ollama Setup

curl -fsSL https://ollama.ai/install.sh | sh
ollama pull llama3

License

MIT © 2026 Raul Kivi

About

Learn and use Linux through natural language — translates plain English into ranked, explained shell commands using local or cloud Ollama models

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages