Skip to main content

kvm config

The kvm config command manages seat configurations. A configuration is a named bundle of hotkey macros and Stream Deck button bindings. Each configuration is assigned to a scope, and every station resolves to exactly one configuration, most-specific wins:

rx (a specific remote station) > global (all stations).

Command TypeDisplayNet
Minimum Version5.0

Resolution is whole-configuration replacement, not a merge. The single most-specific assigned configuration supplies all macros, all buttons, and all dials for that station; less-specific configurations are not layered underneath it. If you assign an rx-scoped configuration, it must therefore contain the complete set you want at that station, because it replaces the global configuration entirely. A global configuration is the walk-up default every station inherits without any sign-in.

Configuration names contain no spaces. Use underscores; the management UI renders an underscore as a space. If you pass a name with spaces to create, rename, or clone, the engine stores the underscore form (Front LobbyFront_Lobby). A name that already contains spaces, such as one left by an earlier migration, can still be addressed with show, rename, and delete by wrapping it in double quotes: kvm config show "RX 6cdffb00f077 macros".

There are two ways to author a configuration's contents, and they agree on where the result goes.

By seat. kvm streamdeck bind and kvm streamdeck dial bind write into the configuration that seat already resolves, so a seat's buttons and dials land alongside its macros and take effect immediately. On a system with nothing assigned yet, the global configuration is created on first use. Both accept config=<name> to write into a configuration the seat does not currently resolve, and unbind searches wherever bind would have written.

By configuration. kvm config macro add, kvm config button add, and kvm config dial add name the configuration as their first argument. Create the configuration, add its contents, then assign it to a scope.

Macros are authored only this second way. A button or dial is addressed by (configuration, seat, index), so naming a seat is natural. A macro has no seat at all, and the removed kvm macro define had to invent a configuration from a scope to compensate.

Names and triggers are unique within a configuration, as is a (page, button) slot. Two configurations may each hold a macro called openrun, and clone copies names verbatim. Config-owned macros are not tied to a device scope of their own; the configuration's assignment decides where they apply.

Assigning, unassigning, or deleting a configuration changes the macros and buttons active at a live station the instant it runs. Before reassigning or deleting a configuration bound to a station you did not just set up, confirm with the operator at that desk.

Usage

kvm config list
kvm config show <name>
kvm config create <name>
kvm config clone <source> <newname>
kvm config rename <old> <new>
kvm config delete <name>
kvm config assign <name> global|rx <device_id>
kvm config unassign global|rx <device_id>
kvm config macro add <config> <name> <trigger> <builtin|command|script|sendkeys> <action...>
kvm config macro remove <config> <name>
kvm config macro enable <config> <name>
kvm config macro disable <config> <name>
kvm config button add <config> <remote_id> <button> [<builtin|command|script|sendkeys> <action...>] [icon=<name>] [label=<text>|-] [color=<rrggbb>] [bg=<rrggbb>] [notify[=<name>]] [model=<key>]
kvm config button remove <config> <remote_id> <button> [model=<key>]
kvm config dial add <config> <remote_id> <dial> <notify[=<name>]|adjust|select>
[rotate=<action...>] [press=<action...>]
[items=<a,b,c>|@<provider>] [range=<lo>-<hi>[:<step>]]
[notify[=<name>]] [label=<text...>]
kvm config dial remove <config> <remote_id> <dial>
note

<remote_id> in button/dial subcommands is the RX seat Stream Deck bindings are keyed per seat (not per deck), so button add/remove and dial add/remove take the RX seat the button map belongs to, the same seat you'd assign the configuration to with rx. See kvm streamdeck.

Subcommands

SubcommandDescription
listReturns a summary of every configuration: its macro, button, and dial counts and the scopes it is assigned to.
showReturns one configuration in full: every macro, Stream Deck button, and Stream Deck dial it contains.
create / clone / rename / deleteManage configuration objects. clone deep-copies a source configuration's macros, buttons, and dials into a new name.
assign / unassignBind (or unbind) a configuration to a scope: global or rx <device_id>. Takes effect at the live station immediately.
macro add / macro remove / macro enable / macro disableAuthor this configuration's hotkey macros. This is the only way to author a macro. Name and trigger are each unique within the configuration. enable/disable keep a macro's definition but stop it firing; re-enabling is refused if another enabled macro has taken its trigger meanwhile.
button add / button removeAuthor config-owned Stream Deck bindings directly for a seat (<remote_id>). A (remote_id, page, model, button) slot is unique within the configuration, so two seats can bind the same button in one shared configuration, and one seat can hold both an any-deck binding and a per-model layout on that button. Buttons accept the same action types, tile arguments, and modifiers as kvm streamdeck bind, including sendkeys, the optional icon= / label= / color= / bg= appearance, notify[=<name>] (which makes the action optional), and model=<key>.
dial add / dial removeAuthor config-owned Stream Deck dial bindings directly for a seat (<remote_id>). Takes the same modes, candidate sources, and modifiers as kvm streamdeck dial bind, which documents them in full. Re-adding a dial replaces its binding.

Arguments

ArgumentDescription
scopeWhere a seat configuration applies, as one of two forms: global (all stations) or rx <device_id> (one specific remote station). A station resolves to the most specific assigned scope, rx over global, and that single configuration fully replaces the less specific one.

Examples

Create a configuration, add a macro and a button, and assign it to a seat
kvm config create theater_ops
kvm config macro add theater_ops wallcycle ctrl+alt+n builtin focus_next
kvm config button add theater_ops 6cdffb00f077 0 builtin fullscreen_toggle
kvm config assign theater_ops rx 6cdffb00f077
kvm config show theater_ops
kvm config unassign rx 6cdffb00f077

Return value

kvm config list

Each entry summarizes one configuration: its name, the number of macros, Stream Deck button bindings, and dial bindings it holds, and the scopes it is assigned to (empty when the configuration exists but is not assigned anywhere).

kvm config list
{
"status": "SUCCESS",
"request_id": null,
"result": {
"kvm_config_list": [
{ "Name": "Global", "Macros": 3, "Bindings": 1, "DialBindings": 6, "Scopes": ["global"] },
{ "Name": "theater_ops", "Macros": 2, "Bindings": 4, "DialBindings": 0, "Scopes": ["rx:6cdffb00f077"] }
]
},
"error": null
}

kvm config show

Returns one configuration in full: every macro and every Stream Deck binding it contains. Binding entries carry the same fields as kvm streamdeck list, including RemoteId (the owning seat), Model when the binding is model-specific, and the optional Icon / Label / IconColor / Background / LabelColor / NotifyName when set. Both macro and binding entries mask type: text in a sendkeys ActionPayload (type:••••).

The one field named differently is the button index: ButtonIndex here, Button in streamdeck list. Both are long-standing published names.

kvm config show Global
{
"status": "SUCCESS",
"request_id": null,
"result": {
"kvm_config": [
{
"Name": "Global",
"Macros": [
{
"Name": "wallcycle",
"TriggerDisplay": "ctrl+alt+n",
"ActionType": "builtin",
"ActionPayload": "focus_next",
"Enabled": true
}
],
"Bindings": [
{
"RemoteId": "6CDFFB00F077",
"Page": "default",
"ButtonIndex": 0,
"ActionType": "builtin",
"ActionPayload": "focus_next",
"Enabled": true
},
{
"RemoteId": "6CDFFB00F077",
"Page": "default",
"Model": "mk2",
"ButtonIndex": 12,
"ActionType": "command",
"ActionPayload": "preset apply Wide",
"Enabled": true,
"Label": "Wide",
"LabelColor": "FFD24A"
}
],
"DialBindings": [
{
"RemoteId": "6CDFFB00F077",
"Dial": 0,
"Mode": "select",
"Enabled": true,
"NotifyName": "Volume",
"Candidates": "#0-100:5",
"StripLabel": "Volume"
}
]
}
]
},
"error": null
}

Management subcommands

create, clone, rename, delete, assign, unassign, macro add|remove and button add|remove all return the same envelope.

kvm config create theater_ops
{
"status": "SUCCESS",
"request_id": null,
"result": null,
"error": null
}

Errors

Error response
{
"status": "ERROR",
"request_id": null,
"result": null,
"error": {
"message": "<description>",
"reason": "KVM API ERROR"
}
}

Common error conditions:

  • Configuration not found, or a name collision on create / rename / clone
  • Invalid scope. Must be global or rx <device_id> (assign / unassign)
  • Duplicate macro name, trigger already bound in the configuration, or (remote_id, page, model, button) already bound (macro add / button add)
  • Unknown model= key, or a button index the named model does not have (button add)
  • Macro or binding not found in the configuration (macro remove / button remove)

REST API

Endpoint typeDisplayNet API command
AddressPOST /api/displaynet/<operation>, or name the operation in the body of a POST /api/displaynet. See Sending commands.
RoleUser
SubcommandOperationParameters
configkvm_configaction [args]*
config_assignkvm_config_assignname scope [id]
config_button_addkvm_config_button_addconfig remote_id button [action_type] [payload] [icon] [label] [color] [bg] [labelcolor] [notify] [model]
config_button_removekvm_config_button_removeconfig remote_id button [model]
config_clonekvm_config_clonesource new_name
config_createkvm_config_createname
config_deletekvm_config_deletename
config_dial_addkvm_config_dial_addconfig remote_id dial mode [rotate] [press] [items] [range] [notify] [label] [model]
config_dial_removekvm_config_dial_removeconfig remote_id dial [model]
config_listkvm_config_list
config_macro_addkvm_config_macro_addconfig name trigger action_type payload
config_macro_disablekvm_config_macro_disableconfig name
config_macro_enablekvm_config_macro_enableconfig name
config_macro_removekvm_config_macro_removeconfig name
config_renamekvm_config_renameold_name new_name
config_showkvm_config_showname
config_unassignkvm_config_unassignscope [id]

A parameter in brackets is optional. A parameter marked * takes the remainder of the command line as one string. Pass the text exactly as you would type it on the TCI interface.

Every action has a typed operation taking named fields. A name containing spaces needs no quoting, the button and dial modifiers (model, icon, label, notify) are separate optional fields rather than key=value tokens, and a missing or unknown field is rejected before the command runs.

kvm_config takes a raw grammar line instead: action and args, spelled as under Usage above.

See also