Skip to content

Session ​

Session is the per-terminal runtime object in Klix. If App is the application definition, Session is the active instance.

See also:

Why Session Exists ​

A framework like Klix needs a place to hold runtime state that is not global:

  • current application state
  • metadata about the terminal
  • runtime UI handles
  • input history
  • background tasks

That is what Session does.

What Lives On A Session ​

The current implementation exposes these important attributes:

  • session.id
  • session.state
  • session.metadata
  • session.history
  • session.ui
  • session.input_engine

session.ui and session.input_engine are attached during startup. They are None until the runtime has been built.

Typed State ​

The most common reason to use Session is typed state access:

python
from dataclasses import dataclass
import klix

@dataclass
class MyState(klix.SessionState):
    logged_in: bool = False
    username: str = ""

app = klix.App(name="mytool", state_schema=MyState)

@app.command("/login", help="Log in")
def login(session: klix.Session):
    session.state.logged_in = True
    session.state.username = "alice"

See Working with State.

Terminal Metadata ​

Klix captures a small TerminalMetadata object on startup. It currently contains:

  • env
  • width
  • height
  • start_time
  • term_program
  • interactive

Example:

python
@app.command("/env", help="Show terminal metadata")
def env(session: klix.Session):
    session.ui.output.json(
        {
            "interactive": session.metadata.interactive,
            "term_program": session.metadata.term_program,
            "size": [session.metadata.width, session.metadata.height],
        }
    )

Background Tasks ​

Session.create_task() lets you schedule session-scoped async work:

python
import asyncio

@app.command("/watch", help="Run a background watcher")
async def watch(session: klix.Session):
    async def worker():
        for i in range(3):
            await asyncio.sleep(1)
            session.ui.print(f"tick {i + 1}", dim=True)

    session.create_task(worker())

Klix tracks these tasks and waits on them during shutdown.

How It Fits The Architecture ​

Every handler and middleware function gets a Session because it is the shortest path to the active runtime:

  • state
  • UI
  • metadata
  • background tasks

That keeps function signatures simple without forcing global variables.

Common Mistakes ​

Using session.ui before startup ​

If you instantiate a Session yourself outside the normal App.run() path, you are responsible for attaching session.ui and session.input_engine.

Putting app definition into session state ​

State should hold runtime data, not command definitions, renderer objects, or application configuration that already lives on App.

Assuming session.history is fully managed everywhere ​

session.history is the live per-session command history backing the input engine.

That means:

  • Up/Down arrow navigation reads from it
  • duplicate consecutive commands are skipped
  • AppConfig(max_history_size=...) trims it automatically

The field is still just a Python list, so if you mutate it directly, do it deliberately.

Released under the MIT License.