# App: Execution

**Page:** api/app/execution

[Download Raw Markdown](./api/app/execution.md)

---

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



# App: Execution

The App Execution API resolves, searches, and runs applications across configured package sources. Use these endpoints to look up candidates, plan an execution, delegate to a terminal session, run preflight checks, or batch multiple requests in a single call. The API supports query-parameter selectors, JSON body selectors, and bookmarkable path-based URLs.


  By default, run endpoints are command-only and return the exact shell command without calling `hoody-terminal`. Legacy delegation is opt-in via `HOODY_RUN_ENABLE_TERMINAL_EXECUTE=true`.


## Configuration

### `GET /api/v1/run/config`

Returns the full persisted runtime configuration including sources, profiles, and the currently selected profile.

This endpoint takes no parameters.




```bash
curl -X GET 'https://api.hoody.com/api/v1/run/config' \
  -H 'Authorization: Bearer <token>'
```




```javascript
const config = await client.app.configuration.get();
```




```json
{
  "version": 3,
  "sources": [
    {
      "source_id": "nixpkgs",
      "enabled": true,
      "priority": 100,
      "provider": "nix",
      "source_type": "nix-pkgs"
    }
  ],
  "profiles": [
    {
      "name": "default",
      "description": "Default profile (inherits global sources)"
    }
  ],
  "selected_profile": "default",
  "recipes": [],
  "webhooks": []
}
```




---

## Searching for Candidates

### `GET /api/v1/run/search`

Search for runnable application candidates across all configured and enabled package sources. Returns a ranked list of candidates with stable ordering for pick-by-index operations. The returned `set_id` can be used with subsequent run requests to ensure race-free candidate selection.

### Parameters

| Name | In | Type | Required | Description |
|------|-----|------|----------|-------------|
| `app` | query | string | Yes | Primary name query (aliases `q`, `name`) |
| `os` | query | `app_Os` | No | Target OS filter |
| `source` | query | array | No | Source kind filter (repeatable) |
| `kind` | query | `app_AppKind` | No | App kind filter (`gui`, `cli`, `any`) |
| `arch` | query | `app_Arch` | No | Target CPU architecture filter |
| `tags` | query | array | No | Free-form tags for filtering and ranking (repeatable) |
| `profile` | query | string | No | Named profile for default preferences |
| `channel` | query | string | No | Release channel hint (for example `stable` or `beta`) |
| `version` | query | string | No | Exact version or provider-defined version constraint |
| `variant` | query | string | No | Provider-specific variant hint (for example `portable` or `headless`) |
| `publisher` | query | string | No | Publisher hint for curated registries |
| `repo` | query | string | No | Repository hint such as `owner/name` |
| `release` | query | string | No | Release hint such as a tag name |
| `asset` | query | string | No | Desired asset name or pattern |
| `limit` | query | integer | No | Max candidates to return (default 25) |




```bash
curl -X GET 'https://api.hoody.com/api/v1/run/search?app=firefox&os=linux&kind=any&limit=10' \
  -H 'Authorization: Bearer <token>'
```




```javascript
const result = await client.app.execution.searchCandidates({
  app: "firefox",
  os: "linux",
  kind: "any",
  limit: 10
});
```




```json
{
  "set_id": "a1b2c3d4e5f6",
  "candidates": [
    {
      "candidate_id": "nix-firefox-128",
      "title": "Firefox (nixpkgs)",
      "description": "Mozilla Firefox web browser via nixpkgs",
      "version": "128.0.3",
      "provider": "nix",
      "source_id": "nixpkgs",
      "score": 95,
      "run_plan": {
        "command": "nix run nixpkgs#firefox"
      }
    }
  ]
}
```




```json
{
  "error": "missing app",
  "code": 400
}
```

| Error Code | Title | Description | Resolution |
|------------|-------|-------------|------------|
| `MISSING_APP` | Missing app query | No app name was provided in the request | Set `app`, `q`, or `name` to the desired program |
| `INVALID_SELECTOR` | Invalid selector parameter | One or more selector parameters could not be parsed | Check enum values and numeric fields, then retry |
| `UNKNOWN_PROFILE` | Unknown profile | The requested profile does not exist | Call `listProfiles` or `getConfig` and choose a valid profile name |




```json
{
  "error": "candidate resolution failed",
  "code": 502
}
```

| Error Code | Title | Description | Resolution |
|------------|-------|-------------|------------|
| `SOURCE_RESOLUTION_FAILED` | Source resolution failed | Candidate resolution could not be completed because upstream source work failed | Retry or inspect provider/source health |




### `POST /api/v1/run/search/paged`

Resolve a full ranked candidate set under a bounded cap, then page through it with an opaque cursor. This is the stable pagination contract for large result sets. The SDK call returns an async iterator that transparently pages through results.

**Request Body**: JSON body conforming to the `app_PagedSearchRequest` schema.




```bash
curl -X POST 'https://api.hoody.com/api/v1/run/search/paged' \
  -H 'Authorization: Bearer <token>' \
  -H 'Content-Type: application/json' \
  -d '{
    "selector": {
      "app": "code",
      "os": "linux",
      "kind": "any"
    },
    "page_size": 25
  }'
```




```javascript
const iterator = client.app.execution.searchCandidatesPagedIterator({
  selector: { app: "code", os: "linux", kind: "any" },
  page_size: 25
});
for await (const page of iterator) {
  console.log(page.items);
}
```




```json
{
  "set_id": "a1b2c3d4e5f6",
  "total_count": 42,
  "items": [
    {
      "candidate_id": "nix-vscode-1.85",
      "title": "Visual Studio Code (nixpkgs)",
      "description": "Open-source code editor",
      "provider": "nix",
      "source_id": "nixpkgs",
      "score": 92,
      "run_plan": {
        "command": "nix run nixpkgs#vscode"
      }
    }
  ],
  "next_cursor": "eyJzZXRJZCI6ImExYjJjM2Q0ZTVmNiIsIm9mZnNldCI6MjV9"
}
```




```json
{
  "error": "missing app",
  "code": 400
}
```




```json
{
  "error": "cursor set expired",
  "code": 409
}
```

| Error Code | Title | Description | Resolution |
|------------|-------|-------------|------------|
| `CURSOR_SET_EXPIRED` | Cursor set expired | The cached candidate set referenced by the cursor is no longer available | Restart pagination from the first page |




```json
{
  "error": "candidate resolution failed",
  "code": 502
}
```




---

## Running Applications

### `GET /api/v1/run/run`

Resolve and select an application using query parameters, then return the exact shell command to run. Supports all selector fields plus pick mode, output control, deferred execution metadata, and redirect behavior.

### Parameters

| Name | In | Type | Required | Description |
|------|-----|------|----------|-------------|
| `app` | query | string | Yes | Primary name query |
| `os` | query | `app_Os` | No | Target OS filter |
| `source` | query | array | No | Source kind filter (repeatable) |
| `kind` | query | `app_AppKind` | No | App kind filter |
| `arch` | query | `app_Arch` | No | Target CPU architecture filter |
| `tags` | query | array | No | Free-form tags for filtering and ranking (repeatable) |
| `profile` | query | string | No | Named profile for default preferences |
| `channel` | query | string | No | Release channel hint |
| `version` | query | string | No | Exact version or provider-defined version constraint |
| `variant` | query | string | No | Provider-specific variant hint |
| `publisher` | query | string | No | Publisher hint for curated registries |
| `repo` | query | string | No | Repository hint such as `owner/name` |
| `release` | query | string | No | Release hint such as a tag name |
| `asset` | query | string | No | Desired asset name or pattern |
| `pick` | query | `app_PickMode` | No | Candidate selection mode (`ask`, `first`, `index`, `id`) |
| `pick_index` | query | integer | No | Candidate index (required when `pick=index`) |
| `candidate_id` | query | string | No | Specific candidate ID (required when `pick=id`) |
| `set_id` | query | string | No | Bind pick to a specific candidate set |
| `terminal_id` | query | integer | No | Terminal session ID (default 1) |
| `display` | query | string | No | X11 DISPLAY number |
| `origin` | query | string | No | Origin identifier for observability propagation |
| `defer_pid` | query | integer | No | Defer command injection until this PID exits |
| `defer_start_time_ticks` | query | string | No | Start-time ticks used to avoid PID reuse bugs |
| `defer_timeout_ms` | query | integer | No | Maximum defer wait time in milliseconds |
| `defer_poll_ms` | query | integer | No | Defer polling interval in milliseconds |
| `dry_run` | query | boolean | No | If true, force command-only response (no delegation) |
| `print_curl` | query | `app_PrintCurlMode` | No | Generate curl command (`hoody-run` or `hoody-terminal`) |
| `format` | query | `app_OutputFormat` | No | Output format (`json` or `html`) |
| `redirect` | query | boolean | No | Redirect to display page after scheduling |
| `redirect_to` | query | string | No | Override redirect target URL |
| `limit` | query | integer | No | Max candidates (default 25) |




```bash
curl -X GET 'https://api.hoody.com/api/v1/run/run?app=firefox&os=linux&kind=any&pick=first&terminal_id=1' \
  -H 'Authorization: Bearer <token>'
```




```javascript
const result = await client.app.execution.runAppGet({
  app: "firefox",
  os: "linux",
  kind: "any",
  pick: "first",
  terminal_id: 1
});
```




```json
{
  "status": "dry-run",
  "set_id": "a1b2c3d4e5f6",
  "selected": {
    "candidate_id": "nix-firefox-128",
    "title": "Firefox (nixpkgs)",
    "description": "Mozilla Firefox web browser via nixpkgs",
    "version": "128.0.3",
    "provider": "nix",
    "source_id": "nixpkgs",
    "score": 95,
    "run_plan": {
      "command": "nix run nixpkgs#firefox"
    },
    "shell_command": "nix run nixpkgs#firefox"
  },
  "shell_command": "nix run nixpkgs#firefox"
}
```




```json
{
  "error": "missing app",
  "code": 400
}
```

| Error Code | Title | Description | Resolution |
|------------|-------|-------------|------------|
| `MISSING_APP` | Missing app query | No app name was provided in the request | Set `app` to the desired program name |
| `INVALID_SELECTOR` | Invalid selector parameter | One or more selector parameters could not be parsed | Check enum values and numeric fields, then retry |
| `UNKNOWN_PROFILE` | Unknown profile | The requested profile does not exist | Choose a profile returned by `listProfiles` or `getConfig` |
| `INVALID_PICK` | Invalid pick request | The pick mode requirements were not satisfied or the selected candidate was not found | Search first, then supply a valid `pick_index` or `candidate_id` |




```json
{
  "error": "invalid terminal url",
  "code": 500
}
```

| Error Code | Title | Description | Resolution |
|------------|-------|-------------|------------|
| `INVALID_TERMINAL_URL` | Invalid terminal URL | Curl generation could not build a valid hoody-terminal execute URL | Check `HOODY_TERMINAL_URL` and retry |




```json
{
  "error": "candidate resolution failed",
  "code": 502
}
```

| Error Code | Title | Description | Resolution |
|------------|-------|-------------|------------|
| `SOURCE_RESOLUTION_FAILED` | Source resolution failed | Candidate resolution could not be completed because upstream source work failed | Retry or inspect provider/source health |




```json
{
  "error": "required local tools are unavailable",
  "code": 503
}
```

| Error Code | Title | Description | Resolution |
|------------|-------|-------------|------------|
| `LOCAL_TOOLS_UNAVAILABLE` | Required local tools are unavailable | The selected candidate requires local tooling that is not currently available | Install or repair the required toolchain, then retry |




### `POST /api/v1/run/run`

Same behavior as `GET /api/v1/run/run` but accepts the full Selector as a JSON request body. Useful for programmatic clients and complex selectors.

**Request Body**: JSON body conforming to the `app_Selector` schema.




```bash
curl -X POST 'https://api.hoody.com/api/v1/run/run' \
  -H 'Authorization: Bearer <token>' \
  -H 'Content-Type: application/json' \
  -d '{
    "app": "firefox",
    "os": "linux",
    "kind": "any",
    "pick": "first",
    "terminal_id": 1
  }'
```




```javascript
const result = await client.app.execution.runAppPost({
  app: "firefox",
  os: "linux",
  kind: "any",
  pick: "first",
  terminal_id: 1
});
```




```json
{
  "status": "dry-run",
  "set_id": "a1b2c3d4e5f6",
  "selected": {
    "candidate_id": "nix-firefox-128",
    "title": "Firefox (nixpkgs)",
    "description": "Mozilla Firefox web browser via nixpkgs",
    "version": "128.0.3",
    "provider": "nix",
    "source_id": "nixpkgs",
    "score": 95,
    "run_plan": {
      "command": "nix run nixpkgs#firefox"
    },
    "shell_command": "nix run nixpkgs#firefox"
  },
  "shell_command": "nix run nixpkgs#firefox"
}
```




```json
{
  "error": "missing app",
  "code": 400
}
```

| Error Code | Title | Description | Resolution |
|------------|-------|-------------|------------|
| `MISSING_APP` | Missing app query | No app name was provided in the request body | Set `app` to the desired program name |
| `INVALID_SELECTOR` | Invalid selector parameter | One or more selector fields could not be parsed | Check enum values and numeric fields, then retry |
| `UNKNOWN_PROFILE` | Unknown profile | The requested profile does not exist | Choose a profile returned by `listProfiles` or `getConfig` |
| `INVALID_PICK` | Invalid pick request | The pick mode requirements were not satisfied or the selected candidate was not found | Search first, then supply a valid `pick_index` or `candidate_id` |




```json
{
  "error": "invalid terminal url",
  "code": 500
}
```

| Error Code | Title | Description | Resolution |
|------------|-------|-------------|------------|
| `INVALID_TERMINAL_URL` | Invalid terminal URL | Curl generation could not build a valid hoody-terminal execute URL | Check `HOODY_TERMINAL_URL` and retry |




```json
{
  "error": "candidate resolution failed",
  "code": 502
}
```

| Error Code | Title | Description | Resolution |
|------------|-------|-------------|------------|
| `SOURCE_RESOLUTION_FAILED` | Source resolution failed | Candidate resolution could not be completed because upstream source work failed | Retry or inspect provider/source health |




```json
{
  "error": "required local tools are unavailable",
  "code": 503
}
```

| Error Code | Title | Description | Resolution |
|------------|-------|-------------|------------|
| `LOCAL_TOOLS_UNAVAILABLE` | Required local tools are unavailable | The selected candidate requires local tooling that is not currently available | Install or repair the required toolchain, then retry |




### `GET /api/v1/run/go/{rest}`

Resolve an application using clean, bookmarkable path-based URLs. Supports both positional and key-value path segments.

Positional examples:
- `/api/v1/run/go/{app}`
- `/api/v1/run/go/{os}/{app}`
- `/api/v1/run/go/{os}/{source}/{app}`
- `/api/v1/run/go/{os}/{source}/{kind}/{app}`

Key-value example: `/api/v1/run/go/app/{app}/os/{os}/source/{source}/kind/{kind}/pick/{pick}/...`

### Parameters

| Name | In | Type | Required | Description |
|------|-----|------|----------|-------------|
| `rest` | path | string | Yes | Path segments for positional or key-value app specification |
| `os` | query | `app_Os` | No | Target OS filter when not supplied in the path |
| `source` | query | array | No | Source kind filter (repeatable) |
| `kind` | query | `app_AppKind` | No | App kind filter when not supplied in the path |
| `arch` | query | `app_Arch` | No | Target CPU architecture filter |
| `tags` | query | array | No | Free-form tags for filtering and ranking (repeatable) |
| `profile` | query | string | No | Named profile for default preferences |
| `channel` | query | string | No | Release channel hint |
| `version` | query | string | No | Exact version or provider-defined version constraint |
| `variant` | query | string | No | Provider-specific variant hint |
| `publisher` | query | string | No | Publisher hint for curated registries |
| `repo` | query | string | No | Repository hint such as `owner/name` |
| `release` | query | string | No | Release hint such as a tag name |
| `asset` | query | string | No | Desired asset name or pattern |
| `pick` | query | `app_PickMode` | No | Candidate selection mode (`ask`, `first`, `index`, `id`) |
| `pick_index` | query | integer | No | Candidate index (required when `pick=index`) |
| `candidate_id` | query | string | No | Specific candidate ID (required when `pick=id`) |
| `set_id` | query | string | No | Bind pick to a specific candidate set |
| `terminal_id` | query | integer | No | Terminal session ID when not supplied in the path |
| `display` | query | string | No | X11 DISPLAY number |
| `origin` | query | string | No | Origin identifier for observability propagation |
| `defer_pid` | query | integer | No | Defer command injection until this PID exits |
| `defer_start_time_ticks` | query | string | No | Start-time ticks used to avoid PID reuse bugs |
| `defer_timeout_ms` | query | integer | No | Maximum defer wait time in milliseconds |
| `defer_poll_ms` | query | integer | No | Defer polling interval in milliseconds |
| `dry_run` | query | boolean | No | If true, force command-only response (no delegation) |
| `print_curl` | query | `app_PrintCurlMode` | No | Generate curl command (`hoody-run` or `hoody-terminal`) |
| `format` | query | `app_OutputFormat` | No | Output format (`json` or `html`) |
| `redirect` | query | boolean | No | Redirect to display page after scheduling |
| `redirect_to` | query | string | No | Override redirect target URL |
| `limit` | query | integer | No | Max candidates (default 25) |




```bash
curl -X GET 'https://api.hoody.com/api/v1/run/go/linux/nix/firefox?pick=first&terminal_id=1' \
  -H 'Authorization: Bearer <token>'
```




```javascript
const result = await client.app.execution.runPathBased({
  rest: "linux/nix/firefox",
  pick: "first",
  terminal_id: 1
});
```




```json
{
  "status": "dry-run",
  "set_id": "a1b2c3d4e5f6",
  "selected": {
    "candidate_id": "nix-firefox-128",
    "title": "Firefox (nixpkgs)",
    "description": "Mozilla Firefox web browser via nixpkgs",
    "version": "128.0.3",
    "provider": "nix",
    "source_id": "nixpkgs",
    "score": 95,
    "run_plan": {
      "command": "nix run nixpkgs#firefox"
    },
    "shell_command": "nix run nixpkgs#firefox"
  },
  "shell_command": "nix run nixpkgs#firefox"
}
```




```json
{
  "error": "missing app",
  "code": 400
}
```

| Error Code | Title | Description | Resolution |
|------------|-------|-------------|------------|
| `MISSING_APP` | Missing app query | No app name was provided in the request | Set the app in the path or query string |
| `INVALID_SELECTOR` | Invalid selector parameter | One or more selector parameters could not be parsed | Check enum values and numeric fields, then retry |
| `UNKNOWN_PROFILE` | Unknown profile | The requested profile does not exist | Choose a profile returned by `listProfiles` or `getConfig` |
| `INVALID_PICK` | Invalid pick request | The pick mode requirements were not satisfied or the selected candidate was not found | Search first, then supply a valid `pick_index` or `candidate_id` |




```json
{
  "error": "invalid terminal url",
  "code": 500
}
```

| Error Code | Title | Description | Resolution |
|------------|-------|-------------|------------|
| `INVALID_TERMINAL_URL` | Invalid terminal URL | Curl generation could not build a valid hoody-terminal execute URL | Check `HOODY_TERMINAL_URL` and retry |




```json
{
  "error": "candidate resolution failed",
  "code": 502
}
```

| Error Code | Title | Description | Resolution |
|------------|-------|-------------|------------|
| `SOURCE_RESOLUTION_FAILED` | Source resolution failed | Candidate resolution could not be completed because upstream source work failed | Retry or inspect provider/source health |




```json
{
  "error": "required local tools are unavailable",
  "code": 503
}
```

| Error Code | Title | Description | Resolution |
|------------|-------|-------------|------------|
| `LOCAL_TOOLS_UNAVAILABLE` | Required local tools are unavailable | The selected candidate requires local tooling that is not currently available | Install or repair the required toolchain, then retry |




### `GET /api/v1/run/t/{terminal_id}/go/{rest}`

Same as `/api/v1/run/go/{rest}` but with `terminal_id` extracted from the path prefix. Allows clean URLs that specify both the target terminal and the application in a single path.

Example: `/api/v1/run/t/2/go/linux/nix/firefox` runs Firefox in terminal 2.

### Parameters

| Name | In | Type | Required | Description |
|------|-----|------|----------|-------------|
| `terminal_id` | path | integer | Yes | Terminal session ID (1-65535) |
| `rest` | path | string | Yes | Path segments for app specification |
| `os` | query | `app_Os` | No | Target OS filter when not supplied in the path |
| `source` | query | array | No | Source kind filter (repeatable) |
| `kind` | query | `app_AppKind` | No | App kind filter when not supplied in the path |
| `arch` | query | `app_Arch` | No | Target CPU architecture filter |
| `tags` | query | array | No | Free-form tags for filtering and ranking (repeatable) |
| `profile` | query | string | No | Named profile for default preferences |
| `channel` | query | string | No | Release channel hint |
| `version` | query | string | No | Exact version or provider-defined version constraint |
| `variant` | query | string | No | Provider-specific variant hint |
| `publisher` | query | string | No | Publisher hint for curated registries |
| `repo` | query | string | No | Repository hint such as `owner/name` |
| `release` | query | string | No | Release hint such as a tag name |
| `asset` | query | string | No | Desired asset name or pattern |
| `pick` | query | `app_PickMode` | No | Candidate selection mode (`ask`, `first`, `index`, `id`) |
| `pick_index` | query | integer | No | Candidate index (required when `pick=index`) |
| `candidate_id` | query | string | No | Specific candidate ID (required when `pick=id`) |
| `set_id` | query | string | No | Bind pick to a specific candidate set |
| `display` | query | string | No | X11 DISPLAY number |
| `origin` | query | string | No | Origin identifier for observability propagation |
| `defer_pid` | query | integer | No | Defer command injection until this PID exits |
| `defer_start_time_ticks` | query | string | No | Start-time ticks used to avoid PID reuse bugs |
| `defer_timeout_ms` | query | integer | No | Maximum defer wait time in milliseconds |
| `defer_poll_ms` | query | integer | No | Defer polling interval in milliseconds |
| `dry_run` | query | boolean | No | If true, force command-only response (no delegation) |
| `print_curl` | query | `app_PrintCurlMode` | No | Generate curl command (`hoody-run` or `hoody-terminal`) |
| `format` | query | `app_OutputFormat` | No | Output format (`json` or `html`) |
| `redirect` | query | boolean | No | Redirect to display page after scheduling |
| `redirect_to` | query | string | No | Override redirect target URL |
| `limit` | query | integer | No | Max candidates (default 25) |




```bash
curl -X GET 'https://api.hoody.com/api/v1/run/t/2/go/linux/nix/firefox?pick=first' \
  -H 'Authorization: Bearer <token>'
```




```javascript
const result = await client.app.execution.runTerminalAnchored({
  terminal_id: 2,
  rest: "linux/nix/firefox",
  pick: "first"
});
```




```json
{
  "status": "dry-run",
  "set_id": "a1b2c3d4e5f6",
  "selected": {
    "candidate_id": "nix-firefox-128",
    "title": "Firefox (nixpkgs)",
    "description": "Mozilla Firefox web browser via nixpkgs",
    "version": "128.0.3",
    "provider": "nix",
    "source_id": "nixpkgs",
    "score": 95,
    "run_plan": {
      "command": "nix run nixpkgs#firefox"
    },
    "shell_command": "nix run nixpkgs#firefox"
  },
  "shell_command": "nix run nixpkgs#firefox"
}
```




```json
{
  "error": "missing app",
  "code": 400
}
```

| Error Code | Title | Description | Resolution |
|------------|-------|-------------|------------|
| `MISSING_APP` | Missing app query | No app name was provided in the request | Set the app in the path or query string |
| `INVALID_SELECTOR` | Invalid selector parameter | One or more selector parameters could not be parsed | Check enum values and numeric fields, then retry |
| `UNKNOWN_PROFILE` | Unknown profile | The requested profile does not exist | Choose a profile returned by `listProfiles` or `getConfig` |
| `INVALID_PICK` | Invalid pick request | The pick mode requirements were not satisfied or the selected candidate was not found | Search first, then supply a valid `pick_index` or `candidate_id` |




```json
{
  "error": "invalid terminal url",
  "code": 500
}
```

| Error Code | Title | Description | Resolution |
|------------|-------|-------------|------------|
| `INVALID_TERMINAL_URL` | Invalid terminal URL | Curl generation could not build a valid hoody-terminal execute URL | Check `HOODY_TERMINAL_URL` and retry |




```json
{
  "error": "candidate resolution failed",
  "code": 502
}
```

| Error Code | Title | Description | Resolution |
|------------|-------|-------------|------------|
| `SOURCE_RESOLUTION_FAILED` | Source resolution failed | Candidate resolution could not be completed because upstream source work failed | Retry or inspect provider/source health |




```json
{
  "error": "required local tools are unavailable",
  "code": 503
}
```

| Error Code | Title | Description | Resolution |
|------------|-------|-------------|------------|
| `LOCAL_TOOLS_UNAVAILABLE` | Required local tools are unavailable | The selected candidate requires local tooling that is not currently available | Install or repair the required toolchain, then retry |




---

## Preflight

### `POST /api/v1/run/preflight`

Resolve, optionally pick, and normalize the execution plan for a selector without scheduling execution. Use this endpoint to inspect what would happen — including missing requirements, recommended mode, and effective policy — before actually running a request.

**Request Body**: JSON body conforming to the `app_Selector` schema.




```bash
curl -X POST 'https://api.hoody.com/api/v1/run/preflight' \
  -H 'Authorization: Bearer <token>' \
  -H 'Content-Type: application/json' \
  -d '{
    "app": "firefox",
    "os": "linux",
    "kind": "any",
    "pick": "first"
  }'
```




```javascript
const plan = await client.app.execution.preflight({
  app: "firefox",
  os: "linux",
  kind: "any",
  pick: "first"
});
```




```json
{
  "set_id": "a1b2c3d4e5f6",
  "selected": {
    "candidate_id": "nix-firefox-128",
    "title": "Firefox (nixpkgs)",
    "description": "Mozilla Firefox web browser via nixpkgs",
    "version": "128.0.3",
    "provider": "nix",
    "source_id": "nixpkgs",
    "score": 95,
    "run_plan": {
      "command": "nix run nixpkgs#firefox"
    },
    "shell_command": "nix run nixpkgs#firefox"
  },
  "shell_command": "nix run nixpkgs#firefox",
  "recommended_mode": "dry-run",
  "terminal_request_preview": {
    "terminal_url": "http://127.0.0.1:7682/api/v1/terminal/execute",
    "terminal_id": 1,
    "display": ":0",
    "origin": "hoody-run",
    "command": "nix run nixpkgs#firefox"
  },
  "redirect_target": "/apps/nixpkgs/firefox",
  "missing_requirements": [],
  "warnings": [],
  "effective_policy": {
    "require_verified": false,
    "require_integrity": false,
    "allow_delegated_execution": true,
    "allow_redirect": true,
    "deny_providers": [],
    "deny_source_ids": []
  }
}
```




```json
{
  "error": "missing app",
  "code": 400
}
```




```json
{
  "error": "candidate resolution failed",
  "code": 502
}
```




---

## Batch Execution

### `POST /api/v1/run/batch`

Process multiple search or command-only run items in one request. Each item produces its own success or error payload. Use this endpoint to amortize overhead when you need to resolve or run several apps at once.

**Request Body**: JSON body conforming to the `app_BatchRequest` schema.




```bash
curl -X POST 'https://api.hoody.com/api/v1/run/batch' \
  -H 'Authorization: Bearer <token>' \
  -H 'Content-Type: application/json' \
  -d '{
    "items": [
      {
        "request_id": "req-1",
        "mode": "search",
        "selector": { "app": "firefox", "os": "linux", "kind": "any" }
      },
      {
        "request_id": "req-2",
        "mode": "run",
        "selector": { "app": "code", "os": "linux", "kind": "any", "pick": "first" }
      }
    ]
  }'
```




```javascript
const result = await client.app.execution.runBatch({
  items: [
    { request_id: "req-1", mode: "search", selector: { app: "firefox", os: "linux", kind: "any" } },
    { request_id: "req-2", mode: "run", selector: { app: "code", os: "linux", kind: "any", pick: "first" } }
  ]
});
```




```json
{
  "items": [
    {
      "result": "search",
      "request_id": "req-1",
      "search": {
        "set_id": "a1b2c3d4e5f6",
        "candidates": [
          {
            "candidate_id": "nix-firefox-128",
            "title": "Firefox (nixpkgs)",
            "description": "Mozilla Firefox web browser via nixpkgs",
            "provider": "nix",
            "source_id": "nixpkgs",
            "score": 95,
            "run_plan": { "command": "nix run nixpkgs#firefox" }
          }
        ]
      }
    },
    {
      "result": "run",
      "request_id": "req-2",
      "run": {
        "status": "dry-run",
        "set_id": "b2c3d4e5f6a7",
        "shell_command": "nix run nixpkgs#vscode"
      }
    }
  ]
}
```




---

## API Documentation

### `GET /api/v1/run/openapi.json`

Returns the OpenAPI 3.0.3 specification for this API in JSON format. Converted from the canonical YAML source.

This endpoint takes no parameters.




```bash
curl -X GET 'https://api.hoody.com/api/v1/run/openapi.json' \
  -H 'Authorization: Bearer <token>'
```




```javascript
const spec = await client.app.docs.getJson();
```




```json
{
  "openapi": "3.0.3",
  "info": {
    "title": "Hoody App Execution API",
    "version": "1.0.0"
  },
  "paths": {}
}
```




### `GET /api/v1/run/openapi.yaml`

Returns the OpenAPI 3.0.3 specification for this API in YAML format.

This endpoint takes no parameters.




```bash
curl -X GET 'https://api.hoody.com/api/v1/run/openapi.yaml' \
  -H 'Authorization: Bearer <token>'
```




```javascript
const spec = await client.app.docs.getYaml();
```




```yaml
openapi: 3.0.3
info:
  title: Hoody App Execution API
  version: 1.0.0
paths: {}
```