Appearance
Events
Events are Klix's lifecycle and notification hook system. They are simpler than middleware and broader in scope.
See also:
Why Events Exist
Some behavior should happen because something occurred, not because you are wrapping a command. Examples:
- app started
- app is exiting
- a line of input was received
- a command is about to dispatch
- an error occurred
That is what the event bus is for.
Current Event Model
The event bus is:
- in-process
- ordered
- sync/async aware
- minimal by design
Listeners are stored per event name and run in registration order.
Registering Events
python
@app.on("start")
def on_start(session: klix.Session):
session.ui.print("Started.", color="accent")Async listeners work too:
python
@app.on("start")
async def warmup(session: klix.Session):
...Events Actively Emitted Today
The current runtime emits these directly from App.run() or command dispatch:
startinputcommandinterrupterrorexit
Persistence also checks for state_migration handlers when loading persistent state.
Events Named In The Spec But Not Fully Emitted Today
The framework design mentions events like:
resizefocusblur
Those names can be registered, but the current runtime loop does not actively emit them yet.
Documenting that clearly matters because it changes how you should use the API in production.
Event Flow Example
For a command like /deploy prod, the runtime roughly does this:
- emit
startonce at app startup - emit
inputwith the raw line - parse the command
- run middleware
- emit
commandduring dispatch - run the handler
- emit
exiton shutdown
Realistic Example
python
@app.on("start")
def on_start(session: klix.Session):
session.ui.layout.header.set("Deploy CLI", color="accent")
session.ui.layout.status.set("Ready", "Use /help", color="muted")
session.ui.layout.redraw_ui()
@app.on("input")
def on_input(text: str, session: klix.Session):
session.ui.print(f"received: {text}", color="muted", dim=True)
@app.on("command")
def on_command(cmd: klix.ParsedCommand, session: klix.Session):
session.ui.layout.status.set("Running", cmd.name, color="muted")
session.ui.layout.redraw_ui()
@app.on("exit")
def on_exit(session: klix.Session):
session.ui.print("Shutting down.", color="muted")Events vs Middleware
If you need before/after command behavior, use middleware.
If you need notification-style hooks, use events.
A good rule:
- middleware changes flow
- events observe flow
Pitfalls
Assuming every spec event is emitted
Stick to the events currently emitted by the runtime unless you are deliberately extending the core.
Putting business logic entirely in events
Events are useful for side effects, but core command behavior usually belongs in handlers or middleware.