# Terminals

**Page:** kit/terminals

[Download Raw Markdown](./kit/terminals.md)

---

# Terminals

**Your shell is a URL.** Execute commands via HTTP, share terminal sessions with a link, collaborate in real-time—no SSH keys, no configuration, just pure HTTP.

**Launch GUI applications instantly:** Type `firefox &` in the terminal and it appears in your browser via the matching [display URL](/kit/displays/). No setup. No configuration. Just type and see.

Every Hoody container includes **hoody-terminal**, transforming your Linux shell into a first-class web service accessible via HTTP endpoints.

---

## What You Can Do

**hoody-terminal** provides complete shell control through HTTP:

- **🌐 Web Terminal UI** - Full-featured browser terminal—replaces SSH for most use cases
- **🖥️ Launch GUI Apps Instantly** - Type `firefox &` and it appears in browser—zero configuration
- **⚡ Execute Commands** - Run any shell command via POST request, get `stdout`/`stderr`/exit codes
- **🔄 Persistent Sessions** - Stateful terminals that remember working directory and environment
- **👥 Multiplayer Sessions** - Multiple users typing in the same terminal simultaneously
- **📊 System Monitoring** - Query CPU, memory, disk, processes, ports via HTTP
- **📡 WebSocket Streaming** - Real-time output for long-running commands
- **📸 Screenshots** - Capture terminal state as PNG/JPEG/GIF


**Access & Security:**
- **Traditional SSH** - SSH connections for automation/advanced users. See [SSH →](/foundation/networking/ssh/)
- **SSH to Remote Servers** - Connect to other servers through the web UI using SSH parameters (no SSH client needed)
- **Proxy Permissions** - Control terminal access with IP whitelist, passwords, or JWT. See [Permissions →](/foundation/proxy/permissions/)


---

## API Endpoints Summary

**Official Technical Reference:**

For complete endpoint documentation with all parameters, responses, and examples:

**Command Execution:**
- **[POST /api/v1/terminal/execute](/api/terminal/commands/#post-apiv1terminalexecute)** - Execute shell commands
  - Body params: `command`, `id`, `timeout`, `wait`, `cwd` (per-command working directory), `env`
  - Query params: `terminal_id`, `cwd` (initial working directory for new/reset local sessions), `cwd_auto_create`, `shell`, `user`, `ssh_host`, `ssh_user`, `ssh_password`, `ssh_key`, `reset`
  - Modes: Synchronous (`wait: true`) or Asynchronous (`wait: false`)
- **[GET /api/v1/terminal/result/\{command_id\}](/api/terminal/commands/#get-apiv1terminalresultcommand_id)** - Poll async command result
  - Returns: `status`, `exit_code`, `stdout`, `stderr`, `duration_ms`
- **[POST /api/v1/terminal/execute/\{command_id\}/abort](/api/terminal/commands/#post-apiv1terminalexecutecommand_idabort)** - Abort a running command (SIGINT or force SIGKILL)
  - Body: `{ "force": false }`
- **[POST /api/v1/terminal/write](/api/terminal/commands/#post-apiv1terminalwrite)** - Type raw input into a session PTY (interactive prompts, y/n, sudo password)
  - Query params: `terminal_id`
  - Body: `{ "input": "text", "enter": true }` — raw byte injection as if typed at a keyboard

**Session Management:**
- **[POST /api/v1/terminal/create](/api/terminal/sessions/#post-apiv1terminalcreate)** - Explicitly create a terminal session
  - Query params: `terminal_id`, `shell`, `user`, `cwd`, `display`, `ssh_host`, ...
- **[GET /api/v1/terminal/sessions](/api/terminal/sessions/#get-apiv1terminalsessions)** - List all active sessions
  - Returns: Local and SSH sessions with status, resource usage, timestamps
- **[DELETE /api/v1/terminal/\{terminal_id\}](/api/terminal/sessions/#delete-apiv1terminalterminal_id)** - Terminate session
  - Kills all processes in the session
- **[GET /api/v1/terminal/history/\{terminal_id\}](/api/terminal/sessions/#get-apiv1terminalhistoryterminal_id)** - Command history
  - Returns: All commands with status, exit codes, duration
- **[GET /api/v1/terminal/raw](/api/terminal/sessions/#get-apiv1terminalraw)** - Export complete output
  - Query params: `terminal_id`, `format` (download|text|html)
- **[GET /api/v1/terminal/screenshot](/api/terminal/sessions/#get-apiv1terminalscreenshot)** - Visual terminal snapshot
  - Query params: `terminal_id`, `format` (png|jpeg|gif), `foreground`, `background`, `fontsize`

**Terminal Automation (TUI Control):**
- **[GET /api/v1/terminal/snapshot](/api/terminal/automation/#get-rendered-terminal-snapshot)** - Read rendered terminal screen (lines, cursor, fullscreen state)
  - Query params: `terminal_id`, `include_colors`, `include_highlights`, `scroll_offset`
- **[GET /api/v1/terminal/find](/api/terminal/automation/#search-terminal-screen-with-regex)** - PCRE2 regex search on screen/scrollback
  - Query params: `terminal_id`, `pattern`, `scope`, `limit`, `case_insensitive`
- **[POST /api/v1/terminal/press](/api/terminal/automation/#send-named-key-presses-to-terminal)** - Send named key presses (mode-aware DECCKM/DECKPAM)
  - Body: `{ "key": "enter" }` or `{ "keys": [...] }`
- **[POST /api/v1/terminal/paste](/api/terminal/automation/#paste-text-into-terminal)** - Bracketed paste with UTF-8 support
  - Body: `{ "text": "...", "bracketed": true }`
- **[POST /api/v1/terminal/wait](/api/terminal/automation/#wait-for-terminal-condition)** - Block until screen settles or regex matches, returns atomic snapshot
  - Body: `{ "mode": "stable|regex|either", "pattern": "...", "timeout_ms": 5000, "debounce_ms": 100 }`
- **[GET /api/v1/terminal/keys](/api/terminal/automation/#list-supported-key-names)** - List supported key names for `/press`
- **[GET /api/v1/terminal/automation/metrics](/api/terminal/automation/#get-terminal-automation-metrics)** - Global vterm metrics (session count, memory used/cap, active waiters)
- **[GET /api/v1/terminal/\{terminal_id\}/automation](/api/terminal/automation/#get-per-session-automation-state)** - Per-session automation state (dimensions, seq, idle ms, alt-screen)

**System Resource Monitoring:**
- **[GET /api/v1/system/resources](/api/terminal/monitoring/#get-system-resources)** - System stats
  - Returns: CPU, memory, disk, network usage
- **[GET /api/v1/system/processes](/api/terminal/monitoring/#list-system-processes)** - List processes
  - Query params: `sort` (cpu|memory|pid), `limit`, `filter` (by name)
- **[GET /api/v1/system/processes/\{pid\}](/api/terminal/monitoring/#get-process-details)** - Process details
  - Returns: Command, working directory, parent/child relationships, environment
- **[POST /api/v1/system/process/signal](/api/terminal/monitoring/#send-signal-to-process)** - Send Unix signals
  - Body: `{"pid": 12345, "signal": "SIGTERM"}` or `{"name": "nginx", "signal": "SIGHUP"}`

**System Control:**
- **[POST /api/v1/system/shutdown](/api/terminal/monitoring/#shutdown-system)** - Shutdown the system
- **[POST /api/v1/system/reboot](/api/terminal/monitoring/#reboot-system)** - Reboot the system

**System Introspection:**
- **[GET /api/v1/system/ports](/api/terminal/monitoring/#list-network-ports)** - List listening ports
  - Query params: `http_only`, `hoody_only`, `user`, `port`
- **[GET /api/v1/system/daemon](/api/terminal/monitoring/#get-daemon-programs-configuration)** - List hoody-daemon programs
  - Returns: hoody-daemon-managed services with status, uptime, configuration
- **[GET /api/v1/system/displays](/api/terminal/monitoring/#get-display-information)** - List X11 displays
  - Returns: Active display sessions, resolutions, users

**WebSocket:**
- **[GET /api/v1/terminal/ws](/api/terminal/sessions/#get-apiv1terminalws)** - WebSocket terminal connection
  - Real-time bidirectional terminal I/O

**Health:**
- **[GET /api/v1/terminal/health](/api/terminal/monitoring/#health-check)** - Service health check

**Web Interface & Authentication:**
- **[GET /](/api/terminal/web-interface/)** - Browser terminal UI
  - 39 query parameters for customization (session, shell, SSH, display, desktop, panel, theme, font, etc.)
- **[GET /api/v1/terminal/openapi.json](/api/terminal/web-interface/#get-openapi-specification-json)** - OpenAPI specification
- **[GET /api/v1/terminal/openapi.yaml](/api/terminal/web-interface/#get-openapi-specification-yaml)** - OpenAPI YAML spec

---

## Core Capabilities

### 1. Web-Native Terminal (Main Entry Point)

**This is how most users access containers—replaces SSH for daily work:**

```
https://{project}-{container}-terminal-1.{server}.containers.hoody.icu
https://{project}-{container}-terminal-2.{server}.containers.hoody.icu
https://{project}-{container}-terminal-3.{server}.containers.hoody.icu
```

**Each number is a separate terminal session in the SAME container:**

- `terminal-1` - Your main terminal session
- `terminal-2` - A second terminal for monitoring logs
- `terminal-3` - A third terminal for running tests

**All in one container.** Switch between them by opening different URLs. Each maintains its own state.

**Open in ANY browser—phone, tablet, laptop, TV**—and you have a full Linux terminal. No SSH client needed. No configuration. Just a URL.

**Key insight:** The number in the URL (`terminal-1`, `terminal-2`) IS the terminal ID. Switching terminals doesn't change containers—you're just opening another shell session in the same computer.

**Your work persists across all terminals:**
- Files you create in terminal-1 are visible in terminal-2
- Services you start in terminal-2 are accessible from terminal-3
- Environment on the container remains consistent
- This is one computer with multiple shell sessions

**Display integration:** Pair a terminal with a display by setting the `display` field when the session is created — the kit then exports `DISPLAY=:N` into that shell. The common convention is to match the numbers:
- `terminal-1` with `display: "1"` → `DISPLAY=:1`
- `terminal-2` with `display: "2"` → `DISPLAY=:2`
- `terminal-5` with `display: "5"` → `DISPLAY=:5`

With that pairing in place, GUI programs you launch in terminal-5 appear in [`display-5`](/kit/displays/). There is no automatic `terminal_id ⇒ DISPLAY` mapping — pass the `display` field explicitly (or `export DISPLAY=:3` inside the shell) to target a given display. This lets you organize applications across displays while controlling from any terminal.


**Shell selection—choose your preferred shell:**

Pre-installed shells: 🐚 **bash** (default) • ⚡ **zsh** • 🐠 **fish** • 📋 **tmux** • 🐚 **sh**

| Shell | Description | Launch |
|-------|-------------|--------|
| 🐚 **bash** | Default shell, universal compatibility | Default or `?shell=bash` |
| ⚡ **zsh** | Modern shell, oh-my-zsh compatible, better completion | `?shell=zsh` or `exec zsh` |
| 🐠 **fish** | Friendly shell, syntax highlighting, autosuggestions | `?shell=fish` or `exec fish` |
| 📋 **tmux** | Terminal multiplexer, shared between web and [SSH](/foundation/networking/ssh/) | `?shell=tmux` |
| 🐚 **sh** | Bourne shell, minimal, POSIX-compliant | `?shell=sh` |

**Quick shell switching:**
```bash
exec zsh   # Switch to zsh
exec fish  # Switch to fish
tmux       # Launch tmux
```

**Changing shells via URL:** When switching shells using the `?shell=` parameter on an **existing session**, use `?reset=true` to ensure a clean start:

```txt
# Recommended: Reset when changing shells
https://PROJECT-CONTAINER-terminal-1.hoody.icu/?shell=zsh&reset=true

# This ensures the new shell starts fresh without inheriting state from the previous shell
```

**Customize via URL parameters:**

```txt
?shell=zsh                  # Shell choice
&fontSize=14                # Larger text
&readonly=true              # View-only mode
&title=Production%20Logs    # Custom title
&panel=https://docs.hoody.com&panel-width=40%  # Side panel with docs
```

**See:** [Web Terminal UI →](/api/terminal/web-interface/) for 39 customization options.

**Access web terminal sessions from [SSH →](/foundation/networking/ssh/):**

tmux sessions are shared between web and SSH access. The terminal number in the URL maps to tmux session ID:

```bash
# Web terminal-3: https://{project}-{container}-terminal-3.{server}.containers.hoody.icu
# SSH to same session:
ssh user@container
tmux attach -t 3

# Now you're in the exact same session as the web terminal
# Edit files, see command history—everything synced
```

This lets you access web terminal sessions from traditional [SSH clients](/foundation/networking/ssh/) while maintaining full session state.

### 2. HTTP Shell Execution (For Automation)

**For scripts and AI agents, use the HTTP API directly:**


  
    ```bash
    # Execute a command in your container
    hoody terminal sessions exec --command "ls -la /app" --wait

    # Run a command asynchronously
    hoody terminal sessions exec --command "npm run build" --no-wait --timeout 300
    ```
  
  
    ```typescript
    import { HoodyClient } from '@hoody-ai/hoody-sdk';

    const client = new HoodyClient({ baseURL: 'https://api.hoody.icu', token: process.env.HOODY_TOKEN });
    const containerClient = await client.withContainer({ id: CONTAINER_ID, project_id: PROJECT_ID, server: SERVER });

    // Execute a shell command (synchronous)
    const result = await containerClient.terminal.execution.execute(
      { command: 'ls -la /app', wait: true },  // request body
      { terminal_id: '1' }  // query params — terminal_id matches the terminal-1 URL
    );
    console.log(result.data.stdout);
    ```
  
  
    ```bash
    curl -X POST "https://$PROJECT-$CONTAINER-terminal-1.$SERVER.containers.hoody.icu/api/v1/terminal/execute" \
      -H "Content-Type: application/json" \
      -d '{"command": "ls -la /app", "wait": true}'
    ```
  




**Response:**
```json
{
  "success": true,
  "command_id": "cmd-123",
  "terminal_id": "1",
  "status": "completed",
  "exit_code": 0,
  "stdout": "total 48\ndrwxr-xr-x 5 user user 4096 Nov 9 14:30 .\n...",
  "stderr": "",
  "duration_ms": 5
}
```

**The breakthrough:** Your entire shell is now accessible to:
- AI agents (can execute commands via HTTP)
- Mobile devices (POST from your phone)
- Other containers (cross-container orchestration)
- Embedded iframes (terminals in documentation)
- Automation scripts (no SSH setup needed)

**The URL terminal number determines which session executes the command:**
- `terminal-1.hoody.icu/execute` → Executes in terminal session 1
- `terminal-2.hoody.icu/execute` → Executes in terminal session 2
- Each session is isolated but in the same container

### 3. Stateful Sessions

**Sessions persist across requests:**

```javascript
// Execute in terminal-1
const terminalUrl = 'https://PROJECT_ID-CONTAINER_ID-terminal-1.SERVER_NAME.containers.hoody.icu';

await fetch(terminalUrl + '/api/v1/terminal/execute', {
  method: 'POST',
  body: JSON.stringify({ command: 'cd /app', wait: true })
});

// Later, same terminal-1 - still in /app directory
await fetch(terminalUrl + '/api/v1/terminal/execute', {
  method: 'POST',
  body: JSON.stringify({ command: 'ls', wait: true })
});
// Lists contents of /app (working directory preserved)
```

**Critical understanding:** Each terminal URL (`terminal-1`, `terminal-2`, `terminal-3`) represents a distinct shell session within the SAME container:

- Files created in terminal-1 are immediately accessible in terminal-2
- Processes started in terminal-2 can be seen from terminal-3
- All terminals share the same filesystem, users, services—it's ONE computer

**State persists within each terminal session:**
- Current working directory (`cd` commands remembered)
- Environment variables (exports remain)
- Shell history
- Background processes
- Open file descriptors

**Work persists across the container:** Files, services, databases—everything remains regardless of which terminal you use.

#### Override Working Directory with `cwd`

**Don't want to `cd` first? Use the `cwd` parameter to execute commands in any directory:**

```javascript
// Execute in /var/log without changing session's working directory
await fetch(terminalUrl + '/api/v1/terminal/execute', {
  method: 'POST',
  body: JSON.stringify({
    command: 'tail -f app.log',
    cwd: '/var/log',
    wait: false
  })
});

// Session's working directory unchanged—next command runs in original location
await fetch(terminalUrl + '/api/v1/terminal/execute', {
  method: 'POST',
  body: JSON.stringify({ command: 'pwd' }) // Still in /home/user
});
```

**Practical uses:**
- **One-off commands in specific directories** - Check logs, run tests, inspect files without navigating
- **Parallel operations** - Different terminals in different directories simultaneously
- **CI/CD workflows** - Execute build commands in consistent locations regardless of session state
- **Scripts** - Always run from the correct directory without `cd` chains

```javascript
// Build frontend and backend simultaneously in different directories
const build = async () => {
  // Terminal-1: Frontend build
  fetch(terminal1Url + '/execute', {
    method: 'POST',
    body: JSON.stringify({
      command: 'npm run build',
      cwd: '/app/frontend',
      wait: false
    })
  });

  // Terminal-2: Backend build (same time)
  fetch(terminal2Url + '/execute', {
    method: 'POST',
    body: JSON.stringify({
      command: 'go build',
      cwd: '/app/backend',
      wait: false
    })
  });
};
```

**Key insight:** `cwd` overrides directory temporarily for that ONE command only—session state remains untouched.

**Important:** The `cwd` parameter affects the command execution directory but **does NOT change the session's working directory**. If the terminal is already running with a different working directory, `cwd` only applies to that single command.

**For guaranteed directory control:** Use `?reset=true` when you need to ensure a specific starting directory:

```txt
# Guarantee terminal starts in /app directory
https://PROJECT-CONTAINER-terminal-1.hoody.icu/?reset=true

# Then use cwd parameter to execute in specific locations
POST /api/v1/terminal/execute
{
  "command": "npm test",
  "cwd": "/app/frontend"  // Executes in /app/frontend, session stays in /home/user
}
```

**Reset + cwd workflow:**
```javascript
// Reset terminal to clean state
await fetch(terminalUrl + '?reset=true');

// Now session is in /home/user
// Use cwd for specific directory execution without changing session
await fetch(terminalUrl + '/api/v1/terminal/execute', {
  method: 'POST',
  body: JSON.stringify({
    command: 'npm run build',
    cwd: '/app/dist'  // Runs in /app/dist, session remains in /home/user
  })
});
```

#### Fresh Start with `reset`

**Need a clean slate? Use `?reset=true` to restart the shell session:**

```txt
https://PROJECT-CONTAINER-terminal-1.hoody.icu/?reset=true
```

**What `reset` does:**
- ✅ Kills all processes in the session
- ✅ Clears environment variables
- ✅ Resets working directory to `/home/user`
- ✅ Clears shell history
- ✅ Fresh `.bashrc` / `.zshrc` execution
- ✅ Removes temporary state and caches

**When to use `reset`:**

```javascript
// After testing that polluted the environment
// URL: ?reset=true
// Result: Clean environment, no leaked variables

// After failed deployment left processes running
// URL: ?reset=true
// Result: All processes killed, fresh start

// After experimenting with system configurations
// URL: ?reset=true
// Result: Back to default state

// Switching between different project contexts
// URL: ?reset=true
// Result: No leftover environment from previous project
```

**Practical workflow:**

```javascript
// Option 1: Reset via URL parameter (web terminal)
window.location = terminalUrl + '?reset=true';

// Option 2: Reset via DELETE endpoint (API)
await fetch(terminalUrl + '/api/v1/terminal/1', {
  method: 'DELETE'  // Kills session, next request creates fresh one
});

// Next command executes in brand new session
await fetch(terminalUrl + '/api/v1/terminal/execute', {
  method: 'POST',
  body: JSON.stringify({ command: 'env' })  // Clean environment
});
```

**Reset vs Delete:**
- **`?reset=true`** - Immediate clean start, auto-reconnects web terminal
- **`DELETE /terminal/{id}`** - Kills session, requires new request to recreate
- Both give you a fresh shell—choose based on whether you're using the web UI or API

**Common scenarios:**
- **Development cycles** - Reset between test runs to avoid state contamination
- **User demos** - Start each demo with a clean environment
- **CI/CD stages** - Reset before each deployment step
- **Troubleshooting** - Eliminate environment issues by starting fresh

### 4. Multiplayer by Default

**Share a terminal URL and everyone types together:**

Multiple users connecting to:
```
https://{project}-{container}-terminal-1.{server}.containers.hoody.icu
```

Each connected client:
- ✅ Sees the same terminal output (the PTY broadcasts to every attached client)
- ✅ Can type commands simultaneously (all share one shell/screen)
- ✅ Can attach read-only with `?readonly=true` (input blocked for that client only — mix read-only viewers with read-write collaborators in the same session)

**Perfect for:**
- Pair programming (both typing in same session)
- Teaching Linux (instructor and students share terminal)
- Customer support (solve issues together)
- Team debugging (everyone sees live output)

**See:** [Multiplayer by Default →](/vision/multiplayer/) for collaboration philosophy.

### 5. Launch GUI Applications Instantly

**The killer feature: Start any GUI program and see it immediately in your browser.**

```bash
# In a terminal paired with display 2 (created with display: "2"), run Firefox
firefox &

# It appears in display-2
# Open: https://{project}-{container}-display-2.{server}.containers.hoody.icu
```

**That's it.** Pair the session with a display, type the command in the terminal URL, and the GUI appears in the matching display URL. No configuration. No setup. **Instant graphical applications.**

**Works with ANY GUI program:**

```bash
# In terminal-3
code /app              # VS Code opens in display-3
libreoffice report.pdf # LibreOffice opens in display-3
gimp photo.jpg         # GIMP opens in display-3
chrome                 # Chrome opens in display-3
```

**Why this is revolutionary:**

Traditional remote desktop: Configure VNC/RDP server, install client, connect to desktop, open terminal, run program (finally).

Hoody: Type command in terminal URL. Program appears in display URL. **Done.**

**Your phone can now run:**
- Terminal URL on phone → Type `code .`
- Display URL on tablet → See VS Code running
- Control from anywhere, view from anywhere

**Perfect for:**
- Quick GUI app testing (start in browser instantly)
- Mobile development workflows (command on phone, view on tablet)
- Teaching (instructor types, students see GUI appear)
- Documentation (embed terminal + display showing live app)

See [Displays →](./displays/) for the full desktop experience.

#### Auto-started display services

The first time a terminal/desktop session for display `N` is created (CLI, SDK call, or URL), Hoody Terminal boots an X server on `:N` and attaches the `dunst` notification daemon to it. That's why the URL trick above just works — and it's also why notifications sent to display `N` via the [Notifications kit](./notifications/) start dispatching as soon as the session exists.

### 6. SSH to Remote Servers (No Client Needed)

**The breakthrough: Manage ANY server from a browser—no SSH client, no keys, no configuration.**

Hoody Terminal becomes your SSH client. Connect to remote servers via HTTP—the Hoody container makes the SSH connection FOR you.

**Traditional SSH workflow:**
1. Install SSH client on your device
2. Generate SSH keys
3. Copy keys to server
4. Remember server addresses and ports
5. Use command line to connect

**Hoody workflow:**
1. Open terminal URL in browser
2. Add SSH parameters to URL
3. You're connected

#### Connect via URL Parameters

**Password authentication:**
```txt
https://PROJECT-CONTAINER-terminal-1.hoody.icu/
  ?ssh_host=production-server.com
  &ssh_user=admin
  &ssh_password=your_password
```

**SSH key authentication:**


**Note on `ssh_key`:** This is the **base64-encoded private key content**, not a file path. The container cannot access paths on your device — the key must be embedded in the request. For CLI/URL use, base64-encode the file first: `base64 -w0 ~/.ssh/id_rsa | jq -sRr @uri`.


```txt
# Base64-encode the key first:
# SSH_KEY=$(base64 -w0 /home/user/.ssh/id_rsa | jq -sRr @uri)
https://PROJECT-CONTAINER-terminal-1.hoody.icu/
  ?ssh_host=192.168.1.100
  &ssh_user=root
  &ssh_key=<base64-encoded-private-key-content>
```

**Custom port:**
```txt
# Base64-encode the key first:
# SSH_KEY=$(base64 -w0 /keys/deploy_key | jq -sRr @uri)
https://PROJECT-CONTAINER-terminal-1.hoody.icu/
  ?ssh_host=server.example.com:2222
  &ssh_user=deploy
  &ssh_key=<base64-encoded-private-key-content>
```

**You're now controlling the remote server—through HTTP—from any device with a browser.**

#### Connect via API (Automation)

**The SSH connection persists—send commands repeatedly to the same remote server:**

```javascript
// Connect to production database server
const remoteSession = await fetch(terminalUrl + '/api/v1/terminal/execute', {
  method: 'POST',
  body: JSON.stringify({
    command: 'systemctl status postgresql',
    wait: true
  }),
  headers: {
    'Content-Type': 'application/json'
  }
}).then(r => r.text());
```

**URL already has SSH params:**
```javascript

// Base64-encode the private key before embedding in the URL
const sshKey = readFileSync('/secure/postgres.key', 'base64');
const terminalUrl = 'https://PROJECT-CONTAINER-terminal-5.hoody.icu' +
  '?ssh_host=db-server.internal' +
  '&ssh_user=postgres' +
  '&ssh_key=' + encodeURIComponent(sshKey);
```

Now every POST to this URL executes commands on `db-server.internal`:

```javascript
// All these execute on the REMOTE server, not the Hoody container
await fetch(terminalUrl + '/api/v1/terminal/execute', {
  method: 'POST',
  body: JSON.stringify({ command: 'pg_dump production > backup.sql' })
});

await fetch(terminalUrl + '/api/v1/terminal/execute', {
  method: 'POST',
  body: JSON.stringify({ command: 'du -sh backup.sql' })
});

await fetch(terminalUrl + '/api/v1/terminal/execute', {
  method: 'POST',
  body: JSON.stringify({ command: 'gzip backup.sql' })
});
```

**The SSH connection stays open—session state persists across requests.**

#### Why This Changes Everything

**Manage servers from phones/tablets:**
- No SSH app needed
- No terminal emulator
- Just a browser and a URL

**Share server access without credentials:**
```txt
https://docs-server-terminal-1.hoody.icu?ssh_host=docs.internal&ssh_user=readonly
```
Send this URL to your team. They can:
- ✅ Execute commands on `docs.internal`
- ✅ Access immediately (no credential setup)
- ✅ View output in browser
- ❌ Never see the actual SSH credentials

**Control via proxy permissions:**
- IP whitelist for production servers
- Password protect staging access
- JWT tokens for automated deployments
- See [Permissions →](/foundation/proxy/permissions/)

#### Practical Remote Server Workflows

**Monitor production logs from phone:**
```txt
# base64 -w0 /keys/aws-prod.pem | jq -sRr @uri  → use that value for ssh_key
https://PROJECT-CONTAINER-terminal-monitor.hoody.icu/
  ?ssh_host=prod-app-1.aws.com
  &ssh_user=ubuntu
  &ssh_key=<base64-encoded-private-key-content>
  &command=tail%20-f%20/var/log/app.log
```

Bookmark this URL. Open on phone. See live production logs—no SSH client needed.

**Multi-server deployment script:**
```javascript
const servers = [
  'web-1.production.com',
  'web-2.production.com',
  'web-3.production.com'
];

// Base64-encode deploy key once before the loop

const deployKey = encodeURIComponent(readFileSync('/secure/deploy.key', 'base64'));

// Deploy to all servers via HTTP
for (const server of servers) {
  const terminalUrl = `https://PROJECT-CONTAINER-terminal-deploy.hoody.icu` +
    `?ssh_host=${server}` +
    `&ssh_user=deploy` +
    `&ssh_key=${deployKey}`;

  await fetch(terminalUrl + '/api/v1/terminal/execute', {
    method: 'POST',
    body: JSON.stringify({
      command: 'cd /app && git pull && systemctl restart app',
      wait: true,
      timeout: 300
    })
  });
  
  console.log(`Deployed to ${server}`);
}
```

**Database backup automation:**
```javascript

// Runs on Hoody container, connects to DB server via SSH, executes backup
const pgKey = encodeURIComponent(readFileSync('/keys/postgres.key', 'base64'));
const backupUrl = 'https://PROJECT-CONTAINER-terminal-backup.hoody.icu' +
  '?ssh_host=db-primary.internal' +
  '&ssh_user=postgres' +
  '&ssh_key=' + pgKey;

// This command runs on db-primary.internal, not Hoody container
await fetch(backupUrl + '/api/v1/terminal/execute', {
  method: 'POST',
  body: JSON.stringify({
    command: `
      pg_dump production | gzip > /backups/prod_$(date +%Y%m%d).sql.gz &&
      aws s3 cp /backups/prod_$(date +%Y%m%d).sql.gz s3://backups/ &&
      echo "Backup complete"
    `,
    wait: true
  })
});
```

**Security audit from phone:**
```txt
# base64 -w0 /keys/security-audit.key | jq -sRr @uri  → use that value for ssh_key
https://PROJECT-CONTAINER-terminal-audit.hoody.icu/
  ?ssh_host=firewall.company.com
  &ssh_user=security
  &ssh_key=<base64-encoded-private-key-content>
  &command=iptables%20-L%20-n%20-v
```

Open URL. See firewall rules. No laptop. No SSH client. Just HTTP.

#### SSH Connection Persistence

**Connections auto-maintain until you reset:**

```javascript

// ssh_key must be base64-encoded private key content, not a file path
const sshKeyB64 = readFileSync('/path/to/key', 'base64');
// Session created with SSH params
const url = terminalUrl + '?ssh_host=server.com&ssh_user=admin&ssh_key=' + encodeURIComponent(sshKeyB64);

// First command: Connects via SSH
await fetch(url + '/execute', { method: 'POST', body: JSON.stringify({ command: 'pwd' }) });

// Subsequent commands: Reuses connection (fast)
await fetch(url + '/execute', { method: 'POST', body: JSON.stringify({ command: 'ls' }) });
await fetch(url + '/execute', { method: 'POST', body: JSON.stringify({ command: 'df -h' }) });

// Connection stays open across requests—no reconnection overhead
```

**Reset to change servers:**
```javascript
// Switch to different server
window.location = terminalUrl +
  '?reset=true' +  // Closes previous SSH connection
  '&ssh_host=new-server.com' +
  '&ssh_user=deploy' +
  // ssh_key must be base64-encoded private key content, not a file path
  '&ssh_key=' + encodeURIComponent(readFileSync('/keys/deploy.key', 'base64'));
```

**Key insights:**
- ✅ SSH connections maintained by Hoody container
- ✅ Your device only uses HTTP (browser/fetch)
- ✅ Sessions persist—fast repeated commands
- ✅ Credentials stored securely in container (keys in `/keys/`)
- ✅ Access control via proxy permissions, not SSH keys
- ✅ Works from ANY device with a browser

**This transforms server management:** Your phone can now control production servers, run database backups, monitor logs, deploy code—all via HTTP, all without an SSH client.

### 7. AI Agent Side Panel (hoody-agent Integration)

**The perfect pairing: Terminal + AI agent side-by-side in one browser window.**

Hoody Terminal supports embedding **hoody-agent** directly in a side panel—giving you an AI assistant that can see your terminal, suggest commands, and help you work.

#### Setup: Terminal with Agent Panel

**Add the agent URL as a side panel:**

```txt
https://PROJECT-CONTAINER-terminal-1.hoody.icu/
  ?panel=https://PROJECT-CONTAINER-workspaces-1.hoody.icu
  &panel-width=40%
```

**What you get:**
- **Left 40%**: Hoody Agent (chat interface, suggestions, explanations)
- **Right 60%**: Terminal (command execution)
- **Same container**: Agent and terminal share filesystem, processes, state

**The workflow:**
1. Ask agent: "How do I find large files?"
2. Agent responds: `du -sh * | sort -h`
3. Execute command in terminal (right side)
4. Agent sees result and offers next step
5. Repeat—AI-assisted shell work

#### Why This Integration is Powerful

**Each terminal can have its own dedicated agent:**

```txt
# Terminal-1 with agent-1 (configured for frontend context)
https://PROJECT-CONTAINER-terminal-1.hoody.icu/
  ?panel=https://PROJECT-CONTAINER-workspaces-1.hoody.icu
  &panel-width=35%

# Terminal-2 with agent-2 (configured for backend context)
https://PROJECT-CONTAINER-terminal-2.hoody.icu/
  ?panel=https://PROJECT-CONTAINER-workspaces-2.hoody.icu
  &panel-width=35%

# Terminal-3 with agent-3 (configured for DevOps context)
https://PROJECT-CONTAINER-terminal-3.hoody.icu/
  ?panel=https://PROJECT-CONTAINER-workspaces-3.hoody.icu
  &panel-width=35%
```

**Each agent instance:**
- ✅ Configured for specific context (via profiles, memory, system prompt)
- ✅ Has access to terminal history in its pane
- ✅ Can see files and processes in the container
- ✅ Provides specialized assistance based on its configuration

**Bookmark these URLs—instant AI-assisted development environments.**

#### Practical Use Cases

**1. Learning Linux/DevOps:**
```txt
https://PROJECT-CONTAINER-terminal-1.hoody.icu/
  ?panel=https://PROJECT-CONTAINER-workspaces-1.hoody.icu
  &panel-width=40%
```

- Ask agent to explain commands before running them
- Agent provides context, flags, common patterns
- Execute in terminal, see results
- Agent explains output and suggests next steps

**2. Debugging Issues:**
```txt
https://PROJECT-CONTAINER-terminal-2.hoody.icu/
  ?panel=https://PROJECT-CONTAINER-workspaces-2.hoody.icu
  &panel-width=35%
```

- Describe problem to agent: "API returning 500 errors"
- Agent suggests diagnostic commands: `tail -f /var/log/app.log`
- Execute commands in terminal
- Agent analyzes logs, suggests fixes
- Apply fixes, agent monitors results

**3. Infrastructure Management:**
```txt
https://PROJECT-CONTAINER-terminal-3.hoody.icu/
  ?panel=https://PROJECT-CONTAINER-workspaces-3.hoody.icu
  &panel-width=40%
  &ssh_host=production-server.com
  &ssh_user=admin
```

- Combined SSH + Agent + Terminal
- SSH to production server (via HTTP)
- Agent helps with server management commands
- Safe infrastructure changes with AI assistance

**4. Code Review + Testing:**
```txt
https://PROJECT-CONTAINER-terminal-4.hoody.icu/
  ?panel=https://PROJECT-CONTAINER-workspaces-4.hoody.icu
  &panel-width=45%
```

- Agent reviews code in `/app/src`
- Suggests improvements and test commands
- Execute tests in terminal: `npm test`
- Agent analyzes test output, suggests fixes
- Iterate until tests pass

#### Agent Panel Features

**What the agent can do from the panel:**
- 📖 **Read files** in the container
- 🔍 **Execute commands** (if you grant permission)
- 📊 **Analyze output** from terminal
- 💡 **Suggest solutions** based on context
- 📝 **Remember conversation** across page reloads (via agent state)
- 🔗 **Access container services** (databases, web servers, etc.)

**Panel width customization:**
```txt
&panel-width=30%   # Smaller panel, more terminal space
&panel-width=50%   # Equal split
&panel-width=60%   # Larger panel for complex agent responses
```

Pick based on your workflow—debugging needs more terminal space, learning needs more agent space.

#### Advanced: Multi-Agent Workflows

**Multiple agents for complex projects:**

```bash
# Frontend terminal with agent-1 (configured for React/TypeScript)
open "https://PROJECT-CONTAINER-terminal-1.hoody.icu/?panel=https://PROJECT-CONTAINER-workspaces-1.hoody.icu"

# Backend terminal with agent-2 (configured for Go/databases)
open "https://PROJECT-CONTAINER-terminal-2.hoody.icu/?panel=https://PROJECT-CONTAINER-workspaces-2.hoody.icu"

# Database terminal with agent-3 (configured for PostgreSQL)
open "https://PROJECT-CONTAINER-terminal-3.hoody.icu/?panel=https://PROJECT-CONTAINER-workspaces-3.hoody.icu&ssh_host=db.internal"
```

**Each agent instance configured differently:**
- agent-1: React/TypeScript context (via profiles and memory)
- agent-2: Go/API context (via profiles and memory)
- agent-3: PostgreSQL/DBA context (via profiles and memory)

**All working in the same container**—files created by one terminal visible to others, services accessible across terminals, perfect for full-stack development.

#### Why This is the Future of Development

**Traditional setup:**
1. Open terminal application
2. Open separate AI chat in browser
3. Switch between them
4. Copy/paste commands and output
5. Context lost between apps

**Hoody setup:**
1. Open one URL (terminal + agent)
2. Agent sees what you type
3. Agent sees command output
4. Suggest, execute, analyze—all in one window
5. Context preserved automatically

**The URL is the environment.** Share the URL, you share the entire setup—terminal, agent, SSH connection, panel layout, everything.

**Perfect for:**
- 🎓 **Teaching** - Instructor shares terminal+agent URL, students learn with AI assistance
- 👥 **Pair Programming** - Both developers see terminal and agent suggestions
- 🐛 **Support** - Share debugging session with AI already analyzing the problem
- 📚 **Documentation** - Embed terminal+agent showing live examples

See [Web Terminal UI →](/api/terminal/web-interface/) for all panel customization options.

### 8. System Introspection

**Query your container's state via HTTP:**


  
    ```bash
    # Get CPU/memory/disk stats
    hoody terminal system resources

    # List running processes sorted by CPU
    hoody terminal processes list --sort cpu --limit 10

    # Check what ports are listening
    hoody terminal system ports

    # View X11 displays
    hoody terminal system display-info
    ```
  
  
    ```typescript
    // Get system resource stats
    const resources = await containerClient.terminal.system.getResources();
    console.log(`CPU: ${resources.data.cpu}%, Memory: ${resources.data.memory}%`);

    // List running processes sorted by CPU
    const procs = await containerClient.terminal.system.listProcesses({ sort: 'cpu', limit: 10 });

    // Check listening ports
    const ports = await containerClient.terminal.system.listPorts();

    // View X11 displays
    const displays = await containerClient.terminal.system.getDisplayInfo();
    ```
  
  
    ```bash
    # Get CPU/memory/disk stats
    curl "https://$PROJECT-$CONTAINER-terminal-1.$SERVER.containers.hoody.icu/api/v1/system/resources"

    # List running processes sorted by CPU
    curl "https://$PROJECT-$CONTAINER-terminal-1.$SERVER.containers.hoody.icu/api/v1/system/processes?sort=cpu&limit=10"

    # Check what ports are listening
    curl "https://$PROJECT-$CONTAINER-terminal-1.$SERVER.containers.hoody.icu/api/v1/system/ports"

    # View X11 displays
    curl "https://$PROJECT-$CONTAINER-terminal-1.$SERVER.containers.hoody.icu/api/v1/system/displays"
    ```
  


**All system information accessible via HTTP endpoints.** No need to SSH in and run commands—just query the API.

### 9. Remote SSH Execution

**Execute commands on OTHER servers through hoody-terminal:**



**The container becomes an HTTP-to-SSH bridge.** Your phone can now execute commands on your production servers via HTTP.

---

## Why This Changes Everything

### Traditional Terminals

```
SSH Client (installed) → SSH Server (configured) → Shell (finally)
```

**Problems:**
- SSH client required (not available on phones, tablets, watches)
- Key management (private keys, known_hosts, permissions)
- Port forwarding complexity
- Not embeddable (can't iframe SSH)
- Not multiplayer (one session per connection)
- AI can't use (binary protocol)

### Hoody Terminals

```
Any HTTP Client → hoody-terminal URL → Shell (immediately)
```

**Advantages:**
- ✅ Any device with browser works (phones, tablets, watches, TVs)
- ✅ Zero key management (URL is the credential)
- ✅ Naturally embeddable (`<iframe src="terminal-url" />`)
- ✅ Multiplayer by default (share URL = instant collaboration)
- ✅ AI-native (LLMs understand HTTP requests)
- ✅ Observable (all HTTP requests logged)
- ✅ MITM-able via hoody-exec (enhance any command automatically)

### HTTP Unlocks New Possibilities

**Because terminals are HTTP:**

1. **Embed in Documentation**
   ```html
   <iframe src="https://demo-terminal.hoody.icu/?cmd=bHMgLWxh&readonly=true" />
   ```
   Live terminals in your docs showing actual command execution.

2. **Phone Executes Production Commands**
   ```javascript
   // From mobile browser
   await fetch(terminalUrl + '/execute', {
     method: 'POST',
     body: JSON.stringify({
       command: 'pm2 restart api',
       wait: true
     })
   });
   ```

3. **AI Orchestrates Infrastructure**
   ```javascript
   // AI agent deploys automatically
   const steps = [
     'git pull origin main',
     'npm install --production',
     'npm run build',
     'pm2 restart app'
   ];
   
   for (const cmd of steps) {
     await fetch(terminalUrl + '/execute?terminal_id=deploy', {
       method: 'POST',
       body: JSON.stringify({ command: cmd, wait: true })
     });
   }
   ```

4. **Cascading Execution**
   ```javascript
   // Terminal A executes command that triggers Terminal B
   await fetch(containerA_terminal + '/execute', {
     method: 'POST',
     body: JSON.stringify({
       command: `curl -X POST ${containerB_terminal}/execute -d '{"command":"npm test"}'`,
       wait: true
     })
   });
   ```

---

## Common Workflows

### Quick Command Execution

**One-off commands with immediate results:**



### Long-Running Tasks

**Start task asynchronously, check later:**

```javascript
// Use terminal-3 for build tasks
const buildTerminalUrl = 'https://PROJECT_ID-CONTAINER_ID-terminal-3.SERVER_NAME.containers.hoody.icu';

const response = await fetch(buildTerminalUrl + '/api/v1/terminal/execute', {
  method: 'POST',
  body: JSON.stringify({
    command: 'npm run build',
    wait: false,
    timeout: 300
  })
});

const { command_id } = await response.json();

// Poll for result
const checkStatus = async () => {
  const result = await fetch(buildTerminalUrl + `/api/v1/terminal/result/${command_id}`)
    .then(r => r.json());
  
  if (result.status === 'completed') {
    console.log(`Build finished in ${result.duration_ms}ms`);
    console.log(result.stdout);
  } else {
    setTimeout(checkStatus, 2000);
  }
};

checkStatus();
```

**Check progress visually:** Open the web terminal URL in your browser to watch the build running in real-time—same terminal-3 URL shows live output.

**Mix workflows:** Start command via API (from phone, script, CI/CD), then monitor progress visually in the web terminal from any browser.

### Deployment Pipeline

**Multi-step workflows—commands execute in sequence in the same session:**

```javascript
const deployCommands = [
  'cd /app',
  'git pull origin main',
  'npm ci',
  'npm run build',
  'pm2 restart api',
  'pm2 logs api --lines 50'
];

// Use terminal-2 for deployments
const deployUrl = 'https://PROJECT_ID-CONTAINER_ID-terminal-2.SERVER_NAME.containers.hoody.icu';

for (const command of deployCommands) {
  const response = await fetch(deployUrl + '/api/v1/terminal/execute', {
    method: 'POST',
    body: JSON.stringify({ command, wait: true })
  });
  
  const result = await response.json();
  
  if (result.exit_code !== 0) {
    console.error(`Failed at: ${command}`);
    console.error(result.stderr);
    break;
  }
  
  console.log(`✓ ${command}`);
}

// All commands executed in terminal-2's session
// Working directory persisted across commands (cd /app stayed active)
```

### System Health Checks

**Monitor container resources:**

```javascript
async function checkHealth(terminalUrl) {
  const response = await fetch(terminalUrl + '/api/v1/system/resources');
  const { cpu, memory, disk } = await response.json();
  
  const alerts = [];
  
  if (cpu.usage_percent > 80) {
    alerts.push(`⚠️ CPU at ${cpu.usage_percent}%`);
  }
  
  if (memory.usage_percent > 85) {
    alerts.push(`⚠️ Memory at ${memory.usage_percent}%`);
  }
  
  if (disk.usage_percent > 90) {
    alerts.push(`⚠️ Disk at ${disk.usage_percent}%`);
  }
  
  return alerts;
}

// Run every 5 minutes
setInterval(() => {
  const alerts = await checkHealth(terminalUrl);
  if (alerts.length > 0) {
    console.log('Health alerts:', alerts);
  }
}, 300000);
```

---

## Use Cases

### Development Teams

**Collaborative debugging:** Team member encounters a bug. Instead of screen sharing:
1. Share terminal URL: `https://{project}-{container}-terminal-2.{server}.containers.hoody.icu`
2. Senior dev opens URL on phone while in meeting
3. Types fix directly in shared session
4. Bug resolved in 30 seconds

**No screen share setup. No "can you see this?". Just instant collaboration.**

### AI-First Development

**AI agents execute while you orchestrate:**

```javascript
// AI agent executes commands via the terminal HTTP API
const TERMINAL_URL = 'https://PROJECT_ID-CONTAINER_ID-terminal-1.SERVER_NAME.containers.hoody.icu';

const commands = [
  'npm create vite@latest my-app -- --template react-ts',
  'cd my-app && npm install',
  'npm run dev'
];

for (const command of commands) {
  const result = await fetch(`${TERMINAL_URL}/api/v1/terminal/execute`, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ command, wait: true })
  });
  console.log(await result.json());
}

// You described what you want built. AI executed it via HTTP.
```

### DevOps Automation

**No SSH setup needed for automation:**

```python
# Deploy from GitHub Actions, GitLab CI, any CI/CD
import requests

terminal_url = os.environ['HOODY_TERMINAL_URL']

response = requests.post(
    f'{terminal_url}/api/v1/terminal/execute',
    json={
        'command': './deploy.sh production',
        'terminal_id': 'ci',
        'wait': False,
        'timeout': 600
    }
)

command_id = response.json()['command_id']
# Monitor deployment status via command_id
```

### Customer Support

**Solve issues together in real-time:**

Support agent and customer both open:
```
https://{customer-container}-terminal-1.{server}.containers.hoody.icu
```

Both see the same terminal. Both can type. Agent fixes issue while customer watches. No more "type this command" followed by typing errors.

### Mobile Administration

**Admin your servers from anywhere:**

Your phone's browser → Terminal URL → Execute:
- `systemctl restart nginx`
- `tail -f /var/log/app.log`
- `docker ps`
- `htop`

**Full Linux shell on your phone.** Because it's just a URL.

### Documentation with Live Examples

**Embed working terminals in docs:**

```html
<!-- Your documentation -->
<p>To check system status, run:</p>

<iframe 
  src="https://demo-terminal.hoody.icu/?cmd=c3lzdGVtY3RsIHN0YXR1cyBuZ2lueA==&readonly=true"
  height="400"
/>
```

Readers see ACTUAL execution, not just code blocks. Interactive learning.

---

## Best Practices

### Use Same Terminal URL for Related Tasks

Group related commands using the same terminal URL to maintain session context:

```javascript
// ✅ Good - Same terminal URL maintains state
const deployUrl = 'https://PROJECT_ID-CONTAINER_ID-terminal-2.SERVER_NAME.containers.hoody.icu';

await fetch(deployUrl + '/execute', {
  method: 'POST',
  body: JSON.stringify({ command: 'cd /app', wait: true })
});

await fetch(deployUrl + '/execute', {
  method: 'POST',
  body: JSON.stringify({ command: 'npm install', wait: true })
});
// Runs in /app (working directory preserved)

// ❌ Bad - Different terminal URLs = different sessions
await fetch('...terminal-1.hoody.icu/execute', {
  body: JSON.stringify({ command: 'cd /app' })
});

await fetch('...terminal-2.hoody.icu/execute', {
  body: JSON.stringify({ command: 'npm install' })
});
// Runs in ~ (terminal-2 has its own separate session)
```

**Remember:** terminal-1, terminal-2, terminal-3 are all in the SAME container. They all see the same files, same services, same system. They just have independent shell sessions (separate working directories, separate command history).

### Async for Long-Running Commands

Always use `wait: false` for commands that might take >3 seconds:

```javascript
// ✅ Async for builds
await fetch('.../execute', {
  body: JSON.stringify({
    command: 'npm run build',
    wait: false,
    timeout: 300
  })
});

// ❌ Sync would block for minutes
```

### Set Timeouts Appropriately

Prevent runaway processes with sensible timeouts:

```javascript
{
  command: 'npm install',
  timeout: 300,  // 5 minutes max
  wait: false
}
```

### Check Exit Codes

Don't assume success—verify exit codes:

```javascript
const result = await execute({ command: 'npm test', wait: true });

if (result.exit_code !== 0) {
  console.error('Tests failed:', result.stderr);
  // Handle failure
} else {
  console.log('Tests passed!');
}
```

### Clean Up Sessions

Delete sessions when done to prevent resource leaks:

```bash
# List active sessions
GET /api/v1/terminal/sessions

# Delete old sessions
DELETE /api/v1/terminal/{terminal_id}
```

### Use Web UI for Interactive Work

For debugging or exploration, open the web URL directly:
```
https://{project}-{container}-terminal-1.{server}.containers.hoody.icu
```

Better than API for: typing multiple commands, seeing colored output, scrolling history.

### Monitor System Resources

Query resource endpoints before intensive operations:

```javascript
const { cpu, memory, disk } = await fetch('.../system/resources')
  .then(r => r.json());

if (cpu.usage_percent > 90) {
  console.warn('CPU at capacity - delay operation');
}
```

---

## Useful Questions

### Can I execute commands that require sudo?

Yes, if the terminal is running as root or the user has sudo permissions. Configure the user when creating the container or use `user` parameter when starting the terminal session. For security, consider using separate containers for privileged vs unprivileged operations.

### How do I execute commands on remote servers via SSH?

Include SSH parameters in the execute request: `ssh_host`, `ssh_user`, `ssh_password` (or `ssh_key`). The hoody-terminal service establishes the SSH connection and executes the command, returning results via HTTP. Your container becomes an HTTP-to-SSH gateway.

### Can AI agents really use terminals effectively?

Absolutely. LLMs understand HTTP natively and can construct command execution requests without special training. They can handle multi-step workflows, check exit codes, parse output, and adapt based on results—all via standard HTTP calls. No SDK needed.

### What happens to running commands if I close my browser?

Commands continue executing on the server. Terminal sessions are server-side, not browser-side. Close your laptop, command keeps running. Check status later via the `/result/{command_id}` endpoint.

### Can I embed terminals in my application?

Yes! Use iframes to embed terminal URLs directly in your app. Common pattern: documentation with live command execution, dashboards showing server logs, customer portals with diagnostic terminals.

### How many terminal sessions can one container have?

Theoretically unlimited. Practically: hundreds of concurrent sessions work fine. Each session consumes minimal RAM (~10MB). Use different `terminal_id` values for isolated sessions or same `terminal_id` for shared/multiplayer sessions.

### Does the web terminal work on mobile devices?

Yes! Native browser support on iOS and Android. The UI adapts to touch input, includes an on-screen keyboard option, and supports mobile gestures. Full Linux terminal from your phone's browser.

### Can I capture screenshots of terminal sessions?

Yes, via `GET /api/v1/terminal/screenshot?terminal_id=1&format=png`. Returns visual snapshot as PNG/JPEG/GIF. Useful for documentation, tutorials, or monitoring dashboards showing live terminal state.

### How do I get the complete command history for a session?

Use `GET /api/v1/terminal/history/{terminal_id}` to retrieve all commands executed, their exit codes, and execution times. Perfect for auditing, debugging, or understanding what changed in a session.

---

## Troubleshooting

### Commands Return 404 or Connection Error

**Check container is running:**
```bash
curl "https://api.hoody.icu/api/v1/containers/{container_id}?runtime=true" \
  -H "Authorization: Bearer $HOODY_TOKEN"
```

Verify `status: "running"` and `runtime_info.terminals` shows active sessions.

**Start container if stopped:**
```bash
curl -X POST "https://api.hoody.icu/api/v1/containers/{container_id}/start" \
  -H "Authorization: Bearer $HOODY_TOKEN"
```

### Web Terminal Won't Load

**Possible causes:**

1. **Container not running** - Start it via Hoody API
2. **Wrong URL** - Verify terminal-1 (not terminal1 or terminal)
3. **Proxy permissions** - Check if terminal access is restricted
4. **Browser blocking iframe** - Some browsers block cross-origin iframes

**Quick test:**
```bash
# Direct browser access (not iframe)
https://{project}-{container}-terminal-1.{server}.containers.hoody.icu
```

### Command Hangs or Times Out

**For long-running commands, use async mode:**

```javascript
// ✅ Correct - Async for npm install
{
  command: 'npm install',
  wait: false,
  timeout: 300
}

// ❌ Wrong - Sync will timeout
{
  command: 'npm install',
  wait: true  // Blocks for minutes!
}
```

**Increase timeout if needed:**
```javascript
{ timeout: 600 }  // 10 minutes for large builds
```

### Exit Code Always 0 But Command Failed

**Check stderr, not just exit_code:**

```javascript
const result = await execute({ command: 'npm test', wait: true });

// Some commands exit 0 but write errors to stderr
if (result.stderr.includes('ERROR') || result.stderr.includes('FAIL')) {
  console.error('Command had errors:', result.stderr);
}
```

### Session State Not Persisting

**Ensure using same terminal_id:**

```javascript
// ✅ Correct - Same session
terminal_id: "prod-session"  // State persists

// ❌ Wrong - Different sessions
terminal_id: Math.random()  // New session each time
```

**Sessions are deleted on:**
- Explicit DELETE request
- Container restart
- Terminal service restart

### Can't Access Remote SSH Host

**Check SSH parameters:**

```javascript
{
  command: 'ls',
  ssh_host: 'prod.example.com',
  ssh_port: 22,  // Default if omitted
  ssh_user: 'admin',
  ssh_password: 'your-password'  // Or ssh_key
}
```

**Verify SSH connectivity:**
```bash
# Test from container first
ssh admin@prod.example.com
```

**Common issues:**
- Firewall blocking SSH port
- Wrong credentials
- Host or network unreachable from the container (host key verification is not an issue — the kit connects with `StrictHostKeyChecking=no`, so unknown hosts are accepted automatically)

---

## What's Next

**Explore other interactive services:**


  
    Full desktop environments accessible via URL—run VS Code, browsers, any GUI application.
    
    [Explore Displays →](./displays/)
  
  
  
    Chrome automation as REST API—control browsers via HTTP, scrape websites, run tests.
    
    [Explore Browser →](./browser/)
  
  
  
    Transform any script into an HTTP endpoint—your code becomes an API automatically.
    
    [Explore Exec →](./exec/)
  


**Master terminal workflows:**
- **[Sessions →](/api/terminal/sessions/)** - Manage persistent terminal sessions
- **[Commands →](/api/terminal/commands/)** - Sync/async execution patterns
- **[Monitoring →](/api/terminal/monitoring/)** - System introspection APIs

---

> **Your shell is a URL.**  
> **Execute from anywhere.**  
> **Collaborate in real-time.**  
> **AI-native by design.**

**This is how terminals work in the HTTP era.**