Files
tasksquire/AGENTS.md
2026-02-02 10:55:47 +01:00

6.4 KiB

Agent Development Guide for TaskSquire

This guide is for AI coding agents working on TaskSquire, a Go-based TUI (Terminal User Interface) for Taskwarrior.

Project Overview

  • Language: Go 1.22.2
  • Architecture: Model-View-Update (MVU) pattern using Bubble Tea framework
  • Module: tasksquire
  • Main Dependencies: Bubble Tea, Lip Gloss, Huh, Bubbles (Charm ecosystem)

Build, Test, and Lint Commands

Building and Running

# Run directly
go run main.go

# Build binary
go build -o tasksquire main.go

# Run tests
go test ./...

# Run tests for a specific package
go test ./taskwarrior

# Run a single test
go test ./taskwarrior -run TestTaskSquire_GetContext

# Run tests with verbose output
go test -v ./taskwarrior

# Run tests with coverage
go test -cover ./...

Linting and Formatting

# Format code (always run before committing)
go fmt ./...

# Lint with golangci-lint (available via nix-shell)
golangci-lint run

# Vet code for suspicious constructs
go vet ./...

# Tidy dependencies
go mod tidy

Development Environment

# Enter Nix development shell (provides all tools)
nix develop

# Or use direnv (automatically loads .envrc)
direnv allow

Project Structure

tasksquire/
├── main.go              # Entry point: initializes TaskSquire, TimeSquire, and Bubble Tea
├── common/              # Shared state, components interface, keymaps, styles, utilities
├── pages/               # UI pages/views (report, taskEditor, timePage, pickers, etc.)
├── components/          # Reusable UI components (input, table, timetable, picker)
├── taskwarrior/         # Taskwarrior CLI wrapper, models, config
├── timewarrior/         # Timewarrior integration, models, config
└── test/                # Test fixtures and data

Code Style Guidelines

Imports

  • Standard Library First: Group standard library imports, then third-party, then local
  • Local Import Pattern: Use tasksquire/<package> for internal imports
import (
    "context"
    "fmt"
    "log/slog"
    
    tea "github.com/charmbracelet/bubbletea"
    "github.com/charmbracelet/lipgloss"
    
    "tasksquire/common"
    "tasksquire/taskwarrior"
)

Naming Conventions

  • Exported Types: PascalCase (e.g., TaskSquire, ReportPage, Common)
  • Unexported Fields: camelCase (e.g., configLocation, activeReport, pageStack)
  • Interfaces: Follow Go convention, often ending in 'er' (e.g., TaskWarrior, TimeWarrior, Component)
  • Constants: PascalCase or SCREAMING_SNAKE_CASE for exported constants
  • Test Functions: TestFunctionName or TestType_Method

Types and Interfaces

  • Interface-Based Design: Use interfaces for main abstractions (see TaskWarrior, TimeWarrior, Component)
  • Struct Composition: Embed common state (e.g., pages embed or reference *common.Common)
  • Pointer Receivers: Use pointer receivers for methods that modify state or for consistency
  • Generic Types: Use generics where appropriate (e.g., Stack[T] in common/stack.go)

Error Handling

  • Logging Over Panicking: Use log/slog for structured logging, typically continue execution
  • Error Returns: Return errors from functions, don't log and return
  • Context: Errors are often logged with slog.Error() or slog.Warn() and execution continues
// Typical pattern
if err != nil {
    slog.Error("Failed to get tasks", "error", err)
    return nil // or continue with default behavior
}

Concurrency and Thread Safety

  • Mutex Protection: Use sync.Mutex to protect shared state (see TaskSquire.mu)
  • Lock Pattern: Lock before operations, defer unlock
ts.mu.Lock()
defer ts.mu.Unlock()

Configuration and Environment

  • Environment Variables: Respect TASKRC and TIMEWARRIORDB
  • Fallback Paths: Check standard locations (~/.taskrc, ~/.config/task/taskrc)
  • Config Parsing: Parse Taskwarrior config format manually (see taskwarrior/config.go)

MVU Pattern (Bubble Tea)

  • Components Implement: Init() tea.Cmd, Update(tea.Msg) (tea.Model, tea.Cmd), View() string
  • Custom Messages: Define custom message types for inter-component communication
  • Cmd Chaining: Return commands from Init/Update to trigger async operations
type MyMsg struct {
    data string
}

func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
    switch msg := msg.(type) {
    case MyMsg:
        // Handle custom message
        return m, nil
    }
    return m, nil
}

Styling with Lip Gloss

  • Centralized Styles: Define styles in common/styles.go
  • Theme Colors: Parse colors from Taskwarrior config
  • Reusable Styles: Create style functions, not inline styles

Testing

  • Table-Driven Tests: Use struct slices for test cases
  • Test Setup: Create helper functions like TaskWarriorTestSetup()
  • Temp Directories: Use t.TempDir() for isolated test environments
  • Prep Functions: Include prep func() in test cases for setup

Documentation

  • TODO Comments: Mark future improvements with // TODO: description
  • Package Comments: Document package purpose at the top of main files
  • Exported Functions: Document exported functions, types, and methods

Common Patterns

Page Navigation

  • Pages pushed onto stack via common.PushPage()
  • Pop pages with common.PopPage()
  • Check for subpages with common.HasSubpages()

Task Operations

// Get tasks for a report
tasks := ts.GetTasks(report, "filter", "args")

// Import/create task
ts.ImportTask(&task)

// Mark task done
ts.SetTaskDone(&task)

// Start/stop task
ts.StartTask(&task)
ts.StopTask(&task)

JSON Handling

  • Custom Marshal/Unmarshal for Task struct to handle UDAs (User Defined Attributes)
  • Use json.RawMessage for flexible field handling

Key Files to Reference

  • common/component.go - Component interface definition
  • common/common.go - Shared state container
  • taskwarrior/taskwarrior.go - TaskWarrior interface and implementation
  • pages/main.go - Main page router pattern
  • taskwarrior/models.go - Data model examples

Development Notes

  • Logging: Application logs to app.log in current directory
  • Virtual Tags: Filter out Taskwarrior virtual tags (see virtualTags map)
  • Color Parsing: Custom color parsing from Taskwarrior config format
  • Debugging: VSCode launch.json configured for remote debugging on port 43000