AGENTS.md

AGENTS.md

MCP server exposing Lunatask to LLMs. Primary use case is letting the user say "remind me to call mom tomorrow" to their preferred MCP-supporting LLM, that LLM calls create_task, and the user sees the task in their desktop/mobile apps.

If you know what doc-agent is, use it to check go module APIs often. You can check context7 for details on various libraries directly if the MCP tools are available:

Commands

Run in order of most to least often

task fmt lint:fix test # frequently
task # before committing

Architecture

cmd/lunatask-mcp-server.go  → Config, tool registration, SSE server
tools/
  ├── areas/               → list_areas_and_goals tool
  ├── habits/              → list_habits, track_habit tools
  ├── tasks/               → create/update/delete_task tools
  ├── timestamp/           → get_timestamp tool
  └── shared/              → Provider interfaces, error helpers

Data flow: SSE/STDIO request → MCP server → tool handler → lunatask client → Lunatask API

Domain model: Areas contain Goals. Habits are separate. Tasks always belong to an Area and might belong to a Goal within that area.

Adding New Functionality

New MCP tool:

  1. Create package in tools/ with Handler type and NewHandler() constructor
  2. Add handler methods (Handle, HandleCreate, etc.) returning (*mcp.CallToolResult, error)
  3. Put description constants in prose.go within the package
  4. Register tool with mcpServer.AddTool() in cmd/lunatask-mcp-server.go

Key Patterns

  • 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
  • Error returns: Handlers return (result, nil) with IsError: true—application errors go in the result, not the Go error
  • Enum translation: Human strings ("high") → API integers (1) in handlers before calling client
  • Provider interfaces: tools/ defines interfaces (AreaProvider, etc.) that cmd/ types implement, keeping packages decoupled

Gotchas

  • Area/goal/habit IDs are static in config, not fetched—Lunatask API has no list endpoint
  • CreateTask returns (nil, nil) on HTTP 204 (task already exists)—not an error
  • No tests exist yet
  • All files need appropriate SPDX headers based on content (task reuse checks this)