Skip to main content

1.5B edge-native shell agent — natural language to shell commands, 50ms latency on phone/edge

Project description

ShellWhisperer

License: MIT Python 3.10+ Tests

Natural language → shell commands. 50ms on edge.

A 1.5B parameter edge-native shell agent fine-tuned from Qwen3-1.5B. Converts natural language descriptions into safe, correct shell commands — designed to run on phones and edge devices via ONNX Runtime or llama.cpp GGUF.

Features

  • Edge-native: Runs in <50ms on mobile/edge via ONNX or GGUF
  • Multi-OS: Linux, macOS, Windows PowerShell prompts
  • Safety-first: Built-in guardrails against destructive commands (rm -rf /, fork bombs, pipe-to-shell)
  • Context-aware: Uses working directory, OS type, and recent command history
  • Multiple backends: HuggingFace Transformers, ONNX Runtime, llama.cpp
  • Streaming: WebSocket streaming for real-time output
  • Fine-tune your own: LoRA training on Fable5 traces or custom data

Quick Start

Install

pip install shell-whisperer

# With training support:
pip install "shell-whisperer[train]"

# With GGUF inference:
pip install "shell-whisperer[gguf]"

# Everything:
pip install "shell-whisperer[train,gguf,dev]"

One-shot Prediction

# Basic usage
sw "find all python files over 100 lines"
# → find . -name "*.py" -exec wc -l {} + | awk '$1 > 100'

sw "kill the process on port 8080"
# → lsof -ti:8080 | xargs kill -9

sw --os-type macos "install ffmpeg"
# → brew install ffmpeg

sw --os-type windows "show all listening ports"
# → Get-NetTCPConnection -State Listen | Format-Table LocalPort, OwningProcess -AutoSize

Interactive Mode

sw --interactive

sw> find all python files over 100 lines
┌─────────────────────────────────────────────────────────┐
│ find . -name "*.py" -exec wc -l {} + | awk '$1 > 100'  │
└─────────────────────────────────────────────────────────┘
42.5ms

sw> !os macos
OS set to: macos

sw> install ffmpeg
┌──────────────────────┐
│ brew install ffmpeg  │
└──────────────────────┘
28.1ms

Start API Server

sw --serve --port 8000
# Or specify model:
sw --serve --model ./models/shell-whisperer-merged --port 8000

Fine-Tuning

Prepare Training Data

ShellWhisperer extracts training pairs from Fable5 trace formats:

from shell_whisperer.data_extractor import load_training_data

# Load from JSONL traces (auto-detects format)
pairs = load_training_data("./traces/glint_data.jsonl", fmt="auto")

# Or specify format explicitly
from shell_whisperer.data_extractor import (
    extract_bash_from_glint,
    extract_bash_from_armand0e,
    extract_bash_from_vfable,
)

pairs = extract_bash_from_glint("./traces/glint.jsonl")
pairs = extract_bash_from_armand0e("./traces/armand0e.jsonl")
pairs = extract_bash_from_vfable("./traces/vfable.jsonl")

Supported Trace Formats

Glint — Command traces with shell intent metadata:

{"type": "shell_intent", "intent": "find all python files over 100 lines"}
{"type": "shell_command", "command": "find . -name '*.py' -exec wc -l {} + | awk '$1 > 100'", "shell": "bash", "exit_code": 0}

armand0e — Structured shell session logs:

{"event": "command_executed", "prompt": "show disk usage sorted by size", "command": "du -sh * | sort -rh", "exit_status": 0}

v-Fable — Validated Fable traces with confirmation signals:

{"role": "user", "utterance": "find all json files modified recently"}
{"role": "assistant", "tool_call": {"name": "execute_shell", "arguments": {"command": "find . -name '*.json' -mtime -7"}}, "validation": {"confirmed": true, "exit_code": 0}}

Train with LoRA

# LoRA fine-tune (default)
sw train --data ./traces/data.jsonl --epochs 3

# Full fine-tune
sw train --data ./traces/data.jsonl --full-finetune

# Custom parameters
sw train \
  --data ./traces/data.jsonl \
  --model-name Qwen/Qwen3-1.5B \
  --output-dir ./models/my-shell-whisperer \
  --epochs 5 \
  --lr 1e-4 \
  --batch-size 8 \
  --os-type linux

Training in Python

from shell_whisperer.trainer import TrainConfig, train_lora
from shell_whisperer.data_extractor import load_training_data

# Load data
pairs = load_training_data("./traces/data.jsonl", include_builtin=True)
print(f"Training with {len(pairs)} pairs")

# Configure and train
config = TrainConfig(
    model_name="Qwen/Qwen3-1.5B",
    output_dir="./models/shell-whisperer-lora",
    epochs=3,
    learning_rate=2e-4,
    lora_r=16,
    use_4bit=True,
    use_unsloth=True,
)

adapter_path = train_lora(config=config, training_pairs=pairs)

# Merge adapter with base model
from shell_whisperer.trainer import merge_and_save

merge_and_save(
    adapter_path=adapter_path,
    output_dir="./models/shell-whisperer-merged",
)

Export for Edge

# Export to ONNX
sw export --format onnx --model ./models/shell-whisperer-merged

# Export to GGUF (for llama.cpp)
sw export --format gguf --model ./models/shell-whisperer-merged

# 4-bit quantization (smallest, fastest)
sw export --format 4bit --model ./models/shell-whisperer-merged

# 8-bit quantization
sw export --format 8bit --model ./models/shell-whisperer-merged

# Export all formats
sw export --format all --model ./models/shell-whisperer-merged

Memory Estimates

Format RAM Required Latency (edge)
FP32 ~6.0 GB ~200ms
FP16 ~3.0 GB ~100ms
8-bit ~1.5 GB ~60ms
4-bit ~0.75 GB ~50ms
GGUF Q4_K_M ~0.84 GB ~50ms

Inference

Python API

from shell_whisperer import ShellWhisperer

# Load model
sw = ShellWhisperer(os_type="linux")
sw.load_model("./models/shell-whisperer-merged")

# Predict
result = sw.predict("find all python files over 100 lines")
print(result.command)
# → find . -name "*.py" -exec wc -l {} + | awk '$1 > 100'

# Context-aware prediction
result = sw.predict(
    "find config files",
    working_directory="/etc",
    recent_history=["ls -la", "cd /etc"],
    os_type="linux",
)

# Batch prediction
results = sw.predict_batch([
    "find all python files over 100 lines",
    "kill the process on port 8080",
    "show disk usage sorted by size",
])

# Streaming
for token in sw.predict_stream("find all python files"):
    print(token, end="", flush=True)

# Safety warnings
result = sw.predict("delete everything")
if result.safety_warnings:
    for warning in result.safety_warnings:
        print(f"⚠ {warning}")

sw.unload()

REST API

# Start server
sw --serve --port 8000

# Predict
curl -X POST http://localhost:8000/predict \
  -H "Content-Type: application/json" \
  -d '{"prompt": "find all python files over 100 lines", "os_type": "linux"}'

# Batch predict
curl -X POST http://localhost:8000/predict/batch \
  -H "Content-Type: application/json" \
  -d '{"prompts": ["find python files", "kill port 8080"]}'

# Health check
curl http://localhost:8000/health

# Model info
curl http://localhost:8000/info

WebSocket Streaming

const ws = new WebSocket("ws://localhost:8000/ws/stream");

ws.onopen = () => {
  ws.send(JSON.stringify({
    prompt: "find all python files over 100 lines",
    os_type: "linux"
  }));
};

ws.onmessage = (event) => {
  const data = JSON.parse(event.data);
  if (data.token) {
    process.stdout.write(data.token);
  } else if (data.done) {
    console.log("\nCommand:", data.command);
    if (data.safety_warnings.length) {
      console.log("Warnings:", data.safety_warnings);
    }
  }
};

Example Training Pairs

Built-in high-quality pairs from real-world shell usage:

Natural Language Shell Command Quality
find all python files over 100 lines find . -name "*.py" -exec wc -l {} + | awk '$1 > 100' 0.85
kill the process on port 8080 lsof -ti:8080 | xargs kill -9 0.80
show disk usage sorted by size du -sh * | sort -rh 0.75
recursively search for TODO in all python files grep -rn "TODO" --include="*.py" . 0.83
rename all .txt files to .md for f in *.txt; do mv "$f" "${f%.txt}.md"; done 0.84
remove all stopped docker containers docker container prune -f 0.73
show all git commits by the current user this month git log --author="$(git config user.name)" --since="$(date +%Y-%m-01)" --oneline 0.88
list all unique IPs that connected via SSH grep "Accepted" /var/log/auth.log | awk '{print $11}' | sort -u 0.84

Safety System

ShellWhisperer includes a built-in safety layer that:

  1. Blocks destructive commands: rm -rf /, fork bombs, dd to disk
  2. Warns on sudo: Flags commands requiring elevated privileges
  3. Flags pipe-to-shell: Warns about curl | bash patterns
  4. Prevents chmod 777: Warns about insecure permissions
result = sw.predict("delete all files")
# Safety warning: ⚠ SAFETY: Destructive: recursive force-delete

Architecture

┌─────────────────────────────────────────┐
│           Natural Language Input         │
└──────────────┬──────────────────────────┘
               │
┌──────────────▼──────────────────────────┐
│         System Prompt (OS-specific)       │
│    LINUX_PROMPT / MACOS_PROMPT /         │
│    WINDOWS_PROMPT + Safety Rules          │
└──────────────┬──────────────────────────┘
               │
┌──────────────▼──────────────────────────┐
│       Qwen3-1.5B (LoRA fine-tuned)       │
│         1.5B parameters                  │
└──────────────┬──────────────────────────┘
               │
┌──────────────▼──────────────────────────┐
│          Output Cleaning                  │
│   - Strip markdown/backticks             │
│   - Remove model prefixes                │
│   - Multi-line pipe/chain handling        │
└──────────────┬──────────────────────────┘
               │
┌──────────────▼──────────────────────────┐
│          Safety Check                     │
│   - rm -rf protection                    │
│   - sudo warning                         │
│   - pipe-to-shell detection              │
└──────────────┬──────────────────────────┘
               │
┌──────────────▼──────────────────────────┐
│         Shell Command Output              │
└───────────────────────────────────────────┘

Project Structure

shell-whisperer/
├── pyproject.toml
├── README.md
├── src/shell_whisperer/
│   ├── __init__.py           # Package init + exports
│   ├── prompts.py            # OS-specific system prompts + safety rules
│   ├── data_extractor.py     # Fable5 trace extraction + quality filtering
│   ├── trainer.py            # LoRA/Full fine-tuning on Qwen3-1.5B
│   ├── exporter.py           # ONNX, GGUF, 4-bit/8-bit export + memory estimation
│   ├── inference.py          # Multi-backend inference (Transformers, ONNX, llama.cpp)
│   ├── server.py             # FastAPI server (REST + WebSocket)
│   └── cli.py                # CLI: sw predict, train, export, serve
└── tests/
    ├── test_data_extractor.py
    └── test_inference.py

Development

# Install dev dependencies
pip install -e ".[dev]"

# Run tests
pytest

# Lint
ruff check src/ tests/

# Type check
mypy src/

License

MIT

Ecosystem

Part of the FableForge ecosystem — 21 open-source projects built from 210K real agent traces:

Project Description
Anvil Self-verified coding agent
VerifyLoop Plan→Execute→Verify→Recover framework
ErrorRecovery Self-healing middleware (3,725 error patterns)
FableForge-14B The fine-tuned 14B model (4-stage training)
ShellWhisperer 1.5B edge agent (phone/RPi, 50ms)
ReasonCritic Verification model (130 benchmark tasks)
TraceCompiler Compile traces → LoRA skills
AgentRuntime Persistent agent daemon (systemd for AI)
AgentSwarm Multi-agent from real trace transitions
AgentTelemetry Datadog for agents (token tracking, costs)
BenchAgent HumanEval for tool-use (107 tasks)
AgentDev VSCode extension with verification
TraceViz Trace replay visualizer (Next.js)
AgentSkills npm for agent behaviors
AgentCurriculum 5-stage progressive training
AgentFuzzer Adversarial testing for agents
AgentConstitution Safety guardrails from traces
CostOptimizer Token cost reduction (50-80%)
AgentProfiler Behavioral fingerprinting
TrajectoryDistiller Trace→training data pipeline
Fable5-Dataset HuggingFace dataset release

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

fableforge_shell_whisperer-0.1.0.tar.gz (35.4 kB view details)

Uploaded Source

Built Distribution

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

fableforge_shell_whisperer-0.1.0-py3-none-any.whl (34.3 kB view details)

Uploaded Python 3

File details

Details for the file fableforge_shell_whisperer-0.1.0.tar.gz.

File metadata

File hashes

Hashes for fableforge_shell_whisperer-0.1.0.tar.gz
Algorithm Hash digest
SHA256 5dc5f9a0a15c2b6bd7a875119281ec3f4b188b18740f7b055eea27a36df58007
MD5 d06ae760b7fa9e40614d00dde706793f
BLAKE2b-256 8a9cf1a20a1290e0dfe148995e640f17772374d953b55423cb3d7bd484084c5b

See more details on using hashes here.

Provenance

The following attestation bundles were made for fableforge_shell_whisperer-0.1.0.tar.gz:

Publisher: release.yml on KingLabsA/shell-whisperer

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file fableforge_shell_whisperer-0.1.0-py3-none-any.whl.

File metadata

File hashes

Hashes for fableforge_shell_whisperer-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 ba4ca0e9253d579650e821919c7d9682f40fd227faabce7452b19be10e87591a
MD5 5a3bfd7e27c11ec4008c8fb8bdc6ea2e
BLAKE2b-256 9ebe5e1088666852bfe3cce0667091fb80c3154870401179b8b04d16e62fc5bc

See more details on using hashes here.

Provenance

The following attestation bundles were made for fableforge_shell_whisperer-0.1.0-py3-none-any.whl:

Publisher: release.yml on KingLabsA/shell-whisperer

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

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