<!--
SPDX-FileCopyrightText: Amolith <amolith@secluded.site>

SPDX-License-Identifier: CC0-1.0
-->

# Architecture & Design

This document provides a comprehensive guide to the codebase architecture and core design decisions. The project uses a clean three-layer architecture that separates concerns between MCP server handling, business logic, and API client operations.

## Architecture Overview

This is an MCP (Model Context Protocol) server that exposes Lunatask API functionality to LLMs. The codebase uses a clean three-layer architecture:

### Layer 1: Main Entry Point (`cmd/lunatask-mcp-server.go`)

- Loads TOML configuration from `config.toml` (or custom path via `-c/--config`)
- Creates and configures the MCP SSE server (Server-Sent Events transport)
- Implements Provider interfaces (`AreaProvider`, `GoalProvider`, `HabitProvider`) that wrap config structs
- Registers all MCP tools with their handlers
- Validates configuration on startup (areas/goals must have names and IDs, timezone must be valid)

### Layer 2: Tools Package (`tools/`)

- Bridges MCP tool calls to Lunatask API client
- Handles MCP request/response formatting
- Performs pre-validation and argument transformation (e.g., string priorities → integers)
- Consumes Provider interfaces to access configuration without tight coupling
- Contains handlers for: timestamp parsing, area/goal listing, task CRUD, habit tracking

### Layer 3: Lunatask Package (`lunatask/`)

- Low-level HTTP client for Lunatask REST API (`https://api.lunatask.app/v1`)
- Defines request/response types with JSON tags
- Uses `go-playground/validator` for request validation
- Contains API methods for tasks (`CreateTask`, `UpdateTask`, `DeleteTask`) and habits (`TrackHabitActivity`)

## Key Design Patterns

**Provider Interfaces**: The tools package defines `AreaProvider`, `GoalProvider`, and `HabitProvider` interfaces. The main package's config structs implement these, allowing tools to access config data without importing main or knowing config structure details.

**String-to-Integer Mapping**: MCP tools accept human-readable strings that get translated to API integers:
- Priority: `"lowest"`=-2, `"low"`=-1, `"neutral"`=0, `"high"`=1, `"highest"`=2
- Eisenhower matrix: `"uncategorised"`=0, `"both urgent and important"`=1, `"urgent, but not important"`=2, `"important, but not urgent"`=3, `"neither urgent nor important"`=4

**Natural Language Date Parsing**: Uses `github.com/ijt/go-anytime` with timezone support. The `get_timestamp` tool parses expressions like "tomorrow at 3pm" into RFC3339 timestamps. Timezone is configured in `config.toml` using IANA/Olson format (e.g., `America/New_York`).

## Validation Happens at Two Levels

1. **Tools layer**: Type checking, area/goal relationship validation, string-to-int translation
2. **Lunatask layer**: go-playground/validator tags enforce API constraints (UUID format, string lengths, numeric ranges, enum values)

This prevents invalid requests from reaching the API and provides better error messages.
