status widget development

status views system:

  status line areas:
    area A: left side (usually context/project info)
    area B: middle (usually session info, llm status)
    area C: right side (usually time, system info)

  status rendering:
    - status_renderer.py manages three status areas
    - each frame, all plugins' get_status_line() called
    - results combined and rendered in terminal
    - status updated every frame (real-time)

  status view registry:
    - plugins register status views via core_status_views
    - each view has a name, priority, and render function
    - views sorted by priority and rendered in order

core status views:

  base class: CoreStatusView
    location: kollabor/io/core_status_views.py

  core status view structure:
    from kollabor.io.core_status_views import CoreStatusView

    class MyStatusView(CoreStatusView):
        def __init__(self, priority=50):
            super().__init__(
                name="my_status_view",
                priority=priority
            )

        def render(self, width: int) -> str:
            """
            render status view content

            args:
                width: available width for this view

            returns:
                rendered content string
            """
            # render status content
            return "status"

  registering status views:
    from kollabor.io.core_status_views import core_status_views

    # in plugin initialize()
    view = MyStatusView(priority=50)
    core_status_views.register(view)

  status view priority:
    - higher priority = rendered first (leftmost in area)
    - use priority to control ordering
    - recommended: 10-100 range

status widget integration:

  widget system:
    location: kollabor/ui/widgets/

  available widgets:
    - LabelWidget          (static text)
    - ProgressWidget       (progress bar)
    - CheckboxWidget       (checkbox for modals)
    - DropdownWidget       (dropdown selection)
    - SliderWidget         (slider for numeric values)
    - SpinBoxWidget        (numeric input with arrows)
    - TextInputWidget      (text input field)

  widget usage in status:
    from kollabor.ui.widgets import LabelWidget, ProgressWidget

    def render_status_with_widgets(self, width: int) -> str:
        # create label widget
        label = LabelWidget(text="status: active")

        # create progress widget
        progress = ProgressWidget(
            value=75,
            maximum=100,
            width=20
        )

        # render widgets
        return label.render() + " " + progress.render()

design system integration:

  import design system:
    from kollabor.ui.design_system import T, S, C, Box, TagBox, solid, solid_fg

  theme access:
    T().primary                   (primary accent color gradient)
    T().dark                      (dark background gradient)
    T().text                      (main text color - rgb tuple)
    T().text_dim                  (dimmed text color - rgb tuple)
    T().success                   (success color)
    T().error                     (error color)
    T().warning                   (warning color)

  style constants:
    S.BOLD, S.RESET_BOLD          (bold text)
    S.DIM, S.RESET_DIM            (dimmed text)
    S.UNDERLINE, S.RESET_UNDERLINE (underlined text)

  box rendering (solid block style):
    # top edge
    solid_fg("▄" * width, T().dark[0])

    # content with solid background
    solid(f"   {text:<{content_width}}", T().dark[0], T().text, width)

    # bottom edge
    solid_fg("▀" * width, T().dark[0])

  TagBox rendering (tag + content):
    TagBox.render(
        lines=["content line 1", "content line 2"],
        tag_bg=T().primary[0],        (tag background color)
        tag_fg=T().text_dark,         (tag foreground color)
        tag_width=3,                  (tag width)
        content_colors=T().dark[0],   (content background)
        content_fg=T().text,          (content foreground)
        content_width=width - 7,      (content width)
        tag_chars=[" > "],            (tag characters)
    )

  modern widget styling:
    # widgets have render_modern() method
    widget = DropdownWidget(options=["opt1", "opt2"])
    modern_render = widget.render_modern(
        width=30,
        state="open",
        theme=T()
    )

creating custom status widgets:

  pattern 1: simple text status

    class SimpleTextStatusView(CoreStatusView):
        def render(self, width: int) -> str:
            # simple text
            return "status: active"

    # register in plugin
    core_status_views.register(SimpleTextStatusView(priority=50))

  pattern 2: status with design system

    from kollabor.ui.design_system import T, S

    class StyledStatusView(CoreStatusView):
        def render(self, width: int) -> str:
            # use theme colors
            text = f"{S.BOLD}status:{S.RESET_BOLD} active"
            return text

    core_status_views.register(StyledStatusView(priority=50))

  pattern 3: dynamic status with data

    class DynamicStatusView(CoreStatusView):
        def __init__(self, data_source, priority=50):
            super().__init__("dynamic_status", priority)
            self.data_source = data_source

        def render(self, width: int) -> str:
            # get current data
            value = self.data_source.get_value()

            # render based on data
            if value > 90:
                status = "critical"
            elif value > 70:
                status = "warning"
            else:
                status = "normal"

            return f"cpu: {value}% ({status})"

  pattern 4: status with widgets

    from kollabor.ui.widgets import ProgressWidget

    class WidgetStatusView(CoreStatusView):
        def render(self, width: int) -> str:
            # create progress widget
            progress = ProgressWidget(
                value=75,
                maximum=100,
                width=20
            )

            # render widget
            return f"progress: {progress.render()}"

example 1: cpu monitor status widget

  plugins/cpu_monitor/plugin.py:
    from kollabor.io.core_status_views import CoreStatusView
    import psutil

    class CpuMonitorStatusView(CoreStatusView):
        def __init__(self, priority=50):
            super().__init__("cpu_monitor", priority)

        def render(self, width: int) -> str:
            # get cpu usage
            cpu_percent = psutil.cpu_percent(interval=0.1)

            # format status
            return f"cpu: {cpu_percent:5.1f}%"

    # register in plugin initialize()
    from kollabor.io.core_status_views import core_status_views

    class CpuMonitorPlugin(BasePlugin):
        def initialize(self):
            view = CpuMonitorStatusView(priority=50)
            core_status_views.register(view)

example 2: memory monitor with design system

  plugins/memory_monitor/plugin.py:
    from kollabor.io.core_status_views import CoreStatusView
    from kollabor.ui.design_system import T, S
    import psutil

    class MemoryMonitorStatusView(CoreStatusView):
        def render(self, width: int) -> str:
            # get memory usage
            mem = psutil.virtual_memory()
            used_gb = mem.used / (1024**3)
            total_gb = mem.total / (1024**3)
            percent = mem.percent

            # use theme colors
            if percent > 90:
                color = T().error
            elif percent > 70:
                color = T().warning
            else:
                color = T().success

            # format with color
            status = f"mem: {used_gb:.1f}/{total_gb:.1f}gb ({percent:.0f}%)"
            return status

    core_status_views.register(MemoryMonitorStatusView(priority=51))

example 3: session time counter

  plugins/session_timer/plugin.py:
    from kollabor.io.core_status_views import CoreStatusView
    from datetime import datetime, timedelta
    import time

    class SessionTimerStatusView(CoreStatusView):
        def __init__(self, priority=52):
            super().__init__("session_timer", priority)
            self.start_time = datetime.now()

        def render(self, width: int) -> str:
            # calculate elapsed time
            elapsed = datetime.now() - self.start_time
            hours, remainder = divmod(elapsed.seconds, 3600)
            minutes, seconds = divmod(remainder, 60)

            # format time
            if elapsed.days > 0:
                return f"time: {elapsed.days}d {hours:02d}:{minutes:02d}:{seconds:02d}"
            else:
                return f"time: {hours:02d}:{minutes:02d}:{seconds:02d}"

    core_status_views.register(SessionTimerStatusView(priority=52))

example 4: tool execution counter

  plugins/tool_counter/plugin.py:
    from kollabor.io.core_status_views import CoreStatusView
    from kollabor.events.models import EventType, Hook, HookPriority

    class ToolCounterStatusView(CoreStatusView):
        def __init__(self, priority=53):
            super().__init__("tool_counter", priority)
            self.tool_count = 0

        def render(self, width: int) -> str:
            return f"tools: {self.tool_count}"

    class ToolCounterPlugin(BasePlugin):
        def initialize(self):
            # register status view
            self.status_view = ToolCounterStatusView(priority=53)
            core_status_views.register(self.status_view)

            # register hook to count tools
            self.event_bus.register(
                EventType.TOOL_EXECUTION,
                Hook(
                    func=self.count_tool,
                    priority=HookPriority.LOW,
                    plugin_name=self.name
                )
            )

        async def count_tool(self, context):
            """increment tool counter"""
            self.status_view.tool_count += 1
            return context

status widget best practices:

  [1] keep status updates lightweight
      - get_status_line() called every frame
      - avoid expensive operations
      - cache expensive calculations

  [2] use appropriate priority
      - priority controls render order
      - higher priority = leftmost position
      - use 10-100 range

  [3] respect terminal width
      - width parameter passed to render()
      - keep output within width limit
      - truncate long text if needed

  [4] use design system consistently
      - access theme via T()
      - use style constants from S
      - match application aesthetic

  [5] handle errors gracefully
      - wrap render() in try-except
      - return fallback string on error
      - don't crash status line

  [6] provide useful information
      - status should be informative
      - avoid redundant information
      - show actionable data

  [7] consider performance
      - avoid blocking i/o in render()
      - use cached data
      - update asynchronously

status widget testing:

  manual testing:
    [1] start kollabor with your plugin
    [2] observe status line updates
    [3] verify rendering in different terminal widths
    [4] check performance (should not lag)

  automated testing:
    - create test that renders status view
    - verify output format
    - check width handling
    - test error conditions

  example test:
    def test_status_view_render():
        view = MyStatusView(priority=50)
        result = view.render(width=50)

        assert isinstance(result, str)
        assert len(result) <= 50
        assert "expected_text" in result

