1<!--
2SPDX-FileCopyrightText: Amolith <amolith@secluded.site>
3
4SPDX-License-Identifier: CC0-1.0
5-->
6
7# AGENTS.md
8
9MCP server exposing Lunatask (task/habit tracker) to LLMs via SSE. Primary use case: Home Assistant voice assistant says "remind me to call mom tomorrow" → HA's LLM calls this server's `create_task` tool → task appears in Lunatask.
10
11All of Lunatask's API docs are local (uncommitted), so feel free to read them _liberally_ while working on the client. The index, telling you which files to read for which topics, is in lunatask/docs/index.md
12
13## Commands
14
15```sh
16just # Run all checks (fmt, lint, staticcheck, test, vuln, reuse)
17just build # Build with version info
18just run # Build and run
19```
20
21## Architecture
22
23```
24cmd/lunatask-mcp-server.go → Config, tool registration, SSE server
25tools/ → MCP tool handlers
26```
27
28**Data flow**: SSE request → MCP server → tool handler → lunatask client → Lunatask API
29
30**Domain model**: Areas contain Goals. Habits are separate. Tasks belong to an Area and optionally a Goal.
31
32## Adding New Functionality
33
34**New MCP tool**:
351. Add handler method to `tools/` (on `Handlers` struct)
362. Register tool with `mcpServer.AddTool()` in `cmd/lunatask-mcp-server.go`
37
38**New API endpoint**: Add method to `lunatask/Client` with request/response types
39
40## Key Patterns
41
42- **Tool descriptions are prompts**: The verbose `mcp.WithDescription()` strings guide the *calling* LLM's behavior—they explain workflows, valid values, and when to use each tool
43- **Error returns**: Handlers return `(result, nil)` with `IsError: true`—application errors go in the result, not the Go error
44- **Enum translation**: Human strings (`"high"`) → API integers (`1`) in handlers before calling client
45- **Provider interfaces**: `tools/` defines interfaces (`AreaProvider`, etc.) that `cmd/` types implement, keeping packages decoupled
46
47## Gotchas
48
49- Area/goal/habit IDs are static in config, not fetched—Lunatask API has no list endpoint
50- `CreateTask` returns `(nil, nil)` on HTTP 204 (task already exists)—not an error
51- `update_task` MCP tool requires `name` even for partial updates
52- No tests exist yet
53- All files need SPDX headers (`just reuse` checks this)