This is the research inventory for the first WorkLouderCTL compatibility adapter. It records what exists, where it is authoritative, and how it must be verified. The tested snapshot is documented in the 2026-08-02 audit.
The inspected Codex build reads settings through settings-read and writes a
partial settings object through settings-write. Renderer calls reach the
native host through the vscode://codex/<method> bridge and then invalidate
the get-settings query. The Codex Micro UI uses the same setting definitions
and setter for agent source, single-tap behavior, layout, brightness, and
auto-off.
WorkLouderCTL therefore targets the versioned settings bridge for online
transactions. The implemented codex-config-toml-read-v1 adapter reads the
[desktop] table in $CODEX_HOME/config.toml, validates only keys with the
codex-micro- prefix, and preserves unknown prefixed keys. It hashes the source
before and after capture, recursively fills inherited defaults, and excludes
all unrelated Codex configuration from its output. Offline mutation still
uses the same frozen definitions. The Codex Companion Bridge now supplies the
online snapshot/CAS/apply/restore client and reference main-process integration;
the released Codex build still needs to install that external listener. Raw
Chromium LevelDB mutation is not part of the configuration path.
The current read and offline-candidate command surface is:
worklouderctl codex doctor [--strict] [--config PATH] [--app PATH]
worklouderctl codex inspect [--config PATH] [--app PATH]
worklouderctl codex export --output FILE [--config PATH] [--app PATH]
worklouderctl codex bridge [--socket PATH] [--token PATH] inspect
worklouderctl codex config [--socket PATH] [--token PATH] snapshot --output FILE
worklouderctl codex config diff BASE.json CANDIDATE.json
worklouderctl codex config [--socket PATH] [--token PATH] apply --input CANDIDATE.json --backup BEFORE.json
worklouderctl codex config [--socket PATH] [--token PATH] restore --input BEFORE.json --backup CURRENT.json
worklouderctl codex agent-key assignments [--socket PATH] [--token PATH]
worklouderctl codex agent-key snapshot --output AGENT_KEYS.json [--socket PATH] [--token PATH]
worklouderctl codex agent-key get --input AGENT_KEYS.json SLOT
worklouderctl codex agent-key set --input AGENT_KEYS.json SLOT --command COMMAND_ID --output CANDIDATE.json
worklouderctl codex agent-key set --input AGENT_KEYS.json SLOT --skill-name NAME --skill-path PATH --output CANDIDATE.json
worklouderctl codex agent-key set --input AGENT_KEYS.json SLOT --thread-host HOST --thread-key KEY --title TITLE --output CANDIDATE.json
worklouderctl codex agent-key set --input AGENT_KEYS.json SLOT --keycap KEYCAP_ID --output CANDIDATE.json
worklouderctl codex agent-key clear --input AGENT_KEYS.json SLOT --output CANDIDATE.json
worklouderctl codex agent-key apply --input CANDIDATE.json --backup BEFORE.json [--socket PATH] [--token PATH]
worklouderctl codex agent-key restore --input BEFORE.json --backup CURRENT.json [--socket PATH] [--token PATH]
worklouderctl codex agent-source get --input SNAPSHOT.json
worklouderctl codex agent-source set --input SNAPSHOT.json VALUE --output CANDIDATE.json
worklouderctl codex agent-key tap-mode get --input SNAPSHOT.json
worklouderctl codex agent-key tap-mode set --input SNAPSHOT.json enabled|disabled --output CANDIDATE.json
worklouderctl codex command-key get --input SNAPSHOT.json SLOT
worklouderctl codex command-key set --input SNAPSHOT.json SLOT \
[--keycap KEYCAP] [--command COMMAND_ID | --skill-name NAME --skill-path PATH | --clear-action] \
--output CANDIDATE.json
worklouderctl codex command-key reset --input SNAPSHOT.json SLOT --output CANDIDATE.json
worklouderctl codex dial mode get --input SNAPSHOT.json
worklouderctl codex dial mode set --input SNAPSHOT.json composer-navigation|reasoning|conversation-scroll|custom --output CANDIDATE.json
worklouderctl codex dial gesture get --input SNAPSHOT.json left|right|click|long-press
worklouderctl codex dial gesture set --input SNAPSHOT.json GESTURE \
[--command COMMAND_ID | --skill-name NAME --skill-path PATH] --output CANDIDATE.json
worklouderctl codex dial gesture clear --input SNAPSHOT.json GESTURE --output CANDIDATE.json
worklouderctl codex joystick get --input SNAPSHOT.json up|right|down|left
worklouderctl codex joystick set --input SNAPSHOT.json DIRECTION \
[--command COMMAND_ID | --skill-name NAME --skill-path PATH] --output CANDIDATE.json
worklouderctl codex joystick clear --input SNAPSHOT.json DIRECTION --output CANDIDATE.json
worklouderctl codex reset layout --input SNAPSHOT.json --output CANDIDATE.json
worklouderctl codex lighting brightness get --input SNAPSHOT.json
worklouderctl codex lighting brightness set --input SNAPSHOT.json VALUE --output CANDIDATE.json
worklouderctl codex lighting auto-off get --input SNAPSHOT.json
worklouderctl codex lighting auto-off set --input SNAPSHOT.json VALUE --output CANDIDATE.json
worklouderctl codex voice get --input SNAPSHOT.json
worklouderctl codex voice set --input SNAPSHOT.json push-to-talk|realtime --output CANDIDATE.jsonCandidate input is a complete codex export snapshot. The editor verifies the
frozen definitions and effective view, preserves unknown prefixed settings,
hashes canonical explicit settings with codex-settings-revision-v1, and
publishes/reopens a complete candidate. Command Key updates preserve the
current keycap when omitted, keep command and Skill representations mutually
exclusive, and reset from the frozen slot default. The source TOML SHA-256 is
retained as the online transaction's source CAS value. The bridge also compares
the canonical settings revision, performs complete explicit-setting replacement,
and verifies exact explicit/effective readback before reporting success.
Lighting brightness is a typed integer from 0 through 100. Auto-off accepts
exactly off, 30-seconds, 1-minute, 3-minutes, 10-minutes, 30-minutes,
or 1-hour. Both editors preserve unknown settings, keep inherited defaults
implicit for no-op candidates, and use the complete settings bridge transaction
for CAS apply/readback/restore.
Voice mode reads or replaces codex-micro-layout.voiceButtonMode. Its exact
values are push-to-talk and realtime; the latter is labeled Voice Chat in
the GUI. The editor materializes the effective layout only for a real change,
preserves unknown layout fields, and leaves an inherited default implicit for a
no-op candidate.
Agent Key snapshots use the separate codex-agent-keys-revision-v1 global-state
revision. Offline set/clear changes one AG00–AG05 slot, preserves the other
five values and their unknown fields, atomically publishes, and reopens the
candidate. Apply/restore replaces the complete six-slot object through
set-global-state with revision CAS, immutable backup, session idempotency,
exact readback, stale-CAS rejection, and automatic rollback. The custom
assignment object does not imply codex-micro-agent-source=custom; source
selection remains an explicit settings candidate and transaction.
The installed Codex app exposes these Codex Micro setting records:
| Setting | Observed default | Meaning |
|---|---|---|
codex-micro-agent-source |
recent |
Source/order for Agent Key assignments |
codex-micro-single-tap-agent-keys |
false |
Single tap brings the assigned task forward |
codex-micro-layout |
schema version 1 |
Command-key, dial, joystick, and voice assignments |
codex-micro-lighting-brightness |
100 |
Global Tier 1 lighting intensity |
codex-micro-lighting-auto-off |
3-minutes |
Idle auto-off duration |
Agent source values observed in the UI are pinned, recent, priority, and
custom. Custom Agent Key assignments may reference a task, command/shortcut,
keycap, or skill.
| Surface | Logical IDs |
|---|---|
| Agent Keys | AG00, AG01, AG02, AG03, AG04, AG05 |
| Command Keys | ACT06, ACT07, ACT08, ACT09, ACT10_ACT11, ACT12 |
| Analog joystick | up, right, down, left |
| Dial gestures | left, right, click, longPress |
ACT10_ACT11 is one double-width logical slot backed by two physical switch
signals. The observed default Command Keycaps are FAST, APPR, REJ,
SPLIT, MIC, and CODEX.
- Agent Keys: task assignment plus idle, thinking, complete, needs-input, error, and unassigned lighting states.
- Voice button modes:
push-to-talkandrealtime/Voice Chat. - Dial modes:
composer-navigation,reasoning,conversation-scroll, andcustom. - Default joystick commands: plan-mode toggle, forward, sidebar toggle, and back.
- Custom dial and joystick assignments: Codex command, skill, or empty.
- Long-pressing the dial opens Codex Micro settings.
The gesture editor is active only in custom mode. Mode changes retain all
gesture mappings. In custom mode, each gesture stores a command object, Skill
object, or null; outside custom mode the built-in runtime behavior remains
authoritative.
Joystick direction editing is independent of dial mode. Each direction stores
a command object, Skill object, or null. An inherited default is reported
until a candidate materializes the frozen layout; setting a direction to its
effective default is a no-op and leaves that layout implicit.
Layout reset writes the complete frozen installed-build default, covering Command Keys, joystick, dial mode/gestures, and voice-button mode. It preserves all sibling settings and does not touch Agent Key assignment storage. An inherited default layout is a no-op and remains implicit.
The inspected build contains 38 keycap identifiers:
FAST APPR REJ SPLIT MIC CODEX BUG OAI TERM DWN DEL NEW NAV MAGIC
DIFF PLAY GIT BRCH BRANCH MRG PR PAINT LAB PARTY TIME MIND+ MIND-
EMPT1 EMPT2 EMPT3 EMPT4 SETUP FOLD UPL APPS YOLO YEET EMPT5
Their actions cover fast mode, approval/decline, task fork, voice input, submit, feedback, OpenAI docs, terminal, copy-conversation Markdown, archive, new task, browser, pin, review, environment action, Git/branch/PR operations, photo/file attachment, settings, side chat, task management, reasoning level, folder open, Skills, and custom composer commands.
The installed Work Louder integration uses vendor notifications including:
| Method | Role inferred from call sites |
|---|---|
v.oai.hid |
Agent/Command key HID events |
v.oai.rad |
Analog/radial input events |
v.oai.thstatus |
Per-task status lighting |
v.oai.rgbcfg |
Key and ambient RGB configuration |
Observed lighting effects are off, solid, snake, rainbow, breath, gradient, and shallow breath. Auto-off values are off, 30 seconds, 1/3/10/30 minutes, and 1 hour.
The read-only cache adapter exposes the current semantic configuration without opening a device transport or changing the Input process/GUI state:
worklouderctl input config snapshot --output SNAPSHOT.json [--device DEVICE_ID]It selects the requested or sole cached device, captures regular
keymap.json and optional smart_actions.json files byte-for-byte, rejects
symlink sources, and excludes host-only input_storage.json. Before atomic
publication it verifies source stability, SHA-1, SHA-256, canonical base64,
semantic JSON, safe paths, and the full deterministic revision; it then reopens
the result and rereads the sources. The snapshot core (deviceId, files, and
revision) matches a bridge snapshot of the same bytes and feeds every offline
semantic command directly.
The primary transport uses the authenticated Input Companion Bridge. The CLI client and Input-main reference server expose:
worklouderctl bridge status
worklouderctl device --transport bridge status
worklouderctl device --transport bridge files [--path PATH] [--recursive]
worklouderctl device --transport bridge export --output DIRECTORY
worklouderctl device --transport bridge config snapshot --output SNAPSHOT.json
worklouderctl device --transport bridge config validate --input SNAPSHOT.json
worklouderctl device --transport bridge config apply \
--input CANDIDATE.json --backup PRE_APPLY.json
worklouderctl device --transport bridge config restore \
--input ORIGINAL.json --backup PRE_RESTORE.jsonInput owns the connected session and serializes requests through its existing
service container. It reports firmware, active profile/layer, battery/charging
state, device identity, transport, file names, sizes, and device checksums.
Export reads raw file bytes through the bridge, verifies device SHA-1 plus host
SHA-256, and atomically publishes a typed bundle accepted by config validate
and config diff. The config snapshot command adds exact base64 content and a
deterministic full-configuration revision. Validation recomputes sizes, both
digests, and the revision; --expected-revision enables a live read-only
compare-and-swap preflight.
Apply and restore use the same complete snapshot envelope. The CLI creates or reopens an immutable pre-mutation backup, while Input owns serialized CAS, idempotency, complete-set replacement, readback, and automatic rollback. These mutation behaviors pass the isolated cross-language writer fixture; an installed Input version must advertise the corresponding capabilities before the commands run against a device.
Input 0.18.0 does not natively ship the bridge; the exact-release installer supplies it after version/hash verification. The verified read-only direct compatibility path remains available as:
worklouderctl device --transport direct [--input-mode require-closed|restart] statusThe observed keymap.json shape contains:
version
activeProfileId
profiles[]
id, name
layers[]
id, name, color, layout, lights
macrosUsed[]
multiActionsUsed[]
multiActions[]
macros[]
macrosGroups[]
multiActionsGroups[]
linkedApps[]
deviceSpecificConfig? # device/model dependent
Input 0.18.0 also models smartActions and smartActionGroups. The connected
Codex Micro stores them in a separate smart_actions.json file.
- profile create, rename, select, and delete;
- layer create, rename, reorder, delete, and application link;
- six normal layer selectors and six temporary layer selectors;
- six profile selectors;
- Mac/Windows label mode;
- touch-sensor layer cycling and AppSense automatic switching.
The frozen Codex Micro model has a maximum of six profiles and six layers per profile. Other device models still require their own versioned limits.
The first semantic CLI slice operates on a complete revisioned snapshot rather than a partial keymap fragment:
worklouderctl profile list --input SNAPSHOT.json
worklouderctl profile show --input SNAPSHOT.json --id ID
worklouderctl profile create --input SNAPSHOT.json --name NAME --output CANDIDATE.json
worklouderctl profile duplicate --input SNAPSHOT.json --id ID \
[--name NAME] --output CANDIDATE.json
worklouderctl profile delete --input SNAPSHOT.json --id ID --output CANDIDATE.json
worklouderctl profile select --input SNAPSHOT.json --id ID --output CANDIDATE.json
worklouderctl profile rename --input SNAPSHOT.json --id ID --name NAME --output CANDIDATE.json
worklouderctl layer list --input SNAPSHOT.json [--profile ID]
worklouderctl layer show --input SNAPSHOT.json [--profile ID] --id ID
worklouderctl layer create --input SNAPSHOT.json [--profile ID] \
--name NAME --output CANDIDATE.json
worklouderctl layer duplicate --input SNAPSHOT.json [--profile ID] \
--id ID [--name NAME] --output CANDIDATE.json
worklouderctl layer delete --input SNAPSHOT.json [--profile ID] \
--id ID --output CANDIDATE.json
worklouderctl layer move --input SNAPSHOT.json [--profile ID] \
--id ID --to INDEX --output CANDIDATE.json
worklouderctl layer rename --input SNAPSHOT.json [--profile ID] \
--id ID --name NAME --output CANDIDATE.json
worklouderctl layer color --input SNAPSHOT.json [--profile ID] \
--id ID --color '#RRGGBB' --output CANDIDATE.json
worklouderctl layer lighting show --input SNAPSHOT.json [--profile ID] --id ID
worklouderctl layer lighting set --input SNAPSHOT.json [--profile ID] \
--id ID --zone backlight --effect breath --brightness 0.5 \
--speed 0.5 --magic 0.5 --color '#RRGGBB' [--apply-to-all] \
--output CANDIDATE.json
worklouderctl layer joystick show --input SNAPSHOT.json [--profile ID] --id ID
worklouderctl layer joystick mode set --input SNAPSHOT.json [--profile ID] \
--id ID radial --output CANDIDATE.json
worklouderctl layer joystick sector add --input SNAPSHOT.json [--profile ID] \
--id ID --index INDEX --output CANDIDATE.json
worklouderctl layer joystick sector delete --input SNAPSHOT.json [--profile ID] \
--id ID --index INDEX --output CANDIDATE.json
worklouderctl appsense list --input SNAPSHOT.json
worklouderctl appsense show --input SNAPSHOT.json --id APP_ID
worklouderctl appsense link --input SNAPSHOT.json [--profile ID] \
--layer ID --name NAME [--process BUNDLE_ID] [--path APP_PATH] \
--output CANDIDATE.json
worklouderctl appsense set --input SNAPSHOT.json --id APP_ID \
[--name NAME] [--process BUNDLE_ID|--clear-process] \
[--path APP_PATH|--clear-path] --output CANDIDATE.json
worklouderctl appsense unlink --input SNAPSHOT.json [--profile ID] \
--layer ID --output CANDIDATE.json
worklouderctl control list --input SNAPSHOT.json [--profile ID] --layer ID
worklouderctl control show --input SNAPSHOT.json [--profile ID] \
--layer ID --control key:ROW:COLUMN
worklouderctl control set --input SNAPSHOT.json [--profile ID] \
--layer ID --control encoder:INDEX:press --assignment KC_MUTE \
--output CANDIDATE.jsonThese commands validate the entire snapshot offline, preserve unknown fields
and non-keymap bytes, rewrite keymap.json as compact ordered JSON, update its
size/SHA-1/SHA-256, and recompute the full configuration revision. Candidate
files are atomically published and reopened. Apply and rollback remain separate
explicit transaction steps through the Input-owned bridge.
Profile and layer object IDs are stable CLI identifiers allocated from the
largest existing ID plus one. Input 0.18.0's persisted activeProfileId is
instead a zero-based profile-array index; list/show report both values and
profile select resolves the object ID before writing the index. Deletion
keeps that index valid. A newly created profile contains the protected Codex
layer template with layer ID zero and no per-layer lights.
A layer is protected when any layout assignment begins with KV_OAI_. The
protected layer stays at position zero and is excluded from duplicate, delete,
move-to/from-zero, per-layer lighting edits, and Input control set writes.
control list and control show remain available for inspection. Configure
its six Agent Keys, eight logical Command Key slots, combined/independent
microphone keys, dial, and joystick through
the codex command family; codex reset layout is the Codex GUI Reset layout
equivalent. New normal layers use the frozen Codex Micro empty layout and copy
the last layer's lighting when present. Duplicate performs a deep copy with a
new ID and removes linkedAppId so the copy does not silently inherit an
AppSense binding.
The observed Input 0.18.0 layer color is a 24-bit RGB integer. The CLI accepts
#RRGGBB, 0xRRGGBB, or decimal 0..16777215, stores the integer, and reports
both the integer and normalized uppercase colorHex. This field is layer
metadata; backlight and underglow objects remain separate lighting surfaces.
- 13 switches, including the double-width Codex Command Key surface;
- encoder counter-clockwise, clockwise, and click;
- planar joystick sectors/radial assignments;
- touch-sensor behavior where exposed by the device adapter.
The implemented physical IDs are key:ROW:COLUMN,
encoder:INDEX:ccw|cw|press, and joystick:SECTOR. List/show report the exact
device token and classify it as basic, internal, action, multiAction,
or vendor. Set modifies only an existing physical slot; assignment-only edits
leave joystick angles unchanged.
layer joystick show/mode/sector implements the released Input 0.18.0 radial
editor contract. mode set ... radial installs the observed KI_X/KC_NONE
two-sector seed when fewer than two sectors exist. Sector add inserts
KC_NONE; add/delete enforce the inclusive 2–8 count range. Both operations
recompute every angle: sector zero remains 0.1875..0.3125 turns and the
remaining 0.875 turns are divided equally among the other sectors, modulo
one. The GUI's disabled JOYSTICK option is not advertised as writable.
spec/input-assignment-tokens-0.18.0.json freezes 184 KC_* tokens and 43
KI_* tokens recovered from the Input 0.18.0 ASAR, plus KA_A<ID> and
KA_M<ID> reference formats. Reference IDs must exist in root macros or
multiActions; profile usage arrays are recomputed in Input's string order.
The catalog records the source ASAR SHA-256 and the observed Codex Micro
[2,4,4,3] key matrix. Existing KV_* assignments are accepted for strict
read/preservation but rejected as new user assignments.
The inspected Input UI exposes 171 basic-key choices across:
- alphanumeric and glyph keys;
- modifiers, arrows, navigation, editing, and locks;
F1–F24;- number-pad keys;
- media, volume, power, sleep, stop, and brightness;
- Layer 1–6 and temporary Layer 1–6;
- Profile 1–6;
- Cheat Sheet show, hold, hide, and toggle.
Simple mode records a chord or phrase. Advanced mode represents ordered key press, release, click, and delay events. An Action carries an ID, name, optional color, and event list; groups are separate referenced collections.
Validation must cover balanced modifier release, referenced IDs, maximum event counts, permitted keycodes, and preserved ordering. Hardware verification must observe the emitted chord rather than relying on the displayed Action name.
The current offline Action interface is:
worklouderctl action list --input SNAPSHOT.json
worklouderctl action show --input SNAPSHOT.json --id ID
worklouderctl action create --input SNAPSHOT.json --name NAME --output CANDIDATE.json
worklouderctl action rename --input SNAPSHOT.json --id ID --name NAME --output CANDIDATE.json
worklouderctl action event add --input SNAPSHOT.json --id ID \
--assignment KC_C --type press --delay 0 --output CANDIDATE.json
worklouderctl action event set --input SNAPSHOT.json --id ID --index INDEX \
[--assignment TOKEN] [--type release|press|click] [--delay MILLISECONDS] \
--output CANDIDATE.json
worklouderctl action event delete --input SNAPSHOT.json --id ID \
--index INDEX --output CANDIDATE.json
worklouderctl action event move --input SNAPSHOT.json --id ID \
--from INDEX --to INDEX --output CANDIDATE.json
worklouderctl action delete --input SNAPSHOT.json --id ID --output CANDIDATE.json
worklouderctl action group list --input SNAPSHOT.json
worklouderctl action group show --input SNAPSHOT.json --id GROUP_ID
worklouderctl action group create --input SNAPSHOT.json --name NAME \
--action ACTION_ID [--action ACTION_ID] [--color '#RRGGBB'] [--tag TAG] \
--output CANDIDATE.json
worklouderctl action group set --input SNAPSHOT.json --id GROUP_ID \
[--name NAME] [--color '#RRGGBB'|--clear-color] \
[--tag TAG|--clear-tags] --output CANDIDATE.json
worklouderctl action group member add --input SNAPSHOT.json --id GROUP_ID \
--action ACTION_ID --output CANDIDATE.json
worklouderctl action group member remove --input SNAPSHOT.json --id GROUP_ID \
--action ACTION_ID --output CANDIDATE.json
worklouderctl action group member move --input SNAPSHOT.json --id GROUP_ID \
--from INDEX --to INDEX --output CANDIDATE.json
worklouderctl action group delete --input SNAPSHOT.json --id GROUP_ID \
[--keep-members] --output CANDIDATE.jsonspec/input-actions-0.18.0.json freezes the ASAR-derived model. Action IDs use
Input's last-action-ID-plus-one allocation. Event types are release 0, press
1, and click 2; delay is an integer from 0 through 9999 milliseconds.
A sole deleted event resets to {act:1,delay:0,kc:"KC_NONE"}, matching the
editor's one-event invariant.
Action deletion is referentially complete across existing layer keys,
encoders, joystick sectors, other Action events, four Multi Action branches,
Action groups, and profile usage arrays. References become KC_NONE; empty
Action groups are removed; macrosUsed is recomputed in Input string order.
The candidate still preserves unrelated file bytes and unknown JSON fields.
Stored groups keep ordered, unique actionIds, optional tags, and optional
color. New group IDs use the maximum existing group ID plus one, matching
Input's import path rather than assuming the array is sorted. Default group
deletion matches the Input 0.18.0 GUI: members that occur in no other stored
group are deleted with the normal Action cascade; shared members survive.
--keep-members removes only the group object. Member removal rejects a
resulting empty group so the snapshot remains valid.
The UI offers tap, double tap, hold, and tap-then-hold branches. The device
fields are kcOnTap, kcOnDoubleTap, kcOnHold, and kcOnTapHold, with tt
for the tapping term. Input 0.18.0 creates a Multi Action with four KC_NONE
assignments and a 250 ms tapping term; its GUI displays that term as fixed.
worklouderctl multi-action list --input SNAPSHOT.json
worklouderctl multi-action show --input SNAPSHOT.json --id ID
worklouderctl multi-action create --input SNAPSHOT.json [--name NAME] \
[--color '#RRGGBB'] [--icon ICON] --output CANDIDATE.json
worklouderctl multi-action set --input SNAPSHOT.json --id ID \
[--name NAME] [--color '#RRGGBB'|--clear-color] \
[--icon ICON|--clear-icon] [--tap TOKEN] [--double-tap TOKEN] \
[--hold TOKEN] [--tap-hold TOKEN] [--tapping-term MILLISECONDS] \
--output CANDIDATE.json
worklouderctl multi-action delete --input SNAPSHOT.json --id ID \
--output CANDIDATE.json
worklouderctl multi-action group list --input SNAPSHOT.json
worklouderctl multi-action group show --input SNAPSHOT.json --id GROUP_ID
worklouderctl multi-action group create --input SNAPSHOT.json --name NAME \
--multi-action ID [--multi-action ID] --output CANDIDATE.json
worklouderctl multi-action group set --input SNAPSHOT.json --id GROUP_ID \
[--name NAME] [--color '#RRGGBB'|--clear-color] \
[--tag TAG|--clear-tags] --output CANDIDATE.json
worklouderctl multi-action group member add --input SNAPSHOT.json --id GROUP_ID \
--multi-action ID --output CANDIDATE.json
worklouderctl multi-action group member remove --input SNAPSHOT.json --id GROUP_ID \
--multi-action ID --output CANDIDATE.json
worklouderctl multi-action group member move --input SNAPSHOT.json --id GROUP_ID \
--from INDEX --to INDEX --output CANDIDATE.json
worklouderctl multi-action group delete --input SNAPSHOT.json --id GROUP_ID \
[--keep-members] --output CANDIDATE.jsonspec/input-multi-actions-0.18.0.json freezes the model and source ASAR hash.
Multi Action IDs use Input's last-resource-ID-plus-one allocation; group IDs
use maximum-ID-plus-one. New branch assignments must exist in the frozen token
catalog and self-reference is rejected. Delete replaces matching physical,
Action-event, and nested Multi Action tokens with KC_NONE, removes group
membership, drops empty groups, and recomputes multiActionsUsed. Multi Action
group delete applies the same orphan/shared-member rule as Action groups.
Backlight and underglow each carry effect, brightness, speed, magic, and color.
The inspected effect list is off, solid, snake, rainbow, breath, and gradient.
Brightness, speed, and magic are normalized numbers in 0..1; color is stored
as a 24-bit integer. The default Codex Micro lighting is solid white backlight
at 1/0.5/1 and rainbow white underglow at 1/0.55/1. layer lighting set
updates only supplied fields. --apply-to-all copies the selected zone to all
layers in the profile and initializes both default zones on a layer that had no
lights object, matching the inspected Input 0.18.0 mapping behavior.
A linked application is stored in root linkedApps as
{id,name,process,path}; the selected layer stores the same ID in
linkedAppId. IDs follow Input 0.18.0's first missing nonnegative integer rule,
which is intentionally different from the maximum-plus-one profile, layer,
Action, and group rules. A record needs a non-empty process or path.
On macOS, process is the application bundle identifier; automatic detection
normally stores an empty path and derives a -mac name.
appsense list/show return the stored identity plus all profile/layer
bindings. link creates the root record and layer reference together. set
can rename or deliberately update detected identity fields while preventing an
empty identity. unlink removes the selected layer reference and removes the
root record when that was its only binding. This shared-reference guard keeps
the generated candidate referentially valid even though the Input GUI normally
creates one binding per record.
The frozen Input delete behavior is also preserved: deleting a layer or
profile does not garbage-collect now-unreferenced linkedApps, while
duplicating a layer omits linkedAppId. Snapshot validation permits an
unreferenced root record but rejects a layer reference to a missing record.
Input's host focus service polls once per second and sends changed
appName/process/path data to the device. The device firmware owns identity
matching and the actual layer transition; the algorithm is not present in the
Input renderer or main process. Therefore candidate/apply/readback/restore
proves configuration parity, while full runtime parity additionally needs an
A/B focus transition and device-status read.
appsense test now reads that runtime path through Input instead of opening or
focusing an application itself:
worklouderctl --json appsense test \
--expected-process com.example.app \
--expected-profile-index 0 --expected-layer-index 2 \
--timeout-ms 5000The report requires Input's collector to be active, the selected device to be
registered, and focusedApp to equal lastForwardedApp. Optional identity and
raw device-status expectations are polled until the timeout. Input 0.18.0
reports profile index as zero-based and firmware layer index as one-based; its
renderer subtracts one from the layer value. A timeout is a typed conflict
(exit status 5). The isolated bridge fixture verifies focus forwarding and
selectedProfileIndex=0/selectedLayerIndex=2; a released-Input A/B focus
transition remains a separate compatibility gate.
Input 0.18.0 advertises and implements:
- type text;
- run a command;
- open a URL;
- launch an application;
- name, group, search, reuse, and bind actions.
The offline smart-action editor now validates and preserves the separate
smart_actions.json authority. It supports list/show/create/set/delete for all
four typed payloads and smart-action group metadata plus ordered member CRUD.
Action keys use canonical SA_<ID> names; new IDs start at 1 and use
maximum-plus-one. Groups start at ID 0, may be empty, and container deletion
does not delete member actions. A Smart Action deletion replaces physical
SA_<ID> assignments with KC_NONE and removes group membership while keeping
the group valid. Unknown root, record, and payload fields survive edits, and a
Smart-only candidate leaves the exact keymap.json bytes unchanged.
control set accepts an existing SA_<ID> only for physical controls on normal
Input layers. It rejects every write to the Codex protected layer before a
candidate is published; cheat-sheet bind inherits the same guard. Action
events and Multi Action branches retain their own frozen assignment grammar.
The CLI reports command definitions with requiresCommandPermission: true;
definition editing does not toggle the host permission.
The Input database has a smartActionCmdEnabled permission field. Command
execution remains explicitly separate from device deployment:
worklouderctl input permission command snapshot --output HOST_SETTINGS.json
worklouderctl input permission command get --input HOST_SETTINGS.json
worklouderctl input permission command set --input HOST_SETTINGS.json enabled \
--output HOST_SETTINGS_ENABLED.json
worklouderctl input permission command apply \
--input HOST_SETTINGS_ENABLED.json --backup HOST_SETTINGS_BEFORE.json \
--expected-revision REVISION --idempotency-key RETRY_KEY
worklouderctl input permission command restore \
--input HOST_SETTINGS.json --backup HOST_SETTINGS_CURRENT.json \
--expected-revision CURRENT_REVISION --idempotency-key RESTORE_KEYThe snapshot includes showedAnalyticsPopUp, analyticsConsented, and
smartActionCmdEnabled. Offline set changes only the last field. The Input
Companion Bridge owns complete-DTO replacement, CAS, idempotent replay, exact
readback, explicit restore, and automatic rollback; it never writes LokiJS
storage behind the running application's back. The SHA-256 revision frames
those booleans in that order after
worklouder-input-host-settings-revision-v1\0. Live replacement delegates to
Input's ApplicationService.getAppSettings/saveAppSettings authority.
Preset catalog capture uses the Input-owned provider rather than reading or editing LokiJS directly:
worklouderctl input preset snapshot --output PRESET_CATALOG.json
worklouderctl preset list --catalog PRESET_CATALOG.json \
--device codex_micro --layout universal --os mac --search figma
worklouderctl preset show --catalog PRESET_CATALOG.json --id 9002
worklouderctl preset preview --catalog PRESET_CATALOG.json --id 9002 \
--output figma.png
worklouderctl preset install --input CONFIG.json --catalog PRESET_CATALOG.json \
--id 9002 --profile 0 --output FIGMA_CANDIDATE.jsonThe catalog snapshot has a recursive-key-sorted SHA-256 revision and preserves
the saved-first/default-second order supplied by Input. Filters match exact
device, layout, and OS membership (mac = 0, windows = 1); search is a
case-insensitive substring over the preset name and tags. List/show expose
metadata and resource counts without returning multi-megabyte image fields.
Preview accepts only bounded base64 PNG, JPEG, or WebP data, publishes to a new
path atomically, and verifies byte-exact readback.
Install reproduces the frozen Input 0.18.0 algorithm: no more than six layers,
last-existing-ID allocation for Actions and Multi Actions, maximum-ID
allocation for groups and the appended layer, exact equality-field reuse,
preset-tag propagation, and complete KA_/KM_ reference remapping. It then
rehashes and reopens a full configuration candidate for the existing
snapshot/CAS/apply/readback/rollback transaction. All 17 hash-pinned bundled
defaults were candidate-verified, including the literal preset ID 90017.
Renderer-only selected-layer state is reported as a runtime boundary, not
written into the keymap.
Input hosts windows for Cheat Sheet and the joystick radial menu. Cheat Sheet combines Keys, Actions, Multi Actions, and Smart Actions for the active layer. The device emits show/hide/toggle notifications while Input renders the result.
The configuration side is available without opening either window:
worklouderctl cheat-sheet catalog
worklouderctl cheat-sheet bindings --input CONFIG.json --profile 0 --layer 1
worklouderctl cheat-sheet bind --input CONFIG.json --profile 0 --layer 1 \
--control encoder:0:press hold --output CANDIDATE.json
worklouderctl radial show --input CONFIG.json --profile 0 --layer 1The four values map to the exact released tokens: show → KI_CS_SHOW,
hold → KI_CS_SHOW_TMP, hide → KI_CS_HIDE, and toggle →
KI_CS_TOGGLE. Input exposes them for Creator Micro V2 and Codex Micro from
firmware 0.5.0; the tested boundary is Codex Micro v0.6.0. The candidate
uses the same complete-snapshot validation, atomic publication, bridge apply,
readback, and rollback as other physical-control assignments.
The radial menu has no separate persisted settings in Input 0.18.0.
radial show reads the selected layer's ordered joystick sectors and resolves
Action, Multi Action, and Smart Action names, colors, and icons from the same
complete snapshot that Input supplies to its overlay. KC_* and KI_* labels
come from the exact macOS HID primary-label map for the snapshot language;
KV_* retains Input's literal 1 placeholder. Sector count, angles, and
assignments remain editable through layer joystick and control set.
Input remains responsible for kb.radial notifications, animation, and the
three-second auto-close; inspection does not open the overlay window.
- application and firmware version discovery;
- device identity, transport, battery, profile, and layer status;
- device file list/read/write RPC;
- Input logs and input-monitoring permissions;
- firmware download, USB flashing, progress, and recovery;
- full settings reset;
- migration and runtime selection after a preset install.
These operations use distinct policy gates from normal semantic edits. The installed Input updater/flasher remains the implementation provider. The CLI invokes and observes that provider rather than owning a second firmware or transport implementation.
The first read-only operational commands are implemented:
worklouderctl input permissions [--device DEVICE_ID]
worklouderctl input firmware check [--device DEVICE_ID]
worklouderctl input firmware plan --output FIRMWARE_PLAN.json \
[--device DEVICE_ID]
worklouderctl input firmware update --plan FIRMWARE_PLAN.json \
--backup FIRMWARE_CONFIG_BEFORE.json --receipt FIRMWARE_UPDATE.json \
--expected-revision CONFIG_REVISION --idempotency-key UPDATE_KEY
worklouderctl input logs collect --output INPUT_LOG_BUNDLE \
[--max-entries 5000]On macOS, the permission result is Input's one released Input Monitoring
boolean; it is not expanded into an Accessibility claim. Firmware check uses
Input's current compatibility and .bin release selection. Log collection
sanitizes inside the Input adapter before bridge transport, then publishes a
private, hash-verified bundle. Firmware planning freezes the release, exact
configuration revision, USB blocker, and seven Input-owned update phases without
flashing. When Input injects the complete high-level update authority, the CLI
adds immutable backup, plan/config CAS, idempotent delegation, exact firmware
and configuration postflight, and an inspectable receipt around that provider.
Reset and bootloader recovery use separate Input-owned authorities.
The reset authority is implemented as a read-only, versioned default candidate
builder plus the existing configuration transaction:
worklouderctl input reset plan --plan RESET_PLAN.json \
--candidate RESET_CANDIDATE.json
worklouderctl input reset apply --plan RESET_PLAN.json \
--candidate RESET_CANDIDATE.json --backup RESET_BEFORE.json \
--receipt RESET_RECEIPT.json --expected-revision CONFIG_REVISION \
--idempotency-key RESET_KEY
worklouderctl input recovery plan --backup CONFIG_BEFORE_RECOVERY.json \
--plan RECOVERY_PLAN.json
worklouderctl input recovery apply --plan RECOVERY_PLAN.json \
--backup CONFIG_BEFORE_RECOVERY.json --receipt RECOVERY_RECEIPT.json \
--idempotency-key RECOVERY_KEYInput owns the exact default layout for the connected
app/device/device-kit/firmware/layout tuple. The CLI freezes its revision,
captures a complete backup, applies it through device.config.apply, verifies
the exact Input version immediately before mutation, performs exact readback,
and restores through device config restore.
Bootloader recovery is a separate Input-owned authority. Its read-only plan binds the exact Input/device-kit versions, original device and firmware, Input-detected bootloader identity, Input-selected release, and complete pre-recovery configuration revision. Apply delegates programmer and reconnect to Input, then reuses the existing complete configuration transaction to restore that exact backup. Success requires exact target-firmware and original configuration-revision postflight; the CLI does not implement the programmer, transport, or a firmware downgrade.
Each capability records one of four evidence levels:
- official — described by an official Work Louder source;
- static — present in the installed Codex/Input package;
- state — present in a frozen cache/device readback;
- behavior — exercised with literal output and post-state verification.
A public write-support claim requires all four levels for the exact version adapter and a verified rollback.