> ## Documentation Index
> Fetch the complete documentation index at: https://docs.nelieo.com/llms.txt
> Use this file to discover all available pages before exploring further.

# GET /substrate/v1/apps — list all tracked applications

> Retrieve the full list of applications the NSP daemon is tracking, including probe status, runtime type, confidence score, and available action counts.

The `/apps` endpoint returns every application the daemon has discovered and is actively tracking. Each entry in the response is an `AppSummary` — a lightweight view of that process's identity, runtime, probe health, and state coverage. You typically call this endpoint first to discover which process IDs are available before calling `/state`, `/action`, or `/schema`.

## Endpoint

```http theme={null}
GET /substrate/v1/apps
X-Substrate-Key: <key>
```

**Rate limit:** 100 requests per second. This endpoint reads from the daemon's in-memory process registry and never triggers a probe cycle, so it is very fast (typically under 1 ms).

## Response Fields

<ResponseField name="total" type="integer" required>
  Total number of applications in the `apps` array.
</ResponseField>

<ResponseField name="apps" type="AppSummary[]" required>
  Array of tracked application summaries. See the expandable section below for all fields.

  <Expandable title="AppSummary fields">
    <ResponseField name="pid" type="integer" required>
      The OS process ID. Use this value as the `{pid}` path parameter in `/state/{pid}`, `/schema/{pid}`, `/watch/{pid}`, `/diff/{pid}`, and `/learn/{pid}`.
    </ResponseField>

    <ResponseField name="app_id" type="string" required>
      A stable, semantic identifier that survives daemon restarts, e.g. `"gmail-chrome-12847"`. When you attach a long-running agent to a specific application, prefer `app_id` over `pid` — the daemon resolves the current PID automatically if the process restarts.
    </ResponseField>

    <ResponseField name="app_name" type="string" required>
      Human-readable application name derived from semantic labeling, e.g. `"Gmail"`, `"Mission Planner"`.
    </ResponseField>

    <ResponseField name="runtime" type="string" required>
      Runtime kind. One of `v8`, `jvm`, `clr`, `native`, or `unknown`.
    </ResponseField>

    <ResponseField name="runtime_name" type="string" required>
      Human-readable runtime label, e.g. `"JavaScript (V8)"`, `".NET CLR"`, `"Java (JVM)"`.
    </ResponseField>

    <ResponseField name="probe_status" type="string" required>
      Current probe lifecycle state. Possible values:

      | Value        | Meaning                                                  |
      | ------------ | -------------------------------------------------------- |
      | `detecting`  | Runtime has been identified; probe not yet attached      |
      | `attaching`  | Probe attachment in progress                             |
      | `cold_probe` | First probe cycle running — no state available yet       |
      | `active`     | Probe healthy and producing state                        |
      | `error`      | Last probe cycle failed; daemon will retry automatically |
      | `detached`   | Process exited or probe was manually stopped             |
    </ResponseField>

    <ResponseField name="confidence" type="float" required>
      State quality score from `0.0` to `1.0`. Values above `0.90` indicate high-fidelity semantic labeling. Values below `0.75` suggest the semantic engine is still learning the application's object layout — consider submitting corrections via `POST /learn/{pid}`.
    </ResponseField>

    <ResponseField name="object_count" type="integer" required>
      Number of SSF state objects in the latest snapshot after filtering. This is the number of keys in the `objects` map returned by `/state`.
    </ResponseField>

    <ResponseField name="action_count" type="integer" required>
      Number of typed actions available for this application. Call `GET /schema/{pid}` to see their signatures.
    </ResponseField>

    <ResponseField name="last_captured_at" type="datetime">
      ISO 8601 timestamp of the most recent successful state capture. `null` if no capture has completed yet.
    </ResponseField>

    <ResponseField name="has_state" type="boolean" required>
      `true` if at least one successful state snapshot is available. When `false`, the probe is still in its cold-start cycle — wait and poll until `has_state` becomes `true` before calling `/state`.
    </ResponseField>

    <ResponseField name="current_view" type="string | null">
      Semantic view name, e.g. `"gmail_inbox"`. Available only for V8 apps; `null` for JVM, CLR, and native processes.
    </ResponseField>

    <ResponseField name="current_url" type="string | null">
      Current URL for browser and Electron apps. `null` for non-web runtimes.
    </ResponseField>
  </Expandable>
</ResponseField>

## Examples

<CodeGroup>
  ```bash curl theme={null}
  curl -H "X-Substrate-Key: sk_nsp_..." \
       http://127.0.0.1:7842/substrate/v1/apps
  ```

  ```python Python SDK theme={null}
  from nelieo import NspClient

  client = NspClient(api_key="sk_nsp_...", base_url="http://127.0.0.1:7842")

  apps = await client.list_apps()

  for app in apps:
      print(
          f"{app.app_name:25s}  {app.runtime:6s}  "
          f"conf={app.confidence:.2f}  "
          f"objects={app.object_count}  "
          f"status={app.probe_status}"
      )
  ```
</CodeGroup>

### Example Response

```json theme={null}
{
  "total": 2,
  "apps": [
    {
      "pid": 12847,
      "app_id": "gmail-chrome-12847",
      "app_name": "Gmail",
      "runtime": "v8",
      "runtime_name": "JavaScript (V8)",
      "probe_status": "active",
      "confidence": 0.97,
      "object_count": 23,
      "action_count": 5,
      "last_captured_at": "2026-07-20T13:00:00Z",
      "has_state": true,
      "current_view": "gmail_inbox",
      "current_url": "https://mail.google.com/mail/u/0/#inbox"
    },
    {
      "pid": 4521,
      "app_id": "mission-planner-4521",
      "app_name": "Mission Planner",
      "runtime": "clr",
      "runtime_name": ".NET CLR",
      "probe_status": "active",
      "confidence": 0.95,
      "object_count": 47,
      "action_count": 12,
      "last_captured_at": "2026-07-20T13:00:01Z",
      "has_state": true,
      "current_view": null,
      "current_url": null
    }
  ]
}
```

## Notes

* The response always reflects cached data. Calling `/apps` never triggers a new probe cycle.
* The daemon updates this list continuously as processes start, exit, or change runtime state. You do not need to re-register anything — it happens automatically.
* Apps with `has_state: false` are in a cold probe cycle. Poll `/apps` every few seconds until `has_state` becomes `true` before attempting to read state or execute actions.
* An app with `probe_status: "error"` will be retried automatically. If it stays in `error` for more than 30 seconds, check the daemon logs for probe attachment failures.
