@@ -0,0 +1,158 @@
+# AGENTS.md
+
+This file provides guidance to AI coding agents when working with code in this repository.
+
+## Build Commands
+
+All commands use `just` task runner:
+
+- **Development workflow**: `just` (runs fmt, lint, staticcheck, test, vuln, reuse)
+- **Format code**: `just fmt` (uses gofumpt)
+- **Lint**: `just lint` (uses golangci-lint)
+- **Static analysis**: `just staticcheck` (uses staticcheck)
+- **Test**: `just test` (runs all tests with verbose output)
+- **Single test**: `go test -v ./path/to/package -run TestName`
+- **Vulnerability check**: `just vuln` (uses govulncheck)
+- **License compliance**: `just reuse` (REUSE specification)
+- **Build**: `just build` (outputs to `./lunatask-mcp-server`, supports GOOS/GOARCH env vars)
+- **Run**: `just run` (builds and runs with version injection)
+- **Compress binary**: `just pack` (requires upx, run after build)
+- **Clean**: `just clean` (removes binary) or `just clean-all` (removes binary and config)
+
+Version is injected at build time via git describe, so always use `just build` or `just run` rather than plain `go build`.
+
+## Licensing
+
+This project is REUSE compliant. All files must have SPDX headers:
+
+- **Code files** (`.go`): `SPDX-License-Identifier: AGPL-3.0-or-later`
+- **Documentation** (`.md`, `.toml`): `SPDX-License-Identifier: CC0-1.0`
+- **Copyright**: `SPDX-FileCopyrightText: Amolith <amolith@secluded.site>`
+
+Always include both lines in new files.
+
+## 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`).
+
+## Configuration System
+
+On first run, the server generates `config.toml` with placeholder values and exits. Users must:
+
+1. Add their Lunatask API access token
+2. Configure areas with real IDs from Lunatask (areas can have nested goals)
+3. Configure habits with real IDs
+4. Set timezone in IANA format (e.g., `America/New_York`, not `EST`)
+5. Optionally customize server host/port (defaults to `localhost:8080`)
+
+The config uses TOML (not JSON) per project philosophy. Example structure:
+
+```toml
+access_token = "your-token"
+timezone = "America/New_York"
+
+[server]
+host = "localhost"
+port = 8080
+
+[[area]]
+name = "Work"
+id = "uuid-here"
+
+ [[area.goal]]
+ name = "Q1 Project"
+ id = "uuid-here"
+
+[[habit]]
+name = "Exercise"
+id = "uuid-here"
+```
+
+## Critical Implementation Details
+
+### Goal Validation in Task Operations
+
+When creating or updating tasks with a `goal_id`, the tools package validates that the goal belongs to the specified area. This prevents associating tasks with goals from different areas, which Lunatask may reject or handle incorrectly.
+
+### Update vs Create Semantics
+
+`UpdateTask` reuses `CreateTaskRequest` type but has different semantics:
+- Only provided fields are updated (partial updates)
+- Empty strings for text fields (name, note, scheduled_on) clear existing values
+- Empty strings for enum fields (status, motivation) also clear values
+- The tools handler only sends fields present in MCP request arguments
+
+### Empty Package Files
+
+`lunatask/notes.go`, `lunatask/people.go`, and `lunatask/timeline.go` exist but are empty. These are placeholders for future Lunatask API features. Don't remove them without checking if they're imported elsewhere.
+
+### MCP Tool Workflow Dependencies
+
+Several tools must be called in specific order:
+1. `list_areas_and_goals` → provides IDs for `create_task`/`update_task`
+2. `get_timestamp` → provides formatted timestamps for task scheduling and habit tracking
+3. `list_habits_and_activities` → provides IDs for `track_habit_activity`
+
+The MCP tool descriptions document these workflows, and the LLM system prompts (in README.md) reinforce the pattern.
+
+### 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.
+
+### Version Injection
+
+The `version` variable in main is set via ldflags during build: `-ldflags "-X main.version=..."`. The justfile extracts version from `git describe --long`. Don't hardcode version strings; if version is empty, it displays a helpful message about using `just build`.
+
+## Testing Considerations
+
+- Tests should use `go test -v ./...` to run all packages
+- Mock the HTTP client in lunatask package tests (set `Client.HTTPClient` to custom `*http.Client`)
+- Mock Provider interfaces in tools package tests
+- Timezone-dependent tests should explicitly set timezone in config
+- Natural language date parsing is non-deterministic (relative to "now"), so test with absolute dates or mock time
+
+## Related Documentation
+
+The README.md contains extensive documentation about:
+- MCP tool descriptions and parameters (authoritative reference for tool behavior)
+- Example LLM system prompts showing real-world usage patterns
+- User-specific workflow rules (area workflows, estimate requirements, status defaults)
+- Contribution workflow using pr.pico.sh (SSH-based patches, no GitHub account needed)
+
+When modifying tools, ensure MCP descriptions in `cmd/lunatask-mcp-server.go` stay synchronized with actual behavior.