Build a Counter App

Build your first interactive Milo app with a reducer and Kida template.

2 min read 496 words

This tutorial walks through a simple counter app: the smallest useful interactive Milo program.

What You'll Learn

0/4 complete
  • Write a pure reducer function
  • Create a Kida terminal template
  • Wire them together withApp
  • Run with hot reload viamilo dev

Build the Counter

  1. 1

    Create a reducer

    A pure function that manages your state

    A reducer takes the current state and an action, then returns the next state. It does not mutate the old state.

    # app.py
    from milo import App, Action
    
    
    def reducer(state, action):
        if state is None:
            return {"count": 0}
        if action.type == "@@KEY" and action.payload.char == " ":
            return {**state, "count": state["count"] + 1}
        if action.type == "@@KEY" and action.payload.char == "r":
            return {**state, "count": 0}
        return state
    

    The reducer handles three cases:

    Action Condition Result
    @@INIT state is None Return default state{"count": 0}
    @@KEY char == " " Increment counter
    @@KEY char == "r" Reset counter to 0
  2. 2

    Create a template

    Render state to the terminal with Kida

    Milo uses Kida templates for rendering. Create a template file:

    {# counter.kida #}
    Count: {{ count }}
    
    [SPACE] Increment  [R] Reset  [Ctrl+C] Quit
    

    Your state dict becomes the template context. {{ count }}renders the current value ofstate["count"].

  3. 3

    Wire it together

    Create an App and run the event loop

    app = App(template="counter.kida", reducer=reducer, initial_state=None)
    final_state = app.run()
    print(f"Final count: {final_state['count']}")
    

    Appconnects input, state, and rendering: it reads keyboard input, dispatches @@KEYactions to the reducer, re-renders the template on each state change, and returns the final state when the user quits.

  4. 4

    Run it

    Start your app with hot reload

    milo dev app:app --watch .
    

Tip

Themilo dev command uses the module:attribute convention. app:appmeans "importapp.py and look up the app attribute." The --watchflag enables hot reload, so template edits show up immediately.

What Just Happened?

flowchart LR K[Keyboard] -->|"@@KEY"| R[Reducer] R -->|new state| S[Store] S -->|state dict| T[Kida Template] T -->|ANSI output| Term[Terminal]
  1. KeyReader captures raw terminal input and producesKeyobjects.
  2. Store dispatches@@KEYactions to your reducer.
  3. Reducer returns new state.
  4. Kida template renders state to terminal output.
  5. LiveRenderer diffs and redraws changed lines.

This is Milo's Elm-style architecture: every state transition is explicit and testable.

Next Steps