A Next-Generation AI-Powered Terminal Emulator Built with Rust ๐ฆ
Transform natural language into powerful terminal commands with AI assistance
- Project Overview
- โจ Key Features
- ๐๏ธ Architecture Explained
- ๐งฉ Core Working Logic
- ๐ API Integration
- ๐ Function-by-Function Guide
- ๐ง Step-by-Step Execution Flow
- ๐๏ธ Dependencies & Setup
- ๐ Usage Examples
- ๐ก Teaching Explanation (ELI5)
- ๐ง Extension Ideas
- ๐ค Contributing
Linara Terminal is a modern, AI-enhanced terminal emulator written in Rust that bridges the gap between human language and command-line interfaces. Think of it as your personal terminal assistant that understands plain English!
Traditional terminals require you to remember exact command syntax:
- โ "I want to see all files including hidden ones" โ You need to know:
ls -la - โ "Remove the folder called 'old-project'" โ You need to know:
rm -r old-project - โ "Show me what's inside config.txt" โ You need to know:
cat config.txt
Linara Terminal makes this easy:
- โ
Just type: "list all files" โ Instantly executes
ls -la - โ
Just type: "remove folder old-project" โ Executes
rm -r old-project - โ Just type: "view config.txt" โ Shows file contents with line numbers
| Feature | Description |
|---|---|
| ๐ค AI Natural Language | Convert English to shell commands using Google Gemini 2.0 Flash |
| โก Lightning Fast | Local pattern matching for instant responses (no API call needed) |
| ๐จ Beautiful GUI | Modern dark theme with authentic terminal aesthetics |
| ๐ Clipboard Operations | Full copy/paste/cut support (Ctrl+C/V/X) |
| ๐ Smart Autocomplete | Intelligent command suggestions from history, PATH, and files |
| ๐ก๏ธ Safety First | Detects and blocks dangerous commands (like rm -rf /) |
| ๐ File Viewer | Built-in file viewer with syntax highlighting and line numbers |
| ๐ง Gibberish Detection | Filters out nonsense input before making API calls |
| ๐ Auto-Retry | Smart retry logic with exponential backoff for API failures |
| ๐ฏ Context-Aware | Tracks current directory, git branches, and command history |
Linara-Terminal/
โ
โโโ src/
โ โโโ main.rs # GUI, terminal logic, command execution
โ โโโ ai_assistant.rs # AI/NLP engine, API integration
โ โโโ [compiled files]
โ
โโโ Cargo.toml # Rust dependencies and metadata
โโโ Cargo.lock # Dependency lock file
โโโ .env # Environment variables (API keys)
โโโ README.md # This file!
Pattern: Event-Driven GUI with Asynchronous AI Backend
Think of it like a restaurant:
- Frontend (GUI) = The dining room where customers interact
- Backend (AI Engine) = The kitchen where magic happens
- Event Loop = The waiters taking orders and delivering food
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ USER INTERFACE (egui) โ
โ โโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโโโโ โ
โ โ Terminal โ โ Input Box โ โ Autocomplete โ โ
โ โ Display โ โ + Cursor โ โ Suggestions โ โ
โ โโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโโโโ โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ TERMINAL LOGIC (main.rs) โ
โ โโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโโโ โ
โ โ Command โ โ Directory โ โ Clipboard โ โ
โ โ Parsing โ โ Management โ โ Operations โ โ
โ โโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโโโ โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ AI ASSISTANT (ai_assistant.rs) โ
โ โโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโโโ โ
โ โ Pattern โ โ OpenRouter โ โ Gibberish โ โ
โ โ Matching โ โ API Client โ โ Detection โ โ
โ โโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโโโ โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ EXTERNAL SYSTEMS โ
โ โโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโโโ โ
โ โ OpenRouter โ โ System โ โ File System โ โ
โ โ API โ โ Commands โ โ โ โ
โ โโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโโโ โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
Simple Version:
You type "list files"
โ Terminal checks if it's a known pattern (YES! "list files" = "ls")
โ Executes "ls" command
โ Shows output on screen
Complex Version (AI-assisted):
You type "show me what's in config.txt"
โ Terminal checks local patterns (no match)
โ Sends to AI Assistant
โ AI converts to "view config.txt"
โ Terminal validates command
โ Executes command
โ Shows file contents with line numbers
- User Types Input โ
TerminalApp::update()captures keystrokes - Enter Pressed โ
execute_command()parses input - Is it a command? โ Execute directly via
std::process::Command - Is it natural language? โ Send to
AIAssistant::generate_command() - AI Processing:
- Check gibberish filter
- Check local pattern cache
- Check 5-minute response cache
- Make API call to OpenRouter
- Validate response
- Execute Translated Command โ
run_command_and_render() - Display Results โ Add lines to terminal output
What happens when you run cargo run?
fn main() -> Result<(), eframe::Error> {
// 1. Load environment variables from .env file
dotenvy::dotenv().ok();
// 2. Configure the window
let options = eframe::NativeOptions {
viewport: egui::ViewportBuilder::default()
.with_inner_size([1000.0, 700.0])
.with_title("Linara Terminal"),
..Default::default()
};
// 3. Launch the GUI application
eframe::run_native(
"Terminal",
options,
Box::new(|cc| {
// Set dark theme
cc.egui_ctx.set_visuals(egui::Visuals::dark());
Ok(Box::new(TerminalApp::new()))
}),
)
}Step-by-step breakdown:
- Load secrets from
.env(API key, model name) - Create window with 1000x700 pixels
- Apply dark theme for terminal aesthetics
- Initialize TerminalApp which contains all the logic
- Start event loop that listens for user input
What happens when the terminal starts?
impl TerminalApp {
fn new() -> Self {
// 1. Get current directory
let current_dir = env::current_dir().to_string_lossy().to_string();
// 2. Get user info
let username = env::var("USER").unwrap_or("user".to_string());
let hostname = get_hostname();
// 3. Initialize data structures
let mut app = Self {
lines: VecDeque::new(), // Terminal output
input_buffer: String::new(), // What you're typing
cursor_pos: 0, // Where cursor is
command_history: Vec::new(), // Previous commands
common_commands: vec![...], // 200+ common commands
ai: AIAssistant::new(), // AI engine
rt: tokio::runtime::Runtime::new(), // Async runtime
// ... more fields
};
// 4. Scan system for available commands
app.scan_path_commands();
// 5. Show welcome message
app.add_system_info();
// 6. Show first prompt
app.show_prompt();
app
}
}Think of it like setting up a workspace:
- ๐ Find where you are (current directory)
- ๐ค Know who you are (username/hostname)
- ๐ Prepare notepad (terminal lines buffer)
- ๐ Scan available tools (system commands)
- ๐ Say hello (welcome message)
โถ๏ธ Ready for input (show prompt)
When you type and press Enter:
User Input: "list all files"
โ
Step 1: Is it a built-in command? (help, clear, cd, exit, etc.)
โ NO
Step 2: Is it a direct system command? (ls, git, python, etc.)
โ NO
Step 3: Is it instant-pattern-matched? ("list all files" โ "ls -la")
โ YES!
Step 4: Execute "ls -la"
โ
Step 5: Capture output
โ
Step 6: Display in terminal
Code flow:
fn execute_command(&mut self, command: &str) {
let parts = self.parse_command_with_quotes(command);
let cmd_name = parts[0];
let args = parts[1..];
// Built-in commands
match cmd_name {
"help" => self.show_help(),
"clear" => self.lines.clear(),
"cd" => self.change_directory(&args),
"exit" => std::process::exit(0),
_ => {
// External command - try to execute
let output = Command::new(&cmd_name)
.args(&args)
.current_dir(&self.current_dir)
.output();
match output {
Ok(result) => self.display_output(result),
Err(_) => {
// Not found! Try AI interpretation
let ai_result = self.ai.generate_command(command);
self.execute_ai_suggested_command(ai_result);
}
}
}
}
}What is OpenRouter? OpenRouter is a unified API gateway that provides access to multiple AI models. We use Google's Gemini 2.0 Flash Experimental (free tier) to convert natural language to shell commands.
API Details:
- Endpoint:
https://openrouter.ai/api/v1/chat/completions - Model:
google/gemini-2.0-flash-exp:free - Context Window: 1,048,576 tokens (1M!)
- Cost: $0.00 (Free tier with rate limits)
- Authentication: Bearer token (API key)
Request Structure:
{
"model": "google/gemini-2.0-flash-exp:free",
"messages": [
{
"role": "system",
"content": "You are a helpful assistant that converts natural language to Linux commands."
},
{
"role": "user",
"content": "Convert natural language to Linux command. Return ONLY the command.\n\nInput: list all files\nOutput:"
}
]
}Response Structure:
{
"choices": [
{
"message": {
"role": "assistant",
"content": "ls -la"
}
}
]
}Three-Layer Performance Optimization:
Layer 1: INSTANT PATTERNS (0ms)
โโ "list files" โ "ls"
โโ "go home" โ "cd ~"
โโ "clear screen" โ "clear"
Layer 2: RESPONSE CACHE (5-minute TTL)
โโ "create folder test" โ "mkdir test" (cached for 5 min)
โโ "remove old-data" โ "rm -r old-data" (cached for 5 min)
Layer 3: AI API CALL (500-2000ms)
โโ Novel/complex requests go to OpenRouter
Code implementation:
pub async fn generate_command(&self, input: &str) -> Result<String> {
// LAYER 1: Instant patterns (local HashMap lookup)
if let Some(cmd) = self.get_local_command(input) {
return Ok(cmd); // Returns in <1ms!
}
// LAYER 2: Check 5-minute cache
if let Some(cached) = self.get_cached_response(input) {
return Ok(cached); // Returns in <1ms!
}
// LAYER 3: Make API call
let response = self.client
.post(OPENROUTER_URL)
.header("Authorization", format!("Bearer {}", api_key))
.json(&request)
.send()
.await?;
let command = extract_command_from_response(response);
// Cache for future use
self.cache_response(input, &command);
Ok(command)
}Transient errors (network issues, rate limits) are automatically retried:
// Retry up to 3 times with exponential backoff
for attempt in 0..3 {
match self.client.post(OPENROUTER_URL).send().await {
Ok(response) if response.status() == 429 => {
// Rate limited - wait and retry
let backoff_ms = match attempt {
0 => 300, // First retry: 300ms
1 => 800, // Second retry: 800ms
_ => 0
};
sleep(Duration::from_millis(backoff_ms)).await;
continue; // Try again
}
Ok(response) => return Ok(response), // Success!
Err(e) => last_error = e, // Network error - retry
}
}
// All retries failed
Err(last_error)User-friendly error messages:
if error.contains("429") || error.contains("rate-limited") {
show_message("๐ฆ You're being rate-limited by the free model.");
show_message(" โข Wait a few seconds and try again");
show_message(" โข Or add your own OpenRouter key");
} else if error.contains("timeout") {
show_message("โฐ AI timed out. Try again.");
} else {
show_message(&format!("โ Error: {}", error));
}Purpose: Initialize the entire terminal application with all necessary components.
What it does:
- Gets current directory and user info
- Initializes all data structures (output buffer, history, etc.)
- Loads 200+ common command names
- Scans system PATH for available executables
- Creates AI assistant instance
- Shows welcome banner
Analogy: Like a chef preparing their kitchen before opening the restaurant.
fn new() -> Self {
// Get environment info
let current_dir = env::current_dir().to_string_lossy().to_string();
let username = env::var("USER").unwrap_or("user".to_string());
// Create terminal with empty state
let mut app = Self {
lines: VecDeque::new(),
input_buffer: String::new(),
command_history: Vec::new(),
ai: AIAssistant::new(),
// ...
};
// Setup autocomplete database
app.scan_path_commands();
// Show welcome
app.add_system_info();
app.show_prompt();
app
}Purpose: Called 60 times per second to render the UI and handle input.
Parameters:
&mut self- Mutable reference to terminal statectx: &egui::Context- GUI rendering context_frame: &mut eframe::Frame- Window frame
What it does:
- Renders terminal output lines
- Processes keyboard input (Enter, Backspace, arrows)
- Handles clipboard operations (Ctrl+C/V/X)
- Manages cursor blinking animation
- Updates autocomplete suggestions
Analogy: Like a movie running at 60 frames per second, constantly checking "what's new?"
fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) {
// Request continuous repainting for cursor blink
ctx.request_repaint_after(Duration::from_millis(500));
egui::CentralPanel::default().show(ctx, |ui| {
// Display all output lines
for line in &self.lines {
ui.label(&line.text);
}
// Handle keyboard input
if ctx.input(|i| i.key_pressed(Key::Enter)) {
self.execute_command(&self.input_buffer.clone());
}
if ctx.input(|i| i.key_pressed(Key::Backspace)) {
self.input_buffer.pop();
}
// Handle clipboard
if ctx.input(|i| i.modifiers.ctrl && i.key_pressed(Key::C)) {
self.copy_to_clipboard();
}
});
}Purpose: Central hub that decides how to handle user input.
Parameters:
&mut self- Terminal statecommand: &str- Raw input from user
Returns: Nothing (mutates state, displays output)
Decision tree:
Is it "help"? โ Show help menu
Is it "clear"? โ Clear screen
Is it "cd"? โ Change directory
Is it "exit"? โ Close program
Is it executable? โ Run it
Command not found? โ Try AI interpretation
Code:
fn execute_command(&mut self, command: &str) {
let parts = self.parse_command_with_quotes(command);
let cmd_name = parts[0];
match cmd_name {
"help" => self.show_help(),
"clear" => self.lines.clear(),
"cd" => self.change_directory(&parts[1..]),
"exit" => std::process::exit(0),
_ => {
// Try to execute as system command
match Command::new(&cmd_name).args(&parts[1..]).output() {
Ok(output) => self.display_output(output),
Err(_) => {
// Not found - try AI
let ai_cmd = self.rt.block_on(
self.ai.generate_command(command)
);
self.execute_ai_command(ai_cmd);
}
}
}
}
}Purpose: Protect users from accidentally destroying their system.
Parameters:
&self- Terminal referencecommand: &str- Command to validate
Returns: Option<String> - Warning message if dangerous, None if safe
Dangerous patterns detected:
rm -rf /- Deletes entire filesystemrm -rf ~- Deletes home directory:(){ :|:& };:- Fork bomb (crashes system)mkfs- Formats disk (destroys data)dd if=- Direct disk write
Example:
fn is_dangerous_command(&self, command: &str) -> Option<String> {
let cmd_lower = command.to_lowercase();
if cmd_lower.contains("rm -rf /") {
return Some("โ ๏ธ CRITICAL: This would delete your ENTIRE system!");
}
if cmd_lower.contains(":(){ :|:& };:") {
return Some("โ ๏ธ Fork bomb detected! This would crash your system!");
}
None // Safe
}Purpose: Split command into parts while respecting quoted strings.
Why needed?
Simple split_whitespace() breaks on filenames with spaces:
- โ
rm "my file.txt"โ["rm", "\"my", "file.txt\""](WRONG!) - โ
rm "my file.txt"โ["rm", "my file.txt"](CORRECT!)
Example:
fn parse_command_with_quotes(&self, command: &str) -> Vec<String> {
let mut parts = Vec::new();
let mut current = String::new();
let mut in_quotes = false;
for ch in command.chars() {
match ch {
'"' | '\'' if !in_quotes => in_quotes = true,
'"' | '\'' if in_quotes => in_quotes = false,
' ' if !in_quotes => {
if !current.is_empty() {
parts.push(current.clone());
current.clear();
}
}
_ => current.push(ch),
}
}
if !current.is_empty() {
parts.push(current);
}
parts
}Test cases:
Input: rm "my file.txt"
Output: ["rm", "my file.txt"]
Input: echo 'Hello World'
Output: ["echo", "Hello World"]
Input: ls -la /home
Output: ["ls", "-la", "/home"]
Purpose: Create and configure the AI assistant with all optimizations.
What it sets up:
- HTTP client with connection pooling (20 max connections, 60s keepalive)
- 5-minute response cache (HashMap)
- Local pattern dictionary (100+ instant commands)
- Async communication channel
Think of it like: Building a super-fast delivery system with shortcuts!
pub fn new() -> Self {
// Ultra-fast HTTP client
let client = reqwest::Client::builder()
.timeout(Duration::from_secs(5))
.pool_max_idle_per_host(20)
.tcp_keepalive(Duration::from_secs(60))
.build()
.expect("Failed to build HTTP client");
// Instant-response patterns
let mut local_commands = HashMap::new();
local_commands.insert("list files", "ls");
local_commands.insert("list all files", "ls -la");
local_commands.insert("go home", "cd ~");
// ... 100+ more patterns
Self {
client,
cache: Arc::new(Mutex::new(HashMap::new())),
local_commands,
}
}Purpose: Detect and reject random/meaningless input before making expensive API calls.
Detection strategies:
- Too short: Less than 2 characters
- No vowels: "sdfghj" has no vowels = gibberish
- Repeated characters: "aaaaa" or "asdasdasd"
- Uncommon patterns: "qweasd", "zxcfgh"
- Incoherent phrases: "how hello", "what is the"
- Short nonsense tokens: 3-5 letter words not in common word list
Example:
pub fn is_gibberish(input: &str) -> bool {
let input = input.trim().to_lowercase();
// Too short
if input.len() < 2 { return true; }
// Allow meaningful words
let meaningful = ["open", "list", "show", "create", "remove"];
if meaningful.iter().any(|&w| input.contains(w)) {
return false;
}
// Check for single-word 3-5 letter nonsense
let words: Vec<&str> = input.split_whitespace().collect();
if words.len() == 1 {
let word = words[0];
if (3..=5).contains(&word.len()) {
let common = ["list", "show", "open", "help", "view"];
if !common.contains(&word) {
return true; // "adsa", "qwer" = gibberish!
}
}
}
// Check vowel ratio
let vowels = input.chars().filter(|&c| "aeiou".contains(c)).count();
let consonants = input.chars().filter(|&c| c.is_alphabetic() && !"aeiou".contains(c)).count();
if consonants > 0 && (vowels == 0 || consonants as f32 / vowels as f32 > 4.0) {
return true; // "sdfghj" has no vowels
}
false
}Test cases:
"adsa" โ true (gibberish)
"qwer" โ true (gibberish)
"sdfghj" โ true (no vowels)
"list files" โ false (valid)
"show me" โ false (valid)
Purpose: Convert natural language to shell commands using smart caching and AI.
Parameters:
&self- AI assistant referencenatural_input: &str- User's English request
Returns: Result<String, Error> - Shell command or error
Step-by-step flow:
Step 1: Check if gibberish
โ NO
Step 2: Check local patterns (instant)
โ NOT FOUND
Step 3: Check 5-minute cache
โ NOT FOUND
Step 4: Make API call to OpenRouter
โ
Step 5: Parse JSON response
โ
Step 6: Validate command
โ
Step 7: Cache result
โ
Step 8: Return command
Code with retry logic:
pub async fn generate_command(&self, natural_input: &str) -> Result<String> {
// FILTER: Reject gibberish
if Self::is_gibberish(natural_input) {
return Err("I don't understand that input.");
}
// OPTIMIZATION 1: Instant patterns
if let Some(cmd) = self.get_local_command(natural_input) {
return Ok(cmd);
}
// OPTIMIZATION 2: Cache lookup
if let Some(cached) = self.get_cached_response(natural_input) {
return Ok(cached);
}
// LAST RESORT: API call with retry logic
for attempt in 0..3 {
let response = self.client
.post(OPENROUTER_URL)
.header("Authorization", format!("Bearer {}", api_key))
.json(&request)
.send()
.await;
match response {
Ok(resp) if resp.status() == 200 => {
let command = extract_command(resp);
self.cache_response(natural_input, &command);
return Ok(command);
}
Ok(resp) if resp.status() == 429 => {
// Rate limited - retry with backoff
sleep(Duration::from_millis(300 * (attempt + 1))).await;
continue;
}
Err(e) => return Err(e),
}
}
Err("Max retries exceeded")
}Purpose: Ensure AI-generated response is actually an executable command, not hallucination.
Validation checks:
- Not empty
- Remove code fences (
bash) - First token is executable in PATH or known builtin
- Reject sentence-like patterns
Example:
fn looks_like_valid_command(command: &str) -> bool {
let cleaned = command
.trim_start_matches("```bash")
.trim_start_matches("```")
.trim_end_matches("```")
.trim();
let first_token = cleaned.split_whitespace().next().unwrap_or("");
// Allow known builtins
if ["cd", "cursor", "code"].contains(&first_token) {
return true;
}
// Check if executable exists in PATH
if let Ok(path) = env::var("PATH") {
for dir in path.split(':') {
let exe_path = Path::new(dir).join(first_token);
if exe_path.is_file() && is_executable(&exe_path) {
return true;
}
}
}
false
}Test cases:
"ls -la" โ true (ls is in PATH)
"cd /home" โ true (builtin)
"cursor ." โ true (allowlist)
"this is a sentence" โ false (not executable)
"Hello world" โ false (not a command)
Let's trace what happens when you type "view hai.py" and press Enter:
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ 1. USER TYPES: "view hai.py" โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ 2. GUI CAPTURES INPUT (update function) โ
โ - Every keystroke updates input_buffer โ
โ - Enter key detected โ trigger execute_command() โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ 3. PARSE COMMAND (parse_command_with_quotes) โ
โ Result: ["view", "hai.py"] โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ 4. CHECK BUILT-IN COMMANDS โ
โ "view" โ Not in [help, clear, cd, exit, pwd] โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ 5. TRY SYSTEM COMMAND โ
โ Command::new("view").arg("hai.py") โ NOT FOUND! โ
โ (view is not a standard Linux command) โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ 6. CHECK INSTANT PATTERNS โ
โ AIAssistant::get_instant_command("view hai.py") โ
โ โ No instant match โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ 7. AI INTERPRETATION โ
โ - Check gibberish: "view hai.py" โ VALID โ
โ - Check local patterns: "view file" โ "view" โ
โ - Pattern matched! Return "view hai.py" โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ 8. VALIDATE AI RESPONSE โ
โ - Not dangerous command โ โ
โ - Looks executable โ โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ 9. EXECUTE "view hai.py" (Built-in handler) โ
โ - Check if file exists โ
โ - Read file contents โ
โ - Add line numbers โ
โ - Detect syntax (Python) โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ 10. DISPLAY OUTPUT โ
โ ๐ hai.py (Python, 45 bytes) โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โ 1 | print("Hello World") โ
โ 2 | x = 42 โ
โ 3 | print(f"The answer is {x}") โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ 11. UPDATE TERMINAL STATE โ
โ - Add output lines to display buffer โ
โ - Save "view hai.py" to command history โ
โ - Clear input buffer โ
โ - Show new prompt โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
Example: "list files"
Input: "list files"
โ
get_instant_command() lookup
โ
HashMap["list files"] = "ls"
โ
Execute "ls" directly
โ
Display results
Total time: < 1 millisecond!
Example: "show me what's in config.txt"
Input: "show me what's in config.txt"
โ
Not in instant patterns
โ
Not in 5-minute cache
โ
Make API call to OpenRouter
โ (500-2000ms network delay)
Parse JSON: "view config.txt"
โ
Validate command
โ
Cache for 5 minutes
โ
Execute "view config.txt"
โ
Display file contents
Total time: ~1 second (first time)
Next time: < 1ms (cached!)
| Crate | Version | Purpose |
|---|---|---|
eframe |
0.28 | GUI framework (windowing, rendering) |
egui |
0.28 | Immediate-mode GUI library |
tokio |
1.0 | Async runtime for concurrent operations |
reqwest |
0.12 | HTTP client for API calls |
serde |
1.0 | JSON serialization/deserialization |
dotenvy |
0.15 | Environment variable loading from .env |
anyhow |
1.0 | Error handling utilities |
Why each one?
- eframe/egui: Modern, lightweight GUI that doesn't need Qt/GTK
- tokio: Enables non-blocking API calls (terminal stays responsive)
- reqwest: Industry-standard HTTP client with connection pooling
- serde: Parse JSON responses from OpenRouter API
- dotenvy: Keep API keys secure in .env file (not hardcoded)
# Install Rust (if not already installed)
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
# Verify installation
rustc --version # Should show 1.70+
cargo --versiongit clone https://github.com/zoxilsi/Linara-Terminal.git
cd Linara-TerminalCreate .env file in project root:
# .env file
OPENROUTER_API_KEY=sk-or-v1-YOUR_API_KEY_HERE
OPENROUTER_MODEL=google/gemini-2.0-flash-exp:freeGet your API key:
- Visit https://openrouter.ai/
- Sign up (free)
- Go to Settings โ Keys
- Create new key
- Copy to
.envfile
# Debug build (faster compile, slower runtime)
cargo build
cargo run
# Release build (slower compile, optimized runtime)
cargo build --release
./target/release/terminal-appExpected output:
Compiling terminal-app v0.1.0
Finished dev [unoptimized + debuginfo] target(s) in 45.2s
Running `target/debug/terminal-app`
Then the GUI window opens! ๐
FROM rust:1.70
WORKDIR /app
COPY . .
RUN cargo build --release
CMD ["./target/release/terminal-app"]# Traditional way
ls -la
# Natural language way
list all files
show me all files
what files are here# View file contents
view config.txt
show me what's in README.md
read package.json
# Create directories
mkdir test-folder
create folder my-project
make directory data
# Remove files/folders
rm old-file.txt
remove folder old-project
delete file temp.log# Change directory
cd /home/user/projects
go to home
go back
go up
# Show location
pwd
where am i
current location# Find files
find . -name "*.py"
search for python files
# Git operations
git status
git add .
git commit -m "Update"
show me git status# Clear screen
clear
clear screen
clean terminal
# View history
history
show command history
# Get help
help
explain ls
what is grepCtrl+C โ Copy selected text (or current line)
Ctrl+V โ Paste from clipboard
Ctrl+X โ Cut selected text
Shift+Arrows โ Select text
๐ user ๐ ~/projects ๐ฟ main
> list all files
โก ls -la
total 48
drwxr-xr-x 6 user user 4096 Oct 5 10:30 .
drwxr-xr-x 12 user user 4096 Oct 5 09:15 ..
-rw-r--r-- 1 user user 256 Oct 5 10:25 config.txt
drwxr-xr-x 8 user user 4096 Oct 5 10:30 .git
๐ user ๐ ~/projects ๐ฟ main
> view config.txt
๐ config.txt (Text, 256 bytes)
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
1 | app_name=MyApp
2 | version=1.0.0
3 | debug=true
๐ user ๐ ~/projects ๐ฟ main
> create folder test
โก mkdir test
โ
Command executed successfully
๐ user ๐ ~/projects ๐ฟ main
> go to test
โ
Directory changed
๐ user ๐ .../projects/test ๐ฟ main
>
Imagine you're ordering pizza, but you don't speak "pizza language" fluently. Linara Terminal is like having a smart translator!
Traditional Terminal (No Translator):
You: "I want a large pepperoni pizza"
Terminal: "Error: command not found"
You: ๐ข *has to learn the exact code: ORDER_PIZZA --size=L --topping=pepperoni*
Linara Terminal (With AI Translator):
You: "I want a large pepperoni pizza"
Translator: "Oh! You mean: ORDER_PIZZA --size=L --topping=pepperoni"
Terminal: "โ
Pizza ordered!"
You: ๐
Think of it like a LEGO building system:
- The Window (GUI) = The building table where you see everything
- Your Words (Input) = The LEGO pieces you want to use
- The Smart Helper (AI) = Friend who knows which pieces to use
- The Computer (System) = The instruction manual that builds stuff
Story Example:
You say: "Show me my toys"
- Window hears you
- Smart Helper thinks: "Hmm, 'show toys' = look in the toy box"
- Smart Helper says: "Use the
lscommand!" (like saying "open toy box") - Computer opens the toy box
- Window shows you: ๐ ๐งธ ๐ฎ ๐จ
Trick 1: The Memory Shortcut (Cache)
- If you ask the same question twice, it remembers the answer!
- Like asking "Where are my shoes?" โ Mom remembers you left them by the door
Trick 2: The Pattern Book (Local Commands)
- Common phrases have instant translations
- "list files" always means "ls" (like "hello" always means ๐)
Trick 3: The Smart Brain (AI API)
- For new questions, asks a super-smart robot (Gemini AI)
- Robot knows EVERY command in existence!
Like a parent saying "Don't touch the hot stove!"
If you try dangerous commands:
You: "delete everything"
Safety Guard: "โ ๏ธ STOP! That would delete your whole computer!"
Terminal: *blocks the command*
Protected from:
- Deleting important files
- Breaking your system
- Typing gibberish that makes no sense
-
Command Prediction
- Analyze history to predict next command
- Pre-fetch autocomplete suggestions in background
-
Smarter Caching
- Increase cache TTL to 30 minutes
- Add persistent cache (save to disk)
-
Parallel Execution
- Run multiple commands simultaneously
- Background tasks with progress bars
-
Syntax Highlighting
- Color code different command parts
- Highlight errors in red
-
Themes
- Light/dark mode toggle
- Custom color schemes (Dracula, Monokai, etc.)
-
Split Panes
- Multiple terminals in one window
- Tabs for different sessions
-
Multi-Model Support
- Switch between GPT-4, Claude, Gemini
- Fallback to backup model if primary fails
-
Context Awareness
- Remember previous commands in conversation
- "do it again" = repeat last command
-
Error Auto-Fix
- Detect command errors
- Suggest corrections automatically
-
Command Whitelist
- Admin approval for dangerous commands
- Sandboxed execution mode
-
Audit Logging
- Track all executed commands
- Export to file for review
-
Encrypted Secrets
- Store API keys in system keyring
- Auto-rotate credentials
-
Cloud Sync
- Sync history across devices
- Share command aliases with team
-
Plugin System
- Custom command handlers
- Third-party extensions
-
Remote Execution
- SSH into servers
- Execute commands on multiple machines
-
Command Metrics
- Track most-used commands
- Time each command execution
-
AI Training
- Fine-tune model on your command history
- Personalized command suggestions
-
Script Generator
- Convert command sequences to bash scripts
- One-click script export
We welcome contributions! Here's how to get started:
- Check existing issues
- Create new issue with:
- Steps to reproduce
- Expected vs actual behavior
- Terminal output / screenshots
- Open discussion in Issues
- Describe use case
- Propose implementation approach
- Fork the repository
- Create feature branch:
git checkout -b feature/amazing-feature - Make changes
- Test thoroughly
- Commit:
git commit -m "Add amazing feature" - Push:
git push origin feature/amazing-feature - Open Pull Request
- Follow Rust conventions (
cargo fmt) - Run linter (
cargo clippy) - Add tests for new features
- Update documentation
MIT License - See LICENSE file for details.
- egui - Amazing immediate-mode GUI framework
- OpenRouter - Unified API gateway for AI models
- Google Gemini - Powerful language model
- Rust Community - Best programming community ever!
- ๐ Bug Reports: GitHub Issues
- ๐ฌ Discussions: GitHub Discussions
- ๐ง Email: support@linara-terminal.dev
Made with โค๏ธ and ๐ฆ Rust
โญ Star this repo if you find it useful!