skillZs
★ LIVE SKILL TAGS ★
>>> LIVE SKILLS INDEX <<<
* OPEN SOURCE *
NO LOGIN, NO TRACKING
※ REAL INSTALL DATA ※
← back to all skills
reason-machines/hermes-skills132 installs

hermes-ide-terminal

AI-native terminal emulator & IDE built with Tauri, React, and Rust

How do I install this agent skill?

npx skills add https://github.com/reason-machines/hermes-skills --skill hermes-ide-terminal
view source ↗

Is this agent skill safe to install?

  • Gen Agent Trust Hubpass

    The Hermes IDE Terminal skill provides documentation and setup instructions for an AI-native terminal emulator. It includes standard development procedures such as installing the Rust toolchain via the official rustup.rs script and configuring the Anthropic CLI for agent capabilities. The skill describes an automated project scanning feature that analyzes codebase structure to provide context for AI interactions. No malicious patterns were detected; all identified behaviors are consistent with the documented purpose of an IDE development environment.

  • Socketpass

    No alerts

  • Snykpass

    Risk: LOW · No issues

What does this agent skill do?

Hermes IDE Terminal Skill

Skill by ara.so — Hermes Skills collection.

Overview

Hermes IDE is an AI-native terminal emulator built with Tauri 2, React 18, and Rust. It provides:

  • Agent mode for Claude with rich chat interface, image support, and persistent conversations
  • Multi-session terminal management with split panes and WebGL rendering
  • Git integration with built-in panel for staging, commits, and inline diffs
  • AI intelligence including ghost-text suggestions, prompt composer, and error pattern matching
  • Project awareness that scans your codebase to build context for AI agents
  • Cross-platform support for macOS, Windows, and Linux

Installation

Pre-built Binaries

Download from the official website:

# Visit https://www.hermes-ide.com/download
# Choose your platform: macOS (Intel/Apple Silicon), Windows, Linux (.deb/.AppImage/.rpm)

Build from Source

Prerequisites:

# Check versions
node --version  # 18+
rustc --version # 1.70+

Platform-specific dependencies:

# Linux (Debian/Ubuntu)
sudo apt install libwebkit2gtk-4.1-dev libappindicator3-dev librsvg2-dev patchelf

# macOS
xcode-select --install

# Windows
# Install Visual Studio Build Tools with "Desktop development with C++"
# Install WebView2 Runtime from Microsoft

Clone and build:

git clone https://github.com/hermes-hq/hermes-ide.git
cd hermes-ide
npm install
npm run tauri dev    # Development mode with hot-reload
npm run tauri build  # Production build

Architecture

Hermes IDE uses a layered architecture:

React Frontend (TypeScript) ← Tauri IPC Bridge → Rust Backend
     UI & State                                   PTY, DB, Scanner

Key directories:

  • src/ - React/TypeScript frontend (components, hooks, state, terminal)
  • src-tauri/ - Rust backend (PTY management, SQLite, project scanning)
  • src/api/ - Tauri IPC command wrappers
  • src/terminal/ - Terminal pool & AI intelligence engine

Configuration

Claude Agent Setup

Hermes uses your existing claude CLI authentication:

# Install Claude CLI first
npm install -g @anthropic-ai/claude-cli

# Authenticate (choose one method)
claude auth login              # Pro/Max account
claude auth api-key $ANTHROPIC_API_KEY  # API key

In Hermes IDE:

  1. Open Command Palette (Cmd/Ctrl+K)
  2. Type "Claude"
  3. Select "Start Claude Agent Session"
  4. Conversations persist across restarts

Project Scanning

Hermes automatically scans projects to build AI context:

// Project scanning happens automatically when you:
// 1. Open a terminal in a directory
// 2. Attach a project via sidebar
// 3. Use Cmd/Ctrl+Shift+P → "Scan Project"

// Detected information includes:
// - Languages and frameworks
// - Project structure
// - Dependencies
// - Git repository info

Terminal Configuration

Configure shell and environment in settings:

{
  "shell": {
    "program": "/bin/zsh",
    "args": ["-l"]
  },
  "environment": {
    "TERM": "xterm-256color",
    "COLORTERM": "truecolor"
  },
  "fontSize": 14,
  "fontFamily": "JetBrains Mono, monospace"
}

Key Features & Usage

Terminal Sessions

// Create new session
// Cmd/Ctrl+T

// Switch sessions
// Cmd/Ctrl+1-9 (first 9 sessions)
// Or use sidebar

// Split panes
// Cmd/Ctrl+D (horizontal)
// Cmd/Ctrl+Shift+D (vertical)

// Close session
// Cmd/Ctrl+W

Git Integration

Access via sidebar panel:

# All git operations available via UI
# - View staged/unstaged/untracked files
# - Click files to see inline diffs
# - Stage/unstage with checkboxes
# - Commit with message input
# - Push/Pull buttons

# Or use git commands directly in terminal
git add .
git commit -m "feat: add new feature"
git push origin main

AI Ghost-Text Suggestions

Hermes provides real-time command suggestions:

# Start typing and ghost text appears
git com█
# Suggestion: git commit -m "message"

# Accept with Tab or Right Arrow
# Reject with Esc or continue typing

Prompt Composer

Use natural language for autonomous execution:

# Open Prompt Composer: Cmd/Ctrl+Shift+P
# Type natural language instructions:

"Create a new React component called UserProfile with TypeScript"
"Fix all eslint errors in src/"
"Run tests and commit if they pass"

# Hermes executes commands and tracks progress

Command Palette

Access all features quickly:

# Open: Cmd/Ctrl+K
# Fuzzy search for:
# - Commands
# - Settings
# - Projects
# - Sessions
# - Git operations

Development Workflow

Frontend Development

// src/components/Terminal.tsx
import React, { useEffect, useRef } from 'react';
import { Terminal } from 'xterm';
import { FitAddon } from 'xterm-addon-fit';

export const TerminalComponent: React.FC = () => {
  const terminalRef = useRef<HTMLDivElement>(null);
  const xtermRef = useRef<Terminal | null>(null);

  useEffect(() => {
    if (!terminalRef.current) return;

    const term = new Terminal({
      fontFamily: 'JetBrains Mono, monospace',
      fontSize: 14,
      theme: {
        background: '#1e1e1e',
        foreground: '#d4d4d4',
      },
    });

    const fitAddon = new FitAddon();
    term.loadAddon(fitAddon);
    term.open(terminalRef.current);
    fitAddon.fit();

    xtermRef.current = term;

    return () => {
      term.dispose();
    };
  }, []);

  return <div ref={terminalRef} className="terminal-container" />;
};

Backend Development

// src-tauri/src/pty/mod.rs
use portable_pty::{native_pty_system, CommandBuilder, PtySize};
use std::sync::Arc;
use tokio::sync::Mutex;

pub struct PtySession {
    pub id: String,
    pty: Arc<Mutex<Box<dyn portable_pty::MasterPty + Send>>>,
    writer: Arc<Mutex<Box<dyn std::io::Write + Send>>>,
}

impl PtySession {
    pub fn new(shell: &str, cwd: &str) -> Result<Self, Box<dyn std::error::Error>> {
        let pty_system = native_pty_system();
        let pair = pty_system.openpty(PtySize {
            rows: 24,
            cols: 80,
            pixel_width: 0,
            pixel_height: 0,
        })?;

        let mut cmd = CommandBuilder::new(shell);
        cmd.cwd(cwd);
        
        let _child = pair.slave.spawn_command(cmd)?;
        let writer = pair.master.take_writer()?;

        Ok(Self {
            id: uuid::Uuid::new_v4().to_string(),
            pty: Arc::new(Mutex::new(pair.master)),
            writer: Arc::new(Mutex::new(writer)),
        })
    }

    pub async fn write(&self, data: &[u8]) -> Result<(), Box<dyn std::error::Error>> {
        let mut writer = self.writer.lock().await;
        writer.write_all(data)?;
        writer.flush()?;
        Ok(())
    }
}

Tauri IPC Commands

// src-tauri/src/commands.rs
use tauri::command;

#[command]
pub async fn create_terminal_session(
    shell: String,
    cwd: String,
) -> Result<String, String> {
    let session = PtySession::new(&shell, &cwd)
        .map_err(|e| e.to_string())?;
    
    let session_id = session.id.clone();
    
    // Store session in global state
    // ...
    
    Ok(session_id)
}

#[command]
pub async fn write_to_terminal(
    session_id: String,
    data: String,
) -> Result<(), String> {
    // Get session from global state
    // ...
    
    session.write(data.as_bytes())
        .await
        .map_err(|e| e.to_string())?;
    
    Ok(())
}

Frontend API Wrappers

// src/api/terminal.ts
import { invoke } from '@tauri-apps/api/tauri';

export interface TerminalSession {
  id: string;
  cwd: string;
  shell: string;
}

export async function createTerminalSession(
  shell: string,
  cwd: string
): Promise<string> {
  return await invoke<string>('create_terminal_session', {
    shell,
    cwd,
  });
}

export async function writeToTerminal(
  sessionId: string,
  data: string
): Promise<void> {
  await invoke('write_to_terminal', {
    sessionId,
    data,
  });
}

export async function resizeTerminal(
  sessionId: string,
  rows: number,
  cols: number
): Promise<void> {
  await invoke('resize_terminal', {
    sessionId,
    rows,
    cols,
  });
}

Common Patterns

State Management

Hermes uses React Context + useReducer:

// src/state/AppContext.tsx
import React, { createContext, useReducer } from 'react';

interface AppState {
  sessions: TerminalSession[];
  activeSessionId: string | null;
  projects: Project[];
}

type AppAction =
  | { type: 'ADD_SESSION'; session: TerminalSession }
  | { type: 'REMOVE_SESSION'; sessionId: string }
  | { type: 'SET_ACTIVE_SESSION'; sessionId: string };

const appReducer = (state: AppState, action: AppAction): AppState => {
  switch (action.type) {
    case 'ADD_SESSION':
      return {
        ...state,
        sessions: [...state.sessions, action.session],
      };
    case 'REMOVE_SESSION':
      return {
        ...state,
        sessions: state.sessions.filter(s => s.id !== action.sessionId),
      };
    case 'SET_ACTIVE_SESSION':
      return {
        ...state,
        activeSessionId: action.sessionId,
      };
    default:
      return state;
  }
};

export const AppContext = createContext<{
  state: AppState;
  dispatch: React.Dispatch<AppAction>;
} | null>(null);

export const AppProvider: React.FC = ({ children }) => {
  const [state, dispatch] = useReducer(appReducer, {
    sessions: [],
    activeSessionId: null,
    projects: [],
  });

  return (
    <AppContext.Provider value={{ state, dispatch }}>
      {children}
    </AppContext.Provider>
  );
};

Custom Hooks

// src/hooks/useTerminal.ts
import { useContext, useCallback } from 'react';
import { AppContext } from '../state/AppContext';
import { createTerminalSession, writeToTerminal } from '../api/terminal';

export const useTerminal = () => {
  const context = useContext(AppContext);
  if (!context) throw new Error('useTerminal must be used within AppProvider');

  const { state, dispatch } = context;

  const createSession = useCallback(async (shell: string, cwd: string) => {
    const sessionId = await createTerminalSession(shell, cwd);
    dispatch({
      type: 'ADD_SESSION',
      session: { id: sessionId, shell, cwd },
    });
    dispatch({ type: 'SET_ACTIVE_SESSION', sessionId });
    return sessionId;
  }, [dispatch]);

  const write = useCallback(async (data: string) => {
    if (!state.activeSessionId) return;
    await writeToTerminal(state.activeSessionId, data);
  }, [state.activeSessionId]);

  return {
    sessions: state.sessions,
    activeSessionId: state.activeSessionId,
    createSession,
    write,
  };
};

Project Scanning

// src-tauri/src/project/scanner.rs
use std::path::Path;
use walkdir::WalkDir;
use serde::{Serialize, Deserialize};

#[derive(Serialize, Deserialize)]
pub struct ProjectContext {
    pub languages: Vec<String>,
    pub frameworks: Vec<String>,
    pub dependencies: Vec<String>,
    pub structure: String,
}

pub fn scan_project(path: &Path) -> Result<ProjectContext, Box<dyn std::error::Error>> {
    let mut languages = Vec::new();
    let mut frameworks = Vec::new();
    let mut dependencies = Vec::new();

    // Detect package.json (Node.js)
    if path.join("package.json").exists() {
        languages.push("JavaScript".to_string());
        let package_json = std::fs::read_to_string(path.join("package.json"))?;
        let package: serde_json::Value = serde_json::from_str(&package_json)?;
        
        if let Some(deps) = package.get("dependencies") {
            if deps.get("react").is_some() {
                frameworks.push("React".to_string());
            }
            if deps.get("vue").is_some() {
                frameworks.push("Vue".to_string());
            }
        }
    }

    // Detect Cargo.toml (Rust)
    if path.join("Cargo.toml").exists() {
        languages.push("Rust".to_string());
    }

    // Count files by type for structure summary
    let mut file_counts = std::collections::HashMap::new();
    for entry in WalkDir::new(path).max_depth(3) {
        if let Ok(entry) = entry {
            if let Some(ext) = entry.path().extension() {
                *file_counts.entry(ext.to_string_lossy().to_string()).or_insert(0) += 1;
            }
        }
    }

    Ok(ProjectContext {
        languages,
        frameworks,
        dependencies,
        structure: format!("{:?}", file_counts),
    })
}

Testing

Frontend Tests

# Run all tests
npm run test

# Run with coverage
npm run test:coverage

# Watch mode
npm run test:watch
// src/components/__tests__/Terminal.test.tsx
import { render, screen } from '@testing-library/react';
import { TerminalComponent } from '../Terminal';

describe('TerminalComponent', () => {
  it('renders terminal container', () => {
    render(<TerminalComponent />);
    const container = screen.getByClassName('terminal-container');
    expect(container).toBeInTheDocument();
  });
});

Backend Tests

cd src-tauri
cargo test
cargo test -- --nocapture  # Show output
#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_pty_session_creation() {
        let session = PtySession::new("/bin/bash", "/tmp");
        assert!(session.is_ok());
        let session = session.unwrap();
        assert!(!session.id.is_empty());
    }

    #[tokio::test]
    async fn test_write_to_pty() {
        let session = PtySession::new("/bin/bash", "/tmp").unwrap();
        let result = session.write(b"echo test\n").await;
        assert!(result.is_ok());
    }
}

Troubleshooting

Build Issues

Error: webkit2gtk not found

# Linux
sudo apt install libwebkit2gtk-4.1-dev

# If still failing, check pkg-config
pkg-config --modversion webkit2gtk-4.1

Error: Rust toolchain not found

curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
source $HOME/.cargo/env

Error: node-gyp failures on Windows

npm install --global windows-build-tools
npm config set msvs_version 2019

Runtime Issues

Terminal not rendering

// Check terminal element is mounted
useEffect(() => {
  console.log('Terminal ref:', terminalRef.current);
  if (!terminalRef.current) {
    console.error('Terminal container not found');
    return;
  }
  // ...
}, []);

PTY session hangs

// Add timeout to PTY operations
use tokio::time::{timeout, Duration};

let result = timeout(
    Duration::from_secs(5),
    session.write(data)
).await;

if result.is_err() {
    eprintln!("PTY write timed out");
}

Git authentication fails

# Check SSH agent
ssh-add -l

# Or use Git Credential Manager
git config --global credential.helper manager

# Set environment variable in Hermes settings
# GIT_SSH_COMMAND="ssh -i ~/.ssh/id_rsa"

Performance Issues

High CPU usage

# Check terminal rendering settings
# Reduce font size or disable ligatures
# Limit scrollback buffer size in settings

Memory leaks

// Ensure proper cleanup in useEffect
useEffect(() => {
  const term = new Terminal();
  // ...
  
  return () => {
    term.dispose();  // Critical!
  };
}, []);

Environment Variables

# Claude API configuration
export ANTHROPIC_API_KEY=sk-ant-...

# Custom shell
export HERMES_SHELL=/bin/zsh

# Debug logging
export RUST_LOG=debug
export HERMES_DEBUG=1

# Custom config directory
export HERMES_CONFIG_DIR=$HOME/.config/hermes

Contributing

# Fork and clone
git clone https://github.com/YOUR_USERNAME/hermes-ide.git
cd hermes-ide

# Create feature branch
git checkout -b feature/my-feature

# Make changes and test
npm run tauri dev
npm run test
cd src-tauri && cargo test

# Type check
npx tsc --noEmit

# Commit (follows conventional commits)
git commit -m "feat: add new terminal feature"

# Push and open PR
git push origin feature/my-feature

# Sign CLA when prompted

Read CONTRIBUTING.md and DESIGN_PRINCIPLES.md before contributing.

Resources

Add the canonical catalog link to the repository README so users can inspect current installs and available audits. The publishing guide covers the complete discovery path.

<a href="https://skillzs.dev/skills/reason-machines/hermes-skills/hermes-ide-terminal">View hermes-ide-terminal on skillZs</a>