feat(habits)!: enhance habit tracking with consolidated tools

Amolith created

Introduces a more robust mechanism for tracking habits and activities.
This change renames the configuration key for habits and updates the
LLM tools for better interaction and functionality.

The `Config.Habits` field in `config.toml` has been renamed to
`Config.Habit` for consistency and to support these enhancements.

The `list_habits` tool has been removed. It is replaced by the new
`list_habits_and_activities` tool. This tool lists habits and their
IDs, enabling the LLM to better identify entries for tracking or
marking completion via the `track_habit_activity` tool. The description
for `track_habit_activity` has also been updated.

The prompt guidance in `README.md` is updated to leverage these changes,
instructing the LLM to use `list_habits_and_activities` to find
relevant habits when a user indicates completion of a task without
other context.

BREAKING CHANGE:
- The configuration field `Habits` in `config.toml` has been renamed
  to `Habit`. Users must update their configuration files:
  e.g., `Habits = [...]` should become `Habit = [...]`.
- The LLM tool `list_habits` has been removed and is superseded by
  `list_habits_and_activities`. LLM prompts or integrations relying
  on the `list_habits` tool must be updated.

Change summary

README.md |  6 +++++-
main.go   | 48 ++++++++++++++++++++++++------------------------
2 files changed, 29 insertions(+), 25 deletions(-)

Detailed changes

README.md 🔗

@@ -55,7 +55,11 @@ I'm currently using `google/gemini-2.5-flash-preview:thinking` through
 >
 > Task names should be in sentence case.
 >
-> For every request to create a task/reminder:
+> When asked to mark something complete or when the user says they've done
+> something and you have no other context, check the list_habits_and_activities
+> tool for related entries. If one matches, pass its ID to track_habit_activity.
+>
+> For every request to create or change a task/reminder:
 >
 > 1. List the areas and goals and consider which one area is most relevant.
 >    Consider whether the task belongs within any of that area's goals.

main.go 🔗

@@ -51,7 +51,7 @@ type Config struct {
 	Areas       []Area       `toml:"areas"`
 	Server      ServerConfig `toml:"server"`
 	Timezone    string       `toml:"timezone"`
-	Habits      []Habit      `toml:"habits"`
+	Habit       []Habit      `toml:"habit"`
 }
 
 var version = ""
@@ -218,27 +218,6 @@ func NewMCPServer(config *Config) *server.MCPServer {
 		},
 	)
 
-	mcpServer.AddTool(
-		mcp.NewTool(
-			"list_habits",
-			mcp.WithDescription("List habits and their IDs."),
-		),
-		func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) {
-			var b strings.Builder
-			for _, habit := range config.Habits {
-				fmt.Fprintf(&b, "- %s: %s\n", habit.Name, habit.ID)
-			}
-			return &mcp.CallToolResult{
-				Content: []mcp.Content{
-					mcp.TextContent{
-						Type: "text",
-						Text: b.String(),
-					},
-				},
-			}, nil
-		},
-	)
-
 	mcpServer.AddTool(mcp.NewTool("create_task",
 		mcp.WithDescription("Creates a new task"),
 		mcp.WithString("area_id",
@@ -334,8 +313,29 @@ func NewMCPServer(config *Config) *server.MCPServer {
 		return handleDeleteTask(ctx, request, config)
 	})
 
+	mcpServer.AddTool(
+		mcp.NewTool(
+			"list_habits_and_activities",
+			mcp.WithDescription("List habits and their IDs for tracking or marking complete with tracking_habit_activity"),
+		),
+		func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) {
+			var b strings.Builder
+			for _, habit := range config.Habit {
+				fmt.Fprintf(&b, "- %s: %s\n", habit.Name, habit.ID)
+			}
+			return &mcp.CallToolResult{
+				Content: []mcp.Content{
+					mcp.TextContent{
+						Type: "text",
+						Text: b.String(),
+					},
+				},
+			}, nil
+		},
+	)
+
 	mcpServer.AddTool(mcp.NewTool("track_habit_activity",
-		mcp.WithDescription("Tracks an activity for a habit in Lunatask"),
+		mcp.WithDescription("Tracks an activity or a habit in Lunatask"),
 		mcp.WithString("habit_id",
 			mcp.Description("ID of the habit to track activity for."),
 			mcp.Required(),
@@ -757,7 +757,7 @@ func createDefaultConfigFile(configPath string) {
 				ID:   "goal-id-placeholder",
 			}},
 		}},
-		Habits: []Habit{{
+		Habit: []Habit{{
 			Name: "Example Habit",
 			ID:   "habit-id-placeholder",
 		}},