11 KiB
11 KiB
Goaichat Development Plan
Overview
- Goal Build a terminal-based AI chat client in Go that interacts with an OpenAI-compatible API using settings provided via
config.yaml
. - Primary outcomes Provide an interactive chat session with conversational history, robust config handling, and a clean developer experience.
- Assumptions Users run the app locally inside a terminal emulator with network access to the configured API endpoint.
Functional Requirements
- Interactive chat loop Allow continuous message exchange with the AI until the user exits.
- Config-driven startup Parse
config.yaml
forapi.url
,api.key
, model defaults, and future options (e.g., system prompts, temperature, streaming flag). - Persistent history Store chats in a SQLite database located at
$HOME/.local/share/goaichat/goaichat.db
(configurable), capturing session metadata and full message transcripts. - History commands Provide
/list
to enumerate saved chats and allow selecting or reopening them within the session. - Model management Support
/models
command to display configured/available models, persist the user’s choice, and use it for subsequent requests. - Graceful exit controls Support commands like
/exit
,/reset
,/help
. - Error feedback Surface authentication and network issues with actionable terminal messages.
Non-Functional Requirements
- Portability Pure Go solution compatible with Linux/macOS/Windows terminals.
- Security Keep API key out of logs; support environment variable overrides for secrets; ensure persisted data has restrictive filesystem permissions.
- Resilience Retry transient HTTP failures, validate config on load, handle streaming interruptions.
- Observability Include structured logging with verbosity toggle.
Architecture
High-Level Components
- CLI entrypoint
cmd/goaichat/main.go
handles argument parsing and bootstraps the app. - Configuration layer
internal/config
loads, validates, mergesconfig.yaml
with environment overrides. - Application core
internal/app
wires config, client, history, and UI controller. - Chat service
internal/chat
manages conversation state, prompt assembly, tool commands, and transcripts. - Storage layer
internal/storage
handles SQLite connections, schema migrations, and CRUD helpers for sessions, messages, and model preferences. - OpenAI client
internal/openai
wraps REST calls (Chat Completions or Responses API) with streaming support. - Terminal UI
internal/ui
renders chat in the terminal; leveragesgithub.com/charmbracelet/bubbletea
+lipgloss
for layout. - Logging/metrics
internal/telemetry
centralizes loggers and future metrics hooks.
Data Flow
dflow LR
UserInput[(User input)] --> UI[Terminal UI]
UI -->|Submit| ChatCore[Chat service]
ChatCore -->|Build request| OpenAIClient[OpenAI client]
OpenAIClient -->|HTTP call| API[(OpenAI-compatible API)]
API -->|Response/stream| OpenAIClient
OpenAIClient --> ChatCore
ChatCore -->|Update state| Storage[(SQLite history store)]
Storage --> ChatCore
ChatCore --> UI
Config[(config.yaml + env)] --> ConfigPkg[Configuration]
ConfigPkg --> AppCore[Application core]
AppCore --> ChatCore
AppCore --> OpenAIClient
AppCore --> Storage
##- **Persistence & Data Storage (`internal/storage`)
- **Data directory** Resolve user-specific path `$HOME/.local/share/goaichat/` (configurable override) and ensure directories exist with secure permissions.
- **Database** SQLite file `goaichat.db` managed via `modernc.org/sqlite` (pure Go) for portability; allow build tag to switch to `mattn/go-sqlite3` if desired.
- **Schema**
- **`sessions`** (`id`, `name`, `created_at`, `updated_at`, `model_name`, `summary`).
- **`messages`** (`id`, `session_id`, `role`, `content`, `token_count`, `created_at`).
- **`models`** (`id`, `name`, `display_name`, `provider`, `is_default`, `last_used_at`).
{{ ... }}
- **Data access** Provide repository interfaces for chat service to create sessions, append messages, list chats, update selected model, and fetch transcripts.
- **Performance** Enable write-ahead logging, tune connection settings, and guard concurrent access with a request queue or mutex.
## Configuration Handling (`internal/config`)
- **Load order** Default values → `config.yaml` → environment overrides (`GOAICHAT_API_KEY`, etc.) → CLI flags.
- **Parsing** Use `gopkg.in/yaml.v3` with a typed struct, e.g., `Config{ API struct{ URL string; Key string }; Model struct{ Name string; Temperature float64; Stream bool }; Logging struct{ Level string } }`.
- **Validation** Ensure non-empty `API.URL`, `API.Key`; validate URL format and ranges (temperature 0-2); provide default fallbacks.
- **Hot reload (future)** Structure API to support reloading without restart.
- **Sample `config.yaml`**
```yaml
api:
url: "https://api.openai.com/v1"
key: "${OPENAI_API_KEY}"
model:
name: "gpt-4o-mini"
temperature: 0.7
stream: true
ui:
show_timestamps: true
logging:
level: "info"
Terminal UI (internal/ui
)
- Framework Adopt Bubble Tea for TUI state management; use
textinput
component for prompt entry and a scrolling viewport for conversation. - Features
- Message formatting Differentiate user/assistant/system with colors via
lipgloss
. - Streaming display Render tokens incrementally if streaming enabled.
- Shortcut commands
/reset
,/config
,/copy-last
,/save
,/list
,/models
. - Status bar Show model name, latency, active session, and config hints.
- Message formatting Differentiate user/assistant/system with colors via
- Accessibility Support basic ANSI-only fallback.
Chat Service (internal/chat
)
- State Maintain slice of
Message{Role, Content, Timestamp}
plus metadata (tokens, response duration). - Prompt assembly Prepend system prompt from config; limit history by token budget using approximate counts and hydrate from stored transcripts when reopening a session.
- Commands Parse
/
prefixed input before sending to API, including/reset
,/help
,/exit
,/list
,/models
,/config
,/copy-last
,/save
. - Persistence integration Manage session lifecycle, store messages, list sessions, and update preferred model through
internal/storage
.
OpenAI Client (internal/openai
)
- HTTP layer Use net/http with context cancellation, timeout, retry (exponential backoff) on 5xx.
- Endpoints Start with Chat Completions
POST /chat/completions
; optionally add Responses API abstraction. - Streaming Handle Server-Sent Events (SSE) or chunked responses; emit channel of tokens consumed by UI.
- Auth Inject
Authorization: Bearer
header from config/environment. - Telemetry hooks Log request duration; hide sensitive payloads in debug output.
- Testing Mock transport implementation for deterministic tests.
Application Core (internal/app
)
- Lifecycle Initialize logger → load config → instantiate client and chat service → start UI program.
- Dependency injection Pass config structs or interfaces to decouple packages for testing.
- Shutdown Capture signals (Ctrl+C) to flush logs, close session transcripts.
Implementation Roadmap
-
Milestone 1: Project bootstrap
- Create module
go mod init github.com/<user>/goaichat
. - Set up CI (GitHub Actions) running
go test
and lint. - Add basic logging using
log/slog
orzerolog
.
- Create module
-
Milestone 2: Config foundation
- Implement
internal/config
loader with validation and tests. - Support environment overrides and
--config
CLI flag.
- Implement
-
Milestone 3: API integration
- Build
internal/openai
client with non-streaming support first. - Add response parsing, error handling, retries.
- Write integration tests against mock server.
- Build
-
Milestone 4: Persistence foundation
- Design SQLite schema and migrations within
internal/storage
. - Implement repositories for sessions, messages, and models.
- Ensure path resolution to
$HOME/.local/share/goaichat/
with permission checks and tests.
- Design SQLite schema and migrations within
-
Milestone 5: Chat loop MVP
- Implement CLI loop that reads user input, calls chat client, prints responses.
- Integrate persistence for session creation, message storage,
/list
, and/models
commands. - Instrument logging and simple metrics.
-
Milestone 6: Terminal UI
- Integrate Bubble Tea UI replacing basic loop.
- Add viewport rendering, streaming display, command palette.
- Polish keyboard shortcuts and layout.
-
Milestone 7: Enhancements & polish
- Implement transcript saving, timestamp display, configurable prompts.
- Add optional plugins (command to open last response in $EDITOR).
- Harden error messages and retries; tune tests and docs.
Testing & Quality Strategy
- Unit tests Cover config parsing, validation, command parsing, token budgeting.
- Integration tests Use httptest server to simulate OpenAI API scenarios (success, auth error, rate limit, streaming).
- UI tests Leverage Bubble Tea test helpers to simulate model update cycles.
- Static analysis
golangci-lint
for vet, errcheck, gofmt. - Load testing (future) Add simple script to replay prompts for latency measurement.
Developer Tooling & DX
- Makefile Targets:
make build
,make test
,make lint
,make run
. - Task runner Optionally use
taskfile
ormage
. - Documentation Maintain
README.md
,docs/configuration.md
,docs/development.md
. - Sample configs Provide
config.example.yaml
without secrets. - Issue templates For bug reports and feature requests once repo public.
Deployment & Distribution
- Binary releases Cross-compile via
goreleaser
for Linux/macOS/Windows; ensureCGO_ENABLED=0
for static binaries. - Packaging Offer Homebrew tap or
go install
instructions. - Versioning Semantic versioning with tagged releases; changelog via
git-chglog
.
Future Extensions
- Plugin commands Shell hooks, sending to external tools, code interpreter.
- Multi-provider support Add adapters for Anthropic, local LLMs via OpenAI-compatible bridges.
- Conversation persistence SQLite-backed history with search.
- Team collaboration Shared sessions via websockets or tmux integration.
- Telemetry dashboard Optional Prometheus exporter for usage stats.
Risks & Mitigations
- API drift Mitigate with client abstraction and compatibility tests.
- Rate limits Implement exponential backoff, expose retry counters in UI.
- Secret leakage Ensure config accepts env vars, redact logs, document best practices.
- Terminal portability Provide fallback non-TUI mode for minimal terminals.