BanterLab OPAL reference

Every operator-reachable feature in BanterLab is exposed as an OPAL Task — 58 OTs in total, grouped here by resource family. For walkthroughs and copy-pasteable plans see Common BanterLab plans.

All lab-bound OTs require BanterLab to be open in hub. The locator returns nullptr until the activity has been mounted at least once; OTs fail with the canonical not-open message (see Failure messages).


Resource families and permission scopes

Family Read OTs Write OTs Permission scope (writes)
Parameters / presets 3 6 banter.param.write
Codec 2 1 banter.param.write
Test sets 3 9 banter.testset.write
Nodes 1 13 banter.node.write
Audio 2 2 banter.audio.write
Run 1 4 banter.runtime (start-* only)
Policy / RL 1 6 banter.policy.write
Activity 1 2 banter.activity.write
Results 1 — —

Read-only OTs require no permission. Permission scopes match the resource-scope strings used by OpalResourceSemaphore, so granting access also unlocks concurrent serialization for that resource.


Parameters

banter.param.list

List BanterLab parameters with their current value, sweep mode, and range.

Arg Required Default Description
codec no — Filter to params with the given codec scope (fsk, ofdm, dpsk, css, mcfsk, common, meta, preprocessor, gibber, bus, adversary).

Returns: count, params (JSON array of rows; each row has id, label, codec, description, current, default, hardMin, hardMax, decimals, sweepMode, sweepMin, sweepMax, sweepSteps).

{ "task": "banter.param.list" }

banter.param.get

Read one parameter row by id.

Arg Required Description
id yes Parameter id (e.g. fsk_baudRate).

Returns: id, current, sweepMode, row (full JSON object).

{ "task": "banter.param.get", "args": {"id": "fsk_baudRate"} }

banter.param.set

Set one parameter's current value. Bounds-checked against hardMin/hardMax. Codec-scoped params (fsk_*, ofdm_*, dpsk_*, css_*, mcfsk_*) fail with a structured suggestion when the active codec doesn't match. Setting id="codec" with an integer 0-4 is equivalent to banter.codec.set.

Arg Required Description
id yes Parameter id.
value yes New current value (numeric).
{ "task": "banter.param.set", "args": {"id": "fsk_baudRate", "value": 300} }

banter.param.set-sweep

Configure how a parameter is swept during a test run.

Arg Required Default Description
id yes — Parameter id.
mode yes — One of fixed, stepped, random, learning.
min no leave unchanged Lower bound.
max no leave unchanged Upper bound.
steps no 10 Step count for stepped mode (>=1).
{ "task": "banter.param.set-sweep", "args": {"id": "fsk_baudRate", "mode": "learning", "min": 50, "max": 600} }

banter.param.reset

Reset a parameter (or * for all) to its registry default. Sweep state resets to fixed.

Arg Required Description
id yes Parameter id (or *).
{"task": "banter.param.reset", "args": {"id": "*"}}

banter.param.import

Load a parameter snapshot from a JSON file written by banter.param.export.

Arg Required Description
path yes File path.
{"task": "banter.param.import", "args": {"path": "/tmp/params.json"}}

banter.param.export

Save the current parameter set to a JSON file.

Arg Required Description
path yes Destination file path.
{"task": "banter.param.export", "args": {"path": "/tmp/params.json"}}

Presets

banter.preset.list

List the named parameter presets registered in BanterParamSet (audible-fsk, audible-dpsk, audible-dqpsk, ultrasonic-fsk, ultrasonic-dpsk, fast-ofdm, robust-css, max-throughput).

Returns: count, presets (CSV).

{ "task": "banter.preset.list" }

banter.preset.apply

Overwrite the parameter set with a named preset.

Arg Required Description
name yes Preset name (see banter.preset.list).
{"task": "banter.preset.apply", "args": {"name": "audible-fsk"}}

Codecs

banter.codec.list

List the codecs available in BanterCodecRegistry (CSS, DPSK, FSK, MCFSK, OFDM).

Returns: count, codecs (CSV).

{"task": "banter.codec.list"}

banter.codec.get

Read the currently active codec name. Reflects the bus-level codec selection (the codec used by the first node).

Returns: codec.

{"task": "banter.codec.get"}

banter.codec.set

Set the active codec by name. Equivalent to banter.param.set id=codec value=N with the integer encoding (0=FSK, 1=OFDM, 2=DPSK, 3=CSS, 4=MCFSK).

Arg Required Description
codec yes One of FSK, OFDM, DPSK, CSS, MCFSK.
{ "task": "banter.codec.set", "args": {"codec": "FSK"} }

If you intend to change codec and codec-specific parameters in one plan, call banter.codec.set first — the fsk_* / ofdm_* / dpsk_* / css_* / mcfsk_* parameters apply only when the matching codec is active.


Test sets

banter.testset.describe

Describe the currently loaded BanterLab test set: name, description, test count, defaults, execution config, and the path it was loaded from (empty for unsaved in-memory sets).

Returns: name, description, test-count, defaults (JSON), execution (JSON), current-path.

{"task": "banter.testset.describe"}

banter.testset.list-tests

List the per-test summaries inside the current test set.

Returns: count, tests (JSON array of {name, codec, iterations, payload, paramOverlay, nodes}).

{"task": "banter.testset.list-tests"}

banter.testset.describe-test

Return the fully resolved spec for one test (defaults merged with per-test diff).

Arg Required Description
index one of 0-based test index.
name one of Test name.
{"task": "banter.testset.describe-test", "args": {"index": 0}}

banter.testset.new

Create a fresh in-memory test set. Fails with the spec's "unsaved changes" message when one is already loaded — call banter.testset.export first or reimport on a blank file.

Arg Required Description
name yes Test set name.
description no Human description.
{"task": "banter.testset.new", "args": {"name": "demo"}}

banter.testset.set-defaults

Merge a partial overlay onto the current test set's defaults.

Arg Required Description
codec no Codec name.
payload no Default payload.
iterations no Default iterations per test.
parameters no JSON array of param overlay objects.
nodes no JSON array of node names or full BanterNodeSpec objects.
{"task": "banter.testset.set-defaults", "args": {"codec": "FSK", "iterations": 50, "payload": "HELLO"}}

banter.testset.set-execution

Merge an execution-config overlay onto the current test set.

Arg Required Description
connection-string no DB connection string.
ncores no Parallel cores for batch (0 = auto).
settle-time-ms no Per-iteration settle time.
timeout-per-test-ms no Per-test timeout.
quit-on-complete no Quit hub when test set completes.
{"task": "banter.testset.set-execution", "args": {"ncores": 1, "timeout-per-test-ms": 60000}}

banter.testset.add-test

Append a test spec to the current test set. The name is required; everything else is an optional overlay (only the fields you supply override the test set's defaults at run time).

Arg Required Description
name yes Test name.
codec, payload, iterations, parameters, nodes no Overlay fields.
{"task": "banter.testset.add-test", "args": {"name": "t1", "codec": "FSK"}}

banter.testset.remove-test

Remove a test by index or name.

{"task": "banter.testset.remove-test", "args": {"index": 0}}

banter.testset.update-test

Apply an overlay onto an existing test, identified by index or name.

{"task": "banter.testset.update-test", "args": {"index": 0, "iterations": 100}}

banter.testset.import

Replace the current test set with one loaded from a JSON file. Updates the tracked source path so subsequent banter.testset.save calls overwrite this file.

Arg Required Description
path yes Test-set JSON file path.
{"task": "banter.testset.import", "args": {"path": "/tmp/set.json"}}

banter.testset.export

Save the current test set to a JSON file and track its path.

Arg Required Description
path yes Destination file path.
{"task": "banter.testset.export", "args": {"path": "/tmp/set.json"}}

banter.testset.save

Save to the tracked source path. Fails with "test set has not been imported or exported yet" when the path is empty — call banter.testset.export first.

{"task": "banter.testset.save"}

Nodes

banter.node.list

List BanterLab nodes with their I/O routing and adversary flags.

Returns: count, nodes (JSON array of {name, outputDevice, inputDevice, advOut, advIn, codec}).

{"task": "banter.node.list"}

banter.node.add

Add a BanterLab node. When name is omitted, a unique name is auto-generated. Default routing is bus/bus.

Arg Required Default Description
name no auto Node name.
output-device no bus bus, off, or a host audio device name.
input-device no bus Same.
{"task": "banter.node.add", "args": {"name": "Carol"}}

banter.node.remove

Remove a node by name.

{"task": "banter.node.remove", "args": {"name": "Carol"}}

banter.node.rename

Rename a node; the new-name must be non-empty and not already taken.

Arg Required Description
name yes Current name.
new-name yes New name.
{"task": "banter.node.rename", "args": {"name": "Alice", "new-name": "Anna"}}

banter.node.set-routing

Update output/input device routing.

Arg Required Description
name yes Node name.
output-device one of bus, off, or device name.
input-device one of Same.
{"task": "banter.node.set-routing", "args": {"name": "Alice", "output-device": "off"}}

banter.node.set-adversary

Toggle adversary-out / adversary-in flags.

Arg Required Description
name yes Node name.
adv-out one of Adversary mix on TX (bool).
adv-in one of Adversary mix on RX (bool).
{"task": "banter.node.set-adversary", "args": {"name": "Alice", "adv-out": true}}

banter.node.set-adversary-params

Configure the node's adversary effect parameters: noise gain, dribble level, interference tone frequency/amplitude.

Arg Required Default Description
name yes — Node name.
noise no 0 White-noise SNR target.
dribble no 0 Dribble amplitude.
tone-freq no 0 Interference tone frequency (Hz).
tone-amplitude no 0 Interference tone amplitude (0..1).
{"task": "banter.node.set-adversary-params", "args": {"name": "Alice", "noise": 0.1, "tone-freq": 2200, "tone-amplitude": 0.3}}

banter.node.set-monitor-tone

Inject a continuous test tone on the node's output. freq-hz=0 or amplitude-pct=0 disables.

Arg Required Description
name yes Node name.
freq-hz yes Tone frequency.
amplitude-pct yes 0..100.
{"task": "banter.node.set-monitor-tone", "args": {"name": "Alice", "freq-hz": 440, "amplitude-pct": 25}}

banter.node.set-noise-level

Mix white noise into the node's output.

Arg Required Description
name yes Node name.
amplitude-pct yes 0..100.
{"task": "banter.node.set-noise-level", "args": {"name": "Alice", "amplitude-pct": 5}}

banter.node.set-bandpass-margin

Adjust the RX bandpass margin (frequency tolerance for the chirp/tone band).

Arg Required Description
name yes Node name.
margin yes Typically 0.1..2.0.
{"task": "banter.node.set-bandpass-margin", "args": {"name": "Alice", "margin": 0.5}}

banter.node.send

Transmit a single packet from the named node, bypassing the auto-test loop. Payload is UTF-8 text; bytes-on-the-wire equal the UTF-8 encoding.

Arg Required Description
name yes Source node.
payload yes UTF-8 payload.
{"task": "banter.node.send", "args": {"name": "Alice", "payload": "HELLO"}}

banter.node.clear-log

Clear the node's log pane.

{"task": "banter.node.clear-log", "args": {"name": "Alice"}}

banter.node.reset-codec-state

Reset the codec internal state (RX/TX buffers, interleaver, sync trackers) without recreating the codec.

{"task": "banter.node.reset-codec-state", "args": {"name": "Alice"}}

banter.node.reset-drop-count

Reset the audio drop counter on a node. Pass name='*' to reset every node plus the bus drop counter.

{"task": "banter.node.reset-drop-count", "args": {"name": "*"}}

Audio

banter.audio.list-devices

List the host's audio I/O devices in the requested direction. The synthetic bus device is always returned first.

Arg Required Default Description
direction no output input or output.

Returns: count, devices (JSON array of {name, description, is-default, synthetic}).

{"task": "banter.audio.list-devices", "args": {"direction": "output"}}

banter.audio.get-volume

Read the BanterLab bus volume (0..1).

Returns: volume.

{"task": "banter.audio.get-volume"}

banter.audio.set-volume

Set the bus volume; range-checked.

Arg Required Description
volume yes 0.0 (mute) … 1.0 (unity).
{"task": "banter.audio.set-volume", "args": {"volume": 0.5}}

banter.audio.calibrate

Run the OKChirp round-trip calibration; emits a chirp pattern and writes a <nodename>.profile per node. Requires at least 2 nodes.

{ "task": "banter.audio.calibrate" }

Run lifecycle

banter.run.status

Read the live BanterLab run status.

Returns: running, current-test-index, current-iteration, total-iterations, last-score, test-name, codec.

{"task": "banter.run.status"}

banter.run.start-single

Long-running. Run a single interactive test using the named TX/RX nodes. Reports per-iteration progress; cancellable via the runtime.

Arg Required Description
tx-node yes Transmit node name.
rx-node yes Receive node name.
payload no UTF-8 payload override.
iterations no Iteration override.
{"task": "banter.run.start-single", "args": {"tx-node": "Alice", "rx-node": "Bob", "payload": "HELLO", "iterations": 5}}

banter.run.start-testset

Long-running. Iterate the loaded test set. Per-test + per-iteration progress; cancel triggers bus->abortRun().

Arg Required Default Description
close-on-completion no false Close BanterLab when finished.
{"task": "banter.run.start-testset"}

banter.run.abort

Idempotent abort of any active run. Returns was-running so the LLM can distinguish "stopped a run" from "no-op".

{"task": "banter.run.abort"}

banter.run.skip-test

Skip the current test inside an active test set; the run continues with the next test.

{"task": "banter.run.skip-test"}

Results

banter.results.query

Query the BanterLab results SQLite database.

Arg Required Default Description
session-id no — Filter by session id.
limit no 100 Max rows (1..9999).

Returns: count, rows (JSON array — one entry per iteration with score, codec, params, timestamps), db-path.

{"task": "banter.results.query", "args": {"limit": 50}}

Policy / RL

banter.policy.info

Read RL controller diagnostics.

Returns: active, algorithm, reward-driver, episodes, best-reward, fingerprint, sidecar-path.

{"task": "banter.policy.info"}

banter.policy.set-algorithm

Select the RL algorithm. Auto-creates the controller if no learning run has been started yet.

Arg Required Description
algorithm yes simple-bandit or ppo.
{"task": "banter.policy.set-algorithm", "args": {"algorithm": "simple-bandit"}}

banter.policy.set-reward-driver

Choose how each iteration's outcome becomes a scalar reward.

Arg Required Description
driver yes One of decode-only, decode-and-snr, throughput, resilience, composite.
{"task": "banter.policy.set-reward-driver", "args": {"driver": "decode-and-snr"}}

banter.policy.set-composite-weights

Set the four scalars ([decode, snr, throughput, resilience]) used by the composite reward driver. Defaults: [1.0, 0.3, 0.2, 0.2].

Arg Required Description
weights yes JSON array of 4 numbers.
{"task": "banter.policy.set-composite-weights", "args": {"weights": [1.0, 0.3, 0.2, 0.2]}}

banter.policy.reset

Clear reward history and the episode counter; configuration (algorithm, reward driver, weights) is preserved.

{"task": "banter.policy.reset"}

banter.policy.save

Save the policy blob to <testsetbase>.rlpol. Fails when no controller exists or when the test set has no tracked path.

{"task": "banter.policy.save"}

banter.policy.load

Load the policy blob from the test-set sidecar. The blob's stored fingerprint must match the controller's current fingerprint (derived from the learning-param action space). Mismatches return both fingerprints with a Suggestion to retrain.

{"task": "banter.policy.load"}

Activity

banter.activity.list-panes

List the toggleable panes on the BanterLab activity.

Returns: count, panes (JSON array of {name, visible}).

{"task": "banter.activity.list-panes"}

banter.activity.show-pane

Show or hide a pane by name.

Arg Required Default Description
pane yes — One of bus, testsets, parameters, nodes, learning.
visible no true Visibility flag.
{"task": "banter.activity.show-pane", "args": {"pane": "learning", "visible": true}}

banter.activity.show-results

Open the BanterResults activity (historical run viewer). Emits viewResultsRequested on the bus widget; BanterLabActivity wires that to a navigation push.

{"task": "banter.activity.show-results"}

Failure messages

Every OT follows the OPAL Task System format: "Failed to <action>: <what>. State: <left behind>. Suggestion: <next>." so an LLM can recover programmatically.

Canonical messages used across multiple OTs:


Worked example — full plan from the spec

The 12-step prompt the spec was designed around — reachable end-to-end through the OTs above:

{ "task": "banter.audio.list-devices",   "args": {"direction": "output"} }
{ "task": "banter.audio.list-devices",   "args": {"direction": "input"} }
{ "task": "banter.testset.new",          "args": {"name": "learn-baud-codec-agc"} }
{ "task": "banter.node.add",             "args": {"name": "Alice", "output-device": "default", "input-device": "default"} }
{ "task": "banter.node.add",             "args": {"name": "Bob",   "output-device": "default", "input-device": "default"} }
{ "task": "banter.testset.set-defaults", "args": {"payload": "HELLO", "iterations": 50} }
{ "task": "banter.testset.add-test",     "args": {"name": "learn-baud", "codec": "FSK",
    "parameters": [{"id": "fsk_baudRate", "sweepMode": "learning", "min": 50, "max": 600}]} }
{ "task": "banter.testset.add-test",     "args": {"name": "learn-codec",
    "parameters": [{"id": "codec",        "sweepMode": "learning", "min": 0,  "max": 4}]} }
{ "task": "banter.testset.add-test",     "args": {"name": "learn-agc",
    "parameters": [{"id": "agcMode",      "sweepMode": "learning", "min": 0,  "max": 4}]} }
{ "task": "banter.policy.set-reward-driver", "args": {"driver": "decode-and-snr"} }
{ "task": "banter.testset.export",       "args": {"path": "/tmp/learn.json"} }
{ "task": "banter.run.start-testset" }

For three guided recipes built on this surface — including a learning-sweep walkthrough and a codec comparison — see Common BanterLab plans.


Maintainer note

When adding a new BanterLab feature, ship the OT and its entry in this reference in the same commit. Doc drift is the fastest way for the OPAL surface to lose the LLM's trust — the failure messages and parameter shapes here are what the model uses to plan and recover.