Fast CLI over nanonis-spm for agent-driven Nanonis SPM controller automation
Project description
nspmctl
A thin, fast CLI over nanonis-spm for agent-driven Nanonis SPM
controller automation (real controller or STM Simulator).
nspmctl runs as either a short-lived one-shot command or, by default,
a thin client that forwards to a persistent background daemon. The
daemon holds one warm NanonisController and the open TCP connection
to the instrument, so subsequent agent tool calls converge toward
loopback IPC + Python startup latency instead of paying the import +
connect cost every time.
What this provides
nspmctl: atomic CLI commands (get/set/ramp/act/capabilities/policy/doctor/daemon ...) with stable JSON output schemas.nspmctl daemon: persistent warm-controller daemon, auto-spawned on first call.- Strict write semantics:
setis always a guarded single-step write.rampis always an explicit multi-step trajectory.
- Default runtime policy:
allow_writes=true,dry_run=false.
Performance
End-to-end get bias_v against the STM Simulator on a developer laptop:
| Mode | p50 |
|---|---|
nspmctl --no-daemon get bias_v |
525 ms |
nspmctl get bias_v (warm daemon) |
105 ms |
raw nanonis_spm one-shot floor |
110 ms |
The daemon path approaches the raw nanonis_spm floor and is ~30x
faster than the previous nqctl baseline.
v0.2 support contract
- Stable CLI surface: documented
nspmctlsubcommands and JSON outputs. - Stable Python symbols for embedding:
nspmctl.client.create_client,nspmctl.config.load_settings. - Other Python symbols are provisional and may change across minor releases.
Install
python -m pip install nspmctl
nspmctl capabilities
Editable / from source:
python -m pip install -e .
Configure
- Optionally copy
.env.exampleto.env. - Set runtime values in
config/default_runtime.yaml. - Unified parameter specs are in
config/parameters.yaml.parameters: scalarget/setmappings.actions: non-Get/Setbackend methods withaction_cmdmetadata.
- Regenerate from
nanonis_spm.Nanoniswithscripts/generate_parameters_manifest.py.
Runtime config controls host, candidate ports, timeout, backend, and write policy.
Daemon
# Auto-managed: the first cold call spawns a daemon in the background,
# subsequent calls are warm.
nspmctl get bias_v
# Explicit lifecycle (optional):
nspmctl daemon start
nspmctl daemon status
nspmctl daemon stop
nspmctl daemon restart
nspmctl daemon logs --tail 80
# Diagnostics / CI: bypass the daemon entirely.
nspmctl --no-daemon get bias_v
# or:
$env:NSPMCTL_NO_DAEMON = "1"; nspmctl get bias_v
The daemon exits automatically after 30 minutes of idle. PID + port +
log files live under %LOCALAPPDATA%\nspmctl\ on Windows
(~/.local/state/nspmctl/ on Linux/macOS).
CLI command guide (nspmctl)
Inspect and introspect
Get the machine-readable execution contract (lean payload):
nspmctl capabilities
Capabilities item schemas (nspmctl capabilities):
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://bb-84c.github.io/nspmctl/schemas/capabilities-parameter-item.schema.json",
"title": "nspmctl capabilities parameters.items[*]",
"type": "object",
"required": [
"name",
"label",
"readable",
"writable",
"has_ramp",
"get_cmd",
"set_cmd",
"safety"
],
"properties": {
"name": { "type": "string", "minLength": 1 },
"label": { "type": "string" },
"readable": { "type": "boolean" },
"writable": { "type": "boolean" },
"has_ramp": { "type": "boolean" },
"get_cmd": {
"oneOf": [
{ "type": "null" },
{
"type": "object",
"required": ["command", "payload_index", "arg_fields", "response_fields"],
"properties": {
"command": { "type": "string", "minLength": 1 },
"payload_index": { "type": "integer", "minimum": 0 },
"description": { "type": "string" },
"arg_fields": {
"type": "array",
"items": {
"type": "object",
"required": [
"name",
"type",
"unit",
"wire_type",
"required",
"description",
"default"
],
"properties": {
"name": { "type": "string", "minLength": 1 },
"type": { "type": "string" },
"unit": { "type": "string" },
"wire_type": { "type": "string" },
"required": { "type": "boolean" },
"description": { "type": "string" },
"default": {}
},
"additionalProperties": false
}
},
"response_fields": {
"type": "array",
"items": {
"type": "object",
"required": ["index", "name", "type", "unit", "wire_type", "description"],
"properties": {
"index": { "type": "integer", "minimum": 0 },
"name": { "type": "string", "minLength": 1 },
"type": { "type": "string" },
"unit": { "type": "string" },
"wire_type": { "type": "string" },
"description": { "type": "string" }
},
"additionalProperties": false
}
}
},
"additionalProperties": true
}
]
},
"set_cmd": {
"oneOf": [
{ "type": "null" },
{
"type": "object",
"required": ["command", "arg_fields"],
"properties": {
"command": { "type": "string", "minLength": 1 },
"description": { "type": "string" },
"arg_fields": {
"type": "array",
"items": {
"type": "object",
"required": [
"name",
"type",
"unit",
"wire_type",
"required",
"description",
"default"
],
"properties": {
"name": { "type": "string", "minLength": 1 },
"type": { "type": "string" },
"unit": { "type": "string" },
"wire_type": { "type": "string" },
"required": { "type": "boolean" },
"description": { "type": "string" },
"default": {}
},
"additionalProperties": false
}
}
},
"additionalProperties": true
}
]
},
"safety": {
"oneOf": [
{ "type": "null" },
{
"type": "object",
"required": [
"min_value",
"max_value",
"max_step",
"max_slew_per_s",
"cooldown_s",
"ramp_enabled",
"ramp_interval_s"
],
"properties": {
"min_value": { "type": ["number", "null"] },
"max_value": { "type": ["number", "null"] },
"max_step": { "type": ["number", "null"] },
"max_slew_per_s": { "type": ["number", "null"] },
"cooldown_s": { "type": ["number", "null"] },
"ramp_enabled": { "type": "boolean" },
"ramp_interval_s": { "type": ["number", "null"] }
},
"additionalProperties": false
}
]
}
},
"additionalProperties": false
}
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://bb-84c.github.io/nspmctl/schemas/capabilities-action-command-item.schema.json",
"title": "nspmctl capabilities action_commands.items[*]",
"type": "object",
"required": ["name", "action_cmd", "safety_mode"],
"properties": {
"name": { "type": "string", "minLength": 1 },
"action_cmd": {
"type": "object",
"required": ["command", "arg_fields"],
"properties": {
"command": { "type": "string", "minLength": 1 },
"description": { "type": "string" },
"arg_fields": {
"type": "array",
"items": {
"type": "object",
"required": [
"name",
"type",
"unit",
"wire_type",
"required",
"description",
"default"
],
"properties": {
"name": { "type": "string", "minLength": 1 },
"type": { "type": "string" },
"unit": { "type": "string" },
"wire_type": { "type": "string" },
"required": { "type": "boolean" },
"description": { "type": "string" },
"default": {}
},
"additionalProperties": false
}
}
},
"additionalProperties": true
},
"safety_mode": {
"type": "string",
"enum": ["alwaysAllowed", "guarded", "blocked"]
}
},
"additionalProperties": false
}
Show the legacy full payload (old capabilities surface):
nspmctl showall
Inspect backend command inventory and connectivity preflight:
nspmctl backend commands --match Scan
nspmctl doctor --command-probe
List observable metadata and high-level CLI action descriptors:
nspmctl observables list
nspmctl actions list
Inspect and update runtime policy:
nspmctl policy show
nspmctl policy set --allow-writes true --dry-run false
Execute operations
Read a parameter:
nspmctl get bias_v
For multi-field responses, get returns structured fields (not only one scalar):
nspmctl get scan_buffer
Apply writes with structured args (canonical form):
nspmctl set bias_v --arg Bias_value_V=0.12 (single arg input)
nspmctl set scan_buffer --arg Pixels=512 --arg Lines=512 (multiple args input)
Defaulting/autofill mechanism for partial set:
- Explicit
--argvalues always win. - Missing required set fields trigger one read (
get_cmd) and are filled by normalized field name. - Matching is by field name, not response index position.
- Get-only fields with no set counterpart are ignored.
- Remaining unresolved optional fields can fall back to manifest defaults.
Apply explicit guarded ramp (scalar parameters):
nspmctl ramp bias_v 0.10 0.25 0.01 --interval-s 0.10
Invoke one manifest action command with structured args:
nspmctl act Scan_Action --arg Scan_action=0 --arg Scan_direction=1
nspmctl act Scan_WaitEndOfScan --arg Timeout_ms=5000
For act, required/default behavior is driven by action_cmd.arg_fields in the manifest.
act vs metadata surfaces
nspmctl act <action_name> --arg key=valueexecutes one backend action command from the manifestactionssection.nspmctl actions listlists CLI-level action descriptors (what workflows the CLI supports, with safety hints and templates).nspmctl capabilitiesexposes executable manifest action inventory underaction_commands.items[*](command schema,arg_fields, safety mode).
Output and help
JSON is the default output format. Use --text for human-readable key/value output.
nspmctl -help
nspmctl -help showall
nspmctl -help set
nspmctl -help act
QCodes usage
from qcodes.station import Station
from nspmctl.controller import NanonisController
station = Station()
nanonis = NanonisController("nanonis", auto_connect=True)
station.add_component(nanonis)
print(nanonis.bias_v())
print(nanonis.current_a())
nanonis.close()
Documentation index
- CLI contract:
docs/cli_contract.md - Extension workflow:
docs/extension_workflow.md - Safety model:
docs/safety_model.md - Architecture overview:
docs/architecture.md - Simulator quickstart:
docs/quickstart_simulator.md - Porting to real controller:
docs/porting_to_real_controller.md - Private-index release runbook:
docs/release_private_index.md
Project planning and internal development workflow details: PLAN.md
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file nspmctl-0.2.0.tar.gz.
File metadata
- Download URL: nspmctl-0.2.0.tar.gz
- Upload date:
- Size: 141.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.11.5
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
6ac11f69581eeaa05bd4a38ee7c7f56409725d9e38928277512f0378c7ed727d
|
|
| MD5 |
bb33a672459e7c5fddd79f726bb0eda3
|
|
| BLAKE2b-256 |
9f261c9a0efa11676d78fd698199f43d981c4cea368bd8d8792788138e3c9d9b
|
File details
Details for the file nspmctl-0.2.0-py3-none-any.whl.
File metadata
- Download URL: nspmctl-0.2.0-py3-none-any.whl
- Upload date:
- Size: 128.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.11.5
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
4cefef46f60881dfef6054c2657831e7f7c889de4bf3ca5d9cc4ae9372746dfd
|
|
| MD5 |
f8f2a898d74c6dc39c3c932953cc8f33
|
|
| BLAKE2b-256 |
549fa4c40c39c0cabb25a79961d4aef7070900d44b96ce54e250bc6e1856be39
|