Skip to content

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:

  • start
  • input
  • command
  • interrupt
  • error
  • exit

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:

  • resize
  • focus
  • blur

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:

  1. emit start once at app startup
  2. emit input with the raw line
  3. parse the command
  4. run middleware
  5. emit command during dispatch
  6. run the handler
  7. emit exit on 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.

Released under the MIT License.