# Terminal: Command Execution

**Page:** api/terminal/commands

[Download Raw Markdown](./api/terminal/commands.md)

---

{/* AUTO-GENERATED — Do not edit manually. Regenerate with: npm run docs:api:generate */}



The Terminal: Command Execution API lets you run shell commands inside an existing terminal session, poll for their results, abort in-flight executions, and send raw keystroke input to a session's PTY. Use these endpoints to automate CLI workflows, drive interactive prompts, or orchestrate remote SSH commands from a backend or agent.

## Execute a command


Execute a command in the specified terminal session. Supports both local bash and remote SSH sessions. The terminal type is determined by URL parameters on first use. By default, if a `DISPLAY` is configured on the session, the endpoint waits for the Hoody Display to be ready before executing the command. This can be disabled with `skip_display_wait=true`. Use `ephemeral=true` for a guaranteed-unique isolated PTY session with no display/dbus and automatic cleanup — ideal for programmatic command execution (like `child_process.exec`). Returns immediately with a `command_id` that can be used to poll for results.


`POST /api/v1/terminal/execute`

### Parameters

| Name | In | Type | Required | Description |
|------|-----|------|----------|-------------|
| `terminal_id` | query | string | No | Terminal session ID (numeric 1-65535). Use `terminal_id=0` as an explicit sentinel meaning "no terminal ID" (treated as absent, useful when a reverse proxy always injects a `terminal_id`). Required unless `ephemeral=true`, in which case it is auto-generated if not provided. |
| `ephemeral` | query | boolean | No | When true, auto-generates a unique `terminal_id` (if not provided), skips display/dbus initialization, and applies aggressive cleanup. Designed for programmatic CLI command execution like `child_process.exec`. Default: `false`. **WARNING:** Do NOT use `ephemeral=true` for GUI applications that require a display. Ephemeral sessions strip the `DISPLAY` environment variable, which means X11/GUI applications will not work. Use a regular terminal session with an explicit `terminal_id` and `display` parameter instead for GUI workloads. |
| `defer_pid` | query | integer | No | Defer command injection until this PID exits (TUI-safe). If set, the API returns immediately regardless of `wait=true`. |
| `defer_start_time_ticks` | query | string | No | Optional `/proc/&lt;pid&gt;/stat` field 22 (starttime in clock ticks since boot) to avoid PID reuse bugs. If it mismatches, command executes immediately. |
| `defer_timeout_ms` | query | integer | No | Max time to wait for `defer_pid` exit before failing. Default: `60000`. |
| `defer_poll_ms` | query | integer | No | Poll interval while waiting for `defer_pid` exit. Default: `50`, minimum: `10`. |
| `reset` | query | boolean | No | Reset existing session and reconfigure (kills current process, clears state, allows switching from bash to SSH or changing any parameter). Use `'true'`, `'1'`, or no value. |
| `cwd` | query | string | No | Working directory for local bash sessions (ignored for SSH). |
| `cwd_auto_create` | query | boolean | No | Auto-create `cwd` when the requested working directory does not exist yet. Only applies when `cwd` is explicitly provided for a new or reset local session. Enable with `'true'`, `'1'`, or no value. Default: `false`. |
| `shell` | query | string | No | Shell to use for local sessions: `bash` (case-insensitive), `zsh`, `fish`, `sh`, etc. Default: server startup command, only applies to new sessions or after reset. |
| `user` | query | string | No | System user to spawn shell as (requires `su` permissions, only applies to new sessions or after reset). |
| `cmd` | query | string | No | Base64-encoded command to execute automatically (works with both new and active shells, executes every time URL is visited). |
| `env` | query | string | No | Environment variable in `KEY=VALUE` format (can be repeated for multiple variables, e.g., `?env=DEBUG=1&env=API_KEY=abc`). |
| `skip_display_wait` | query | boolean | No | Skip waiting for Hoody Display readiness before executing command. By default, if a `DISPLAY` is configured, the endpoint blocks until the display server on port `4000+display_num` is ready. Default: `false`. |
| `display_wait_timeout` | query | integer | No | Timeout in seconds for display readiness wait. Default: `10`, capped at 10 seconds to prevent event-loop pin; values `&le;0` or malformed also map to the 10-second cap. Ignored if `skip_display_wait=true`. |
| `display` | query | string | No | `DISPLAY` environment variable for X11 applications (auto-formats `:display` if number provided, e.g., `?display=1` becomes `DISPLAY=:1`). |
| `ssh_host` | query | string | No | SSH server hostname or IP address (creates SSH session if provided with `ssh_user`). |
| `ssh_user` | query | string | No | SSH username (required if `ssh_host` is provided). |
| `ssh_port` | query | string | No | SSH port number. Default: `22`. |
| `ssh_password` | query | string | No | SSH password for authentication (use with caution, prefer key-based auth). |
| `socks5_host` | query | string | No | SOCKS5 proxy hostname for SSH connection. |
| `socks5_port` | query | string | No | SOCKS5 proxy port. Default: `1080`. |
| `socks5_user` | query | string | No | SOCKS5 proxy username for authentication. |
| `ssh_key` | query | string | No | Base64-encoded SSH private key for key-based authentication (prefer over password-based auth). |
| `socks5_pass` | query | string | No | SOCKS5 proxy password for authentication. |

### Request Body

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `command` | string | Yes | The command to execute. |
| `id` | string | No | Custom command ID (numeric 1-65535, auto-generated if not provided). |
| `timeout` | integer | No | Timeout in seconds (`0` = no timeout). Default: `0`. |
| `wait` | boolean | No | Whether to wait for completion. Default: `true`; forced `false` when `defer_pid` is set. |
| `cwd` | string | No | Working directory for command execution (for local bash only). |
| `env` | object | No | Environment variables as key-value pairs. |

```json
{
  "command": "ls -la",
  "timeout": 30,
  "wait": true
}
```

### Response



```json
{
  "command_id": "42",
  "status": "running"
}
```


```json
{
  "statusCode": 400,
  "error": "Bad Request",
  "message": "Invalid parameter"
}
```

| Error Code | Title | Description | Resolution |
|------------|-------|-------------|------------|
| `VALIDATION_ERROR` | Invalid or missing parameters | Check parameter format and retry | Check parameter format and retry |
| `INVALID_TERMINAL_ID` | Terminal ID must be numeric (1-65535) | Provide valid terminal_id | Provide valid terminal_id |


```json
{
  "statusCode": 403,
  "error": "Forbidden",
  "message": "Cannot create requested working directory"
}
```

| Error Code | Title | Description | Resolution |
|------------|-------|-------------|------------|
| `CWD_PERMISSION_DENIED` | Requested working directory could not be created | Choose a writable path or disable `cwd_auto_create` | Choose a writable path or disable `cwd_auto_create` |


```json
{
  "statusCode": 405,
  "error": "Method Not Allowed",
  "message": "Request method is not POST"
}
```


```json
{
  "statusCode": 500,
  "error": "Internal Server Error",
  "message": "Command execution failed"
}
```

| Error Code | Title | Description | Resolution |
|------------|-------|-------------|------------|
| `EXECUTION_FAILED` | Command execution failed | Check terminal session status | Check terminal session status |



### SDK Example

```typescript
const result = await client.terminal.execution.execute({
  terminal_id: "1",
  data: {
    command: "ls -la",
    timeout: 30,
    wait: true
  }
});
```

## Get command result

Retrieve the current or final results of a command execution. Can be called while a command is running or after completion.

`GET /api/v1/terminal/result/{command_id}`

### Parameters

| Name | In | Type | Required | Description |
|------|-----|------|----------|-------------|
| `command_id` | path | string | Yes | Command ID returned from `/api/v1/terminal/execute` (numeric 1-65535). |

### Response



```json
{
  "command_id": "42",
  "status": "completed",
  "output": "total 12\ndrwxr-xr-x 3 user user 4096 Jan 15 10:30 .\ndrwxr-xr-x 5 user user 4096 Jan 15 10:29 ..",
  "exit_code": 0
}
```


```json
{
  "statusCode": 404,
  "error": "Not Found",
  "message": "Command not found"
}
```

| Error Code | Title | Description | Resolution |
|------------|-------|-------------|------------|
| `COMMAND_NOT_FOUND` | Command ID does not exist | Verify command_id from execute response | Verify command_id from execute response |



### SDK Example

```typescript
const result = await client.terminal.execution.getResult({
  command_id: "42"
});
```

## Abort a running command

Cancel a command that was started via the execute endpoint. Graceful mode (default) sends `SIGINT` via the PTY (equivalent to Ctrl+C). Force mode sends `SIGKILL` to the process group. Partial output captured before abort is preserved in the response.


Idempotent: aborting an already-completed command returns 409 with the existing result. Known limitation: graceful abort may not stop processes that trap `SIGINT` — use `force=true` for those.


`POST /api/v1/terminal/execute/{command_id}/abort`

### Parameters

| Name | In | Type | Required | Description |
|------|-----|------|----------|-------------|
| `command_id` | path | string | Yes | The command ID returned by the execute endpoint. |

### Request Body

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `force` | boolean | No | Send `SIGKILL` to process group instead of `SIGINT`. Default: `false`. |

```json
{
  "force": false
}
```

### Response

```json
{
  "command_id": "42",
  "status": "aborted",
  "output": "partial output captured before abort",
  "exit_code": null
}
```

### SDK Example

```typescript
const result = await client.terminal.abort({
  command_id: "42",
  data: {
    force: false
  }
});
```

## Write input to terminal

Send keyboard input to a terminal session's PTY. The input is written directly to the PTY master fd, exactly as if typed on a physical keyboard. By default, Enter (newline) is automatically appended after the input. Set `enter=false` for raw input without Enter. Supports interactive prompts (y/n), sudo passwords, and any other stdin input. Use empty input `""` to just press Enter.

`POST /api/v1/terminal/write`

### Parameters

| Name | In | Type | Required | Description |
|------|-----|------|----------|-------------|
| `terminal_id` | query | string | Yes | Terminal session ID to write to. |

### Request Body

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `input` | string | Yes | The text to type into the terminal. |
| `enter` | boolean | No | Auto-append Enter (newline) after input. Default: `true`. Set to `false` for raw keystroke input. |

```json
{
  "input": "y",
  "enter": true
}
```

### Response



```json
{
  "status": "ok",
  "bytes_written": 2
}
```


```json
{
  "statusCode": 400,
  "error": "Bad Request",
  "message": "Missing required field"
}
```

| Error Code | Title | Description | Resolution |
|------------|-------|-------------|------------|
| `MISSING_TERMINAL_ID` | `terminal_id` query parameter is required | `terminal_id` query parameter is required | Contact support |
| `MISSING_INPUT` | `input` field is required in request body | `input` field is required in request body | Contact support |


```json
{
  "statusCode": 404,
  "error": "Not Found",
  "message": "Terminal session not found"
}
```

| Error Code | Title | Description | Resolution |
|------------|-------|-------------|------------|
| `SESSION_NOT_FOUND` | No terminal session with the given ID | No terminal session with the given ID | Contact support |


```json
{
  "statusCode": 405,
  "error": "Method Not Allowed",
  "message": "Request method is not POST"
}
```


```json
{
  "statusCode": 409,
  "error": "Conflict",
  "message": "No running process in session"
}
```

| Error Code | Title | Description | Resolution |
|------------|-------|-------------|------------|
| `NO_PROCESS` | Terminal session has no running process to write to | Terminal session has no running process to write to | Contact support |


```json
{
  "statusCode": 500,
  "error": "Internal Server Error",
  "message": "Failed to write input to PTY"
}
```

| Error Code | Title | Description | Resolution |
|------------|-------|-------------|------------|
| `WRITE_FAILED` | Failed to write input to PTY | Failed to write input to PTY | Contact support |



### SDK Example

```typescript
const result = await client.terminal.write({
  terminal_id: "1",
  data: {
    input: "y",
    enter: true
  }
});
```