Skip to content

Define Lua config architecture #8

Description

@inayayousfi

Written by inayayousfi, typed by gpt-5.6-sol running in OpenCode.
Every call here is inayayousfi's, and no agent acted on its own.

Goal

Add Lua configuration without creating a second runtime model. Lua should produce the same native config, behavior, event, action, and state shapes used by bundled Python config today.

Python remains responsible for validation, window and component construction, queue dispatch, state ownership, backend adapters, and process lifecycle. Concrete layouts and user policy should move to Lua.

Existing Runtime Contract

The Lua layer must compile into these existing boundaries:

  • Visual config describes labels, display variants, geometry, component kinds, and stable IDs. It contains no backend output or runtime policy.
  • Root BehaviorBinding records attach behavior to exact SourcePath targets.
  • Every interactive key and generic button has exactly one binding. Missing, duplicate, unresolved, extra, and unknown bindings fail before windows are built.
  • Components emit component.pressed and component.released, then render complete snapshots from the central state store.
  • Events report what happened. Actions request effects. Both use lowercase dot-separated names and native Lua/Python data only.
  • Queue messages never contain Qt objects, backend objects, Python callbacks, Lua functions, or dataclass instances.
  • The keyboard service owns backend lifecycle, output registration, observations, and press handles. Keyboard policy stays in behavior handlers.
  • Durable state is addressed by full app, profile, window, surface, layout, grid, and component paths.

Lua Config Loading

The loader should search the standard per-user config location:

Unix: $XDG_CONFIG_HOME/axidev-osk/config.lua
Unix: ~/.config/axidev-osk/config.lua
Windows: %APPDATA%/axidev-osk/config.lua

If no user config exists, load the bundled default. If user config fails to load or validate, show the error and start with the bundled recovery config.

A Lua root config may define multiple profiles. One profile is active at a time. The active profile compiles into runtime windows, surfaces, layouts, components, and behavior bindings. Reusing a layout must create fresh runtime state for each instance.

Lua Behaviors And Hooks

Lua-defined behavior and hook names register through the same behavior registry as built-ins. Each registration supplies an argument decoder and a Lua callback reference. The queue stores the reference and native arguments, never the function itself.

Callbacks are deferred by default. A blocking before-hook may cancel or replace default behavior. All matching before-hooks run, ordered side messages are preserved, and the last cancel or replace decision wins. After-hooks may add messages but cannot undo effects that already ran.

A callback failure produces behavior.failed. Lua callbacks must not mutate widgets, backend objects, or durable state directly. They return events or actions to the queue.

State And Reload

The main runtime owns durable state. Lua can read snapshots and request state changes through actions.

Config reload, profile switch, restart, and state reset must release active backend handles, remove old behavior bindings and handlers, discard non-preserved state, rebuild fresh layout instances, and leave the runtime usable when one step fails.

Preserved state needs an explicit config policy. Widget lifetime and Lua closure lifetime must never decide persistence.

Bundled Config

The bundled US ISO keyboard should become an ordinary Lua config loaded through the same path as user config. Its current visual geometry, stable component IDs, output behavior, modifier modes, display variants, prompt actions, and Ghost action form the parity target.

Python should not contain US ISO-specific layout knowledge after parity is established.

Acceptance Criteria

  • A Lua root config can define profiles, windows, surfaces, layouts, components, and behavior bindings.
  • User and bundled config use one loading and validation path.
  • Invalid user config visibly falls back to a bundled recovery config.
  • Lua-defined behavior and hook arguments receive runtime validation.
  • Lua callbacks communicate only through events and actions.
  • Blocking hooks can cancel or replace default behavior with deterministic ordering.
  • Durable state remains in the main runtime store.
  • Reload and profile switch clean up old handlers, backend handles, bindings, windows, and non-preserved state.
  • Two uses of one layout receive independent runtime state.
  • Bundled Lua US ISO passes parity tests without Python layout-specific behavior.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

enhancementNew feature or request

Type

No type

Projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions