Smithery Logo
MCPsSkillsDocsPricing
Login
Smithery Logo

Accelerating the Agent Economy

Resources

DocumentationPrivacy PolicySystem Status

Company

PricingAboutBlog

Connect

© 2026 Smithery. All rights reserved.

    cadamsdev

    opentui-dev

    cadamsdev/opentui-dev
    Design
    13
    3 installs

    About

    SKILL.md

    Install

    Install via Skills CLI

    or add to your agent
    • Claude Code
      Claude Code
    • Codex
      Codex
    • OpenClaw
      OpenClaw
    • Cursor
      Cursor
    • Amp
      Amp
    • GitHub Copilot
      GitHub Copilot
    • Gemini CLI
      Gemini CLI
    • Kilo Code
      Kilo Code
    • Junie
      Junie
    • Replit
      Replit
    • Windsurf
      Windsurf
    • Cline
      Cline
    • Continue
      Continue
    • OpenCode
      OpenCode
    • OpenHands
      OpenHands
    • Roo Code
      Roo Code
    • Augment
      Augment
    • Goose
      Goose
    • Trae
      Trae
    • Zencoder
      Zencoder
    • Antigravity
      Antigravity
    ├─
    ├─
    └─

    About

    Build and modify terminal user interfaces using OpenTUI with React or Core API.

    SKILL.md

    OpenTUI Development Skill

    This skill provides comprehensive guidance for building terminal user interfaces (TUIs) using OpenTUI, a TypeScript library for creating component-based terminal applications with React or Core API.

    When to use this skill

    Use this skill when:

    • Building a new terminal user interface (TUI) or CLI application
    • Working with OpenTUI-based projects
    • Creating interactive terminal components (inputs, selects, lists, etc.)
    • Implementing keyboard navigation and event handling in terminals
    • Adding syntax highlighting or code display in terminal UIs
    • Creating diff viewers, text editors, or terminal-based forms
    • Styling terminal applications with borders, colors, and flexbox layouts
    • Debugging or enhancing OpenTUI applications
    • User mentions: TUI, terminal UI, CLI app, OpenTUI, terminal components

    What is OpenTUI

    OpenTUI is a TypeScript framework for building terminal user interfaces with:

    • Component-based architecture: Similar to web frameworks, compose UIs from reusable components
    • React integration: Use familiar React patterns with JSX for declarative terminal UIs
    • Flexbox layouts: CSS Flexbox-like layout system powered by Yoga layout engine
    • Rich components: Built-in inputs, selects, code viewers, diff viewers, and more
    • Type-safe: Full TypeScript support with strict mode
    • High performance: Native Zig rendering layer for optimal performance

    Core Packages

    • @opentui/core - Core library with imperative API and primitives (standalone)
    • @opentui/react - React reconciler for declarative UI development
    • @opentui/solid - SolidJS reconciler (alternative framework)

    Quick Start

    Creating a new OpenTUI React project

    bun create tui --template react
    cd my-tui-app
    bun install
    bun run index.tsx
    

    Manual installation

    bun install @opentui/core @opentui/react react
    

    Basic "Hello World" example

    import { createCliRenderer } from "@opentui/core"
    import { createRoot } from "@opentui/react"
    
    function App() {
      return (
        <box style={{ padding: 2 }}>
          <text fg="#00FF00">Hello, OpenTUI!</text>
        </box>
      )
    }
    
    const renderer = await createCliRenderer({ useAlternateScreen: true })
    createRoot(renderer).render(<App />)
    renderer.start()
    

    TypeScript Configuration

    OpenTUI requires specific TypeScript settings:

    {
      "compilerOptions": {
        "lib": ["ESNext", "DOM"],
        "target": "ESNext",
        "module": "ESNext",
        "moduleResolution": "bundler",
        "jsx": "react-jsx",
        "jsxImportSource": "@opentui/react",
        "strict": true,
        "skipLibCheck": true
      }
    }
    

    Key settings:

    • jsxImportSource: "@opentui/react" - Use OpenTUI's JSX factory
    • moduleResolution: "bundler" - Required for Bun
    • strict: true - Enable strict type checking

    Core Concepts

    1. Renderer

    The renderer manages terminal output, input events, and the rendering loop.

    import { createCliRenderer } from "@opentui/core"
    
    const renderer = await createCliRenderer({
      exitOnCtrlC: true,           // Exit on Ctrl+C (default: true)
      targetFps: 30,               // Target frame rate
      maxFps: 60,                  // Maximum frame rate
      useAlternateScreen: true,    // Use alternate screen (full-screen)
      useMouse: true,              // Enable mouse support
      backgroundColor: "#000000",   // Background color
      useConsole: true,            // Enable console overlay
    })
    
    // Start the render loop
    renderer.start()
    

    Rendering Modes:

    • Live Mode: Call renderer.start() for continuous rendering at target FPS
    • On-Demand: Without start(), renders only when changes occur

    2. Layout System (Flexbox)

    OpenTUI uses Yoga for CSS Flexbox-like layouts:

    <box
      flexDirection="row"          // row | column | row-reverse | column-reverse
      justifyContent="center"      // flex-start | flex-end | center | space-between | space-around
      alignItems="center"          // flex-start | flex-end | center | stretch | baseline
      gap={2}                      // Gap between children
      flexGrow={1}                 // Grow factor
      flexShrink={1}               // Shrink factor
      flexBasis="auto"             // Base size
      flexWrap="wrap"              // no-wrap | wrap | wrap-reverse
    >
      {/* Children */}
    </box>
    

    Size Properties:

    width={40}           // Fixed width in characters
    height={10}          // Fixed height in lines
    width="50%"          // Percentage of parent
    width="auto"         // Auto-size based on content
    minWidth={20}        // Minimum width
    maxWidth={80}        // Maximum width
    

    Spacing:

    padding={2}          // All sides
    paddingLeft={1}      // Individual sides
    margin={1}           // Margin (all sides)
    marginTop={2}        // Individual margins
    

    Position:

    position="relative"  // relative | absolute
    top={5}             // Position from top
    left={10}           // Position from left
    zIndex={999}        // Stack order
    

    3. Colors

    Colors in OpenTUI use RGBA format or hex strings:

    import { RGBA } from "@opentui/core"
    
    // Hex strings (most common)
    <text fg="#FFFFFF" bg="#000000">Text</text>
    
    // RGBA objects
    const red = RGBA.fromHex("#FF0000")
    const blue = RGBA.fromInts(0, 0, 255, 255)  // RGB 0-255
    const transparent = RGBA.fromValues(1.0, 1.0, 1.0, 0.5)  // RGBA 0.0-1.0
    

    4. Text Attributes

    Style text with bold, italic, underline, etc.:

    import { TextAttributes } from "@opentui/core"
    
    <text attributes={TextAttributes.BOLD}>Bold text</text>
    <text attributes={TextAttributes.BOLD | TextAttributes.ITALIC}>Bold italic</text>
    
    // Available attributes:
    // BOLD, DIM, ITALIC, UNDERLINE, BLINK, INVERSE, HIDDEN, STRIKETHROUGH
    

    React Components

    Box Component

    Container with borders, backgrounds, and layout:

    <box
      title="Panel Title"
      border                       // Show border
      borderStyle="single"         // single | double | rounded | bold | classic
      borderColor="#FFFFFF"
      backgroundColor="#1a1a1a"
      focused={true}               // Highlight when focused
      padding={2}
      flexDirection="column"
      width={40}
      height={10}
    >
      <text>Content</text>
    </box>
    

    Border Styles:

    • single - Single line (─│┌┐└┘)
    • double - Double line (═║╔╗╚╝)
    • rounded - Rounded corners (─│╭╮╰╯)
    • bold - Bold/thick line
    • classic - ASCII style (+-|)

    Text Component

    Display text with styling:

    // Simple text
    <text fg="#FFFFFF" bg="#000000">Simple text</text>
    
    // Rich text with children
    <text>
      <span fg="#FF0000">Red text</span>
      {" "}
      <strong>Bold</strong>
      {" "}
      <em>Italic</em>
      {" "}
      <u>Underlined</u>
      <br />
      <a href="https://example.com">Link</a>
    </text>
    
    // Formatted content
    <text content="Preformatted content" fg="#00FF00" />
    

    Input Component

    Single-line text input:

    const [value, setValue] = useState("")
    
    <input
      placeholder="Type here..."
      value={value}
      focused={true}               // Must be focused to receive input
      onInput={setValue}           // Called on every keystroke
      onSubmit={(val) => {         // Called on Enter key
        console.log("Submitted:", val)
      }}
      style={{
        backgroundColor: "#1a1a1a",
        focusedBackgroundColor: "#2a2a2a",
      }}
    />
    

    Textarea Component

    Multi-line text editor:

    import { useRef } from "react"
    import type { TextareaRenderable } from "@opentui/core"
    
    const textareaRef = useRef<TextareaRenderable>(null)
    
    <textarea
      ref={textareaRef}
      placeholder="Type here..."
      focused={true}
      initialValue="Initial text"
      style={{ width: 60, height: 10 }}
    />
    
    // Access value: textareaRef.current?.getText()
    

    Select Component

    List selection with scrolling:

    import type { SelectOption } from "@opentui/core"
    
    const options: SelectOption[] = [
      { name: "Option 1", description: "First option", value: "opt1" },
      { name: "Option 2", description: "Second option", value: "opt2" },
      { name: "Option 3", description: "Third option", value: "opt3" },
    ]
    
    <select
      options={options}
      focused={true}
      onChange={(index, option) => {
        console.log(`Selected ${index}:`, option)
      }}
      showScrollIndicator
      style={{ height: 10 }}
    />
    

    Navigation:

    • Up/Down arrows - Move selection
    • Enter - Confirm selection
    • Auto-scrolls to keep selection visible

    Tab Select Component

    Horizontal tab selection:

    <tab-select
      options={[
        { name: "Home", description: "Dashboard view" },
        { name: "Settings", description: "Configuration" },
        { name: "Help", description: "Documentation" },
      ]}
      focused={true}
      onChange={(index, option) => {
        console.log("Tab changed:", option.name)
      }}
      tabWidth={20}
    />
    

    Scrollbox Component

    Scrollable container for long content:

    <scrollbox
      focused={true}
      style={{
        height: 20,
        rootOptions: { backgroundColor: "#24283b" },
        wrapperOptions: { backgroundColor: "#1f2335" },
        viewportOptions: { backgroundColor: "#1a1b26" },
        contentOptions: { backgroundColor: "#16161e" },
        scrollbarOptions: {
          showArrows: true,
          trackOptions: {
            foregroundColor: "#7aa2f7",
            backgroundColor: "#414868",
          },
        },
      }}
    >
      {/* Long scrollable content */}
      <text>Line 1</text>
      <text>Line 2</text>
      {/* ... many more lines */}
    </scrollbox>
    

    Code Component

    Display code with syntax highlighting:

    import { SyntaxStyle, RGBA } from "@opentui/core"
    
    const syntaxStyle = SyntaxStyle.fromStyles({
      keyword: { fg: RGBA.fromHex("#ff6b6b"), bold: true },
      string: { fg: RGBA.fromHex("#51cf66") },
      comment: { fg: RGBA.fromHex("#868e96"), italic: true },
      function: { fg: RGBA.fromHex("#4dabf7") },
      number: { fg: RGBA.fromHex("#ffd43b") },
    })
    
    <code
      content={codeString}
      filetype="typescript"        // javascript, python, rust, go, etc.
      syntaxStyle={syntaxStyle}
    />
    

    Line Number Component

    Code with line numbers and diff highlights:

    import { useRef, useEffect } from "react"
    import type { LineNumberRenderable } from "@opentui/core"
    
    const lineNumberRef = useRef<LineNumberRenderable>(null)
    
    useEffect(() => {
      // Highlight added line
      lineNumberRef.current?.setLineColor(1, "#1a4d1a")
      lineNumberRef.current?.setLineSign(1, { after: " +", afterColor: "#22c55e" })
      
      // Highlight deleted line
      lineNumberRef.current?.setLineColor(5, "#4d1a1a")
      lineNumberRef.current?.setLineSign(5, { after: " -", afterColor: "#ef4444" })
      
      // Add diagnostic warning
      lineNumberRef.current?.setLineSign(10, { before: "⚠️", beforeColor: "#f59e0b" })
    }, [])
    
    <line-number
      ref={lineNumberRef}
      fg="#6b7280"
      bg="#161b22"
      minWidth={3}
      showLineNumbers={true}
    >
      <code content={codeContent} filetype="typescript" />
    </line-number>
    

    Diff Component

    Unified or split diff viewer:

    <diff
      oldContent={oldCode}
      newContent={newCode}
      filetype="typescript"
      syntaxStyle={syntaxStyle}
      viewMode="unified"           // unified | split
    />
    

    ASCII Font Component

    Display ASCII art text:

    <ascii-font
      text="OPENTUI"
      font="block"                 // tiny | block | slick | shade
      color={RGBA.fromHex("#00FF00")}
    />
    

    React Hooks

    useRenderer()

    Access the renderer instance:

    import { useRenderer } from "@opentui/react"
    
    const renderer = useRenderer()
    
    // Show/hide console overlay
    renderer.console.toggle()
    renderer.console.show()
    renderer.console.hide()
    

    useKeyboard(handler, options?)

    Handle keyboard events:

    import { useKeyboard } from "@opentui/react"
    import type { KeyEvent } from "@opentui/core"
    
    useKeyboard((key: KeyEvent) => {
      console.log("Key:", key.name)
      console.log("Modifiers:", { ctrl: key.ctrl, shift: key.shift, alt: key.meta })
      
      if (key.name === "escape") {
        process.exit(0)
      }
      
      if (key.ctrl && key.name === "s") {
        // Save action
      }
    }, { release: false })  // Set release: true for key release events
    

    Key Event Properties:

    • name - Key name (e.g., "a", "enter", "escape", "up", "down")
    • ctrl - Ctrl key pressed
    • shift - Shift key pressed
    • meta - Alt/Meta key pressed (Linux/Windows)
    • option - Option key pressed (macOS)
    • sequence - Raw key sequence

    useTerminalDimensions()

    Get current terminal size (auto-updates on resize):

    import { useTerminalDimensions } from "@opentui/react"
    
    const { width, height } = useTerminalDimensions()
    
    return (
      <box style={{ width, height }}>
        <text>{`Terminal: ${width}x${height}`}</text>
      </box>
    )
    

    useOnResize(callback)

    Handle terminal resize events:

    import { useOnResize } from "@opentui/react"
    
    useOnResize((width, height) => {
      console.log(`Resized to ${width}x${height}`)
    })
    

    useTimeline(options?)

    Create animations:

    import { useTimeline } from "@opentui/react"
    import { useEffect, useState } from "react"
    
    const [width, setWidth] = useState(0)
    
    const timeline = useTimeline({
      duration: 2000,
      loop: false,
      autoplay: true,
    })
    
    useEffect(() => {
      timeline.add(
        { width },
        {
          width: 50,
          duration: 2000,
          ease: "linear",
          onUpdate: (animation) => {
            setWidth(animation.targets[0].width)
          },
        }
      )
    }, [])
    
    return <box style={{ width }}><text>Animating...</text></box>
    

    Common Patterns

    Multi-view Application

    import { useState } from "react"
    import { useKeyboard } from "@opentui/react"
    
    type View = "home" | "settings" | "help"
    
    function App() {
      const [view, setView] = useState<View>("home")
    
      useKeyboard((key) => {
        if (key.name === "1") setView("home")
        if (key.name === "2") setView("settings")
        if (key.name === "3") setView("help")
        if (key.name === "escape") process.exit(0)
      })
    
      return (
        <box style={{ flexDirection: "column", width: "100%", height: "100%" }}>
          <Header view={view} />
          {view === "home" && <HomeView />}
          {view === "settings" && <SettingsView />}
          {view === "help" && <HelpView />}
          <Footer />
        </box>
      )
    }
    

    Modal Pattern

    import { useState } from "react"
    import { useKeyboard } from "@opentui/react"
    
    function App() {
      const [showModal, setShowModal] = useState(false)
    
      useKeyboard((key) => {
        if (showModal) return  // Modal handles its own keys
        
        if (key.name === "m") {
          setShowModal(true)
        }
      })
    
      return (
        <>
          <MainContent />
          {showModal && (
            <Modal onClose={() => setShowModal(false)} />
          )}
        </>
      )
    }
    
    function Modal({ onClose }: { onClose: () => void }) {
      const [input, setInput] = useState("")
      
      useKeyboard((key) => {
        if (key.name === "escape") onClose()
      })
    
      return (
        <box
          style={{
            position: "absolute",
            top: "50%",
            left: "50%",
            width: 60,
            height: 10,
            backgroundColor: "#1a1a1a",
            border: true,
            borderColor: "#FFFFFF",
          }}
        >
          <input
            placeholder="Enter value..."
            value={input}
            focused={true}
            onInput={setInput}
            onSubmit={(val) => {
              console.log("Submitted:", val)
              onClose()
            }}
          />
        </box>
      )
    }
    

    Focus Management

    import { useState } from "react"
    import { useKeyboard } from "@opentui/react"
    
    type FocusPanel = "left" | "right"
    
    function App() {
      const [focused, setFocused] = useState<FocusPanel>("left")
    
      useKeyboard((key) => {
        if (key.name === "tab") {
          setFocused(focused === "left" ? "right" : "left")
        }
      })
    
      return (
        <box style={{ flexDirection: "row", width: "100%", height: "100%" }}>
          <box
            title="Left Panel"
            style={{ flexGrow: 1, border: true }}
            focused={focused === "left"}
          >
            <text>Content</text>
          </box>
          <box
            title="Right Panel"
            style={{ flexGrow: 1, border: true }}
            focused={focused === "right"}
          >
            <text>Content</text>
          </box>
        </box>
      )
    }
    

    List with Selection

    import { useState } from "react"
    import { useKeyboard } from "@opentui/react"
    
    function FileList({ files }: { files: string[] }) {
      const [selected, setSelected] = useState(0)
    
      useKeyboard((key) => {
        if (key.name === "up") {
          setSelected(Math.max(0, selected - 1))
        }
        if (key.name === "down") {
          setSelected(Math.min(files.length - 1, selected + 1))
        }
        if (key.name === "enter") {
          console.log("Selected:", files[selected])
        }
      })
    
      return (
        <box style={{ flexDirection: "column" }}>
          {files.map((file, idx) => (
            <text
              key={file}
              fg={idx === selected ? "#00FF00" : "#FFFFFF"}
              bg={idx === selected ? "#333333" : undefined}
            >
              {idx === selected ? "> " : "  "}
              {file}
            </text>
          ))}
        </box>
      )
    }
    

    Responsive Layout

    import { useTerminalDimensions } from "@opentui/react"
    
    function App() {
      const { width, height } = useTerminalDimensions()
      
      // Show simplified layout on small terminals
      const isSmall = width < 80
    
      return (
        <box style={{ flexDirection: isSmall ? "column" : "row", width, height }}>
          <Sidebar width={isSmall ? width : 30} />
          <MainContent width={isSmall ? width : width - 30} />
        </box>
      )
    }
    

    Loading Spinner

    import { useState, useEffect } from "react"
    
    function Spinner() {
      const [frame, setFrame] = useState(0)
      const frames = ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"]
    
      useEffect(() => {
        const interval = setInterval(() => {
          setFrame((f) => (f + 1) % frames.length)
        }, 80)
        return () => clearInterval(interval)
      }, [])
    
      return <text fg="#00FFFF">{frames[frame]} Loading...</text>
    }
    

    Code Style Guidelines

    Import Order

    1. External dependencies (React, etc.)
    2. OpenTUI packages
    3. Internal utilities
    4. Components
    5. Type imports (with type keyword)
    import { useState, useEffect } from "react"
    import { useKeyboard, useRenderer } from "@opentui/react"
    import { RGBA, TextAttributes } from "@opentui/core"
    import { formatTime } from "./utils"
    import { Header } from "./components/Header"
    import type { AppState, View } from "./types"
    

    Naming Conventions

    • camelCase: variables, functions, parameters
    • PascalCase: components, classes, types/interfaces
    • UPPER_CASE: constants
    // Good
    const userInput = "text"
    function handleSubmit() {}
    interface UserData {}
    const MAX_RETRIES = 3
    
    // Bad
    const UserInput = "text"
    function HandleSubmit() {}
    interface userData {}
    

    Component Structure

    interface ComponentProps {
      title: string
      items: string[]
    }
    
    export function Component({ title, items }: ComponentProps) {
      // 1. Hooks
      const [selected, setSelected] = useState(0)
      const renderer = useRenderer()
      
      // 2. Event handlers
      useKeyboard((key) => {
        if (key.name === "escape") process.exit(0)
      })
      
      // 3. Effects
      useEffect(() => {
        // Side effects
      }, [])
      
      // 4. Helper functions
      const handleSelect = (index: number) => {
        setSelected(index)
      }
      
      // 5. JSX return
      return (
        <box>
          <text>{title}</text>
          {/* Content */}
        </box>
      )
    }
    

    Best Practices

    Performance

    1. Minimize re-renders: Use useMemo and useCallback for expensive computations
    2. Avoid frequent updates: Throttle or debounce rapid state changes
    3. Use keys properly: Provide stable keys for lists to optimize reconciliation
    4. Optimize large lists: Use virtualization or pagination for long lists

    Focus Management

    1. Only one focused component: Ensure only one input/select has focused={true} at a time
    2. Keyboard routing: Check focus state before handling keyboard events
    3. Visual feedback: Use focused prop on boxes to show focus state with borders

    Layout Tips

    1. Use flexbox: Leverage flexDirection, justifyContent, alignItems for layouts
    2. Percentage widths: Use "50%" for responsive layouts
    3. flexGrow/flexShrink: Use for responsive sizing
    4. Absolute positioning: Use sparingly for modals/overlays

    Debugging

    1. Console overlay: Use renderer.console.show() instead of console.log
    2. Toggle console: Press backtick (`) to toggle console visibility
    3. Environment variables: Set OTUI_DEBUG=true for debug mode
    4. Stats overlay: Set OTUI_SHOW_STATS=true to see performance stats

    Error Handling

    1. Graceful degradation: Handle terminal resize and small screens
    2. Input validation: Validate user input before processing
    3. Error boundaries: Wrap components in error boundaries for production

    Common Gotchas

    1. Console captured: console.log goes to overlay, use renderer.console.show() to view
    2. Focus required: Inputs/selects need focused={true} to receive events
    3. Bun only: OpenTUI is designed for Bun runtime, not Node.js
    4. Zig for builds: Only needed when modifying native code, not for TypeScript changes
    5. Alternate screen: Default is full-screen mode, use useAlternateScreen: false to disable
    6. Key names: Use lowercase names ("a", "enter", "escape"), not "A", "Enter", "Escape"

    Troubleshooting

    Application not rendering

    • Ensure you called renderer.start() after createRoot().render()
    • Check terminal supports ANSI escape codes
    • Try disabling alternate screen: useAlternateScreen: false

    Keyboard input not working

    • Ensure component has focused={true}
    • Check if modal or overlay is capturing input
    • Verify useKeyboard hook is registered

    Layout issues

    • Check parent has explicit dimensions (width, height)
    • Use flexGrow for flexible sizing
    • Ensure flexDirection is set correctly
    • Use browser DevTools-like thinking (Yoga = Flexbox)

    Colors not showing

    • Verify terminal supports 24-bit color
    • Use hex format: "#RRGGBB"
    • Check color values are valid (0-255 for RGB)

    Reference Documentation

    For detailed API references and advanced topics, see:

    • Component API Reference - Complete component props and options
    • Core API Reference - Low-level Core package API
    • Layout Guide - In-depth Yoga/Flexbox layout guide
    • Styling Guide - Colors, text attributes, and styling patterns

    Examples

    The OpenTUI repository contains many examples:

    • Basic counter app
    • Login form with validation
    • File explorer with keyboard navigation
    • Code viewer with syntax highlighting
    • Git diff viewer
    • Multi-view dashboard
    • Modal dialogs
    • Tab navigation

    Resources

    • GitHub: https://github.com/anomalyco/opentui
    • NPM Core: https://www.npmjs.com/package/@opentui/core
    • NPM React: https://www.npmjs.com/package/@opentui/react
    • Awesome OpenTUI: https://github.com/msmps/awesome-opentui
    • Create TUI: https://github.com/msmps/create-tui

    Development Commands

    # Install dependencies
    bun install
    
    # Run application
    bun run index.tsx
    
    # Type check
    bun --bun tsc --noEmit
    
    # Build project (if applicable)
    bun run build
    

    Next Steps

    After implementing a basic OpenTUI application:

    1. Add keyboard shortcuts: Implement common shortcuts (Ctrl+Q, etc.)
    2. Create themes: Extract colors to theme objects for consistency
    3. Add help screen: Show keyboard shortcuts and commands
    4. Implement error handling: Gracefully handle edge cases
    5. Optimize performance: Profile and optimize render performance
    6. Add tests: Write unit tests for components and logic
    7. Document usage: Add README with screenshots and usage guide
    Recommended Servers
    Desktop Commander
    Desktop Commander
    Databutton
    Databutton
    Repository
    cadamsdev/gitarbor-tui
    Files