Skip to main content
NSPClient is the first object you create in any NSP agent. It owns the underlying HTTP connection pool, injects your API key into every request, and exposes every operation the daemon offers — from listing tracked apps to opening a session on a specific application. You always use it as an async with context manager so the connection pool is released cleanly when your agent exits.

Constructor

Authentication

The client reads your API key in one of two ways. Set the NSP_API_KEY environment variable and the client picks it up automatically, or pass api_key= directly to the constructor.

Using NSPClient as an async context manager

Always open NSPClient with async with. The context manager starts the connection pool on entry and drains it on exit, even if an exception is raised inside the block.
client_basic.py
For long-lived processes where you cannot use async with, call await client.aclose() manually in a finally block.

Methods

ping() → bool

Check whether the daemon is reachable. This method never raises — it returns False on any connection or authentication failure, making it safe as a pre-flight health check.

list_apps() → list[AppSummary]

Return all applications currently tracked by the daemon. This call returns the daemon’s cached list and does not trigger new probes. The daemon updates the list automatically as processes start and stop.
Each AppSummary has these fields:
Apps with has_state: False are still in the cold probe phase. Wait for probe_status to become "active" before reading state.

get_state(pid, *, fresh=False) → SubstrateState

Fetch the semantic state snapshot for a specific process. By default this returns the daemon’s cached state in under a millisecond. Pass fresh=True to trigger a new probe cycle, which adds 50ms to 90 seconds of latency depending on the runtime.
Raises: NSPNotFoundError if the PID is not currently tracked.

attach(app_name) → Session

Attach to a running application by name and open a Session. This is the primary way to work with any app — you never need to look up PIDs manually.
Raises: NSPNotFoundError if no tracked app matches the name.

watch(pid) → AsyncStream

Open a raw WebSocket stream for a PID. This is the lower-level entry point for streaming — for most use cases, prefer session.watch() which also keeps the session’s cached state updated.

Complete example

The example below shows the full lifecycle of an NSPClient — connecting, discovering apps, reading state, and executing an action.
monitor_gmail.py