Development
gentleman-bubbletea - Claude MCP Skill
Bubbletea TUI patterns for Gentleman.Dots installer. Trigger: When editing Go files in installer/internal/tui/, working on TUI screens, or adding new UI features.
SEO Guide: Enhance your AI agent with the gentleman-bubbletea tool. This Model Context Protocol (MCP) server allows Claude Desktop and other LLMs to bubbletea tui patterns for gentleman.dots installer. trigger: when editing go files in installer/int... Download and configure this skill to unlock new capabilities for your AI workflow.
š248 stars ⢠219 forks
š„0 downloads
Documentation
SKILL.md## When to Use
Use this skill when:
- Adding new screens to the TUI installer
- Handling keyboard input or navigation
- Creating new UI components with Lipgloss
- Working on screen transitions or state management
---
## Critical Patterns
### Pattern 1: Screen Constants in model.go
All screens MUST be defined as `Screen` constants in `model.go`:
```go
type Screen int
const (
ScreenWelcome Screen = iota
ScreenMainMenu
ScreenOSSelect
// ... new screens go here
ScreenNewFeature // Add new screen
ScreenNewFeatureCat // Add category screen if needed
)
```
### Pattern 2: Model Struct Holds All State
The `Model` struct in `model.go` holds ALL application state:
```go
type Model struct {
Screen Screen
PrevScreen Screen // For back navigation
Width int
Height int
Cursor int
// Add new state here
NewFeatureData []SomeType
NewFeatureScroll int
}
```
### Pattern 3: Update Pattern with Type Switch
All input handling goes through `Update()` with a type switch:
```go
func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
switch msg := msg.(type) {
case tea.KeyMsg:
return m.handleKeyPress(msg)
case tea.WindowSizeMsg:
m.Width = msg.Width
m.Height = msg.Height
return m, nil
case customMsg:
// Handle custom messages
return m, nil
}
return m, nil
}
```
### Pattern 4: Key Handlers Return (Model, Cmd)
Separate handler per screen, always return `(tea.Model, tea.Cmd)`:
```go
func (m Model) handleNewFeatureKeys(key string) (tea.Model, tea.Cmd) {
options := m.GetCurrentOptions()
switch key {
case "up", "k":
if m.Cursor > 0 {
m.Cursor--
// Skip separator
if strings.HasPrefix(options[m.Cursor], "āāā") && m.Cursor > 0 {
m.Cursor--
}
}
case "down", "j":
if m.Cursor < len(options)-1 {
m.Cursor++
if strings.HasPrefix(options[m.Cursor], "āāā") && m.Cursor < len(options)-1 {
m.Cursor++
}
}
case "enter", " ":
// Handle selection
return m.handleNewFeatureSelection()
case "esc":
m.Screen = m.PrevScreen
m.Cursor = 0
}
return m, nil
}
```
---
## Decision Tree
```
Adding a new screen?
āāā Define Screen constant in model.go
āāā Add state fields to Model struct
āāā Add handler in handleKeyPress switch
āāā Create handle{Screen}Keys function in update.go
āāā Add view case in view.go
āāā Add title in GetScreenTitle()
Adding navigation to existing screen?
āāā Use m.PrevScreen for back navigation
āāā Reset m.Cursor = 0 on screen change
āāā Save scroll position if scrollable
Adding scrollable content?
āāā Add {Screen}Scroll int to Model
āāā Calculate visibleItems from m.Height
āāā Handle up/down for scroll position
āāā Reset scroll on screen exit
```
---
## Code Examples
### Example 1: Adding Screen to handleKeyPress
```go
// In handleKeyPress switch statement:
case ScreenNewFeature:
return m.handleNewFeatureKeys(key)
case ScreenNewFeatureCat:
return m.handleNewFeatureCatKeys(key)
```
### Example 2: Screen Options Pattern
```go
func (m Model) GetCurrentOptions() []string {
switch m.Screen {
case ScreenNewFeature:
categories := make([]string, len(m.NewFeatureData)+2)
for i, item := range m.NewFeatureData {
categories[i] = item.Name
}
categories[len(m.NewFeatureData)] = "āāāāāāāāāāāāā"
categories[len(m.NewFeatureData)+1] = "ā Back"
return categories
// ...
}
}
```
### Example 3: Scrollable View Pattern
```go
func (m Model) handleNewFeatureCatKeys(key string) (tea.Model, tea.Cmd) {
data := m.NewFeatureData[m.SelectedNewFeature]
visibleItems := m.Height - 9
if visibleItems < 5 {
visibleItems = 5
}
maxScroll := len(data.Items) - visibleItems
if maxScroll < 0 {
maxScroll = 0
}
switch key {
case "up", "k":
if m.NewFeatureScroll > 0 {
m.NewFeatureScroll--
}
case "down", "j":
if m.NewFeatureScroll < maxScroll {
m.NewFeatureScroll++
}
case "esc", "q", "enter", " ":
m.Screen = ScreenNewFeature
m.NewFeatureScroll = 0
}
return m, nil
}
```
### Example 4: Custom Message Pattern
```go
// Define message type
type newFeatureLoadedMsg struct {
data []SomeType
err error
}
// Send message from command
func loadNewFeatureCmd() tea.Cmd {
return func() tea.Msg {
data, err := loadData()
return newFeatureLoadedMsg{data: data, err: err}
}
}
// Handle in Update
case newFeatureLoadedMsg:
if msg.err != nil {
m.ErrorMsg = msg.err.Error()
return m, nil
}
m.NewFeatureData = msg.data
return m, nil
```
---
## Commands
```bash
cd installer && go build ./cmd/gentleman-installer # Build installer
cd installer && go test ./internal/tui/... # Run TUI tests
cd installer && go test -run TestNewFeature # Run specific test
```
---
## Resources
- **Model**: See `installer/internal/tui/model.go` for state management
- **Update**: See `installer/internal/tui/update.go` for input handling
- **View**: See `installer/internal/tui/view.go` for rendering
- **Styles**: See `installer/internal/tui/styles.go` for Lipgloss stylesSignals
Avg ratingā 0.0
Reviews0
Favorites0
Information
- Repository
- Gentleman-Programming/Gentleman.Dots
- Author
- Gentleman-Programming
- Last Sync
- 3/12/2026
- Repo Updated
- 3/12/2026
- Created
- 1/13/2026
Reviews (0)
No reviews yet. Be the first to review this skill!