This document explains the technology used in OpsTerm โ from the programming language to the communication protocol.
| Layer | Technology | Version |
|---|---|---|
| Language | Python 3 | >= 3.7+ |
| CLI Parser | argparse (stdlib) |
Built-in |
| Config Format | YAML (custom parser) | Zero dep |
| HTTP Client | urllib (stdlib) |
Built-in |
| Database | SQLite via sqlite3 |
Built-in |
| Encryption | cryptography (optional) |
>= 3.0 |
| SSH/SCP | System ssh / scp |
OS default |
| Shell | Zsh plugin (zsh hooks) | Zsh only |
Zero mandatory dependencies โ just Python 3 stdlib. Everything is built-in.
The only optional dependency:pip install cryptography(for vault).
| Factor | Reason |
|---|---|
| Availability | Present on every Linux/macOS, no installation needed |
| Full stdlib | JSON, SQLite, HTTP, argparse, hashlib โ all built-in |
| Cross-platform | Works on Linux & macOS without changes |
| Rapid development | Fast to prototype and build new features |
| Language | Issue |
|---|---|
| Go | Needs cross-platform compilation, binary size >10MB |
| Rust | High learning curve, slow compilation times |
| Node.js | Heavy dependency (node_modules), not available on default systems |
| Bash | Hard to maintain beyond 1000 lines, painful JSON parsing |
Python is the most practical choice for a CLI tool that must be zero-dependency and portable.
This is OpsTerm's main selling point. How is it done?
| Requirement | Typical Library | OpsTerm Solution |
|---|---|---|
| YAML Parsing | PyYAML | Custom minimal parser (~80 lines) |
| HTTP Requests | requests | urllib.request (stdlib) |
| Arg Parsing | click, typer | argparse (stdlib) |
| Database | SQLAlchemy | sqlite3 (stdlib) |
| Encryption | cryptography | hashlib + hmac (stdlib) + optional cryptography |
OpsTerm's YAML parser is minimal โ it only supports the YAML subset that OpsTerm uses:
Supported:
- Key-value: key: value
- Nested mapping via indentation
- Lists: - item
- Nested objects in lists
- Comments (#)
- Strings, numbers, booleans, null
NOT supported:
- YAML anchors (&anchor, *alias)
- Multi-line strings (|, >)
- Inline JSON ({key: value})
- Complex types (timestamps, sets)
Why not use PyYAML?
1. Dependency โ users would need to pip install it first
2. Overkill โ we only use a small YAML subset
3. Maintainable โ the parser is only ~80 lines, easy to understand
CREATE TABLE IF NOT EXISTS history (
id INTEGER PRIMARY KEY AUTOINCREMENT,
timestamp TEXT DEFAULT (datetime('now','localtime')),
mode TEXT, -- 'ai', 'ssh', 'workflow', 'pipe', 'shell', 'scp', 'vault'
input TEXT, -- command/question (max 500 chars)
output TEXT -- response (max 2000 chars)
);
import sqlite3)The AI client uses a format that is compatible with OpenAI.
POST /v1/chat/completions
Authorization: Bearer ***
Content-Type: application/json
{
"model": "deepseek-chat",
"messages": [
{"role": "system", "content": "You are a terminal assistant..."},
{"role": "user", "content": "how to check disk usage"}
],
"temperature": 0.3,
"max_tokens": 1024
}
{
"id": "chatcmpl-...",
"choices": [{
"message": {
"role": "assistant",
"content": "$ df -h /"
}
}]
}
| Provider | Base URL | Auth |
|---|---|---|
| DeepSeek | https://api.deepseek.com/v1 |
API Key |
| OpenAI | https://api.openai.com/v1 |
API Key |
| OpenRouter | https://openrouter.ai/api/v1 |
API Key |
| Ollama (local) | http://localhost:11434/v1 |
None |
| vLLM (self-hosted) | http://your-server:8000/v1 |
Optional |
| Any OpenAI-compat | Configurable | API Key / None |
cryptography.fernet.FernetMaster Password
โ
โผ
PBKDF2 (SHA-256, 600k iterations, salt)
โ
โผ
AES-128-CBC (Fernet)
โ
โผ
Base64-encoded token
โ
โผ
vault.json
If cryptography is not installed, OpsTerm uses a fallback encryption:
1. Key derivation: PBKDF2 from hashlib (stdlib)
2. Encryption: XOR cipher with random IV
3. Integrity: HMAC-SHA256
โ ๏ธ This fallback is less secure than AES. Recommended: pip install cryptography
# Direct SSH
ssh -i ~/.ssh/id_ed25519 -p 22 ubuntu@43.157.204.199 -t
# Multi-hop via ProxyJump
ssh -J ubuntu@10.0.0.1:22 ubuntu@43.157.204.199 -t
# Upload
scp -i ~/.ssh/id_ed25519 local.txt ubuntu@host:/remote/path/
# Download
scp -i ~/.ssh/id_ed25519 ubuntu@host:/remote/path/ local.txt
# Via jump host
scp -o ProxyJump=ubuntu@bastion:22 file.txt ubuntu@internal:/path/
os.execvp() โ replaces the process, interactivesubprocess.run() โ blocking until completesubprocess.run() โ non-interactive, command via SSH| Hook | Timing | Function |
|---|---|---|
preexec |
Before command runs | Save command to last_command.txt |
precmd |
After command finishes | (reserved for future use) |
alias ai-last='ai last'
alias ai-explain='ai explain-last'
ai-ti (AI + Terminal Integration) works:ai-ti() {
# 1. Ask AI
ai "$*"
# 2. Extract command from response (lines starting with $)
# 3. Ask user: run it?
# 4. If yes, execute
}
| Aspect | OpsTerm | Warp.dev | ShellGPT | Claude Code |
|---|---|---|---|---|
| Dependencies | โ Zero | โ Binary | โ ๏ธ pip | โ Binary |
| Custom AI | โ Any provider | โ Vendor lock | โ Many providers | โ Claude only |
| SSH Multi-hop | โ Built-in | โ No | โ No | โ No |
| Workflow | โ Multi-step | โ No | โ No | โ No |
| Vault | โ Encrypted | โ No | โ No | โ No |
| Tab Completion | โ bash+zsh | โ built-in | โ No | โ No |
| Platform | Linux + macOS | macOS only | Linux + macOS | Linux + macOS |
| Weight | ~50KB (script) | ~200MB+ | ~10MB | ~500MB+ |
| Zero Dep | โ Python stdlib | โ | โ (stdin/out) | โ |