Skip to main content
NSP exposes every running application through a unified data model built from three primitives: structured state, typed actions, and a schema that ties them together. Understanding these primitives is the key to writing reliable agents — it tells you exactly what data you can read, what operations you can call, and what safety guarantees you can rely on.

The Substrate Model

NSP treats every running application as a substrate — a live, addressable data source you can read from and write to in real time. The substrate model has three components.

State

A typed JSON snapshot of the application’s current data, normalized to the Substrate Schema Format (SSF) with stable dot-notation keys.

Actions

Typed function signatures discovered from the runtime that your agent can invoke directly — no UI interaction, no mouse clicks.

Schema

A persistent, versioned registry of discovered state structures and action mappings, stored on disk and reused automatically across daemon restarts.

SubstrateState (SSF)

Every application’s state is represented as a SubstrateState object — the core data structure that flows through every part of NSP. You get one of these back from GET /substrate/v1/state/{pid}.

Field Reference

Confidence Score

Every SubstrateState carries a confidence field between 0.0 and 1.0 that represents how certain the probe is in the semantic accuracy of its labels. The daemon uses this score as a safety gate before allowing action execution. Runtime confidence baselines tell you what to expect once a probe is warm:
If you see confidence below the expected baseline for a V8 or JVM app, the probe is likely still in its cold-start phase. Wait a few seconds and re-poll — confidence climbs as the schema cache warms up.

Action Schema

Every action available on a substrate is described by an ActionSchema that tells your agent exactly what parameters to pass, what to expect back, and how risky the operation is.
The confidence on an action schema reflects how reliably NSP can invoke it — separate from the state-level confidence. Both must meet their respective thresholds before execution proceeds.

Reversibility

Every action is classified into one of three reversibility tiers. This is a safety contract enforced at the daemon and SDK level, not a suggestion or annotation.
The action reads data without modifying any application state. There is no confidence gate for read actions — they are safe to call at any confidence level.Examples: get_thread, search, list_contacts, read_document, get_calendar_events
The action modifies application state in a way that can be undone. The daemon requires confidence >= 0.80 before dispatching.Examples: archive, label, move_to_folder, mark_read, star, create_draft
The action causes a permanent side effect that cannot be undone. The daemon requires confidence >= 0.95 and the SDK requires verify=True with a verify_expression. Calling execute without these raises NSPIrreversibleNotConfirmedError.Examples: send_reply, delete_permanently, purchase, submit_form, send_message
After executing the action, NSP waits 200 ms, then polls the app state up to 10 times — evaluating your verify_expression each cycle — before returning. The response includes a verification object with the outcome, which changed fields were observed, and the total latency.

Runtime Probes

Each runtime family uses a fundamentally different technical method to reach the application’s internal state. Understanding which probe applies to your target app helps you predict accuracy, cold-start time, and confidence baselines.

V8 / JavaScript

The V8 probe connects to Chrome or any Electron app via the Chrome DevTools Protocol (CDP) remote debugging port (enabled with --remote-debugging-port=9222). It uses a fast-path state extraction method that returns in 5–50 ms during normal operation. On first encounter with a new app, NSP falls back to a full heap snapshot to build the schema — this takes up to ~47 seconds but runs only once. All subsequent reads use the fast path against the cached schema. Covered apps: Gmail, Slack, VS Code, Notion, GitHub Desktop, Salesforce, WhatsApp Desktop, Discord, Shopify, HubSpot, and any Electron-based application.

JVM / Java

The JVM probe attaches to a running Java process without requiring a restart, reads live object fields using the JVM’s native instrumentation interface, and converts Java objects to SSF JSON using class type metadata. No code changes to the target application are needed. Covered apps: SAP ERP, Eclipse, IntelliJ IDEA, Jenkins, Elasticsearch, ArduPilot GCS (Java build).

CLR / .NET

The CLR probe injects a managed bootstrapper into the target .NET process and reads field values and method return values from the CLR heap, communicating results back to the daemon over an inter-process channel. No changes to the target application are required. Covered apps: Mission Planner, WinForms apps, WPF apps, Visual Studio, Microsoft Office (Excel, Word, PowerPoint), and any .NET 4.x or .NET 6+ desktop app.

Native / C++

The native probe reads raw process memory from compiled binaries that carry no semantic metadata. NSP layers a Visual-Memory Grounding pass on top — correlating memory regions with a local vision model to produce human-readable semantic labels. Covered apps: Bloomberg Terminal, Photoshop, AutoCAD, Chrome internals (C++ layer). Expect confidence in the 0.40–0.75 range rather than the high-nineties seen for managed runtimes.

App Lifecycle

An app moves through a well-defined state machine from the moment NSP detects its process to the moment it exits. Understanding this lifecycle helps you reason about cold-start delays, poll frequency, and WebSocket event timing.
The cold probe delay (3–90 seconds) only occurs the first time NSP encounters an app. On every subsequent start, the daemon reuses the cached schema from disk and reaches an active probe state in under a second.

State Object Keys

NSP stores all state values in a flat dot-notation map rather than nested JSON. This design means your agent can reference any specific value with a single deterministic string — no recursive traversal, no path ambiguity.
Keys are stable across poll cycles for a given app and schema version. If inbox.emails[0].subject resolves to the email subject today, it resolves to the email subject on every subsequent read until the schema version changes. When schema_version increments (a semver bump in the SubstrateState), re-validate any hardcoded key references in your agent.