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 theNSP_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 openNSPClient 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
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.
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.
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.
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 anNSPClient — connecting, discovering apps, reading state, and executing an action.
monitor_gmail.py
