API Reference
This document describes the internal API and architecture of vibe-zsh for developers who want to understand how it works or contribute to the project.
Architecture Overview
βββββββββββββββββββ
β Zsh Plugin β
β (vibe.plugin) β
ββββββββββ¬βββββββββ
β
β Captures buffer
β on Ctrl+G
βΌ
βββββββββββββββββββββββββββββββββββββββββββββββ
β Go Binary (Cobra CLI) β
β ββββββββββββ¬βββββββββββ¬ββββββββββββββββββ β
β β root.go βhistory.goβ version/update β β
β ββββββββββββ΄βββββββββββ΄ββββββββββββββββββ β
ββββββββββ¬βββββββββββββββββββββββββββββββββββββ
β
ββββββββββββββββββββ¬βββββββββββββββββββ
β β β
βΌ βΌ βΌ
βββββββββββββββββββ ββββββββββββββββ ββββββββββββββββ
β Cache Layer β β LLM Client β β History β
β (internal/cache)β β(internal/ β β (internal/ β
β β β client) β β history) β
βββββββββββββββββββ ββββββββ¬ββββββββ ββββββββββββββββ
β
ββββββββββββββββββββΌβββββββββββββββββββ
β β β
βΌ βΌ βΌ
βββββββββββββββββββ ββββββββββββββββ ββββββββββββββββ
β Parser β β Schema β β Progress β
β (JSON/Text) β β (Prompts) β β (Spinner) β
βββββββββββββββββββ ββββββββββββββββ ββββββββββββββββ
β
β via gollm (native per-provider transport)
βΌ
ββββββββββββββββββββββββββββββββββββββββ
β LLM Provider β
β (OpenAI/Anthropic/Groq/OpenRouter/ β
β Ollama/LM Studio/vLLM/β¦) β
ββββββββββββββββββββββββββββββββββββββββCore Components
1. Zsh Plugin (vibe.plugin.zsh)
The entry point for user interaction.
Functions:
vibe() # Main function - generates command from natural language
vh() # Opens interactive history browser
vibe-regenerate() # Regenerates last command with same queryKey Variables:
VIBE_PLUGIN_DIR: Plugin installation directoryVIBE_BINARY: Path to the Go binaryBUFFER: Zsh variable containing current command line
Keybindings:
bindkey '^G' vibe # Ctrl+G - Generate command
bindkey '^Xh' vibe-history # Ctrl+X H - Browse history
bindkey '^Xg' vibe-regenerate # Ctrl+X G - Regenerate last2. Go Binary (Cobra CLI)
Main command-line interface built with Cobra.
Command Structure:
vibe-zsh [flags] <query>
vibe-zsh history [list|clear|last]
vibe-zsh version
vibe-zsh update
vibe-zsh check-updateFlags:
API Configuration:
--api-url string API endpoint URL (default: http://localhost:11434/v1)
--api-key string API authentication key
--model string Model to use (default: llama3:8b)
--temperature float Generation temperature 0.0-2.0 (default: 0.2)
--max-tokens int Maximum response tokens (default: 1000)
--timeout duration Request timeout (default: 30s)
Output Control:
--structured-output Use JSON schema for responses (default: true)
--explanation Show command explanations (default: true)
--warnings Show warnings for dangerous commands (default: true)
--interactive Confirm before executing commands (default: false)
Caching:
--cache Enable response caching (default: true)
--cache-ttl duration Cache lifetime (default: 24h)
Reliability:
--max-retries int Max retry attempts (default: 3)
--json-extraction Extract JSON from corrupted responses (default: true)
--strict-validation Validate response structure (default: true)
--retry-status Show retry progress (default: true)
UI/UX:
--progress Show progress spinner (default: true)
--progress-style string Spinner style: dots, line, circle, bounce, arrow, runes
--stream Stream output with typewriter effect (default: true)
--stream-delay duration Delay between streamed words (default: 20ms)
--debug Enable debug logging (default: false)Exit Codes:
0: Success1: Error (details on stderr)130: Interrupted (Ctrl+C)
3. Configuration (internal/config/config.go)
Manages all configuration from environment variables and command-line flags.
Type:
type Config struct {
// API Configuration
Provider string // gollm provider (openai/anthropic/ollama/β¦)
APIURL string
APIKey string
Model string
Temperature float64
MaxTokens int
Timeout time.Duration
// Output Control
UseStructuredOutput bool
ShowExplanation bool
ShowWarnings bool
InteractiveMode bool
// Caching
EnableCache bool
CacheDir string
CacheTTL time.Duration
// Reliability
MaxRetries int
EnableJSONExtraction bool
StrictValidation bool
ShowRetryStatus bool
// UI/UX
ShowProgress bool
ProgressStyle progress.SpinnerStyle
StreamOutput bool
StreamDelay time.Duration
EnableDebugLogs bool
// System Context
OSName string // Detected OS (macOS/Linux/Windows)
Shell string // Detected shell (zsh/bash/fish)
// History
EnableHistory bool
HistorySize int
HistoryKey string
RegenerateKey string
}Loading:
cfg := config.Load() // Loads from environment variablesEnvironment Variables:
All flags can be set via environment variables with VIBE_ prefix:
VIBE_PROVIDERVIBE_API_URLVIBE_MODELVIBE_TEMPERATUREVIBE_SHOW_PROGRESS- etc.
4. Client (internal/client/client.go)
Wraps a gollm LLM instance and the
vibe response-parsing pipeline. All provider-specific transport, authentication,
and retry logic is handled by gollm; this layer is responsible only for prompt
construction, the multi-strategy JSON parsing fallback, and caching.
Main Type:
type Client struct {
config *config.Config
llm gollm.LLM // built once from config in New()
initErr error // surfaced on first GenerateCommand if construction failed
cache *cache.Cache
}Construction:
func New(cfg *config.Config) *ClientNew builds the gollm LLM from the resolved config (provider, model, key,
generation params). gollm validates the configuration up front β hosted
providers require a correctly-formatted API key, and local providers must be
reachable. If construction fails, the error is stored and returned on the first
GenerateCommand call as an actionable message.
Primary Method:
func (c *Client) GenerateCommand(ctx context.Context, query string) (*schema.CommandResponse, error)Multi-Layer Fallback Strategy:
- Layer 1: Structured Output - Strong JSON-formatting system prompt + strict validation
- Layer 2: Enhanced Parsing - Extracts JSON from text with retries
- Layer 3: Explicit JSON Prompt - Adds explicit JSON formatting instructions (lower temperature)
- Layer 4: Emergency Fallback - Returns helpful error message
Generation:
All requests go through a single helper that calls gollm:
prompt := gollm.NewPrompt(query, gollm.WithSystemPrompt(systemPrompt, gollm.CacheTypeEphemeral))
c.llm.SetOption("temperature", temperature)
content, err := c.llm.Generate(ctx, prompt)gollm constructs the provider-native request (OpenAI chat completions, Anthropic messages, Ollama, etc.), attaches auth, applies retries with backoff, and respects context cancellation. vibe no longer maintains its own HTTP client, request/response structs, or retry loop.
5. Parser (internal/parser/text_parser.go)
Parses LLM responses with robust JSON extraction and text fallback.
Primary Functions:
// Extract valid JSON from corrupted/wrapped responses
func ExtractJSON(corruptedText string) (string, error)
// Parse text-based responses (fallback)
func ParseTextResponse(text string) (*schema.CommandResponse, error)
// Remove ANSI codes, Unicode garbage, etc.
func RemoveGarbagePatterns(text string) string
// Attempt to repair malformed JSON
func AttemptJSONRepair(text string) stringJSON Extraction Strategy:
- Find first
{and last}- validate as JSON - Apply
RemoveGarbagePatternsto clean text - Attempt
AttemptJSONRepairfor malformed JSON - Return error if all strategies fail
Text Parsing (Fallback):
Parses responses in format:
command
# explanation line 1
# explanation line 2
WARNING: dangerous operationHandles:
- Code blocks (```bash)
- Markdown formatting
- Comment prefixes (#, -, *)
- Warning detection
6. Cache (internal/cache/cache.go)
File-based caching system for responses with TTL support.
Type:
type Cache struct {
dir string
ttl time.Duration
}Methods:
func New(dir string, ttl time.Duration) (*Cache, error)
func (c *Cache) Get(query string) (*schema.CommandResponse, bool)
func (c *Cache) Set(query string, resp *schema.CommandResponse) error
func (c *Cache) Clear() errorCache Location:
~/.cache/vibe/Key Generation:
key := sha256(query) // Hashed query as filenameCache Entry Format:
{
"query": "original query",
"response": {
"command": "...",
"explanation": ["..."],
"warning": "..."
},
"timestamp": "2024-01-01T12:00:00Z",
"model": "llama3:8b",
"temperature": 0.2
}TTL Handling:
- Default: 24 hours
- Configurable via
VIBE_CACHE_TTL - Expired entries automatically ignored on read
7. Schema (internal/schema/schema.go)
Defines response structure, JSON schema, and system prompts.
Response Type:
type CommandResponse struct {
Command string `json:"command"`
Explanation []string `json:"explanation"`
Warning string `json:"warning,omitempty"`
Alternatives []string `json:"alternatives,omitempty"`
SafetyLevel string `json:"safety_level,omitempty"`
}
func (c *CommandResponse) Validate() errorJSON Schema:
func GetJSONSchema() map[string]interface{}Returns OpenAI-compatible JSON schema for structured output with:
- Required fields:
command,explanation - Optional fields:
warning,alternatives,safety_level - Strict validation enabled
System Prompt:
func GetSystemPrompt(osName, shell string) stringGenerates OS and shell-aware system prompt that:
- Includes OS context (macOS/Linux/Windows)
- Includes shell context (zsh/bash/fish)
- Warns about OS-specific utilities (BSD vs GNU)
- Enforces strict JSON formatting rules
- Prevents common LLM mistakes (markdown, Unicode, truncation)
Key Prompt Features:
- OS-specific command generation (e.g., BSD
findon macOS) - Strict JSON formatting requirements
- Complete explanation enforcement (no “…”, “???”)
- Warning detection for dangerous commands
- Portable POSIX command preference
8. Additional Components
Progress Spinner (internal/progress/spinner.go):
type Spinner struct {
frames []string
message string
// ...
}
func NewSpinner(style SpinnerStyle) *Spinner
func (s *Spinner) Start(ctx context.Context, initialMsg string)
func (s *Spinner) Update(msg string)
func (s *Spinner) Stop()Styles: dots, line, circle, bounce, arrow, runes
Streamer (internal/streamer/streamer.go):
type Streamer struct {
config *Config
writer io.Writer
}
func StreamWord(w io.Writer, text string, delay time.Duration) error
func StreamCharacter(w io.Writer, text string, delay time.Duration) error
func StreamLine(w io.Writer, text string, delay time.Duration) errorProvides typewriter effect for output.
History (internal/history/history.go):
type History struct {
dir string
maxSize int
filePath string
}
type Entry struct {
Query string `json:"query"`
Command string `json:"command"`
Timestamp time.Time `json:"timestamp"`
Count int `json:"count"`
}
func New(cacheDir string, maxSize int) (*History, error)
func (h *History) Add(query, command string) error
func (h *History) List() ([]Entry, error)
func (h *History) Clear() errorInteractive History UI (internal/history/ui.go):
func ShowInteractive(entries []Entry) (*SelectionResult, error)
func FormatPlainList(entries []Entry) stringUses Bubble Tea for TUI.
Confirmation Dialog (internal/confirm/confirm.go):
func ShowConfirmation(command string) (bool, error)Interactive confirmation prompt for dangerous commands.
Updater (internal/updater/updater.go):
func CheckForUpdatesBackground(currentVersion string)
func ShowUpdateNotification(currentVersion string)
func PerformUpdate(currentVersion string) errorChecks GitHub releases for updates.
Formatter (internal/formatter/formatter.go):
func Format(resp *schema.CommandResponse, showExplanation bool, showWarnings bool) stringFormats response for display.
Logger (internal/logger/logger.go):
func Init(enableDebug bool)
func Debug(format string, args ...interface{})
func LogParsingFailure(attempt int, layer, content string, err error)
func LogLayerSuccess(layer string, layerNum int)Debug logging system.
Errors (internal/errors/errors.go):
var (
ErrInvalidJSON = errors.New("invalid JSON")
ErrNoResponse = errors.New("no response from API")
ErrEmptyResponse = errors.New("empty response")
)
type APIError struct {
StatusCode int
Body string
}
func IsRetryable(err error) boolRequest Flow
User Input
- User types natural language
- Presses
Ctrl+G
Zsh Plugin
- Captures
$BUFFER - Calls Go binary:
vibe-zsh "$BUFFER"
- Captures
Cobra CLI
- Parses flags and arguments
- Initializes configuration
Configuration
- Loads environment variables
- Merges with command-line flags
- Detects OS and shell
Progress Spinner
- Starts spinner if TTY detected
- Shows “Checking cache…” message
Cache Check
- Generates SHA256 hash of query
- Checks
~/.cache/vibe/for cached response - Returns cached response if valid and not expired
LLM Request (Multi-Layer)
- Layer 1: Structured output with JSON schema
- Layer 2: Enhanced parsing with retries (up to 3)
- Layer 3: Explicit JSON prompt with lower temperature
- Layer 4: Emergency fallback with error message
Provider Request (via gollm)
- gollm builds the provider-native request and attaches authentication
- Applies retry logic with backoff internally
- Respects context cancellation (Ctrl+C)
Response Parsing
- Extracts JSON from response
- Validates structure
- Cleans explanations (removes ANSI codes, Unicode)
- Detects garbage/truncated text
Output Formatting
- Streams explanations to stderr with typewriter effect
- Detects and warns about incomplete explanations
- Shows warnings for dangerous commands
Interactive Confirmation (if enabled)
- Shows Bubble Tea confirmation dialog
- User can accept/reject command
Command Output
- Writes command to stdout (captured by Zsh)
- Saves to history if enabled
- Shows update notification if available
Zsh Plugin
- Reads stdout
- Replaces
$BUFFERwith command - User can edit or execute
Error Handling
Error Types
Network Errors:
- Connection refused β Check if API service is running
- Host not found β Check
VIBE_API_URL - Timeout β Check network connection
API Errors:
- 401 Unauthorized β Check
VIBE_API_KEY - 429 Rate Limited β Automatic retry with backoff
- 500 Server Error β Automatic retry with backoff
Parsing Errors:
- Invalid JSON β Falls back to text parsing
- Missing fields β Falls back to next layer
- Validation failure β Falls back to next layer
Cache Errors:
- Non-fatal, logged but don’t stop execution
History Errors:
- Non-fatal, logged but don’t stop execution
Error Output
All errors written to stderr:
fmt.Fprintf(os.Stderr, "Error: %v\n", err)
os.Exit(1)Retry Logic
Retryable errors:
- Network timeouts
- Connection errors
- 5xx status codes
- Rate limits (429)
Non-retryable errors:
- 4xx client errors (except 429)
- Invalid configuration
- Context cancellation
Backoff strategy:
- Initial: 1 second
- Multiplier: 2x
- Maximum: 10 seconds
- Max attempts: 3
Testing
Unit Tests
Run all tests:
make testTest specific package:
go test ./internal/parser
go test ./internal/config
go test ./internal/historyTest with coverage:
go test -cover ./...Test with verbose output:
go test -v ./internal/parserIntegration Tests
Test with live API:
export VIBE_API_URL="http://localhost:11434/v1"
export VIBE_MODEL="llama3:8b"
vibe-zsh "list all files"Test with debug logging:
vibe-zsh --debug "find python files"Test caching:
# First run - should hit API
vibe-zsh "list docker containers"
# Second run - should use cache
vibe-zsh "list docker containers"Test history:
vibe-zsh history list
vibe-zsh history last
vibe-zsh history clearTest interactive mode:
vibe-zsh --interactive "remove all logs"Testing Different Providers
Ollama:
export VIBE_PROVIDER="ollama"
export VIBE_API_URL="http://localhost:11434/v1"
export VIBE_MODEL="llama3:8b"OpenAI:
export VIBE_PROVIDER="openai"
export VIBE_API_KEY="sk-..."
export VIBE_MODEL="gpt-4o"LM Studio:
export VIBE_PROVIDER="lmstudio"
export VIBE_API_URL="http://localhost:1234/v1"
export VIBE_MODEL="local-model"Development
Building
make build # Current platform
make build-all # All platforms (Linux, macOS, Windows)
make install # Build and install to ~/.oh-my-zsh/custom/plugins/vibemake build/make install stamp the version from git tags by default. Use
make build-dev for a build stamped as dev (which the updater never tries to
self-update).
Build manually:
go build -o vibe -ldflags "-X main.version=$(git describe --tags)" main.goProject Structure
vibe-zsh/
βββ cmd/ # Cobra CLI commands
β βββ root.go # Main command + generation logic
β βββ history.go # History subcommands
βββ internal/
β βββ cache/ # Response caching
β βββ client/ # gollm LLM wrapper + parsing pipeline
β β βββ client.go # Main client with fallback layers
β βββ config/ # Configuration management
β βββ confirm/ # Interactive confirmation dialog
β βββ errors/ # Error types and handling
β βββ formatter/ # Response formatting
β βββ history/ # Query history management
β β βββ history.go # History storage
β β βββ ui.go # Interactive TUI
β βββ logger/ # Debug logging
β βββ parser/ # JSON extraction + text parsing
β βββ progress/ # Spinner animations
β βββ schema/ # Response schema + prompts
β βββ streamer/ # Typewriter effect output
β βββ updater/ # Auto-update functionality
βββ main.go # Entry point
βββ vibe.plugin.zsh # Zsh integrationAdding a New Feature
Example: Adding a new spinner style
- Add style to
internal/progress/spinner.go:
const StyleCustom SpinnerStyle = "custom"
var spinnerFrames = map[SpinnerStyle][]string{
// ...
StyleCustom: {"β£Ύ", "β£½", "β£»", "β’Ώ", "β‘Ώ", "β£", "β£―", "β£·"},
}- Update config parser in
cmd/root.go:
case "custom":
return progress.StyleCustom- Update documentation
Example: Adding a new command
- Create new file in
cmd/:
package cmd
var myCmd = &cobra.Command{
Use: "mycommand",
Short: "Description",
Run: func(cmd *cobra.Command, args []string) {
// Implementation
},
}
func init() {
rootCmd.AddCommand(myCmd)
}- Add tests
- Update documentation
Extending Functionality
Adding a new configuration option:
- Add to
Configstruct ininternal/config/config.go - Add environment variable parsing with
getEnv*helper - Add command-line flag in
cmd/root.go - Add flag handling in
initConfig() - Update documentation
- Add tests
Modifying the system prompt:
- Edit
GetSystemPrompt()ininternal/schema/schema.go - Test with multiple LLM providers (Ollama, OpenAI, Claude)
- Ensure OS-specific instructions work correctly
- Test with different shells (zsh, bash)
- Verify JSON output format compliance
Adding a new parsing layer:
- Add method to
Clientininternal/client/client.go - Call in
GenerateCommand()fallback chain - Add logging with
logger.LogLayerSuccess() - Add error handling with
logger.LogParsingFailure() - Test with various LLM outputs
Contributing
See the main README for contribution guidelines.
Code Style
- Follow standard Go conventions
- Use
gofmtfor formatting - Run
go vetbefore committing - Add tests for new functionality
- Update documentation
- Keep functions focused and small
- Use meaningful variable names
- Add comments for complex logic
Pull Request Process
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Make your changes
- Add tests (
go test ./...) - Update documentation (README, API docs, usage docs)
- Commit with clear messages
- Push to your fork
- Submit PR with description of changes
Testing Checklist
Before submitting PR:
- All tests pass (
make test) - Code is formatted (
gofmt -w .) - No lint errors (
go vet ./...) - Documentation updated
- Tested with Ollama
- Tested with OpenAI (if applicable)
- Tested on macOS (if applicable)
- Tested on Linux (if applicable)
Dependencies
vibe-zsh uses minimal external dependencies:
Core Dependencies:
github.com/teilomillet/gollm- Multi-provider LLM access (transport, auth, retries)github.com/spf13/cobra- CLI frameworkgithub.com/charmbracelet/bubbletea- TUI frameworkgithub.com/charmbracelet/bubbles- TUI componentsgithub.com/charmbracelet/lipgloss- Terminal styling
Standard Library:
encoding/json- JSON parsingcrypto/sha256- Cache key generationcontext- Cancellation and timeoutsos,io,time,strings, etc.
Why These Dependencies?
- gollm: Native, multi-provider LLM client β removes the need to maintain a bespoke HTTP client, request/response structs, and retry logic, and adds first-class support for providers like Anthropic that aren’t OpenAI-compatible
- Cobra: Industry-standard CLI framework with excellent flag parsing
- Bubble Tea: Modern, composable TUI framework for interactive features
- Lipgloss: Beautiful terminal styling without complexity
Provider Support
vibe-zsh talks to each provider natively through gollm, so the request/response wire format is provider-specific and handled by gollm β vibe does not construct raw HTTP payloads itself.
Provider kinds:
- Hosted (
openai,anthropic,groq,openrouter,deepseek,google-openai,mistral,cohere) β fixed endpoint, require an API key whose format is validated at startup. - Local (
ollama,lmstudio,vllm) β reachable at a user-suppliedVIBE_API_URL; no API key, but must be running when vibe starts.
Select a provider with VIBE_PROVIDER, or let vibe infer it from VIBE_API_URL.
openai provider always targets api.openai.com. For a self-hosted
OpenAI-compatible gateway, use the lmstudio or vllm provider and set
VIBE_API_URL.Performance Considerations
Caching:
- Cache hits return in <1ms
- Cache misses require API call (1-5s depending on model)
- Cache stored in
~/.cache/vibe/ - Default TTL: 24 hours
Network:
- Timeout: 30s default
- Retry: handled by gollm (configurable via
VIBE_MAX_RETRIES) - Transport managed by gollm’s provider clients
Memory:
- Minimal memory footprint (~10MB)
- No persistent connections
- Cache files are small (<1KB each)
Startup:
- Cold start: ~50ms
- Warm start (cached): <10ms
Security Considerations
API Keys:
- Never logged or printed
- Stored in environment variables only
- Transmitted via HTTPS only
- Not included in cache files
Command Execution:
- Commands never auto-executed
- Interactive mode available for confirmation
- Warnings shown for dangerous commands
- User always has final control
Cache:
- Stored in user’s home directory
- Readable only by user (0644 permissions)
- No sensitive data stored
- Can be cleared anytime
Network:
- HTTPS enforced for remote APIs
- Certificate validation enabled
- No telemetry or tracking
- All requests user-initiated