Dokumen ini menjelaskan secara detail gimana OpsTerm bekerja โ dari mulai user ngetik command sampai hasilnya keluar.
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ USER INTERFACE โ
โ โ
โ โโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโโโโ โ
โ โ CLI Terminal โ โ Zsh Plugin โ โ Pipe (stdin) โ โ
โ โ ai <command> โ โ ai-last โ โ cmd | ai <prompt>โ โ
โ โ ai ssh <svr> โ โ ai-explain โ โ โ โ
โ โโโโโโโโฌโโโโโโโโ โโโโโโโโฌโโโโโโโโ โโโโโโโโโโฌโโโโโโโโโโ โ
โ โ โ โ โ
โโโโโโโโโโโผโโโโโโโโโโโโโโโโโโผโโโโโโโโโโโโโโโโโโโโโผโโโโโโโโโโโโโ
โ โ โ
โผ โผ โผ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ CLI ROUTER (argparse) โ
โ โ
โ โโโโโโโโโโโโ โโโโโโโโโโโโ โโโโโโโโโโ โโโโโโโโ โโโโโโโโโ โ
โ โ ai <ask> โ โ ai ssh โ โai scp โ โai runโ โai vaultโ โ
โ โ (default)โ โ โ โ โ โ โ โ โ โ
โ โโโโโโฌโโโโโโ โโโโโโฌโโโโโโ โโโโโฌโโโโโ โโโโฌโโโโ โโโโโฌโโโโ โ
โโโโโโโโโผโโโโโโโโโโโโโผโโโโโโโโโโโโผโโโโโโโโโโผโโโโโโโโโโโผโโโโโโโ
โ โ โ โ โ
โผ โผ โผ โผ โผ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ ENGINES โ
โ โ
โ โโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโโโโโโ โ
โ โ AI Client โ โ SSH Runner โ โ SCP Transfer โ โ
โ โ (urllib) โ โ (subproc) โ โ (subprocess) โ โ
โ โ OpenAI-compatโ โ multi-hop โ โ local โ remote โ โ
โ โโโโโโโโฌโโโโโโโโ โโโโโโโฌโโโโโโโ โโโโโโโโโโฌโโโโโโโโโโโโ โ
โ โ โ โ โ
โ โโโโโโโโผโโโโโโโโโโโโโโโโโผโโโโโโโโโโโโโโโโโโโโผโโโโโโโโโโโ โ
โ โ Workflow Executor โ โ
โ โ Step: SSH โ SCP โ Local โ Confirm โ Wait โ โ
โ โโโโโโโโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โ โ โ
โ โโโโโโโโโโโโโโโโโโโโโโโโผโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โ โ Vault (Encrypted) โ โ
โ โ AES-128-CBC + PBKDF2 (via cryptography) โ โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โ โ
โ โโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโ โ
โ โ Config Loaderโ โ History โ โ
โ โ (YAML/JSON) โ โ (SQLite) โ โ
โ โโโโโโโโฌโโโโโโโโ โโโโโโโฌโโโโโโโ โ
โโโโโโโโโโโผโโโโโโโโโโโโโโโโโผโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ โ
โผ โผ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ EXTERNAL SYSTEMS โ
โ โ
โ โโโโโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโ โ
โ โ AI Provider API โ โ SSH Servers โ โ Local File โ โ
โ โ (DeepSeek,OpenAI,โ โ (VPS, cloud, โ โ System โ โ
โ โ Ollama, etc) โ โ instances) โ โ (config, vault)โ โ
โ โโโโโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโ โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
ai how to check disk)User input: "ai how to check disk"
โ
โผ
โโโโโโโโโโโโโโโโโโโ
โ 1. Parse args โ โ argparse: subcmd=None (default AI mode)
โโโโโโโโโโฌโโโโโโโโโโ
โ
โผ
โโโโโโโโโโโโโโโโโโโ
โ 2. Load config โ โ config.yaml (API key, model, URL)
โโโโโโโโโโฌโโโโโโโโโโ
โ
โผ
โโโโโโโโโโโโโโโโโโโ
โ 3. Build prompt โ โ + stdin_data if piped
โโโโโโโโโโฌโโโโโโโโโโ
โ
โผ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ 4. AI Chat (ai_chat()) โ
โ POST ke /v1/chat/completions โ
โ Headers: Authorization Bearer โ
โโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ
โผ
โโโโโโโโโโโโโโโโโโโ
โ 5. Parse responseโ โ JSON: choices[0].message.content
โโโโโโโโโโฌโโโโโโโโโโ
โ
โผ
โโโโโโโโโโโโโโโโโโโ
โ 6. Print output โ โ stdout
โโโโโโโโโโฌโโโโโโโโโโ
โ
โผ
โโโโโโโโโโโโโโโโโโโ
โ 7. Auto-exec? โ โ Kalo response ada $, tanya user
โโโโโโโโโโฌโโโโโโโโโโ
โ
โผ
โโโโโโโโโโโโโโโโโโโ
โ 8. Save history โ โ SQLite (mode, input, output)
โโโโโโโโโโโโโโโโโโโโ
ai ssh vps-utama --via bastion)User input: "ai ssh vps-utama --via bastion"
โ
โผ
โโโโโโโโโโโโโโโโโโโโโโโโโ
โ 1. Parse args โ โ subcmd="ssh", server="vps-utama"
โโโโโโโโโโโโฌโโโโโโโโโโโโโโ proxy="bastion"
โ
โผ
โโโโโโโโโโโโโโโโโโโโโโโโโ
โ 2. Load servers.yaml โ โ get_servers()
โโโโโโโโโโโโฌโโโโโโโโโโโโโโ
โ
โผ
โโโโโโโโโโโโโโโโโโโโโโโโโ
โ 3. Lookup server โ โ _server_lookup("vps-utama")
โ vps-utama: โ
โ host: 43.157.. โ
โ user: ubuntu โ
โ key: ~/.ssh/... โ
โโโโโโโโโโโโฌโโโโโโโโโโโโโโ
โ
โผ
โโโโโโโโโโโโโโโโโโโโโโโโโ
โ 4. Resolve proxy โ โ _resolve_proxy("bastion")
โ โ "ubuntu@10.0.0.1"โ โ format: user@host[:port]
โโโโโโโโโโโโฌโโโโโโโโโโโโโโ
โ
โผ
โโโโโโโโโโโโโโโโโโโโโโโโโ
โ 5. Build SSH command โ โ ["ssh", "-J", proxy, "-i", key,
โ "ubuntu@43.157..", "-t"]
โโโโโโโโโโโโฌโโโโโโโโโโโโโโ
โ
โผ
โโโโโโโโโโโโโโโโโโโโโโโโโ
โ 6. execvp() โ โ Replace proses dengan SSH interaktif
โ โ Interactive SSH โ
โโโโโโโโโโโโโโโโโโโโโโโโโ
ai run deploy-app)User input: "ai run deploy-app"
โ
โผ
โโโโโโโโโโโโโโโโโโโโโโโโ
โ 1. Parse args โ โ subcmd="run", workflow="deploy-app"
โโโโโโโโโโโโฌโโโโโโโโโโโโ
โ
โผ
โโโโโโโโโโโโโโโโโโโโโโโโ
โ 2. Load workflows โ โ workflows.yaml
โ deploy-app: โ
โ steps: [...] โ
โโโโโโโโโโโโฌโโโโโโโโโโโโ
โ
โผ
โโโโโโโโโโโโโโโโโโโโโโโโ
โ 3. Iterate steps โ
โ โ
โ Step 1: ssh โโโโโโ SSH ke server + execute command
โ Step 2: scp โโโโโโ SCP file ke server
โ Step 3: local โโโโโโ Local shell command
โ Step 4: confirm โโโโโโ Prompt user Y/n
โ Step 5: wait โโโโโโ time.sleep(n)
โ โ
โโโโโโโโโโโโโโโโโโโโโโโโ
โ
โผ
โโโโโโโโโโโโโโโโโโโโโโโโ
โ 4. Done โ โ "โ
Workflow selesai!"
โโโโโโโโโโโโโโโโโโโโโโโโ
docker ps | ai "any errors?")User input: "docker ps | ai any errors?"
โ
โผ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ 1. stdin detected (not isatty()) โ โ sys.stdin.read()
โโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโ
โ
โผ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ 2. stdin_data = "CONTAINER ID..."โ โ Output docker ps
โโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโ
โ
โผ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ 3. Build prompt: โ
โ "Output dari command: โ
โ ``` โ
โ CONTAINER ID IMAGE... โ
โ ``` โ
โ โ
โ Pertanyaan: any errors?" โ
โโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโ
โ
โผ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ 4. Kirim ke AI โ sama kayak AI Chat flow
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
ai vault set db_password)User input: "ai vault set db_password"
โ
โผ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ 1. Unlock vault โ
โ - Cek OPSTERM_VAULT_PASSWORDโ โ env var
โ - Atau prompt password โ โ getpass()
โ - Derive key via PBKDF2 โ โ 600k iterations, SHA256
โโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโ
โ
โผ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ 2. Encrypt value โ
โ - cryptography.Fernet โ โ AES-128-CBC
โ - atau fallback HMAC+XOR โ
โโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโ
โ
โผ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ 3. Simpan ke vault.json โ
โ {"keys": { โ
โ "db_password": { โ
โ "data": "<encrypted>" โ
โ } โ
โ }, "salt": "<base64>"} โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
OpsTerm tidak punya daemon atau background process. Semua state disimpan di file:
| File | Format | Isi |
|---|---|---|
config.yaml |
YAML | AI provider, model, api_url, shell settings |
servers.yaml |
YAML | Daftar server: host, user, port, key, proxy |
workflows.yaml |
YAML | Daftar workflow: steps (ssh/scp/local) |
vault.json |
JSON (encrypted) | Credential terenkripsi (AES-128) |
history.db |
SQLite | Riwayat command (mode, input, output) |
last_output.txt |
Text | Output command terakhir (buat explain-last) |
last_command.txt |
Text | Command terakhir |
Data flow:
Config dibaca setiap kali command jalan โ tidak ada caching di memory
History ditulis setelah command selesai โ append-only
Vault dibuka pake password โ disimpan di memory SAMPAI ai vault lock
Last output ditulis oleh zsh plugin โ dibaca oleh ai last/explain-last
OPSTERM_API_KEY) โ recommendedconfig.yaml ada di .gitignore)cryptography.fernet.FernetOPSTERM_VAULT_PASSWORD-J flag (secure, encrypted)if result.returncode != 0:
print(f"โ Step {i} gagal")
# Tanya user: lanjut atau stop?
cont = input("Lanjut? [y/N] ")
if cont not in ("y", "yes"):
print("โ Workflow dihentikan.")
return
| Operasi | Waktu (approx) | Catatan |
|---|---|---|
| AI Chat (DeepSeek) | 1-3 detik | Tergantung provider & network |
| SSH Connect | < 1 detik | Langsung execvp, ga ada overhead |
| SCP Transfer | Varies | Tergantung ukuran file & bandwidth |
| Workflow (3 steps) | 5-15 detik | Tergantung step complexity |
| Vault encrypt | < 100ms | PBKDF2 600k iterasi ~50ms |
| Config load | < 10ms | YAML parsing minimal |
| History write | < 5ms | SQLite append |
Memory footprint: ~15-30MB (Python interpreter) + overhead sesuai operasi.
Selanjutnya: ๐ง Tech Stack โ