Simulator-first Python bridge between Nanonis SPM controller interfaces and QCodes.
nqctl: an agent-friendly CLI for atomic read/write/ramp operations.QcodesNanonisSTM: a QCodes instrument wrapper with spec-driven parameters.- 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).
- Stable Python API symbols:
QcodesNanonisSTM,create_client,load_settings. - Stable CLI contract: documented
nqctlcommands and outputs. - Other Python symbols are provisional/internal and may change across minor releases.
Install from a GitHub release (recommended for test users):
- Open the releases page and download the wheel asset (
*.whl), not the auto-generated source zip/tarball. - Create a virtual environment.
- Install the wheel, then install optional runtime integrations.
python -m venv .venv
.\.venv\Scripts\Activate.ps1
python -m pip install --upgrade pip
python -m pip install .\nanonis_qcodes_controller-<version>-py3-none-any.whl
python -m pip install "qcodes>=0.46.0" "nanonis-spm>=1.0.3"
nqctl capabilitiesYou can also install directly from a release URL:
python -m pip install "https://github.com/BB-84C/Nanonis-QCodes-Controller/releases/download/v<version>/nanonis_qcodes_controller-<version>-py3-none-any.whl"Install from source:
python -m pip install .Optional extras:
python -m pip install ".[qcodes]"
python -m pip install ".[nanonis]"- 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. - Trajectory monitor defaults are in
config/default_trajectory_monitor.yaml.
Runtime config controls host, candidate ports, timeout, backend, write policy, and trajectory settings.
Get the machine-readable execution contract (lean payload):
nqctl capabilitiesCapabilities item schemas (nqctl capabilities):
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://bb-84c.github.io/nqctl/schemas/capabilities-parameter-item.schema.json",
"title": "nqctl 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/nqctl/schemas/capabilities-action-command-item.schema.json",
"title": "nqctl 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):
nqctl showallInspect backend command inventory and connectivity preflight:
nqctl backend commands --match Scan
nqctl doctor --command-probeList observable metadata and high-level CLI action descriptors:
nqctl observables list
nqctl actions listInspect and update runtime policy:
nqctl policy show
nqctl policy set --allow-writes true --dry-run falseRead a parameter:
nqctl get bias_vFor multi-field responses, get returns structured fields (not only one scalar):
nqctl get scan_bufferApply writes with structured args (canonical form):
nqctl set bias_v --arg Bias_value_V=0.12 (single arg input)
nqctl 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):
nqctl ramp bias_v 0.10 0.25 0.01 --interval-s 0.10Invoke one manifest action command with structured args:
nqctl act Scan_Action --arg Scan_action=0 --arg Scan_direction=1
nqctl act Scan_WaitEndOfScan --arg Timeout_ms=5000For act, required/default behavior is driven by action_cmd.arg_fields in the manifest.
nqctl act <action_name> --arg key=valueexecutes one backend action command from the manifestactionssection.nqctl actions listlists CLI-level action descriptors (what workflows the CLI supports, with safety hints and templates).nqctl capabilitiesexposes executable manifest action inventory underaction_commands.items[*](command schema,arg_fields, safety mode).
Legacy JSONL readers:
nqctl trajectory tail --directory artifacts/trajectory --limit 20
nqctl trajectory follow --directory artifacts/trajectory --interval-s 0.5SQLite action queries:
nqctl trajectory action list --db-path artifacts/trajectory/trajectory-monitor.sqlite3 --run-name gui-play-001
nqctl trajectory action show --db-path artifacts/trajectory/trajectory-monitor.sqlite3 --run-name gui-play-001 --action-idx 0 --with-signal-windowMonitor config and run loop:
nqctl trajectory monitor config show
nqctl trajectory monitor config set --run-name gui-play-001 --interval-s 0.1 --rotate-entries 6000 --action-window-s 2.5
nqctl trajectory monitor list-signals
nqctl trajectory monitor list-specs
nqctl trajectory monitor run
nqctl trajectory monitor config clearNotes:
run_nameis cleared after each monitor run attempt; set it again before the next run.- Action entries use ISO UTC timestamps and include
delta_valuefor numeric spec changes.
JSON is the default output format. Use --text for human-readable key/value output.
nqctl -help
nqctl -help showall
nqctl -help set
nqctl -help trajectory
nqctl -help actfrom qcodes.station import Station
from nanonis_qcodes_controller.qcodes_driver import QcodesNanonisSTM
station = Station()
nanonis = QcodesNanonisSTM("nanonis", auto_connect=True)
station.add_component(nanonis)
print(nanonis.bias_v())
print(nanonis.current_a())
nanonis.close()- 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 - Trajectory model:
docs/trajectory_model.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