on main help sign in
chore: update `AGENTS.md`, mention `x/ansi` package
7a83144Andrey Nering
AGENTS.md+4−3
@@ -7,17 +7,18 @@
7- **Update Golden Files**: `go test ./... -update` (regenerates .golden files when test output changes)
7- **Update Golden Files**: `go test ./... -update` (regenerates .golden files when test output changes)
8 - Update specific package: `go test ./internal/tui/components/core -update` (in this case, we're updating "core")
8 - Update specific package: `go test ./internal/tui/components/core -update` (in this case, we're updating "core")
9- **Lint**: `task lint:fix`
9- **Lint**: `task lint:fix`
10−- **Format**: `task fmt` (gofumpt -w .)
10+- **Format**: `task fmt` (`gofumpt -w .`)
11+- **Modernize**: `task modernize` (runs `modernize` which make code simplifications)
11- **Dev**: `task dev` (runs with profiling enabled)
12- **Dev**: `task dev` (runs with profiling enabled)
12
13
13## Code Style Guidelines
14## Code Style Guidelines
14
15
15−- **Imports**: Use goimports formatting, group stdlib, external, internal packages
16+- **Imports**: Use `goimports` formatting, group stdlib, external, internal packages
16- **Formatting**: Use gofumpt (stricter than gofmt), enabled in golangci-lint
17- **Formatting**: Use gofumpt (stricter than gofmt), enabled in golangci-lint
17- **Naming**: Standard Go conventions - PascalCase for exported, camelCase for unexported
18- **Naming**: Standard Go conventions - PascalCase for exported, camelCase for unexported
18- **Types**: Prefer explicit types, use type aliases for clarity (e.g., `type AgentName string`)
19- **Types**: Prefer explicit types, use type aliases for clarity (e.g., `type AgentName string`)
19- **Error handling**: Return errors explicitly, use `fmt.Errorf` for wrapping
20- **Error handling**: Return errors explicitly, use `fmt.Errorf` for wrapping
20−- **Context**: Always pass context.Context as first parameter for operations
21+- **Context**: Always pass `context.Context` as first parameter for operations
21- **Interfaces**: Define interfaces in consuming packages, keep them small and focused
22- **Interfaces**: Define interfaces in consuming packages, keep them small and focused
22- **Structs**: Use struct embedding for composition, group related fields
23- **Structs**: Use struct embedding for composition, group related fields
23- **Constants**: Use typed constants with iota for enums, group in const blocks
24- **Constants**: Use typed constants with iota for enums, group in const blocks
internal/ui/AGENTS.md+18
@@ -1,15 +1,25 @@
1# UI Development Instructions
1# UI Development Instructions
2
2
3## General Guidelines
3## General Guidelines
4+
4- Never use commands to send messages when you can directly mutate children or state.
5- Never use commands to send messages when you can directly mutate children or state.
5- Keep things simple; do not overcomplicate.
6- Keep things simple; do not overcomplicate.
6- Create files if needed to separate logic; do not nest models.
7- Create files if needed to separate logic; do not nest models.
7- Never do IO or expensive work in `Update`; always use a `tea.Cmd`.
8- Never do IO or expensive work in `Update`; always use a `tea.Cmd`.
8- Never change the model state inside of a command use messages and than update the state in the main loop
9- Never change the model state inside of a command use messages and than update the state in the main loop
10+- Use the `github.com/charmbracelet/x/ansi` package for any string manipulation
11+ that might involves ANSI codes. Do not manipulate ANSI strings at byte level!
12+ Some useful functions:
13+ * `ansi.Cut`
14+ * `ansi.StringWidth`
15+ * `ansi.Strip`
16+ * `ansi.Truncate`
17+
9
18
10## Architecture
19## Architecture
11
20
12### Main Model (`model/ui.go`)
21### Main Model (`model/ui.go`)
22+
13Keep most of the logic and state in the main model. This is where:
23Keep most of the logic and state in the main model. This is where:
14- Message routing happens
24- Message routing happens
15- Focus and UI state is managed
25- Focus and UI state is managed
@@ -17,35 +27,42 @@ Keep most of the logic and state in the main model. This is where:
17- Dialogs are orchestrated
27- Dialogs are orchestrated
18
28
19### Components Should Be Dumb
29### Components Should Be Dumb
30+
20Components should not handle bubbletea messages directly. Instead:
31Components should not handle bubbletea messages directly. Instead:
21- Expose methods for state changes
32- Expose methods for state changes
22- Return `tea.Cmd` from methods when side effects are needed
33- Return `tea.Cmd` from methods when side effects are needed
23- Handle their own rendering via `Render(width int) string`
34- Handle their own rendering via `Render(width int) string`
24
35
25### Chat Logic (`model/chat.go`)
36### Chat Logic (`model/chat.go`)
37+
26Most chat-related logic belongs here. Individual chat items in `chat/` should be simple renderers that cache their output and invalidate when data changes (see `cachedMessageItem` in `chat/messages.go`).
38Most chat-related logic belongs here. Individual chat items in `chat/` should be simple renderers that cache their output and invalidate when data changes (see `cachedMessageItem` in `chat/messages.go`).
27
39
28## Key Patterns
40## Key Patterns
29
41
30### Composition Over Inheritance
42### Composition Over Inheritance
43+
31Use struct embedding for shared behaviors. See `chat/messages.go` for examples of reusable embedded structs for highlighting, caching, and focus.
44Use struct embedding for shared behaviors. See `chat/messages.go` for examples of reusable embedded structs for highlighting, caching, and focus.
32
45
33### Interfaces
46### Interfaces
47+
34- List item interfaces are in `list/item.go`
48- List item interfaces are in `list/item.go`
35- Chat message interfaces are in `chat/messages.go`
49- Chat message interfaces are in `chat/messages.go`
36- Dialog interface is in `dialog/dialog.go`
50- Dialog interface is in `dialog/dialog.go`
37
51
38### Styling
52### Styling
53+
39- All styles are defined in `styles/styles.go`
54- All styles are defined in `styles/styles.go`
40- Access styles via `*common.Common` passed to components
55- Access styles via `*common.Common` passed to components
41- Use semantic color fields rather than hardcoded colors
56- Use semantic color fields rather than hardcoded colors
42
57
43### Dialogs
58### Dialogs
59+
44- Implement the dialog interface in `dialog/dialog.go`
60- Implement the dialog interface in `dialog/dialog.go`
45- Return message types from `Update()` to signal actions to the main model
61- Return message types from `Update()` to signal actions to the main model
46- Use the overlay system for managing dialog lifecycle
62- Use the overlay system for managing dialog lifecycle
47
63
48## File Organization
64## File Organization
65+
49- `model/` - Main UI model and major components (chat, sidebar, etc.)
66- `model/` - Main UI model and major components (chat, sidebar, etc.)
50- `chat/` - Chat message item types and renderers
67- `chat/` - Chat message item types and renderers
51- `dialog/` - Dialog implementations
68- `dialog/` - Dialog implementations
@@ -56,6 +73,7 @@ Use struct embedding for shared behaviors. See `chat/messages.go` for examples o
56- `logo/` - Logo rendering
73- `logo/` - Logo rendering
57
74
58## Common Gotchas
75## Common Gotchas
76+
59- Always account for padding/borders in width calculations
77- Always account for padding/borders in width calculations
60- Use `tea.Batch()` when returning multiple commands
78- Use `tea.Batch()` when returning multiple commands
61- Pass `*common.Common` to components that need styles or app access
79- Pass `*common.Common` to components that need styles or app access